2.3.0 • Published 12 months ago

serverless-openapi-req-validation v2.3.0

Weekly downloads
-
License
-
Repository
github
Last release
12 months ago

Serverless Openapi Req Validation

This plugin allows you to automatically generate an openapi specifications, describing your application endpoints. Additionally, it injects the necessary types and objects into the existing serverless configuration.

Install

yarn add --dev serverless-openapi-req-validation
# or
npm install -D serverless-openapi-req-validation

Add the following plugin to your serverless.yml or serverless.ts:

plugins:
  - serverless-openapi-req-validation
plugins: ['serverless-openapi-req-validation'];

Usage

This plugin is designed to work with vanilla Serverless Framework. The plugin is split into two part:

  • Openapi v3 generation
  • Request validation with API GateWay

The openapi file can be generated by running sls generate-openapi. The request validation can be toggled by uploadTypes (default false).

Request Validation

If enabled the respective requestBody types are transformed AWS::ApiGateway::Model Cloudformation resources and injected in the same stack, so be in mind with the maximum resources per stack. Currently the request validation within API Gateway works with swagger v2.0. Due to the inherit difference between openapi 3 and 2, anyOf constructs are not supported and skipped in the uploading phase. Meaning Union types are not yet supported and skipped in the uploading phase.

Config Options

All config options are optional. Defaults are shown in the table below.

custom:
    autoOpenapi:
        info:
            title: 'string'
            description: 'string'
        apiType: 'http' | 'httpApi'
        typeFiles: ['./src/types/typefile1.d.ts', './src/**/types.ts']
        apiKeyHeaders: ['Authorization', 'anyOtherName']
        outputDir: 'generated'
        uploadTypes: true | false
        compactOutput: true | false
        useStage: true | false
        basePath: '/string'
        host: 'http://some-host'
        excludeStages: ['production', 'anyOtherStage']
        externalDocs:
            url: http://some-doc
            description: some-description
        servers:
            - url: http://some-server
              description: some-description
        openapiTags:
            - some-tag
