openapi-backend
Version:
Build, Validate, Route, Authenticate and Mock using OpenAPI definitions. Framework-agnostic
282 lines (281 loc) • 10.4 kB
TypeScript
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 {};