feat: establish backend foundation
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { ApiInternalServerErrorResponse, ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class SafeErrorResponseDto {
|
||||
@ApiProperty({ example: 500 })
|
||||
statusCode: number;
|
||||
|
||||
@ApiProperty({ example: 'Internal server error' })
|
||||
message: string;
|
||||
|
||||
@ApiProperty({ example: '/api/v1' })
|
||||
path: string;
|
||||
}
|
||||
|
||||
export function ApiSafeErrorResponse(): MethodDecorator & ClassDecorator {
|
||||
return ApiInternalServerErrorResponse({
|
||||
description: 'Internal server error',
|
||||
type: SafeErrorResponseDto,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ArgumentsHost } from '@nestjs/common';
|
||||
import { HttpExceptionFilter } from './http-exception.filter';
|
||||
|
||||
describe('HttpExceptionFilter', () => {
|
||||
it('does not expose internal error details', () => {
|
||||
const status = jest.fn().mockReturnThis();
|
||||
const json = jest.fn();
|
||||
const filter = new HttpExceptionFilter();
|
||||
const host = {
|
||||
switchToHttp: () => ({
|
||||
getRequest: () => ({
|
||||
path: '/api/v1/health',
|
||||
url: '/api/v1/health?access_token=secret',
|
||||
}),
|
||||
getResponse: () => ({ status, json }),
|
||||
}),
|
||||
} as unknown as ArgumentsHost;
|
||||
|
||||
filter.catch(new Error('database password: secret'), host);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(500);
|
||||
expect(json).toHaveBeenCalledWith({
|
||||
statusCode: 500,
|
||||
message: 'Internal server error',
|
||||
path: '/api/v1/health',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
ArgumentsHost,
|
||||
Catch,
|
||||
ExceptionFilter,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request, Response } from 'express';
|
||||
|
||||
@Catch()
|
||||
export class HttpExceptionFilter implements ExceptionFilter {
|
||||
catch(exception: unknown, host: ArgumentsHost): void {
|
||||
const context = host.switchToHttp();
|
||||
const response = context.getResponse<Response>();
|
||||
const request = context.getRequest<Request>();
|
||||
const status =
|
||||
exception instanceof HttpException
|
||||
? exception.getStatus()
|
||||
: HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
response.status(status).json({
|
||||
statusCode: status,
|
||||
message: status === 500 ? 'Internal server error' : 'Request failed',
|
||||
path: request.path,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user