@vladbasin/strong-api-middleware

Strongly typed API middleware. Generic library which can be integrated with any HTTP stack.

Usage no npm install needed!

<script type="module">
  import vladbasinStrongApiMiddleware from 'https://cdn.skypack.dev/@vladbasin/strong-api-middleware';
</script>

README

Strong API middleware

Strongly typed API middleware. Generic library which can be integrated with any HTTP stack.

Installation

npm

npm install @vladbasin/strong-api-middleware @vladbasin/strong-api-mapping reflect-metadata joi

yarn

yarn add @vladbasin/strong-api-middleware @vladbasin/strong-api-mapping reflect-metadata joi

Usage

This is a generic middleware library. You can integrate it with any HTTP stack. Currently the following packages use this library:

Step-by-step guide

  1. Import reflect-metadata ONCE in your index file:
import 'reflect-metadata';
  1. Define your model
import { body, header, path, query } from '@vladbasin/strong-api-mapping';

export class RequestPayload {
    @path()
    public userId!: number;

    @path({ key: 'userId' })
    public id!: number;

    @query()
    public name!: string;

    @query()
    public isAdmin!: boolean;

    @query({ key: 'lastname' })
    public surname!: string;

    @query({ parser: String })
    public cars!: string[];

    @query({ parser: Number })
    public cash!: number[];

    @body()
    public details!: DetailsType;

    @header({ key: 'Content-Type' })
    public contentType!: string;

    @header({ key: 'X-Info', parser: String })
    public info!: string[];
}
  1. Define validation rules with Joi
export const RequestPayloadSchema = Joi.object<RequestPayload>({
    surname: Joi.string().min(10),
    cars: Joi.array().max(3),
    // other rules for field content...
});
  1. Call handleStrongApiRequest() when you want to process HTTP request
handleStrongApiRequest({
    // configure request handling
    request: {
        // define request payload model which will be automapped
        payload: {
            Model: RequestPayload,
            schema: RequestPayloadSchema,
        },
        provideRaw: () => {
            // synchronously or ASYNChronously provide RawApiRequest object (headers, body, query string) based on your HTTP stack
        },
        handle: ({ payload }) => {
            // handle api request
            // return ApiResponseType<TSuccessModel, TErrorModel>
        },
    },
    // configure response handling
    response: {
        // process request handling error
        processFailure: {
            options: {
                // output possibly sensitive information (useful for debugging)
                allowSensitive: true,
            },
            // OPTIONAL
            responseCreator: (error, options, defaultResponseCreator) => { 
                // create ApiResponseType<TSuccessModel, TErrorModel> when error happens (by default done by this library automatically)
            },
        },
    },
});

This method returns RawApiResponseType which you can later convert to your HTTP stack specific output. For example, @vladbasin/strong-api-middleware-aws-lambda converts it to AWS Lambda function response.

export type RawApiResponseType = {
    statusCode: number;
    headers?: MaybeNullable<Record<string, Maybe<string>>>;
    multiValueHeaders?: MaybeNullable<Record<string, Maybe<string[]>>>;
    body?: MaybeNullable<string>;
};

In addition, you can share request/response models with your API consumers, so they don't need to repeat the same mapping & validation logic. See: @vladbasin/strong-api-client