npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

express-openapi-decorator

v0.0.6

Published

An opiniated library using decorators in order to define openAPI documentation for an endpoint.

Readme

express-openapi-decorator

An opiniated library using decorators in order to define openAPI documentation for an expressJs endpoint.

@doc({
    summary: 'This endpoint will display Hello world.',
})
class HelloWorld extends Endpoint {
    @queryParam({ description: 'The name of person to great.', example: 'Alex' })
    name?: string;

    @errorResponse()
    errorForbidden = new Error(`This name is forbidden.`);

    handler() {
        if (this.name === 'voldemort') {
            throw this.errorForbidden;
        }
        this.res.send(`Hello ${this.name || 'world'}`);
    }
}

This library is not a validator. To validate incoming request use express-openapi-validator

How to use

Install peer dependency:

npm install express

Create a class, extending the abstract class Endpoint, for each endpoints.

@doc({
    summary: 'This endpoint will display Hello world.',
})
class HelloWorld extends Endpoint {
    handler() {
        this.res.send('Hello world');
    }
}

The OpenApi documentation is part of the endpoint instance:

console.log(new HelloWorld().doc);

Add the endpoint to the Router:

import { router } from 'express-openapi-decorator';

const router = Router();
router.get('/api/hello', new HelloWorld());

Create api doc:

const doc: OpenAPIV3.Document = {
    openapi: '3.0.1',
    info: {
        description: 'This API serve an example.',
        version: '1.0.0',
        title: 'Hello world',
    },
    paths: router.doc,
};

Expose router and doc with express:

const port = 3000;
const app = express();
app.get('/api-docs', (_req, res) => res.json(doc));
app.use(router);
app.listen(port, () => {
    logger.info(`Ready to accept connections on port: ${port}`);
});

To visualize the OpenApi documentation use swagger-ui-express: app.use('/ui', swaggerUi.serve, swaggerUi.setup(apiDoc));

Router

const router = Router(); is an extension of express Router, working the same way, but instead to pass request handler to the route, endpoints should be passed.

router.get(path: string, ...endpoints: Endpoint[]) will add the endpoint instances to the given path for the get method (this work for any method). It allow to merge multiple endpoints definition to one, this can be useful for example to create a security middleware:

@doc({
    security: [{ basicAuth: [] }],
})
class SecureEndpoint extends Endpoint {
    handler() {
        if (this.req.headers['authorization'] !== `Basic ${btoa('user:password')}`) {
            throw new Error('Invalid credential');
        }
        next();
    }
}

@doc({
    summary: 'This endpoint will display Hello world.',
})
class HelloWorld extends Endpoint {
    handler() {
        this.res.send('Hello world');
    }
}

router.get('/api/hello', new SecureEndpoint(), new HelloWorld());

router can then be used like a normal express router:

app.use(router);

It is possible to access the endpoints instances with router.endpointInstances.

router.doc return the OpenApi doc for each endpoints added to the router according there path and method.

const app = express();
const doc: OpenAPIV3.Document = {
    openapi: '3.0.1',
    info: {
        description: 'This API serve an example.',
        version: '1.0.0',
        title: 'Hello world',
    },
    paths: router.doc,
};
app.get('/api-docs', (_req, res) => res.json(doc));

Decorators

To define the characteristic of the endpoint, we use decorators.

@doc

The @doc decorator get an OpenAPIV3.OperationObject as first parameter, meaning that it is possible to define the whole endpoint documentation here. However, this definition might get partly overwritten by the following decorators.

@doc({
    summary: 'This endpoint will display Hello world.',
})
class HelloWorld extends Endpoint {}

@pathParam

The @pathParam decorator get an OpenAPIV3.ParameterBaseObject as first parameter, to define the documentation of path parameter. When express will call the handler, the value of the parameter will be automatcally be populated to the endpoint object.

class HelloWorld extends Endpoint {
    @pathParam({ description: 'The name of person to great.', required: true, example: 'Alex' })
    name!: string;

    handler() {
        this.res.send(`Hello ${this.name}`);
    }
}

@queryParam

The @queryParam decorator get an OpenAPIV3.ParameterBaseObject as first parameter, to define the documentation of a query parameter. When express will call the handler, the value of the parameter will be automatcally be populated to the endpoint object.

class HelloWorld extends Endpoint {
    @queryParam({ description: 'The name of person to great.', required: true, example: 'Alex' })
    name!: string;

    handler() {
        this.res.send(`Hello ${this.name}`);
    }
}

@bodyProp

The @bodyProp decorator get an OpenAPIV3.BodySchema as first parameter, to define the documentation of a property from the body sent in the request. When express will call the handler, the value of the property will be automatcally be populated to the endpoint object.

class HelloWorld extends Endpoint {
    @bodyProp({ description: 'The name of person to great.', required: true, example: 'Alex' })
    name!: string;

    handler() {
        this.res.send(`Hello ${this.name}`);
    }
}

@errorResponse

The @errorResponse decorator get an optional OpenAPIV3.ResponsesObject as first parameter. The value of error property must be of type Error, where the message will be automatically used as description in the OpenApi documentation.

class HelloWorld extends Endpoint {
    @errorResponse()
    errorConflict = new Error(`This endpoint is in conflict.`);

    async handler() {
        throw this.errorConflict;
    }
}

Or with status code

class Conflict extends Error {
    statusCode = 409;
}

class HelloWorld extends Endpoint {
    @errorResponse()
    errorConflict = new Conflict(`This endpoint is in conflict.`);

    async handler() {
        throw this.errorConflict;
    }
}

or using http-errors library

import { Conflict } from 'http-errors';

class HelloWorld extends Endpoint {
    @errorResponse()
    errorConflict = new Conflict(`This endpoint is in conflict.`);

    async handler() {
        throw this.errorConflict;
    }
}