OptionDescriptionDefaultExample
infoInfo object according to openapi specifications{ title: Serverless service name, version: Current timeSee info-object
apiTypeAPI type for which your openapi file should be created for. Options are http and httpApihttpApi
uploadTypesBoolean indicating to upload types to API Gateway on deployment via designated serverless event fieldsfalse
compactOutputDuring node construction, use anchors and aliases to keep strictly equal non-null objects as equivalent in YAMLfalsedescription: *a2
typeFilesArray of strings which defines where to find the typescript types to use for the request and response bodies['./src/types/api-types.d.ts']
apiKeyHeadersArray of strings used to define API keys used in auth headers[]apiKeyHeaders: ['Authorization', 'x-api-key']
useStageBoolean to either use current stage in beginning of path or notfalsetrue => dev/openapi for stage `dev
basePathString that can be prepended to every request. Should include leading /-/some-base => http://localhost/some-base/my-endpoint
hostString that overrides the host. With this you can set your custom domain for your application endpoints-http://some-host => {http://some-host}/my-endpoint
excludeStagesArray of strings that contains stages in which openapi should not be created and injected in.[]
externalDocsObject containing the url and optional description of where external documentation is located-externalDocs: { url: 'some-url', description: 'some-description' }
serversArray of server objects[]servers: [ { url: 'some-url', description: 'some-description' } ]

Adding more details

The default openapi file from vanilla Serverless framework will have the correct paths and methods but no details about the requests or responses.

API Summary and Details

The optional attributes summary and description can be used to describe each HTTP request in Openapi.

openapiTags is an optional array that can be used to group HTTP requests with a collapsible name (i.e. grouping two endpoints GET /dogs and POST /dogs together). If not specified, all HTTP requests will be grouped under default.

http:
    summary: 'This is a cool API'
    description: 'Cool API description is here'
    openapiTags: ['Dogs']

Adding Data Types

This plugin uses typescript types to generate the data types for the endpoints. By default, it pulls the types from src/types/api-types.d.ts.

You can then assign these typescript definitions to requests as requestBody on the http or https config, or to the response as seen just below.

Responses

You can also add expected responses to each of the http endpoint events. This is an object that contains the response code with some example details:

responses:
    # response with description and response body
    200:
        description: 'this went well'
        bodyType: 'helloPostResponse'
    # response with just a description
    400:
        description: 'failed Post'
    # shorthand for just a description
    502: 'server error'
}

Post request expected body

When you create a POST or PUT endpoint, you expect to receive a specific structure of data as the body of the request.

You can do that by adding a requestBody to the http event:

http:
    path: 'hello'
    method: 'post'
    requestBody: 'helloPostBody'

or with an additional description:

http:
    path: 'hello'
    method: 'post'
    requestBody: 
        bodyType: 'helloPostBody'
        description: 'Some Description'

Query String Parameters

If you want to specify the query string parameters on an endpoint you can do this by adding an object of queryStringParameters to the event. This has two required properties of required and type as well as an optional description.

http:
    path: 'goodbye'
    method: 'get'
    queryStringParameters:
        bob:
            required: true
            type: 'string'
            description: 'bob'
        count:
            required: false
            type: 'integer'

If no queryStringParameters are defined, the plugin will do its best to generate params based on any Serverless request.parameters.querystrings that are defined.

Alternatively, one can rely on the default implementation of Serverless request.parameters.querystrings. For both scenarios the plugin will manage the injection of the final template for request validation.

Header Params

Works the same way as queryStringParameters, but for headers.

To use it, just define it under headerParameters:

http:
    path: 'goodbye'
    method: 'get'
    headerParameters:
        bob:
            required: true
            type: 'string'
            description: 'bob'
        count:
            required: false
            type: 'integer'

If no headerParameters are defined, the plugin will do its best to generate headers based on any Serverless request.parameters.headers that are defined.

Alternatively, one can rely on the default implementation of Serverless request.parameters.headers. For both scenarios the plugin will manage the injection of the final template for request validation.

Path Parameters

Path parameters are resolved first by looking at request.parameters.paths, and then by resolving any additional parameters in the http event path (i.e. /{id}). By default, the path will be determined during runtime from your Serverless config if omitted in request.parameters.paths. Thus it is for no need to specify this parameter.

Exclude an endpoint

You can exclude some endpoints from the openapi generation by adding exclude to the http event:

http:
    path: 'hello'
    method: 'post'
    exclude: true

Exclude from validation

Alternatively, you can solely exclude some endpoints to be uploaded to API Gateway for validation by adding disableValidation to the http event:

http:
    path: 'hello'
    method: 'post'
    disableValidation: true

Custom operationId

You can override the automatically generated operationId by adding the operationId property to the http event. This can be useful when using code generators.

http:
    path: 'hello'
    method: 'post'
    operationId: 'postHello'

Annotations

The schema generator uses JSDoc for typescript, which is able to convert annotations to JSON schema properties. See their jsdoc for more examples

For example

export interface Shape {
    /**
     * The size of the shape.
     *
     * @pattern ^[a-zA-Z]+$
     */
    size: string;
}

will be translated to

{
    "Shape": {
        "properties": {
            "size": {
                "description": "The size of the shape.",
                "pattern": "^[a-zA-Z]+$",
                "type": "string"
            }
        },
        "type": "object"
    }
}

Automated Descriptions

Serverless

Descriptions in your openapi specifications can be added as follows:

http:
    path: 'path'
    method: post
    description: "Custom path description"
    summary: "Custom path summary"
    queryStringParameters:
        parameter:
            type: 'string'
            description: 'Custom parameter description'
    requestBody: 
        bodyType: SomeBody
        description: 'Custom requestbody description'
    responses:
        202:
            description: "Custom response description"

The above will result in:

{
  "paths": {
    "/path": {
      "post": {
        "summary": "Custom path summary",
        "parameters": [
          {
            "in": "query",
            "name": "parameter",
            "description": "Custom parameter description",
          }
        ],
        "requestBody": {
          "description": "Custom requestbody description",
        },
        "responses": {
          "202": {
            "description": "Custom response description"
          }
        },
        "description": "Custom path description"
      }
    }
  }
}

Typescript

Multiline comment statements are automatically used in the respective component's schema description. The following example:

/**
 * This is a custom shape
 */
export interface Shape {
    /**
     * The size of the shape.
     */
    size: number;
    type: string;
}

, will result in the following openapi schema:

{
    "Shape": {
        "description": "This is a custom shape",
        "title": "Shape",
        "properties": {
            "size": {
                "description": "The size of the shape.",
                "type": "number"
            }
        },
        "type": "object"
    }
}
2.3.0

12 months ago

2.2.0

1 year ago

2.0.2

1 year ago

2.1.0

1 year ago

2.0.1

1 year ago

2.0.0

1 year ago

1.2.0

1 year ago

1.1.4

1 year ago

1.1.3

1 year ago

1.1.2

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago