- Added serverless-offline plugin to package.json and serverless.yml for local development. - Implemented new showSuggestion function in host.yml with appropriate memory size and event configuration. - Removed deprecated getSuggestion function from minglaradmin.yml and updated related handlers. - Enhanced safeHandler to convert Prisma errors to ApiError automatically, improving error handling. - Introduced comprehensive Prisma error handling in ApiError.ts, mapping error codes to user-friendly messages and HTTP status codes.
124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
// safeHandler.ts
|
|
import { APIGatewayProxyEvent, Context, APIGatewayProxyResult } from 'aws-lambda';
|
|
import ApiError from '../helper/ApiError';
|
|
|
|
export const safeHandler = (
|
|
handler: (event: APIGatewayProxyEvent, context?: Context) => Promise<APIGatewayProxyResult | any>
|
|
): ((event: APIGatewayProxyEvent, context: Context) => Promise<APIGatewayProxyResult>) => {
|
|
return async (event, context) => {
|
|
try {
|
|
const result = await handler(event, context);
|
|
|
|
// If handler returned null/undefined → return 204 response
|
|
if (!result) {
|
|
return {
|
|
statusCode: 204,
|
|
body: JSON.stringify({
|
|
success: true,
|
|
statusCode: 204,
|
|
message: 'No content',
|
|
data: null,
|
|
}),
|
|
};
|
|
}
|
|
|
|
// If handler returned a structured Lambda response
|
|
if (result.statusCode && result.body) {
|
|
return {
|
|
statusCode: result.statusCode,
|
|
headers: result.headers || {},
|
|
body: injectStatusCodeIntoBody(result.body, result.statusCode),
|
|
};
|
|
}
|
|
|
|
// If handler returned plain data (not wrapped)
|
|
return {
|
|
statusCode: 200,
|
|
body: JSON.stringify({
|
|
success: true,
|
|
message: 'OK',
|
|
statusCode: 200,
|
|
data: result,
|
|
}),
|
|
};
|
|
} catch (error: any) {
|
|
console.error('❌ Error occurred:', error);
|
|
|
|
// Convert Prisma errors to ApiError automatically
|
|
if (ApiError.isPrismaError(error)) {
|
|
const apiError = ApiError.fromPrismaError(error);
|
|
return {
|
|
statusCode: apiError.statusCode,
|
|
body: JSON.stringify({
|
|
success: false,
|
|
message: apiError.message,
|
|
statusCode: apiError.statusCode,
|
|
data: null,
|
|
error: {
|
|
code: apiError.code || apiError.statusCode,
|
|
description: apiError.message,
|
|
statusCode: apiError.statusCode,
|
|
...(apiError.meta && { meta: apiError.meta }),
|
|
...(process.env.STAGE !== 'prod' && { debug: apiError.stack }),
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (error instanceof ApiError) {
|
|
return {
|
|
statusCode: error.statusCode,
|
|
body: JSON.stringify({
|
|
success: false,
|
|
message: error.message,
|
|
statusCode: error.statusCode,
|
|
data: null,
|
|
error: {
|
|
code: error.code || error.statusCode,
|
|
description: error.message,
|
|
statusCode: error.statusCode,
|
|
...(error.meta && { meta: error.meta }),
|
|
...(process.env.STAGE !== 'prod' && { debug: error.stack }),
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
|
|
// Internal Server Error fallback
|
|
return {
|
|
statusCode: 500,
|
|
body: JSON.stringify({
|
|
success: false,
|
|
message: 'Internal server error',
|
|
statusCode: 500,
|
|
data: null,
|
|
error: {
|
|
code: 500,
|
|
description: 'Internal server error',
|
|
statusCode: 500,
|
|
...(process.env.STAGE !== 'prod' && { debug: error.stack }),
|
|
},
|
|
}),
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
// Utility: safely inject statusCode into the JSON response body
|
|
function injectStatusCodeIntoBody(body: string, statusCode: number): string {
|
|
try {
|
|
const json = JSON.parse(body);
|
|
json.statusCode = statusCode;
|
|
return JSON.stringify(json);
|
|
} catch {
|
|
// If body is not JSON, wrap it
|
|
return JSON.stringify({
|
|
success: true,
|
|
statusCode,
|
|
message: body,
|
|
data: null,
|
|
});
|
|
}
|
|
}
|