UNPKG

16.4 kBTypeScriptView Raw
1/// <reference types="node" />
2import { Application, Binding, BindingAddress, Constructor, Server } from '@loopback/core';
3import { BaseMiddlewareRegistry, ExpressRequestHandler } from '@loopback/express';
4import { HttpServer, HttpServerOptions } from '@loopback/http-server';
5import { OASEnhancerService, OpenApiSpec, OperationObject, ServerObject } from '@loopback/openapi-v3';
6import cors from 'cors';
7import express, { ErrorRequestHandler } from 'express';
8import { PathParams } from 'express-serve-static-core';
9import { IncomingMessage, ServerResponse } from 'http';
10import { ServeStaticOptions } from 'serve-static';
11import { BodyParser } from './body-parsers';
12import { HttpHandler } from './http-handler';
13import { RequestContext } from './request-context';
14import { ControllerClass, ControllerFactory, ControllerInstance, RestRouterOptions, RouteEntry, RouterSpec } from './router';
15import { SequenceFunction, SequenceHandler } from './sequence';
16import { Request, RequestBodyParserOptions, Response } from './types';
17export type HttpRequestListener = (req: IncomingMessage, res: ServerResponse) => void;
18export interface HttpServerLike {
19 requestHandler: HttpRequestListener;
20}
21/**
22 * A REST API server for use with Loopback.
23 * Add this server to your application by importing the RestComponent.
24 *
25 * @example
26 * ```ts
27 * const app = new MyApplication();
28 * app.component(RestComponent);
29 * ```
30 *
31 * To add additional instances of RestServer to your application, use the
32 * `.server` function:
33 * ```ts
34 * app.server(RestServer, 'nameOfYourServer');
35 * ```
36 *
37 * By default, one instance of RestServer will be created when the RestComponent
38 * is bootstrapped. This instance can be retrieved with
39 * `app.getServer(RestServer)`, or by calling `app.get('servers.RestServer')`
40 * Note that retrieving other instances of RestServer must be done using the
41 * server's name:
42 * ```ts
43 * const server = await app.getServer('foo')
44 * // OR
45 * const server = await app.get('servers.foo');
46 * ```
47 */
48export declare class RestServer extends BaseMiddlewareRegistry implements Server, HttpServerLike {
49 /**
50 * Handle incoming HTTP(S) request by invoking the corresponding
51 * Controller method via the configured Sequence.
52 *
53 * @example
54 *
55 * ```ts
56 * const app = new Application();
57 * app.component(RestComponent);
58 * // setup controllers, etc.
59 *
60 * const restServer = await app.getServer(RestServer);
61 * const httpServer = http.createServer(restServer.requestHandler);
62 * httpServer.listen(3000);
63 * ```
64 *
65 * @param req - The request.
66 * @param res - The response.
67 */
68 protected oasEnhancerService: OASEnhancerService;
69 get OASEnhancer(): OASEnhancerService;
70 protected _requestHandler: HttpRequestListener;
71 get requestHandler(): HttpRequestListener;
72 readonly config: RestServerResolvedConfig;
73 private _basePath;
74 protected _httpHandler: HttpHandler;
75 protected get httpHandler(): HttpHandler;
76 /**
77 * Context event subscriptions for route related changes
78 */
79 private _routesEventSubscription;
80 protected _httpServer: HttpServer | undefined;
81 protected _expressApp?: express.Application;
82 get listening(): boolean;
83 get httpServer(): HttpServer | undefined;
84 /**
85 * The base url for the server, including the basePath if set. For example,
86 * the value will be 'http://localhost:3000/api' if `basePath` is set to
87 * '/api'.
88 */
89 get url(): string | undefined;
90 /**
91 * The root url for the server without the basePath. For example, the value
92 * will be 'http://localhost:3000' regardless of the `basePath`.
93 */
94 get rootUrl(): string | undefined;
95 /**
96 *
97 * Creates an instance of RestServer.
98 *
99 * @param app - The application instance (injected via
100 * CoreBindings.APPLICATION_INSTANCE).
101 * @param config - The configuration options (injected via
102 * RestBindings.CONFIG).
103 *
104 */
105 constructor(app: Application, config?: RestServerConfig);
106 protected _setupOASEnhancerIfNeeded(): void;
107 protected _setupRequestHandlerIfNeeded(): void;
108 /**
109 * Get an Express handler for unexpected errors
110 */
111 protected _unexpectedErrorHandler(): ErrorRequestHandler;
112 /**
113 * Apply express settings.
114 */
115 protected _applyExpressSettings(): void;
116 /**
117 * Mount /openapi.json, /openapi.yaml for specs and /swagger-ui, /explorer
118 * to redirect to externally hosted API explorer
119 */
120 protected _setupOpenApiSpecEndpoints(): void;
121 /**
122 * Add a new non-controller endpoint hosting a form of the OpenAPI spec.
123 *
124 * @param path Path at which to host the copy of the OpenAPI
125 * @param form Form that should be rendered from that path
126 */
127 addOpenApiSpecEndpoint(path: string, form: OpenApiSpecForm, router?: express.Router): void;
128 protected _handleHttpRequest(request: Request, response: Response): Promise<void>;
129 protected _setupHandlerIfNeeded(): void;
130 /**
131 * Create an instance of HttpHandler and populates it with routes
132 */
133 private _createHttpHandler;
134 private _setupOperation;
135 private _serveOpenApiSpec;
136 private _redirectToSwaggerUI;
137 /**
138 * Register a controller class with this server.
139 *
140 * @param controllerCtor - The controller class
141 * (constructor function).
142 * @returns The newly created binding, you can use the reference to
143 * further modify the binding, e.g. lock the value to prevent further
144 * modifications.
145 *
146 * @example
147 * ```ts
148 * class MyController {
149 * }
150 * app.controller(MyController).lock();
151 * ```
152 *
153 */
154 controller(controllerCtor: ControllerClass<ControllerInstance>): Binding;
155 /**
156 * Register a new Controller-based route.
157 *
158 * @example
159 * ```ts
160 * class MyController {
161 * greet(name: string) {
162 * return `hello ${name}`;
163 * }
164 * }
165 * app.route('get', '/greet', operationSpec, MyController, 'greet');
166 * ```
167 *
168 * @param verb - HTTP verb of the endpoint
169 * @param path - URL path of the endpoint
170 * @param spec - The OpenAPI spec describing the endpoint (operation)
171 * @param controllerCtor - Controller constructor
172 * @param controllerFactory - A factory function to create controller instance
173 * @param methodName - The name of the controller method
174 */
175 route<I extends object>(verb: string, path: string, spec: OperationObject, controllerCtor: ControllerClass<I>, controllerFactory: ControllerFactory<I>, methodName: string): Binding;
176 /**
177 * Register a new route invoking a handler function.
178 *
179 * @example
180 * ```ts
181 * function greet(name: string) {
182 * return `hello ${name}`;
183 * }
184 * app.route('get', '/', operationSpec, greet);
185 * ```
186 *
187 * @param verb - HTTP verb of the endpoint
188 * @param path - URL path of the endpoint
189 * @param spec - The OpenAPI spec describing the endpoint (operation)
190 * @param handler - The function to invoke with the request parameters
191 * described in the spec.
192 */
193 route(verb: string, path: string, spec: OperationObject, handler: Function): Binding;
194 /**
195 * Register a new generic route.
196 *
197 * @example
198 * ```ts
199 * function greet(name: string) {
200 * return `hello ${name}`;
201 * }
202 * const route = new Route('get', '/', operationSpec, greet);
203 * app.route(route);
204 * ```
205 *
206 * @param route - The route to add.
207 */
208 route(route: RouteEntry): Binding;
209 private bindRoute;
210 /**
211 * Register a route redirecting callers to a different URL.
212 *
213 * @example
214 * ```ts
215 * server.redirect('/explorer', '/explorer/');
216 * ```
217 *
218 * @param fromPath - URL path of the redirect endpoint
219 * @param toPathOrUrl - Location (URL path or full URL) where to redirect to.
220 * If your server is configured with a custom `basePath`, then the base path
221 * is prepended to the target location.
222 * @param statusCode - HTTP status code to respond with,
223 * defaults to 303 (See Other).
224 */
225 redirect(fromPath: string, toPathOrUrl: string, statusCode?: number): Binding;
226 private _externalRoutes;
227 /**
228 * Mount static assets to the REST server.
229 * See https://expressjs.com/en/4x/api.html#express.static
230 * @param path - The path(s) to serve the asset.
231 * See examples at https://expressjs.com/en/4x/api.html#path-examples
232 * @param rootDir - The root directory from which to serve static assets
233 * @param options - Options for serve-static
234 */
235 static(path: PathParams, rootDir: string, options?: ServeStaticOptions): void;
236 /**
237 * Set the OpenAPI specification that defines the REST API schema for this
238 * server. All routes, parameter definitions and return types will be defined
239 * in this way.
240 *
241 * Note that this will override any routes defined via decorators at the
242 * controller level (this function takes precedent).
243 *
244 * @param spec - The OpenAPI specification, as an object.
245 * @returns Binding for the spec
246 *
247 */
248 api(spec: OpenApiSpec): Binding;
249 /**
250 * Get the OpenAPI specification describing the REST API provided by
251 * this application.
252 *
253 * This method merges operations (HTTP endpoints) from the following sources:
254 * - `app.api(spec)`
255 * - `app.controller(MyController)`
256 * - `app.route(route)`
257 * - `app.route('get', '/greet', operationSpec, MyController, 'greet')`
258 *
259 * If the optional `requestContext` is provided, then the `servers` list
260 * in the returned spec will be updated to work in that context.
261 * Specifically:
262 * 1. if `config.openApi.setServersFromRequest` is enabled, the servers
263 * list will be replaced with the context base url
264 * 2. Any `servers` entries with a path of `/` will have that path
265 * replaced with `requestContext.basePath`
266 *
267 * @param requestContext - Optional context to update the `servers` list
268 * in the returned spec
269 */
270 getApiSpec(requestContext?: RequestContext): Promise<OpenApiSpec>;
271 /**
272 * Update or rebuild OpenAPI Spec object to be appropriate for the context of
273 * a specific request for the spec, leveraging both app config and request
274 * path information.
275 *
276 * @param spec base spec object from which to start
277 * @param requestContext request to use to infer path information
278 * @returns Updated or rebuilt spec object to use in the context of the request
279 */
280 private updateSpecFromRequest;
281 /**
282 * Configure a custom sequence class for handling incoming requests.
283 *
284 * @example
285 * ```ts
286 * class MySequence implements SequenceHandler {
287 * constructor(
288 * @inject('send) public send: Send)) {
289 * }
290 *
291 * public async handle({response}: RequestContext) {
292 * send(response, 'hello world');
293 * }
294 * }
295 * ```
296 *
297 * @param sequenceClass - The sequence class to invoke for each incoming request.
298 */
299 sequence(sequenceClass: Constructor<SequenceHandler>): Binding<SequenceHandler>;
300 /**
301 * Configure a custom sequence function for handling incoming requests.
302 *
303 * @example
304 * ```ts
305 * app.handler(({request, response}, sequence) => {
306 * sequence.send(response, 'hello world');
307 * });
308 * ```
309 *
310 * @param handlerFn - The handler to invoke for each incoming request.
311 */
312 handler(handlerFn: SequenceFunction): void;
313 /**
314 * Bind a body parser to the server context
315 * @param parserClass - Body parser class
316 * @param address - Optional binding address
317 */
318 bodyParser(bodyParserClass: Constructor<BodyParser>, address?: BindingAddress<BodyParser>): Binding<BodyParser>;
319 /**
320 * Configure the `basePath` for the rest server
321 * @param path - Base path
322 */
323 basePath(path?: string): void;
324 /**
325 * Start this REST API's HTTP/HTTPS server.
326 */
327 start(): Promise<void>;
328 /**
329 * Stop this REST API's HTTP/HTTPS server.
330 */
331 stop(): Promise<void>;
332 /**
333 * Mount an Express router to expose additional REST endpoints handled
334 * via legacy Express-based stack.
335 *
336 * @param basePath - Path where to mount the router at, e.g. `/` or `/api`.
337 * @param router - The Express router to handle the requests.
338 * @param spec - A partial OpenAPI spec describing endpoints provided by the
339 * router. LoopBack will prepend `basePath` to all endpoints automatically.
340 * This argument is optional. You can leave it out if you don't want to
341 * document the routes.
342 */
343 mountExpressRouter(basePath: string, router: ExpressRequestHandler, spec?: RouterSpec): void;
344 /**
345 * Export the OpenAPI spec to the given json or yaml file
346 * @param outFile - File name for the spec. The extension of the file
347 * determines the format of the file.
348 * - `yaml` or `yml`: YAML
349 * - `json` or other: JSON
350 * If the outFile is not provided or its value is `''` or `'-'`, the spec is
351 * written to the console using the `log` function.
352 * @param log - Log function, default to `console.log`
353 */
354 exportOpenApiSpec(outFile?: string, log?: (message?: any, ...optionalParams: any[]) => void): Promise<void>;
355}
356/**
357 * Create a binding for the given body parser class
358 * @param parserClass - Body parser class
359 * @param key - Optional binding address
360 */
361export declare function createBodyParserBinding(parserClass: Constructor<BodyParser>, key?: BindingAddress<BodyParser>): Binding<BodyParser>;
362/**
363 * The form of OpenAPI specs to be served
364 */
365export interface OpenApiSpecForm {
366 version?: string;
367 format?: string;
368}
369/**
370 * Options to customize how OpenAPI specs are served
371 */
372export interface OpenApiSpecOptions {
373 /**
374 * Mapping of urls to spec forms, by default:
375 * <br>
376 * {
377 * <br>
378 * '/openapi.json': {version: '3.0.0', format: 'json'},
379 * <br>
380 * '/openapi.yaml': {version: '3.0.0', format: 'yaml'},
381 * <br>
382 * }
383 *
384 */
385 endpointMapping?: {
386 [key: string]: OpenApiSpecForm;
387 };
388 /**
389 * A flag to force `servers` to be set from the http request for the OpenAPI
390 * spec
391 */
392 setServersFromRequest?: boolean;
393 /**
394 * Configure servers for OpenAPI spec
395 */
396 servers?: ServerObject[];
397 /**
398 * Set this flag to disable the endpoint for OpenAPI spec
399 */
400 disabled?: true;
401 /**
402 * Set this flag to `false` to disable OAS schema consolidation. If not set,
403 * the value defaults to `true`.
404 */
405 consolidate?: boolean;
406}
407export interface ApiExplorerOptions {
408 /**
409 * URL for the hosted API explorer UI
410 * default to https://loopback.io/api-explorer
411 */
412 url?: string;
413 /**
414 * URL for the API explorer served over `http` protocol to deal with mixed
415 * content security imposed by browsers as the spec is exposed over `http` by
416 * default.
417 * See https://github.com/loopbackio/loopback-next/issues/1603
418 */
419 httpUrl?: string;
420 /**
421 * Set this flag to disable the built-in redirect to externally
422 * hosted API Explorer UI.
423 */
424 disabled?: true;
425}
426/**
427 * RestServer options
428 */
429export type RestServerOptions = Partial<RestServerResolvedOptions>;
430export interface RestServerResolvedOptions {
431 port: number;
432 path?: string;
433 /**
434 * Base path for API/static routes
435 */
436 basePath?: string;
437 cors: cors.CorsOptions;
438 openApiSpec: OpenApiSpecOptions;
439 apiExplorer: ApiExplorerOptions;
440 requestBodyParser?: RequestBodyParserOptions;
441 sequence?: Constructor<SequenceHandler>;
442 expressSettings: {
443 [name: string]: any;
444 };
445 router: RestRouterOptions;
446 /**
447 * Set this flag to `false` to not listen on connections when the REST server
448 * is started. It's useful to mount a LoopBack REST server as a route to the
449 * facade Express application. If not set, the value is default to `true`.
450 */
451 listenOnStart?: boolean;
452}
453/**
454 * Valid configuration for the RestServer constructor.
455 */
456export type RestServerConfig = RestServerOptions & HttpServerOptions;
457export type RestServerResolvedConfig = RestServerResolvedOptions & HttpServerOptions;
458
\No newline at end of file