UNPKG

@typespec/http-server-js

Version:

TypeSpec HTTP server code generator for JavaScript

259 lines 10.2 kB
// Copyright (c) Microsoft Corporation // Licensed under the MIT license. export let module = undefined; // prettier-ignore const lines = [ "// Copyright (c) Microsoft Corporation", "// Licensed under the MIT license.", "", "import type * as http from \"node:http\";", "", "/** A policy that can be applied to a route or a set of routes. */", "export interface Policy {", " /** Optional policy name. */", " name?: string;", "", " /**", " * Applies the policy to the request.", " *", " * Policies _MUST_ call `next()` to pass the request to the next policy _OR_ call `response.end()` to terminate,", " * and _MUST NOT_ do both.", " *", " * If the policy passes a `request` object to `next()`, that request object will be used instead of the original", " * request object for the remainder of the policy chain. If the policy does _not_ pass a request object to `next()`,", " * the same object that was passed to this policy will be forwarded to the next policy automatically.", " *", " * @param request - The incoming HTTP request.", " * @param response - The outgoing HTTP response.", " * @param next - Calls the next policy in the chain.", " */", " (ctx: HttpContext, next: (request?: http.IncomingMessage) => void): void;", "}", "", "/**", " * Create a function from a chain of policies.", " *", " * This returns a single function that will apply the policy chain and eventually call the provided `next()` function.", " *", " * @param name - The name to give to the policy chain function.", " * @param policies - The policies to apply to the request.", " * @param out - The function to call after the policies have been applied.", " */", "export function createPolicyChain<Out extends (ctx: HttpContext, ...rest: any[]) => void>(", " name: string,", " policies: Policy[],", " out: Out,", "): Out {", " let outParams: any[];", " if (policies.length === 0) {", " return out;", " }", "", " function applyPolicy(ctx: HttpContext, index: number) {", " if (index >= policies.length) {", " return out(ctx, ...outParams);", " }", "", " policies[index](ctx, function nextPolicy(nextRequest) {", " applyPolicy(", " {", " ...ctx,", " request: nextRequest ?? ctx.request,", " },", " index + 1,", " );", " });", " }", "", " return {", " [name](ctx: HttpContext, ...params: any[]) {", " outParams = params;", " applyPolicy(ctx, 0);", " },", " }[name] as Out;", "}", "", "/**", " * The type of an error encountered during request validation.", " */", "export type ValidationError = string;", "", "/**", " * An object specifying the policies for a given route configuration.", " */", "export type RoutePolicies<RouteConfig extends { [k: string]: object }> = {", " [Interface in keyof RouteConfig]?: {", " before?: Policy[];", " after?: Policy[];", " methodPolicies?: {", " [Method in keyof RouteConfig[Interface]]?: Policy[];", " };", " };", "};", "", "/**", " * Create a policy chain for a given route.", " *", " * This function calls `createPolicyChain` internally and orders the policies based on the route configuration.", " *", " * Interface-level `before` policies run first, then method-level policies, then Interface-level `after` policies.", " *", " * @param name - The name to give to the policy chain function.", " * @param routePolicies - The policies to apply to the routes (part of the route configuration).", " * @param interfaceName - The name of the interface that the route belongs to.", " * @param methodName - The name of the method that the route corresponds to.", " * @param out - The function to call after the policies have been applied.", " */", "export function createPolicyChainForRoute<", " RouteConfig extends { [k: string]: object },", " InterfaceName extends keyof RouteConfig,", " Out extends (ctx: HttpContext, ...rest: any[]) => void,", ">(", " name: string,", " routePolicies: RoutePolicies<RouteConfig>,", " interfaceName: InterfaceName,", " methodName: keyof RouteConfig[InterfaceName],", " out: Out,", "): Out {", " return createPolicyChain(", " name,", " [", " ...(routePolicies[interfaceName]?.before ?? []),", " ...(routePolicies[interfaceName]?.methodPolicies?.[methodName] ?? []),", " ...(routePolicies[interfaceName]?.after ?? []),", " ],", " out,", " );", "}", "", "/**", " * Options for configuring a router with additional functionality.", " */", "export interface RouterOptions<", " RouteConfig extends { [k: string]: object } = { [k: string]: object },", "> {", " /**", " * The base path of the router.", " *", " * This should include any leading slashes, but not a trailing slash, and should not include any component", " * of the URL authority (e.g. the scheme, host, or port).", " *", " * Defaults to \"\".", " */", " basePath?: string;", "", " /**", " * A list of policies to apply to all routes _before_ routing.", " *", " * Policies are applied in the order they are listed.", " *", " * By default, the policy list is empty.", " *", " * Policies _MUST_ call `next()` to pass the request to the next policy _OR_ call `response.end()` to terminate", " * the response and _MUST NOT_ do both.", " */", " policies?: Policy[];", "", " /**", " * A record of policies that apply to specific routes.", " *", " * The policies are provided as a nested record where the keys are the business-logic interface names, and the values", " * are records of the method names in the given interface and the policies that apply to them.", " *", " * By default, no additional policies are applied to the routes.", " *", " * Policies _MUST_ call `next()` to pass the request to the next policy _OR_ call `response.end()` to terminate", " * the response and _MUST NOT_ do both.", " */", " routePolicies?: RoutePolicies<RouteConfig>;", "", " /**", " * A handler for requests where the resource is not found.", " *", " * The router will call this function when no route matches the incoming request.", " *", " * If this handler is not provided, a 404 Not Found response with a text body will be returned.", " *", " * You _MUST_ call `response.end()` to terminate the response.", " *", " * This handler is unreachable when using the Express middleware, as it will forward non-matching requests to the", " * next middleware layer in the stack.", " *", " * @param ctx - The HTTP context for the request.", " */", " onRequestNotFound?: (ctx: HttpContext) => void;", "", " /**", " * A handler for requests that fail to validate inputs.", " *", " * If this handler is not provided, a 400 Bad Request response with a JSON body containing some basic information", " * about the error will be returned to the client.", " *", " * You _MUST_ call `response.end()` to terminate the response.", " *", " * @param ctx - The HTTP context for the request.", " * @param route - The route that was matched.", " * @param error - The validation error that was thrown.", " */", " onInvalidRequest?: (ctx: HttpContext, route: string, error: ValidationError) => void;", "", " /**", " * A handler for requests that throw an error during processing.", " *", " * If this handler is not provided, a 500 Internal Server Error response with a text body and no error details will be", " * returned to the client.", " *", " * You _MUST_ call `response.end()` to terminate the response.", " *", " * If this handler itself throws an Error, the router will respond with a 500 Internal Server Error", " *", " * @param ctx - The HTTP context for the request.", " * @param error - The error that was thrown.", " */", " onInternalError?(ctx: HttpContext, error: Error): void;", "}", "", "/** Context information for operations carried over the HTTP protocol. */", "export interface HttpContext {", " /** The incoming request to the server. */", " request: http.IncomingMessage;", " /** The outgoing response object. */", " response: http.ServerResponse;", "", " /**", " * Error handling functions provided by the HTTP router. Service implementations may call these methods in case a", " * resource is not found, a request is invalid, or an internal error occurs.", " *", " * These methods will respond to the client with the appropriate status code and message.", " */", " errorHandlers: {", " /**", " * Signals that the requested resource was not found.", " */", " onRequestNotFound: Exclude<RouterOptions[\"onRequestNotFound\"], undefined>;", " /**", " * Signals that the request was invalid.", " */", " onInvalidRequest: Exclude<RouterOptions[\"onInvalidRequest\"], undefined>;", " /**", " * Signals that an internal error occurred.", " */", " onInternalError: Exclude<RouterOptions[\"onInternalError\"], undefined>;", " };", "}", "", ]; export async function createModule(parent) { if (module) return module; module = { name: "router", cursor: parent.cursor.enter("router"), imports: [], declarations: [], }; module.declarations.push(lines); parent.declarations.push(module); return module; } //# sourceMappingURL=router.js.map