1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
import Fastify from 'fastify';
import corsPlugin from './plugins/cors';
import fastifyJwt from '@fastify/jwt';
import authRoutes from './modules/auth/auth.routes';
import dashboardRoutes from './modules/dashboard/dashboard.routes';
import incomesRoutes from './modules/incomes/incomes.routes';
import oneTimeExpensesRoutes from './modules/one-time-expenses/one-time-expenses.routes';
import recurringExpensesRoutes from './modules/recurring-expenses/recurring-expenses.routes';
import usersRoutes from './modules/users/users.routes';
const PORT = Number(process.env.PORT) || 3333;
const HOST = process.env.HOST ?? '0.0.0.0';
const fastify = Fastify({
logger: {
transport:
process.env.NODE_ENV === 'development'
? { target: 'pino-pretty', options: { colorize: true } }
: undefined,
},
});
// ---------------------------------------------------------------------------
// Plugins globais
// ---------------------------------------------------------------------------
fastify.register(corsPlugin);
fastify.register(fastifyJwt, {
secret: process.env.JWT_SECRET || 'super-secret-yaba-jwt-key-2026',
});
// ---------------------------------------------------------------------------
// JWT Middleware
// ---------------------------------------------------------------------------
fastify.addHook('onRequest', async (request, reply) => {
if (request.url.includes('/api/v1/auth') || request.url.startsWith('/health')) {
return; // Pula autenticação para rotas públicas
}
try {
await request.jwtVerify();
} catch (err) {
return reply.status(401).send({ error: 'Não autorizado.' });
}
});
// ---------------------------------------------------------------------------
// Rotas com prefixo /api/v1
// ---------------------------------------------------------------------------
const API_PREFIX = '/api/v1';
fastify.register(authRoutes, { prefix: API_PREFIX });
fastify.register(usersRoutes, { prefix: API_PREFIX });
fastify.register(incomesRoutes, { prefix: API_PREFIX });
fastify.register(recurringExpensesRoutes, { prefix: API_PREFIX });
fastify.register(oneTimeExpensesRoutes, { prefix: API_PREFIX });
fastify.register(dashboardRoutes, { prefix: API_PREFIX });
// ---------------------------------------------------------------------------
// Health check
// ---------------------------------------------------------------------------
fastify.get('/health', async () => ({
status: 'ok',
timestamp: new Date().toISOString(),
version: '1.0.0',
}));
// ---------------------------------------------------------------------------
// Handler de erros global
// ---------------------------------------------------------------------------
fastify.setErrorHandler((error, _request, reply) => {
fastify.log.error(error);
const statusCode = error.statusCode ?? 500;
reply.status(statusCode).send({
error: statusCode >= 500 ? 'Erro interno do servidor.' : error.message,
...(process.env.NODE_ENV === 'development' && { stack: error.stack }),
});
});
// ---------------------------------------------------------------------------
// Start
// ---------------------------------------------------------------------------
try {
await fastify.listen({ port: PORT, host: HOST });
console.log(`🚀 YABA API rodando em http://${HOST}:${PORT}`);
console.log(`📖 Health check: http://${HOST}:${PORT}/health`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
|