swagger-express-middleware icon indicating copy to clipboard operation
swagger-express-middleware copied to clipboard

mock middleware doesn't respect allOf

Open copitz opened this issue 7 years ago • 2 comments

At first: Thank you so much for developing and sharing this awesome project - loving it!

With the 1.0.0-alpha.12 and the following yaml:

paths:
  /applications:
    get:
      tags:
        - applications
      summary: Get all applications
      responses:
        '200':
          description: List of applications
          schema:
            type: array
            items:
              $ref: '#/definitions/application'
    post:
      tags:
        - applications
      summary: Create a new application
      consumes:
        - application/json
      parameters:
        - in: body
          name: properties
          description: Properties of the application to create
          schema:
            type: object
            allOf:
              - $ref: '#/definitions/application'
              - type: object
                required: [type]
                properties:
                  type:
                    readOnly: false
      responses:
        201:
          description: application created

definitions:
  application:
    type: object
    description: Information about an application
    required:
      - name
    properties:
      id:
        type: integer
        example: 2412
        readOnly: true
      type:
        type: string
        example: store
        readOnly: true
      name:
        type: string
        example: Store application 1

I get the following exception

TypeError: Cannot read property 'name' of undefined
    at /srv/node_modules/swagger-express-middleware/lib/mock/edit-collection.js:226:28
    at Array.some (<anonymous>)
    at getResourceNameByName (/srv/node_modules/swagger-express-middleware/lib/mock/edit-collection.js:219:35)
    at getResourceName (/srv/node_modules/swagger-express-middleware/lib/mock/edit-collection.js:150:9)
    at createResources (/srv/node_modules/swagger-express-middleware/lib/mock/edit-collection.js:115:20)
    at mergeCollection (/srv/node_modules/swagger-express-middleware/lib/mock/edit-collection.js:36:19)
    at mockImplementation (/srv/node_modules/swagger-express-middleware/lib/mock/index.js:125:7)
    at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/srv/node_modules/express/lib/router/index.js:317:13)
    at /srv/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
    at next (/srv/node_modules/express/lib/router/index.js:275:10)
    at mockResponse (/srv/node_modules/swagger-express-middleware/lib/mock/index.js:100:5)
    at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/srv/node_modules/express/lib/router/index.js:317:13)
    at /srv/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
    at next (/srv/node_modules/express/lib/router/index.js:275:10)
    at http415 (/srv/node_modules/swagger-express-middleware/lib/request-validator.js:214:3)
    at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/srv/node_modules/express/lib/router/index.js:317:13)
    at /srv/node_modules/express/lib/router/index.js:284:7

when doing the POST request.

I can work around this by adding a properties object with the id property to the response schema object but that would be redundant and meaningless to swagger (swagger UI handles the above yaml as expected: the type property is required for the post request).

If you want I can try to do a PR but I'd need to know where it would be best to hook in and merge the allOf objects.

All the best, Christian

copitz avatar Feb 08 '18 11:02 copitz

FWIMC, I worked around this with an addition to the callback:

const express = require('express')
const middleware = require('swagger-express-middleware')
const mergeWith = require('lodash.mergewith')

const app = express()

function expandAllOf (object) {
  while (object.hasOwnProperty('allOf')) {
    const allOf = object.allOf
    delete object.allOf
    const override = mergeWith({}, ...allOf, object, function (target, source) {
      if (Array.isArray(target)) {
        return target.concat(source).filter((v, i, a) => a.indexOf(v) === i)
      }
      if (typeof target === 'object') {
        expandAllOf(target)
      }
      if (typeof source === 'object') {
        expandAllOf(source)
      }
    })
    Object.assign(object, override)
  }
  Object.keys(object).forEach((key) => {
    if (typeof object[key] === 'object') {
      expandAllOf(object[key])
    }
  })
}

middleware('PetStore.yaml', app, function(err, middleware, api) {
  if (!err && api) {
    expandAllOf(api.paths || {})
    expandAllOf(api.definitions || {})
  }
  app.use(
    middleware.metadata(),
    middleware.CORS(),
    middleware.files(),
    middleware.parseRequest(),
    middleware.validateRequest(),
    middleware.mock()
  );

  app.listen(8000, function() {
    console.log('The PetStore sample is now running at http://localhost:8000');
  });
})

copitz avatar Feb 08 '18 12:02 copitz

@BigstickCarpet any update on this functionality being implemented/improved?

atdiff avatar May 16 '18 14:05 atdiff