feat(F-003): HTTP foundation with request context and error envelope
- request_id generated or sanitized-propagated on every request (x-request-id)
- structured JSON logging (pino), one correlated line per request, injectable logger
- error envelope v2 { error: { statusCode, code, message, details? }, requestId }
- 5xx messages always generic; stack traces stay in server logs only
- explicit parseJson (zod) input validation hook at the API layer
- README HTTP contract section; deps justified in spec/tech.md
- all gates approved; verify.sh green
This commit is contained in:
18
project/src/shared/http-input.ts
Normal file
18
project/src/shared/http-input.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Explicit input validation hook for the API layer.
|
||||
* Call parseJson inside handlers; nothing is validated by magic.
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
import { AppError, type ErrorDetail } from './errors.js';
|
||||
|
||||
export function parseJson<T>(schema: z.ZodType<T>, input: unknown): T {
|
||||
const result = schema.safeParse(input);
|
||||
if (result.success) {
|
||||
return result.data;
|
||||
}
|
||||
const details: ReadonlyArray<ErrorDetail> = result.error.issues.map((issue) => ({
|
||||
path: issue.path.join('.'),
|
||||
message: issue.message,
|
||||
}));
|
||||
throw new AppError(400, 'VALIDATION_ERROR', 'Invalid request payload', details);
|
||||
}
|
||||
Reference in New Issue
Block a user