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

Add more convenience openapi method decorators #4300

Closed
mschnee opened this issue Dec 12, 2019 · 3 comments
Closed

Add more convenience openapi method decorators #4300

mschnee opened this issue Dec 12, 2019 · 3 comments
Assignees
Labels

Comments

@mschnee
Copy link
Contributor

mschnee commented Dec 12, 2019

Convenience Decorators have been added to @loopback/openapi-v3 under the oas namespace.

Tags
[PR]
@oas.tags(...tagNames: string[])
Adds arbitrary tag strings to the path spec for a method or a class.

Deprecated
[(PR]
@oas.deprecated(isDeprecated: boolean = true)
When applied to a class, marks all paths in that controller as deprecated. This can be overridden at the method level with @oas.deprecated(false).

When applied to a method, marks that path as deprecated.

Response
[PR]
@oas.response(responseCode: number, ...modelOrSpecOrRefOrContent: msrc[])
Convenience decorator that lets you use Model objects to easily define responses.

Example

// my.controller.ts
import {oas} from '@loopback/openapi-v3';
import {model, property, Model} from '@loopback/repository';

@model()
class SuccessModel extends Model {
  @property()
  message: string;
}

@model()
class MessageNotFoundModel extends Model {}

@model()
class SomethingNotFoundModel extends Model {}

@oas.deprecated()
export class MyController {
    @oas.get('/greet')
    @oas.tags('v1', 'MyController')
    @oas.response(200, SuccessModel)
    @oas.response(404, MessageNotFoundModel, SomethingNotFoundModel)
    @oas.deprecated(false)
    public async getGreeting() {
        return new SuccessModel({message: 'Hello, world'});
    }

    // This path will appear deprecated in the generated OpenApi spec
    @oas.get('/old-greet')
    public async notDeprecatedGreeting() {
      return 'Hello!'
    }
}

Original Suggestion

Loopback is already generating a fully compliant specification- but right now it's an all or nothing approach with the method convenience decorators. Currently, if you want to add any additional openapi specification data to an api, you are required to provide a nearly complete Operation Object to do so:

@get('/test', {
  tags: ['MyTag']
  responses: {
    '200': {
      description: 'This is required',
      content: {
        'application/json' : {}
      }
    }
  }
)
public async iJustWantToBeTagged() {
}

Instead, we could have done this:

@get('/test')
@tags(['MyTag'])
public async iJustWantToBeTagged() {
}

We have the ability to use decorators to provide metadata so that spec generation can be informed of this additional information. This should include:

  • Convenience decorators for @tags(), @deprecated(), @description(), @respondsWithModel(), which will use configurable defaults for keys for response description and content-type @response()
  • A means of changing that configuration, e.g. this.bind(RestBindings.DEFAULT_RESPONSE_CONTENT_TYPE).to('application/json')
  • Documentation.

Use Cases

Writing and maintaining giant JSON blocks is tedious, cumbersome, and error-prone. Typescript can inform us of a lot of useful information, such as possible response objects, and we can enforce that at a code level, while also making our api controllers neater and easier to maintain.

Examples

@deprecated()
@get('/some/api/{some_first_id}/path/{some_second_id}')
@description('I get some specific piece of data organized under a specific item in another collection')
@tags(['MyFirstTag', 'MySecondTag'])
@response(200, MySuccessModel)
@response(404, SomethingNotFoundError)
@response(404, SomethingElseNotFoundError)
@response(403, [NotAuthorizedForFirstPathError, NotAuthorizedForSecondPathError])
@response(409, {
  description: 'This is a full response item',
  content: {
    'application/json': {
      schema: { }
    }
  }
})
public async iHaveMultipleResponses() {}

Suggested Acceptance Criteria

Add the following convenience method decorators.

@deprecated() // mark as deprecated
@tags(tagName: string[]) // takes an array of strings, just like the spec
@description(desc: string) // takes a single string, just like the spec
@response(statusCode: number, modelOrModels: Model | Model[], optionalDescription?: string)
@response(statusCode: number, spec: ResponseSpec | ReferenceSpec | Model | Model[] ) uses Model classes for `schema: {x-ts-type': Model}` as appropriate.  If no description is provided, use the name defined by RFC 7231 e.g. 'Not Authorized'.  The metadata is a concetenated array in all cases.

Add context-level defaults for some required spec data:

this.bind(RestBindings.DEFAULT_RESPONSE_CONTENT_TYPE).to('application/json')

Stretch Goal:

The default sequence should check the metadata for a method, and if the method returns a response provided in a @response(code, model) decorator, it should assume that response code.  The same for thrown errors, in the case that code throws an instance of a Model.

Add full documentation and examples.
Maybe merge @response() and @respondsWithModel() into a single decorator with both argument sets if it's cleaner.

Acceptance criteria

TBD - will be filled by the team.

@dhmlau
Copy link
Member

dhmlau commented Jan 9, 2020

@jannyHou @bajtos @raymondfeng, what's your thoughts on this? If that's something we should do, maybe we can mark it as help wanted?

@mschnee
Copy link
Contributor Author

mschnee commented Jan 10, 2020

@dhmlau I'll have a preliminary pull request later today, I'm just going through the checklist and updating documentation now.

@mschnee
Copy link
Contributor Author

mschnee commented Feb 21, 2020

Everything is merged, so we're good to go :)

@mschnee mschnee closed this as completed Feb 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants