@studiohyperdrive/swagger-express-ts

Typescript decorators to generate Swagger docs.

Usage no npm install needed!

<script type="module">
  import studiohyperdriveSwaggerExpressTs from 'https://cdn.skypack.dev/@studiohyperdrive/swagger-express-ts';
</script>

README

@studiohyperdrive/swagger-express-ts

Register API endpoints and operations using TypeScript Decorators and generate Swagger Documentation automatically for your express application.

Table of contents

Getting Started

Install the package

# NPM
npm install --save @studiohyperdrive/swagger-express-ts

# Yarn
yarn add --save @studiohyperdrive/swagger-express-ts

Usage

See the demo folder for a working example.

1. Create a router for your api:

import {
    ApiPath,
    Router,
} from '@studiohyperdrive/swagger-express-ts';

@ApiPath({
    path: '/demo',
    version: 1,
    description: 'Demo api',
})
class DemoV1Router extends Router {}

2. Add some definitions:

import {
    ApiDefinition,
    SwaggerApiDefinitionProperties,
    SwaggerModelType,
} from '@studiohyperdrive/swagger-express-ts';

...
class DemoV1Router {
  @ApiDefinition({
        type: SwaggerModelType.OBJECT,
        description: 'Thing',
    })
    public static Thing: SwaggerApiDefinitionProperties = {
        count: {
            type: SwaggerModelType.NUMBER,
            description: 'count',
            required: true,
            example: 10,
        },
    };

    @ApiDefinition({
        type: SwaggerModelType.OBJECT,
        description: 'Item',
    })
    public static Item: SwaggerApiDefinitionProperties = {
        foo: {
            type: SwaggerModelType.STRING,
            description: 'bar',
            required: true,
            example: 'stuff and things',
        },
        thing: {
            type: SwaggerModelType.OBJECT,
            model: 'Thing',
            example: {},
        },
    };
}

3. Register an operation:

import {
    ApiOperationGet,
    SwaggerResponseType,
    SwaggerUtils,
} from '@studiohyperdrive/swagger-express-ts';

...
class DemoV1Router {
    @ApiOperationGet({
        description: 'Get all items',
        responses: {
            200: {
                description: 'OK',
                type: SwaggerResponseType.ARRAY,
                model: 'Item'
            },
        },
    })
    public getItems(app: Application): void {
        app.route(this.baseUrl).get(
            SwaggerUtils.createController((req, res, next) => {
                return {
                    total: 1,
                    pages: 1,
                    page: 1,
                    size: 20,
                    items: [{
                        foo: 'bar',
                        thing: {
                          count: 2,
                        },
                    }],
                };
            })
        );
    }
}

4. Use the middleware to serve your docs

import express from 'express';
import { swaggerExpress } from '@studiohyperdrive/swagger-express-ts';

const app = express();

app.use(swaggerExpress({
    docsPath: '/docs',
    basePath: '/',
    info: {
        version: '1.0.0',
        title: 'My custom API',
    },
    host: 'localhost:3000',
    uiOptions: {
        customFavIcon: 'https://link.to.my/favicon.ico',
    },
}));

The docs will be available on the url you configured. For the example above that would be:

# [host]/[docsPath]

http://localhost:3000/docs

You can filter endpoints by API version:

# [host]/[docsPath]/[version]

http://localhost:3000/docs/v1

Or view the swagger spec as a json file:

# [host]/[docsPath]/json

http://localhost:3000/docs/json

Decorators

There are 7 decorators you can use:

  • @ApiDefinition: register a Swagger schema
  • @ApiPath: register a new API base path
  • @ApiOperationGet: register a GET operation
  • @ApiOperationPost: register a POST operation
  • @ApiOperationPut: register a PUT operation
  • @ApiOperationPatch: register a PATCH operation
  • @ApiOperationDelete: register a DELETE operation

Utils

createController

The createController util has 2 main functions:

  1. Wrap your controller in a try/catch block and properly handle errors.
  2. Remove the boilerplate of returning data.
import { Request, Response, Next, SwaggerUtils } from '@studiohyperdrive/swagger-express-ts';

const controller = async (req: Request, res: Response, next: Next): Promise<Items> => {
    return await fetchThings(req.params);
};

SwaggerUtils.createController(controller);

Any value you return will be send back to the client as a JSON response with status 200. Errors will be handled by the global error handling.

extractVersion

The extractVersion util can be used to extract the version (number) from a number or string input:

import { SwaggerUtils } from '@studiohyperdrive';

SwaggerUtils.extractVersion(1); // = 1
SwaggerUtils.extractVersion('1'); // = 1
SwaggerUtils.extractVersion('v1'); // = 1
SwaggerUtils.extractVersion(); // = null
SwaggerUtils.extractVersion('test'); // = null

getBaseUrl

The getBaseUrl util can be used to get a base url from a path and/or version input:

import { SwaggerUtils } from '@studiohyperdrive';

SwaggerUtils.getBaseUrl({ version: 1, path: '/demo' }); // = /v1/demo
SwaggerUtils.getBaseUrl({ path: '/demo' }); // = /demo
SwaggerUtils.getBaseUrl({ version: 'test', path: '/demo' }); // = /demo

paginated

The paginated util can be used to get a paginated Swagger response:

import { SwaggerUtils } from '@studiohyperdrive';

SwaggerUtils.paginated('Item', 'Item description');
{
    description: 'Paginated result',
    type: 'object',
    properties: {
        items: {
            model: 'Item',
            description: 'Item description',
            type: 'array',
        },
        total: {
            type: 'number,
            required: true,
            example: 76,
        },
        pages: {
            type: 'number,
            required: true,
            example: 4,
        },
        page: {
            type: 'number,
            required: true,
            example: 1,
        },
        size: {
            type: 'number,
            required: true,
            example: 20,
        },
    }
}