Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response body #8

Closed
consense opened this issue Aug 10, 2018 · 5 comments
Closed

Response body #8

consense opened this issue Aug 10, 2018 · 5 comments

Comments

@consense
Copy link
Contributor

As far as I understand it is currently not possible to extract the response body automatically from type of the returned value in the controller./action.

Is there a way to describe it manually? In particular in many cases the definition of the response object is already present in the openapi-doc as it was used as request body in another action (think model-DTO being used as request for updateModel-PUT action and as response for getModel-GET action.
So it would be amazing not having to duplicate the type definitions in actual code as well as inside the @openapi decorator.

Thanks!

@epiphone
Copy link
Owner

Hi! You're right, extracting response types automatically in runtime isn't allowed by Typescript's reflection system ATM. Specifically the problem is we can't unwrap generic types like Promise<MyModel> or Array<MyModel>: see e.g. here for discussion.

As for manually describing response types there's the @OpenAPI decorator as you've hinted above.
In case you've already used MyModel as request body, the corresponding components.schemas.MyModel property should have been populated in the resulting OpenAPI JSON. Thus you can just use a schema reference instead of typing out the whole MyModel schema. I imagine it'd look something like this:

@OpenAPI({
  responses: {
    '200': {
      'application/json': {
        schema: {
          $ref: '#/components/schemas/MyModel'
        }
      }
    } 
  }
})

I understand there's still a bit of boilerplate involved, so you might want to write another decorator that just takes the name of the schema as a string and expands into the above responses object.

One step further would be to write a decorator that takes any class-validator decorated class as a parameter, converts it into JSON schema and expands it into the above responses object - something like @ResponseBody(MyResponseObject). This would also cover the cases where the response body object (MyResponseObject here) isn't used anywhere as a request body type and thus not found under components.schemas.

I'll probably see to implementing the latter at some point, but writing it yourself will definitely be quicker! 😉

@consense
Copy link
Contributor Author

Hi @epiphone ! Thanks for the very extensive and helpful reply!
I added a corresponding commit at https://github.com/ScreenAware/routing-controllers-openapi/commit/bd5676412c9b8e9e1b5168cd040f6dad8e8906c2 but for some reason manage to crash routing-controllers-openapi in my own app when directly referencing the new files in build.

If you want I can ofc try to understand what I might have done to lead to below exception, but maybe this is something which only takes you a minute to understand. Just ping back if you dont feel like looking at a half-finished PR which I could understand :-)

TypeError: Cannot read property '0' of undefined
application.js:630
    at getParamSchema (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:254:73)
    at _.filter.map.queryMeta (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:140:22)
    at arrayMap (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:639:23)
    at Function.map (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:9554:14)
    at interceptor (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:16991:35)
    at thru (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:8795:14)
    at projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:4388:28
    at arrayReduce (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:683:21)
    at baseWrapperValue (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:4387:14)
    at LazyWrapper.lazyValue [as value] (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:1873:16)
    at baseWrapperValue (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:4385:25)
    at LodashWrapper.wrapperValue (projectdir\node_modules\routing-controllers-openapi\node_modules\lodash\lodash.js:9050:14)
    at getQueryParams (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:148:6)
    at getOperation (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:33:10)
    at routes.map.route (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:58:28)
    at Array.map (<anonymous>)
    at getPaths (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:56:29)
    at Object.getSpec (projectdir\node_modules\routing-controllers-openapi\src\generateSpec.ts:208:12)
    at Object.routingControllersToSpec (projectdir\node_modules\routing-controllers-openapi\src\index.ts:28:16)

@epiphone
Copy link
Owner

Published in 1.4.0, thanks @consense!

@ricardo-dlc
Copy link

ricardo-dlc commented Sep 14, 2020

As I understand, this only works if I have a class for the response schema, but what if I want to define my own schema without create a new class. I could do it in this way:

@OpenAPI({
  summary: 'Login',
  description: 'Returns a token',
  responses: {
    '200': {
      description: 'Login successfully',
      content: {
        'application/json': {
          schema: {
            $schema: 'https://json-schema.org/draft-04/schema#',
            type: 'object',
            properties: {
              token: {
                type: 'string'
              }
            }
          }
        }
      }
    }
  }
})

In this way I can see the Schema {token: string} in the Responses section with it respective Example Value, but as you can see it could be a large block of code and also a little bit redundant cause I'm already using the @HttpCode(200) and the @ContentType('application/json') decorators from routing-controllers, so I was wondering if I can use the @ResponseSchema() decorator but since only accepts an string or a Function in the parameters I couldn't figure how to solve with this. I hope you undertand me.

@epiphone
Copy link
Owner

@ricardo-dlc you can define a new decorator function that uses OpenAPI internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants