mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
chore: origin middleware (#7695)
https://linear.app/unleash/issue/2-2489/create-a-first-iteration-of-an-origin-middleware-that-logs-ui-and-api Small spike around what the first iteration of an "origin middleware" would look like. No strong feelings all around, so feel free to tell me this is all wrong and we should go a different route. However diving a little bit into it personally helps me wrap my head around it, so it may help you too.
This commit is contained in:
parent
d8e756586a
commit
50167d4f9e
@ -144,6 +144,7 @@ exports[`should create default config 1`] = `
|
||||
},
|
||||
"migrationLock": true,
|
||||
"navigationSidebar": true,
|
||||
"originMiddleware": false,
|
||||
"outdatedSdksBanner": false,
|
||||
"parseProjectFromSession": false,
|
||||
"personalAccessTokensKillSwitch": false,
|
||||
|
@ -30,6 +30,7 @@ import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
|
||||
import NotFoundError from './error/notfound-error';
|
||||
import { bearerTokenMiddleware } from './middleware/bearer-token-middleware';
|
||||
import { auditAccessMiddleware } from './middleware';
|
||||
import { originMiddleware } from './middleware/origin-middleware';
|
||||
|
||||
export default async function getApp(
|
||||
config: IUnleashConfig,
|
||||
@ -177,6 +178,8 @@ export default async function getApp(
|
||||
rbacMiddleware(config, stores, services.accessService),
|
||||
);
|
||||
|
||||
app.use(`${baseUriPath}/api/admin`, originMiddleware(config));
|
||||
|
||||
app.use(`${baseUriPath}/api/admin`, auditAccessMiddleware(config));
|
||||
app.use(
|
||||
`${baseUriPath}/api/admin`,
|
||||
|
66
src/lib/middleware/origin-middleware.test.ts
Normal file
66
src/lib/middleware/origin-middleware.test.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { originMiddleware } from './origin-middleware';
|
||||
import type { IUnleashConfig } from '../types';
|
||||
import { createTestConfig } from '../../test/config/test-config';
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
const TEST_UNLEASH_TOKEN = 'TEST_UNLEASH_TOKEN';
|
||||
const TEST_USER_AGENT = 'TEST_USER_AGENT';
|
||||
|
||||
describe('originMiddleware', () => {
|
||||
const req = { headers: {}, path: '' } as Request;
|
||||
const res = {} as Response;
|
||||
const next = jest.fn();
|
||||
const loggerMock = {
|
||||
debug: jest.fn(),
|
||||
info: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
fatal: jest.fn(),
|
||||
};
|
||||
const getLogger = jest.fn(() => loggerMock);
|
||||
|
||||
let config: IUnleashConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
config = createTestConfig({
|
||||
getLogger,
|
||||
experimental: {
|
||||
flags: {
|
||||
originMiddleware: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call next', () => {
|
||||
const middleware = originMiddleware(config);
|
||||
|
||||
middleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should log UI request', () => {
|
||||
const middleware = originMiddleware(config);
|
||||
|
||||
middleware(req, res, next);
|
||||
|
||||
expect(loggerMock.debug).toHaveBeenCalledWith('UI request', {
|
||||
method: req.method,
|
||||
});
|
||||
});
|
||||
|
||||
it('should log API request', () => {
|
||||
const middleware = originMiddleware(config);
|
||||
|
||||
req.headers.authorization = TEST_UNLEASH_TOKEN;
|
||||
req.headers['user-agent'] = TEST_USER_AGENT;
|
||||
|
||||
middleware(req, res, next);
|
||||
|
||||
expect(loggerMock.debug).toHaveBeenCalledWith('API request', {
|
||||
method: req.method,
|
||||
userAgent: TEST_USER_AGENT,
|
||||
});
|
||||
});
|
||||
});
|
29
src/lib/middleware/origin-middleware.ts
Normal file
29
src/lib/middleware/origin-middleware.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import type { Request, Response, NextFunction } from 'express';
|
||||
import type { IUnleashConfig } from '../types';
|
||||
|
||||
export const originMiddleware = ({
|
||||
getLogger,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>) => {
|
||||
const logger = getLogger('/middleware/origin-middleware.ts');
|
||||
logger.debug('Enabling origin middleware');
|
||||
|
||||
return (req: Request, _: Response, next: NextFunction) => {
|
||||
if (!flagResolver.isEnabled('originMiddleware')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const isUI = !req.headers.authorization;
|
||||
|
||||
if (isUI) {
|
||||
logger.debug('UI request', { method: req.method });
|
||||
} else {
|
||||
logger.debug('API request', {
|
||||
method: req.method,
|
||||
userAgent: req.headers['user-agent'],
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
@ -70,7 +70,8 @@ export type IFlagKey =
|
||||
| 'insightsV2'
|
||||
| 'integrationEvents'
|
||||
| 'featureCollaborators'
|
||||
| 'improveCreateFlagFlow';
|
||||
| 'improveCreateFlagFlow'
|
||||
| 'originMiddleware';
|
||||
|
||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
|
||||
|
||||
@ -339,6 +340,10 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_IMPROVE_CREATE_FLAG_FLOW,
|
||||
false,
|
||||
),
|
||||
originMiddleware: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE,
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
export const defaultExperimentalOptions: IExperimentalOptions = {
|
||||
|
@ -60,6 +60,7 @@ process.nextTick(async () => {
|
||||
integrationEvents: true,
|
||||
featureCollaborators: true,
|
||||
improveCreateFlagFlow: true,
|
||||
originMiddleware: true,
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
|
Loading…
Reference in New Issue
Block a user