UNPKG

openapi-backend

Version:

Build, Validate, Route, Authenticate and Mock using OpenAPI definitions. Framework-agnostic

282 lines (281 loc) 10.4 kB
import type { Options as AjvOpts } from 'ajv'; import { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'; import { OpenAPIRouter, Request, ParsedRequest, Operation, UnknownParams } from './router'; import { OpenAPIValidator, ValidationResult, AjvCustomizer } from './validation'; export type Document = OpenAPIV3_1.Document | OpenAPIV3.Document; export type PickVersionElement<D extends Document, V30, V31> = D extends OpenAPIV3_1.Document ? V31 : V30; export type SecurityRequirement = OpenAPIV3_1.SecurityRequirementObject | OpenAPIV3.SecurityRequirementObject; /** * Security / Authorization context for requests */ interface SecurityHandlerResults { [name: string]: any; } export interface SecurityContext extends SecurityHandlerResults { authorized: boolean; } /** * Passed context built for request. Passed as first argument for all handlers. */ export interface Context<RequestBody = any, Params = UnknownParams, Query = UnknownParams, Headers = UnknownParams, Cookies = UnknownParams, D extends Document = Document> { api: OpenAPIBackend<D>; request: ParsedRequest<RequestBody, Params, Query, Headers, Cookies>; operation: Operation<D>; validation: ValidationResult; security: SecurityHandlerResults; response: any; } /** * A handler for an operation with request Context and passed arguments from handleRequest */ export type Handler<RequestBody = any, Params = UnknownParams, Query = UnknownParams, Headers = UnknownParams, Cookies = UnknownParams, D extends Document = Document> = (context: Context<RequestBody, Params, Query, Headers, Cookies, D>, ...args: any[]) => any | Promise<any>; /** * Map of operation handlers */ export type HandlerMap = { [operationId: string]: Handler | undefined; }; export type BoolPredicate = (context: Context, ...args: any[]) => boolean; /** * The different possibilities for set matching. * * @enum {string} */ export declare enum SetMatchType { Any = "any", Superset = "superset", Subset = "subset", Exact = "exact" } /** * Constructor options * * @export * @interface Options */ export interface Options<D extends Document = Document> { definition: D | string; apiRoot?: string; strict?: boolean; quick?: boolean; validate?: boolean | BoolPredicate; ajvOpts?: AjvOpts; customizeAjv?: AjvCustomizer; handlers?: HandlerMap & { notFound?: Handler; notImplemented?: Handler; validationFail?: Handler; }; securityHandlers?: HandlerMap; ignoreTrailingSlashes?: boolean; coerceTypes?: boolean; } /** * Main class and the default export of the 'openapi-backend' module * * @export * @class OpenAPIBackend */ export declare class OpenAPIBackend<D extends Document = Document> { document: D; inputDocument: D | string; definition: D; apiRoot: string; initalized: boolean; strict: boolean; quick: boolean; validate: boolean | BoolPredicate; ignoreTrailingSlashes: boolean; ajvOpts: AjvOpts; customizeAjv: AjvCustomizer | undefined; coerceTypes: boolean; handlers: HandlerMap; allowedHandlers: string[]; securityHandlers: HandlerMap; router: OpenAPIRouter<D>; validator: OpenAPIValidator<D>; /** * Creates an instance of OpenAPIBackend. * * @param opts - constructor options * @param {D | string} opts.definition - the OpenAPI definition, file path or Document object * @param {string} opts.apiRoot - the root URI of the api. all paths are matched relative to apiRoot * @param {boolean} opts.strict - strict mode, throw errors or warn on OpenAPI spec validation errors (default: false) * @param {boolean} opts.quick - quick startup, attempts to optimise startup; might break things (default: false) * @param {boolean} opts.validate - whether to validate requests with Ajv (default: true) * @param {boolean} opts.ignoreTrailingSlashes - whether to ignore trailing slashes when routing (default: true) * @param {boolean} opts.ajvOpts - default ajv opts to pass to the validator * @param {boolean} opts.coerceTypes - enable coerce typing of request path and query parameters. Requires validate to be enabled. (default: false) * @param {{ [operationId: string]: Handler | ErrorHandler }} opts.handlers - Operation handlers to be registered * @memberof OpenAPIBackend */ constructor(opts: Options<D>); /** * Initalizes OpenAPIBackend. * * 1. Loads and parses the OpenAPI document passed in constructor options * 2. Validates the OpenAPI document * 3. Builds validation schemas for all API operations * 4. Marks property `initalized` to true * 5. Registers all [Operation Handlers](#operation-handlers) passed in constructor options * * The init() method should be called right after creating a new instance of OpenAPIBackend * * @returns parent instance of OpenAPIBackend * @memberof OpenAPIBackend */ init(): Promise<this>; /** * Loads the input document asynchronously and sets this.document * * @memberof OpenAPIBackend */ loadDocument(): Promise<D>; /** * Handles a request * 1. Routing: Matches the request to an API operation * 2. Validation: Validates the request against the API operation schema * 3. Handling: Passes the request on to a registered handler * * @param {Request} req * @param {...any[]} handlerArgs * @returns {Promise} handler return value * @memberof OpenAPIBackend */ handleRequest(req: Request, ...handlerArgs: any[]): Promise<any>; /** * Registers a handler for an operation * * @param {string} operationId * @param {Handler} handler * @memberof OpenAPIBackend */ registerHandler(operationId: string, handler: Handler): void; /** * Registers multiple handlers * * @param {{ [operationId: string]: Handler }} handlers * @memberof OpenAPIBackend */ register<Handlers extends HandlerMap = HandlerMap>(handlers: Handlers): void; /** * Registers a handler for an operation * * Alias for: registerHandler * * @param {string} operationId * @param {Handler} handler * @memberof OpenAPIBackend */ register<OperationHandler = Handler>(operationId: string, handler: OperationHandler): void; /** * Registers a security handler for a security scheme * * @param {string} name - security scheme name * @param {Handler} handler - security handler * @memberof OpenAPIBackend */ registerSecurityHandler(name: string, handler: Handler): void; /** * Mocks a response for an operation based on example or response schema * * @param {string} operationId - operationId of the operation for which to mock the response * @param {object} opts - (optional) options * @param {number} opts.responseStatus - (optional) the response code of the response to mock (default: 200) * @param {string} opts.mediaType - (optional) the media type of the response to mock (default: application/json) * @param {string} opts.example - (optional) the specific example to use (if operation has multiple examples) * @returns {{ status: number; mock: any }} * @memberof OpenAPIBackend */ mockResponseForOperation(operationId: string, opts?: { code?: number; mediaType?: string; example?: string; }): { status: number; mock: any; }; /** * Validates this.document, which is the parsed OpenAPI document. Throws an error if validation fails. * * @returns {D} parsed document * @memberof OpenAPIBackend */ validateDefinition(): D; /** * Flattens operations into a simple array of Operation objects easy to work with * * Alias for: router.getOperations() * * @returns {Operation<D>[]} * @memberof OpenAPIBackend */ getOperations(): Operation<D>[]; /** * Gets a single operation based on operationId * * Alias for: router.getOperation(operationId) * * @param {string} operationId * @returns {Operation<D>} * @memberof OpenAPIBackend */ getOperation(operationId: string): Operation<D> | undefined; /** * Matches a request to an API operation (router) * * Alias for: router.matchOperation(req) * * @param {Request} req * @returns {Operation<D>} * @memberof OpenAPIBackend */ matchOperation(req: Request): Operation<D> | undefined; /** * Validates a request and returns the result. * * The method will first match the request to an API operation and use the pre-compiled Ajv validation schemas to * validate it. * * Alias for validator.validateRequest * * @param {Request} req - request to validate * @param {(Operation<D> | string)} [operation] * @returns {ValidationStatus} * @memberof OpenAPIBackend */ validateRequest(req: Request, operation?: Operation<D> | string): ValidationResult; /** * Validates a response and returns the result. * * The method will use the pre-compiled Ajv validation schema to validate a request it. * * Alias for validator.validateResponse * * @param {*} res - response to validate * @param {(Operation<D> | string)} [operation] * @param {number} status * @returns {ValidationStatus} * @memberof OpenAPIBackend */ validateResponse(res: any, operation: Operation<D> | string, statusCode?: number): ValidationResult; /** * Validates response headers and returns the result. * * The method will use the pre-compiled Ajv validation schema to validate a request it. * * Alias for validator.validateResponseHeaders * * @param {*} headers - response to validate * @param {(Operation<D> | string)} [operation] * @param {number} [opts.statusCode] * @param {SetMatchType} [opts.setMatchType] - one of 'any', 'superset', 'subset', 'exact' * @returns {ValidationStatus} * @memberof OpenAPIBackend */ validateResponseHeaders(headers: any, operation: Operation<D> | string, opts?: { statusCode?: number; setMatchType?: SetMatchType; }): ValidationResult; } export {};