feat(proxy-backend): configure request body revival for all targets
Signed-off-by: Dan Hoizner <dan.hoizner@gmail.com>
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-proxy-backend': minor
|
||||
---
|
||||
|
||||
The proxy-backend plugin now supports reviving request bodies that have previously been consumed by an express middleware (e.g. `express.json()`). This is done by setting `reviveRequestBody: true` on the proxy configuration. In order to preserve the current behavior, the proxy will **not** revive request bodies by default.
|
||||
|
||||
The following is an example of a proxy configuration that revives request bodies:
|
||||
|
||||
```diff
|
||||
proxy:
|
||||
'/target':
|
||||
target: 'http://proxy-route'
|
||||
+ reviveRequestBody: true
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
'@backstage/plugin-proxy-backend': patch
|
||||
---
|
||||
|
||||
The proxy-backend plugin now supports reviving request bodies that have previously been consumed by an express middleware (e.g. `express.json()`). This is done by setting `reviveConsumedRequestBodies: true` on the proxy `RouterOptions`. In order to preserve the current behavior, the proxy will **not** revive request bodies by default.
|
||||
|
||||
The following is an example of a proxy `createRouter` invocation that revives request bodies:
|
||||
|
||||
```diff
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
discovery,
|
||||
+ reviveConsumedRequestBodies: true,
|
||||
});
|
||||
```
|
||||
@@ -17,6 +17,7 @@ export const proxyPlugin: (
|
||||
options?:
|
||||
| {
|
||||
skipInvalidProxies?: boolean | undefined;
|
||||
reviveConsumedRequestBodies?: boolean | undefined;
|
||||
}
|
||||
| undefined,
|
||||
) => BackendFeature;
|
||||
@@ -30,6 +31,8 @@ export interface RouterOptions {
|
||||
// (undocumented)
|
||||
logger: Logger;
|
||||
// (undocumented)
|
||||
reviveConsumedRequestBodies?: boolean;
|
||||
// (undocumented)
|
||||
skipInvalidProxies?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
Vendored
-5
@@ -50,11 +50,6 @@ export interface Config {
|
||||
* and headers that are set by the proxy will be forwarded.
|
||||
*/
|
||||
allowedHeaders?: string[];
|
||||
/**
|
||||
* Revive request body if it was consumed by a middleware before reaching the proxy. By default, the request
|
||||
* body is not revived.
|
||||
*/
|
||||
reviveRequestBody?: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,10 @@ import { createRouter } from './service/router';
|
||||
* @alpha
|
||||
*/
|
||||
export const proxyPlugin = createBackendPlugin(
|
||||
(options?: { skipInvalidProxies?: boolean }) => ({
|
||||
(options?: {
|
||||
skipInvalidProxies?: boolean;
|
||||
reviveConsumedRequestBodies?: boolean;
|
||||
}) => ({
|
||||
pluginId: 'proxy',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
@@ -44,6 +47,7 @@ export const proxyPlugin = createBackendPlugin(
|
||||
discovery,
|
||||
logger: loggerToWinstonLogger(logger),
|
||||
skipInvalidProxies: options?.skipInvalidProxies,
|
||||
reviveConsumedRequestBodies: options?.reviveConsumedRequestBodies,
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -36,25 +36,30 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction<
|
||||
|
||||
describe('createRouter', () => {
|
||||
describe('where all proxy config are valid', () => {
|
||||
const logger = getVoidLogger();
|
||||
const config = new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'https://example.com:7007',
|
||||
listen: {
|
||||
port: 7007,
|
||||
},
|
||||
},
|
||||
proxy: {
|
||||
'/test': {
|
||||
target: 'https://example.com',
|
||||
headers: {
|
||||
Authorization: 'Bearer supersecret',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
|
||||
beforeEach(() => {
|
||||
mockCreateProxyMiddleware.mockClear();
|
||||
});
|
||||
|
||||
it('works', async () => {
|
||||
const logger = getVoidLogger();
|
||||
const config = new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'https://example.com:7007',
|
||||
listen: {
|
||||
port: 7007,
|
||||
},
|
||||
},
|
||||
proxy: {
|
||||
'/test': {
|
||||
target: 'https://example.com',
|
||||
headers: {
|
||||
Authorization: 'Bearer supersecret',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
@@ -62,6 +67,36 @@ describe('createRouter', () => {
|
||||
});
|
||||
expect(router).toBeDefined();
|
||||
});
|
||||
|
||||
it('revives request bodies when set', async () => {
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
discovery,
|
||||
reviveConsumedRequestBodies: true,
|
||||
});
|
||||
expect(router).toBeDefined();
|
||||
|
||||
expect(
|
||||
mockCreateProxyMiddleware.mock.calls[0][1]?.onProxyReq,
|
||||
).toBeDefined();
|
||||
expect(mockCreateProxyMiddleware.mock.calls[0][1]?.onProxyReq).toEqual(
|
||||
fixRequestBody,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not revive request bodies when not set', async () => {
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
expect(router).toBeDefined();
|
||||
|
||||
expect(
|
||||
mockCreateProxyMiddleware.mock.calls[0][1]?.onProxyReq,
|
||||
).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('where buildMiddleware would fail', () => {
|
||||
@@ -395,10 +430,15 @@ describe('buildMiddleware', () => {
|
||||
});
|
||||
|
||||
it('revives request body when configured', async () => {
|
||||
buildMiddleware('/proxy', logger, '/test', {
|
||||
target: 'http://mocked',
|
||||
reviveRequestBody: true,
|
||||
});
|
||||
buildMiddleware(
|
||||
'/proxy',
|
||||
logger,
|
||||
'/test',
|
||||
{
|
||||
target: 'http://mocked',
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
expect(createProxyMiddleware).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ export interface RouterOptions {
|
||||
config: Config;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
skipInvalidProxies?: boolean;
|
||||
reviveConsumedRequestBodies?: boolean;
|
||||
}
|
||||
|
||||
export interface ProxyConfig extends Options {
|
||||
@@ -69,6 +70,7 @@ export function buildMiddleware(
|
||||
logger: Logger,
|
||||
route: string,
|
||||
config: string | ProxyConfig,
|
||||
reviveConsumedRequestBodies?: boolean,
|
||||
): RequestHandler {
|
||||
const fullConfig =
|
||||
typeof config === 'string' ? { target: config } : { ...config };
|
||||
@@ -177,7 +179,7 @@ export function buildMiddleware(
|
||||
});
|
||||
};
|
||||
|
||||
if (fullConfig.reviveRequestBody) {
|
||||
if (reviveConsumedRequestBodies) {
|
||||
fullConfig.onProxyReq = fixRequestBody;
|
||||
}
|
||||
|
||||
@@ -248,7 +250,13 @@ function configureMiddlewares(
|
||||
try {
|
||||
router.use(
|
||||
route,
|
||||
buildMiddleware(pathPrefix, options.logger, route, proxyRouteConfig),
|
||||
buildMiddleware(
|
||||
pathPrefix,
|
||||
options.logger,
|
||||
route,
|
||||
proxyRouteConfig,
|
||||
options.reviveConsumedRequestBodies,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
if (options.skipInvalidProxies) {
|
||||
|
||||
Reference in New Issue
Block a user