diff --git a/src/generator.coffee b/src/generator.coffee index a9a1b1a..110ba29 100644 --- a/src/generator.coffee +++ b/src/generator.coffee @@ -58,6 +58,11 @@ validateParameters = (parameters, models, path, method) -> # only on put an post unless method?.toLowerCase() in ['put', 'post'] throw new Error("#{errorPrefix} does not allowed body parameters - do you really knows http ?") + + # only known dataType + allowedDataTypes = ['byte', 'boolean', 'int', 'long', 'float', 'double', 'string', 'date', 'file'] + unless parameter.dataType?.toLowerCase() in allowedDataTypes or models[parameter.dataType] + throw new Error("'#{parameter.dataType}' does not match an allowed dataType [#{allowedDataTypes}] nor a known model [#{Object.keys(models)}]") when 'header', 'query' # nothing to check else @@ -105,9 +110,9 @@ addRoutes = (descriptor, resources) -> throw new Error("Resource must contain 'api' attribute") # add models - if _.isObject(resource.api.models) - for id, model of resource.api.models - descriptor.models[id] = validateModel(model, id, descriptor.models) + resource.api.models or= {} + for id, model of resource.api.models + descriptor.models[id] = validateModel(model, id, descriptor.models) # allow api without controllers, but do not generate routes if _.isObject(resource.controller) @@ -132,10 +137,21 @@ addRoutes = (descriptor, resources) -> unless _.isString(operation.nickname) throw new Error("Api #{api.path} operation #{operation.httpMethod} does not specify a nickname - we cannot guess the corresponding controller method") + # make sure the responseClass model is defined + if operation.responseClass + resource.api.models[operation.responseClass] or= descriptor.models[operation.responseClass] + unless resource.api.models[operation.responseClass] + throw new Error("responseClass #{operation.responseClass} doesn't match a model") + # Validates parameters if _.isArray(operation.parameters) # parameter validations validateParameters(operation.parameters, descriptor.models, api.path, operation.httpMethod) + + # make sure the dataType model is defined + for parameter in operation.parameters + if parameter.dataType + resource.api.models[parameter.dataType] or= descriptor.models[parameter.dataType] route = utils.pathToRoute(api.path) unless operation.nickname of resource.controller @@ -199,7 +215,9 @@ module.exports = (app, descriptor, resources, options = {}) -> # Add descriptor to express application for other middlewares app.descriptor = descriptor catch err - throw new Error("Failed to create routes from resources: #{err.toString()}"); + err2 = new Error("Failed to create routes from resources: #{err.toString()}") + err2.stack = err.stack + throw err2; # Express middleware for serving the descRoute. return (req, res, next) -> @@ -225,4 +243,4 @@ module.exports = (app, descriptor, resources, options = {}) -> return res.json(result) - next() \ No newline at end of file + next() diff --git a/test/apiGeneration.coffee b/test/apiGeneration.coffee index 76ca9a9..e0fb37b 100644 --- a/test/apiGeneration.coffee +++ b/test/apiGeneration.coffee @@ -456,6 +456,7 @@ describe 'API generation tests', -> httpMethod: 'GET' ] ], + models: {}, resourcePath: '/source' server.close() done() @@ -475,10 +476,13 @@ describe 'API generation tests', -> .use(swagger.generator(app, apiVersion: '1.0', basePath: root - , [ + , [{ + api: require './fixtures/addressApi.yml' + controller: passed: (req, res) -> res.json status: 'passed' + },{ api: require './fixtures/complexApi.yml' controller: passed: (req, res) -> res.json status: 'passed' - ])) + }])) # use validator also because it manipulates models .use(swagger.validator(app)) server = http.createServer app @@ -491,7 +495,7 @@ describe 'API generation tests', -> it 'should reference models be untouched', (done) -> # when requesting the API description details request.get - url: 'http://'+host+':'+port+'/api-docs.json/example' + url: 'http://'+host+':'+port+'/api-docs.json/address' json: true , (err, res, body) -> return done err if err? @@ -500,14 +504,14 @@ describe 'API generation tests', -> assert.deepEqual body, apiVersion: '1.0' basePath: '/api' - resourcePath: '/example' + resourcePath: '/address' apis: [ - path: '/example' + path: '/address' operations: [ httpMethod: 'POST' nickname: 'passed' parameters: [ - dataType: 'User' + dataType: 'Address' paramType: 'body' required: true ] @@ -524,18 +528,11 @@ describe 'API generation tests', -> city: type: 'string' - User: - id: 'User' + SomethingElse: + id: 'SomethingElse' properties: - id: - type: 'int' - required: true name: type: 'string' - addresses: - type: 'array' - items: - $ref: 'Address' done() describe 'given a properly configured and started server', -> @@ -682,4 +679,5 @@ describe 'API generation tests', -> nickname: 'remove' ] ] - done() \ No newline at end of file + models: {} + done() diff --git a/test/fixtures/addressApi.yml b/test/fixtures/addressApi.yml new file mode 100644 index 0000000..087f6d4 --- /dev/null +++ b/test/fixtures/addressApi.yml @@ -0,0 +1,31 @@ +resourcePath: /address +apis: + +- path: /address + operations: + + - httpMethod: POST + nickname: passed + parameters: + + - dataType: Address + paramType: body + required: true + +models: + + Address: + id: Address + properties: + zipcode: + type: long + street: + type: string + city: + type: string + + SomethingElse: + id: SomethingElse + properties: + name: + type: string diff --git a/test/fixtures/complexApi.yml b/test/fixtures/complexApi.yml index 4e9e840..8a1a3fb 100644 --- a/test/fixtures/complexApi.yml +++ b/test/fixtures/complexApi.yml @@ -6,6 +6,7 @@ apis: - httpMethod: POST nickname: passed + responseClass: SomethingElse parameters: - dataType: User @@ -14,16 +15,6 @@ apis: models: - Address: - id: Address - properties: - zipcode: - type: long - street: - type: string - city: - type: string - User: id: User properties: @@ -35,4 +26,4 @@ models: addresses: type: array items: - $ref: Address \ No newline at end of file + $ref: Address