0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(core): dont throw for status errors in prod (#5690)

* refactor(core): dont throw for status errors in prod

* refactor(core): report to AppInsights
This commit is contained in:
Gao Sun 2024-04-16 17:36:56 +08:00 committed by GitHub
parent de47d6ab5e
commit 368385b93d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 42 additions and 9 deletions

View file

@ -0,0 +1,5 @@
---
"@logto/core": patch
---
Management API will not return 500 in production for status codes that are not listed in the OpenAPI spec

View file

@ -1,6 +1,7 @@
import { createMockUtils } from '@logto/shared/esm';
import { z } from 'zod';
import { EnvSet } from '#src/env-set/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import ServerError from '#src/errors/ServerError/index.js';
import { emptyMiddleware, createContextWithRouteParameters } from '#src/utils/test-utils.js';
@ -135,6 +136,26 @@ describe('koaGuardMiddleware', () => {
await expect(koaGuard({ status: [200, 204] })(ctx, next)).rejects.toThrow(ServerError);
});
it('should not throw when status is invalid in production', async () => {
const ctx = {
...baseCtx,
params: {},
body: {},
guard: {},
response: { status: 301 },
};
const { isProduction } = EnvSet.values;
// eslint-disable-next-line @silverhand/fp/no-mutating-assign
Object.assign(EnvSet.values, { isProduction: true });
// @ts-expect-error
await expect(koaGuard({ status: 200 })(ctx, next)).resolves.toBeUndefined();
// @ts-expect-error
await expect(koaGuard({ status: [200, 204] })(ctx, next)).resolves.toBeUndefined();
// eslint-disable-next-line @silverhand/fp/no-mutating-assign
Object.assign(EnvSet.values, { isProduction });
});
it('should throw when inner middleware throws invalid status', async () => {
const ctx = {
...baseCtx,

View file

@ -1,3 +1,4 @@
import { appInsights } from '@logto/app-insights/node';
import type { Optional } from '@silverhand/essentials';
import { has } from '@silverhand/essentials';
import type { MiddlewareType } from 'koa';
@ -8,7 +9,6 @@ import type { ZodType, ZodTypeDef } from 'zod';
import { EnvSet } from '#src/env-set/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import { ResponseBodyError, StatusCodeError } from '#src/errors/ServerError/index.js';
import assertThat from '#src/utils/assert-that.js';
import { consoleLog } from '#src/utils/console.js';
/** Configure what and how to guard. */
@ -174,6 +174,9 @@ export default function koaGuard<
* Assert the status code matches the value(s) in the config. If the config does not
* specify a status code, it will not assert anything.
*
* In production, it will log a warning if the status code does not match the value(s) in the
* config for better user experience.
*
* @param value The status code to assert.
* @throws {StatusCodeError} If the status code does not match the value(s) in the config.
*/
@ -182,10 +185,17 @@ export default function koaGuard<
return;
}
assertThat(
Array.isArray(status) ? status.includes(value) : status === value,
new StatusCodeError(status, value)
);
if (Array.isArray(status) ? status.includes(value) : status === value) {
return;
}
if (EnvSet.values.isProduction) {
consoleLog.warn('Unexpected status code:', value, 'expected:', status);
void appInsights.trackException(new StatusCodeError(status, value));
return;
}
throw new StatusCodeError(status, value);
};
try {
@ -215,10 +225,7 @@ export default function koaGuard<
// the properties that are not defined in the schema.
ctx.body = result.data;
} else {
if (!EnvSet.values.isProduction) {
consoleLog.error('Invalid response:', result.error);
}
consoleLog.error('Invalid response:', result.error);
throw new ResponseBodyError(result.error);
}
}