first commit
This commit is contained in:
+92
@@ -0,0 +1,92 @@
|
||||
import Fastify from 'fastify';
|
||||
import { ZodError } from 'zod';
|
||||
import { loadConfig } from './config/env.js';
|
||||
import authPlugin from './plugins/auth.js';
|
||||
import mongoPlugin from './plugins/mongo.js';
|
||||
import staticPlugin from './plugins/static.js';
|
||||
import accessRoutes from './routes/access.routes.js';
|
||||
import importRoutes from './routes/import.routes.js';
|
||||
import recipeRoutes from './routes/recipe.routes.js';
|
||||
import { createSourceExtractor } from './services/extractors/index.js';
|
||||
import { ImageStorageService } from './services/image-storage.service.js';
|
||||
import { RecipeParserService } from './services/recipe-parser.service.js';
|
||||
import { AppError } from './utils/errors.js';
|
||||
|
||||
function registerErrorHandling(app) {
|
||||
app.setErrorHandler((error, request, reply) => {
|
||||
if (error instanceof ZodError) {
|
||||
return reply.code(400).send({
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: error.issues[0]?.message ?? '입력값을 확인해 주세요.',
|
||||
details: error.issues,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof AppError) {
|
||||
if (error.statusCode >= 500) request.log.error({ error }, error.message);
|
||||
return reply.code(error.statusCode).send({
|
||||
error: { code: error.code, message: error.message },
|
||||
});
|
||||
}
|
||||
|
||||
request.log.error({ error }, '처리되지 않은 서버 오류');
|
||||
return reply.code(500).send({
|
||||
error: {
|
||||
code: 'INTERNAL_ERROR',
|
||||
message: '요청을 처리하지 못했습니다.',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
app.setNotFoundHandler((_request, reply) => reply.code(404).send({
|
||||
error: { code: 'NOT_FOUND', message: '요청한 경로를 찾을 수 없습니다.' },
|
||||
}));
|
||||
}
|
||||
|
||||
export async function buildApp({ config = loadConfig(), dependencies = {} } = {}) {
|
||||
const app = Fastify({
|
||||
logger: config.nodeEnv === 'test' ? false : { level: config.logLevel },
|
||||
trustProxy: config.nodeEnv === 'production',
|
||||
});
|
||||
app.decorate('config', config);
|
||||
registerErrorHandling(app);
|
||||
|
||||
if (
|
||||
dependencies.allowedEmailRepository
|
||||
&& dependencies.recipeRepository
|
||||
&& dependencies.userRepository
|
||||
) {
|
||||
app.decorate('allowedEmailRepository', dependencies.allowedEmailRepository);
|
||||
app.decorate('recipeRepository', dependencies.recipeRepository);
|
||||
app.decorate('userRepository', dependencies.userRepository);
|
||||
} else {
|
||||
await app.register(mongoPlugin, { config });
|
||||
}
|
||||
|
||||
await app.register(authPlugin, {
|
||||
config,
|
||||
googleClient: dependencies.googleClient,
|
||||
});
|
||||
|
||||
app.decorate(
|
||||
'sourceExtractor',
|
||||
dependencies.sourceExtractor ?? createSourceExtractor({ config }),
|
||||
);
|
||||
app.decorate(
|
||||
'recipeParser',
|
||||
dependencies.recipeParser ?? new RecipeParserService(config.minimax),
|
||||
);
|
||||
app.decorate(
|
||||
'imageStorage',
|
||||
dependencies.imageStorage ?? new ImageStorageService({ root: config.imageRoot }),
|
||||
);
|
||||
|
||||
await app.register(accessRoutes);
|
||||
await app.register(importRoutes);
|
||||
await app.register(recipeRoutes);
|
||||
await app.register(staticPlugin, { config });
|
||||
await app.ready();
|
||||
return app;
|
||||
}
|
||||
Reference in New Issue
Block a user