fix: sanitize unexpected API error responses
- Add a centralized Fastify error handler with server-side error logging - Preserve valid 4xx status codes while normalizing other errors to HTTP 500 - Return generic error messages without exposing sensitive internal details - Add a test endpoint and regression test for unexpected errors
This commit is contained in:
parent
c0ca16f166
commit
0115190510
2 changed files with 32 additions and 1 deletions
|
|
@ -103,4 +103,17 @@ describe("API endpoints", () => {
|
||||||
|
|
||||||
assert.equal(response.statusCode, 404);
|
assert.equal(response.statusCode, 404);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("returns a generic 500 response for unexpected error", async () => {
|
||||||
|
const response = await app.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: "/test-error",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(response.statusCode, 500);
|
||||||
|
assert.deepEqual(response.json(), {
|
||||||
|
error: "Internal Server Error",
|
||||||
|
});
|
||||||
|
assert.equal(response.body.includes("Sensitive internal detail"), false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import Fastify from "fastify";
|
import Fastify, { type FastifyError } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const echoSchema = z.object({
|
const echoSchema = z.object({
|
||||||
|
|
@ -10,6 +10,20 @@ export const buildApp = () => {
|
||||||
logger: true,
|
logger: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.setErrorHandler((error: FastifyError, request, reply) => {
|
||||||
|
request.log.error(error);
|
||||||
|
|
||||||
|
const candidateStatusCode = error.statusCode ?? 500;
|
||||||
|
const statusCode =
|
||||||
|
candidateStatusCode >= 400 && candidateStatusCode < 500
|
||||||
|
? candidateStatusCode
|
||||||
|
: 500;
|
||||||
|
|
||||||
|
return reply.code(statusCode).send({
|
||||||
|
error: statusCode === 500 ? "Internal Server Error" : "Request Error",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/health", async () => ({
|
app.get("/health", async () => ({
|
||||||
status: "ok",
|
status: "ok",
|
||||||
}));
|
}));
|
||||||
|
|
@ -35,6 +49,10 @@ export const buildApp = () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get("/test-error", async () => {
|
||||||
|
throw new Error("Sensitive internal detail");
|
||||||
|
});
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue