Merge pull request #24316 from alecjacobs5401/rootHttpRouter-server-configuration
feat(backend-app-api): enable Node.js server configuration in the rootHttpRouter service
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
Add ability to configure the Node.js HTTP Server when configuring the root HTTP Router service
|
||||
@@ -5,7 +5,7 @@ sidebar_label: Root Http Router
|
||||
description: Documentation for the Root Http Router service
|
||||
---
|
||||
|
||||
The root HTTP router is a service that allows you to register routes on the root of the backend service. This is useful for things like health checks, or other routes that you want to expose on the root of the backend service. It is used as the base router that backs the `httpRouter` service. Most likely you won't need to use this service directly, but rather use the `httpRouter` service.
|
||||
The root HTTP router is a service that allows you to register routes on the root of the backend service. This is useful for things like health checks, or other routes that you want to expose on the root of the backend service. It is used as the base router that backs the `httpRouter` service and starts the Node.js HTTP server on backend startup. Most likely you won't need to use this service directly, but rather use the `httpRouter` service.
|
||||
|
||||
The `/api/:pluginId/` path prefix is reserved for use by plugins to register their own routes via the [HttpRouter](./http-router.md) service.
|
||||
|
||||
@@ -78,3 +78,26 @@ backend.add(
|
||||
```
|
||||
|
||||
Note that requests towards `/api/*` will never be handled by the `routes` handler unless a matching plugin exists, and will instead typically falling through to the `middleware.notFound()` handler. That is the case regardless of whether there is a configured `indexPath` or not.
|
||||
|
||||
The root HTTP Router service also allows for configuration of the underlying Node.js HTTP server object. This is useful for modifying settings on the HTTP server itself, such as server [timeout](https://nodejs.org/api/http.html#servertimeout), [keepAliveTimeout](https://nodejs.org/api/http.html#serverkeepalivetimeout), and [headersTimeout](https://nodejs.org/api/http.html#serverheaderstimeout).
|
||||
|
||||
A `applyDefaults` helper is also made available to use the default app/router configuration while still enabling custom server configuration
|
||||
|
||||
```ts
|
||||
import { rootHttpRouterServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
rootHttpRouterServiceFactory({
|
||||
configure: ({ server, applyDefaults }) => {
|
||||
// apply default app/router configuration
|
||||
applyDefaults();
|
||||
|
||||
// customize the Node.js HTTP Server timeouts
|
||||
server.keepAliveTimeout = 65 * 1000;
|
||||
server.headersTimeout = 66 * 1000;
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
@@ -37,6 +37,7 @@ import { RootHttpRouterService } from '@backstage/backend-plugin-api';
|
||||
import { RootLifecycleService } from '@backstage/backend-plugin-api';
|
||||
import { RootLoggerService } from '@backstage/backend-plugin-api';
|
||||
import { SchedulerService } from '@backstage/backend-plugin-api';
|
||||
import type { Server } from 'node:http';
|
||||
import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api';
|
||||
import { TokenManagerService } from '@backstage/backend-plugin-api';
|
||||
@@ -287,6 +288,8 @@ export interface RootHttpRouterConfigureContext {
|
||||
// (undocumented)
|
||||
app: Express_2;
|
||||
// (undocumented)
|
||||
applyDefaults: () => void;
|
||||
// (undocumented)
|
||||
config: RootConfigService;
|
||||
// (undocumented)
|
||||
lifecycle: LifecycleService;
|
||||
@@ -296,6 +299,8 @@ export interface RootHttpRouterConfigureContext {
|
||||
middleware: MiddlewareFactory;
|
||||
// (undocumented)
|
||||
routes: RequestHandler;
|
||||
// (undocumented)
|
||||
server: Server;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
+25
-19
@@ -22,6 +22,7 @@ import {
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import express, { RequestHandler, Express } from 'express';
|
||||
import type { Server } from 'node:http';
|
||||
import {
|
||||
createHttpServer,
|
||||
MiddlewareFactory,
|
||||
@@ -34,11 +35,13 @@ import { DefaultRootHttpRouter } from './DefaultRootHttpRouter';
|
||||
*/
|
||||
export interface RootHttpRouterConfigureContext {
|
||||
app: Express;
|
||||
server: Server;
|
||||
middleware: MiddlewareFactory;
|
||||
routes: RequestHandler;
|
||||
config: RootConfigService;
|
||||
logger: LoggerService;
|
||||
lifecycle: LifecycleService;
|
||||
applyDefaults: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,15 +57,8 @@ export type RootHttpRouterFactoryOptions = {
|
||||
configure?(context: RootHttpRouterConfigureContext): void;
|
||||
};
|
||||
|
||||
function defaultConfigure(context: RootHttpRouterConfigureContext) {
|
||||
const { app, routes, middleware } = context;
|
||||
app.use(middleware.helmet());
|
||||
app.use(middleware.cors());
|
||||
app.use(middleware.compression());
|
||||
app.use(middleware.logging());
|
||||
app.use(routes);
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
function defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {
|
||||
applyDefaults();
|
||||
}
|
||||
|
||||
/** @public */
|
||||
@@ -81,22 +77,32 @@ export const rootHttpRouterServiceFactory = createServiceFactory(
|
||||
|
||||
const router = DefaultRootHttpRouter.create({ indexPath });
|
||||
const middleware = MiddlewareFactory.create({ config, logger });
|
||||
|
||||
configure({
|
||||
app,
|
||||
routes: router.handler(),
|
||||
middleware,
|
||||
config,
|
||||
logger,
|
||||
lifecycle,
|
||||
});
|
||||
|
||||
const routes = router.handler();
|
||||
const server = await createHttpServer(
|
||||
app,
|
||||
readHttpServerOptions(config.getOptionalConfig('backend')),
|
||||
{ logger },
|
||||
);
|
||||
|
||||
configure({
|
||||
app,
|
||||
server,
|
||||
routes,
|
||||
middleware,
|
||||
config,
|
||||
logger,
|
||||
lifecycle,
|
||||
applyDefaults() {
|
||||
app.use(middleware.helmet());
|
||||
app.use(middleware.cors());
|
||||
app.use(middleware.compression());
|
||||
app.use(middleware.logging());
|
||||
app.use(routes);
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
},
|
||||
});
|
||||
|
||||
lifecycle.addShutdownHook(() => server.stop());
|
||||
|
||||
await server.start();
|
||||
|
||||
Reference in New Issue
Block a user