@koalarx/nest 1.18.21 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,303 @@
1
+ # Tratamento de Erros
2
+
3
+ A biblioteca fornece um sistema robusto de tratamento de erros usando `RequestResult` (Either pattern) que retorna erros em vez de lançá-los com `throw`.
4
+
5
+ ## Erros Predefinidos
6
+
7
+ ### 1. ResourceNotFoundError
8
+
9
+ Lançado quando um recurso não é encontrado.
10
+
11
+ ```typescript
12
+ import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
13
+
14
+ return failure(new ResourceNotFoundError('Pessoa'))
15
+ // Retorna: 404 Not Found
16
+ ```
17
+
18
+ ### 2. ConflictError
19
+
20
+ Lançado quando há conflito (ex: duplicação de dados).
21
+
22
+ ```typescript
23
+ import { ConflictError } from '@koalarx/nest/core/errors/conflict.error'
24
+
25
+ throw new ConflictError('Email already registered')
26
+ // Retorna: 409 Conflict
27
+ ```
28
+
29
+ ### 3. BadRequestError
30
+
31
+ Lançado quando a requisição contém dados inválidos (via Zod).
32
+
33
+ ```typescript
34
+ import { BadRequestError } from '@koalarx/nest/core/errors/bad-request.error'
35
+
36
+ throw new BadRequestError('Invalid user data')
37
+ // Retorna: 400 Bad Request
38
+ ```
39
+
40
+ ### 4. NotAllowedError
41
+
42
+ Lançado quando a operação não é permitida.
43
+
44
+ ```typescript
45
+ import { NotAllowedError } from '@koalarx/nest/core/errors/not-allowed.error'
46
+
47
+ throw new NotAllowedError('This action is not allowed')
48
+ // Retorna: 400 Bad Request
49
+ ```
50
+
51
+ ### 5. WrongCredentialsError
52
+
53
+ Lançado quando credenciais são inválidas.
54
+
55
+ ```typescript
56
+ import { WrongCredentialsError } from '@koalarx/nest/core/errors/wrong-credentials.error'
57
+
58
+ throw new WrongCredentialsError('Invalid email or password')
59
+ // Retorna: 401 Unauthorized
60
+ ```
61
+
62
+ ### 6. NoContentError
63
+
64
+ Lançado quando não há conteúdo para retornar.
65
+
66
+ ```typescript
67
+ import { NoContentError } from '@koalarx/nest/core/errors/no-content.error'
68
+
69
+ throw new NoContentError('No content available')
70
+ // Retorna: 204 No Content
71
+ ```
72
+
73
+ ## Usar RequestResult (Either Pattern)
74
+
75
+ A biblioteca usa `RequestResult<Error, Success>` para retornar sucesso ou erro sem exceções:
76
+
77
+ ```typescript
78
+ import { failure, ok, RequestResult } from '@koalarx/nest/core/request-overflow/request-result'
79
+ import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
80
+
81
+ @Injectable()
82
+ export class ReadPersonHandler extends RequestHandlerBase<
83
+ number,
84
+ RequestResult<ResourceNotFoundError, ReadPersonResponse>
85
+ > {
86
+ constructor(
87
+ private readonly repository: IPersonRepository,
88
+ private readonly mapper: AutoMappingService,
89
+ ) {
90
+ super()
91
+ }
92
+
93
+ async handle(
94
+ id: number,
95
+ ): Promise<RequestResult<ResourceNotFoundError, ReadPersonResponse>> {
96
+ // Buscar no repositório
97
+ const person = await this.repository.read(id)
98
+
99
+ // Retornar erro se não encontrar
100
+ if (!person) {
101
+ return failure(new ResourceNotFoundError('Pessoa'))
102
+ }
103
+
104
+ // Mapear e retornar sucesso
105
+ return ok(this.mapper.map(person, Person, ReadPersonResponse))
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## No Controller
111
+
112
+ O controller verifica `isFailure()` e lança o erro se necessário:
113
+
114
+ ```typescript
115
+ @Get(':id')
116
+ async handle(@Param('id') id: number): Promise<ReadPersonResponse> {
117
+ const response = await this.handler.handle(id)
118
+
119
+ // Se falhou, lança a exceção (que é capturada pelos filtros)
120
+ if (response.isFailure()) {
121
+ throw response.value
122
+ }
123
+
124
+ // Senão, retorna o sucesso
125
+ return response.value
126
+ }
127
+ ```
128
+
129
+ ## Criar Erro Customizado
130
+
131
+ ```typescript
132
+ // src/domain/errors/custom-error.ts
133
+ import { HttpStatus } from '@nestjs/common'
134
+ import { ErrorBase } from '@koalarx/nest/core/errors/error.base'
135
+
136
+ export class CustomError extends ErrorBase {
137
+ public statusCode: number = HttpStatus.FORBIDDEN
138
+
139
+ constructor(message: string, data?: any) {
140
+ super(message, data)
141
+ this.name = 'CustomError'
142
+ }
143
+ }
144
+ ```
145
+
146
+ Use o erro customizado:
147
+
148
+ ```typescript
149
+ return failure(new CustomError('Custom error message'))
150
+ ```
151
+
152
+ E registre no filtro de domínio se necessário (customize o filtro existente).
153
+
154
+ ## Filtros de Exceção
155
+
156
+ Os filtros são registrados automaticamente pelo `KoalaNestModule`:
157
+
158
+ ### 1. Domain Errors Filter
159
+
160
+ Captura e trata erros de domínio (ResourceNotFoundError, ConflictError, etc) quando lançados.
161
+
162
+ **Resposta exemplo:**
163
+ ```json
164
+ {
165
+ "statusCode": 404,
166
+ "message": "Pessoa",
167
+ "data": null
168
+ }
169
+ ```
170
+
171
+ ### 2. Prisma Validation Exception Filter
172
+
173
+ Captura erros do Prisma e os converte em mensagens legíveis.
174
+
175
+ **Erros tratados:**
176
+ - `P2002`: Duplicação de dados única → 409 Conflict
177
+ - `P2003`: Violação de chave estrangeira → 400 Bad Request
178
+ - `P2025`: Registro não encontrado → 404 Not Found
179
+
180
+ **Resposta exemplo:**
181
+ ```json
182
+ {
183
+ "statusCode": 409,
184
+ "message": "Unique constraint failed"
185
+ }
186
+ ```
187
+
188
+ ### 3. Zod Errors Filter
189
+
190
+ Captura e trata erros de validação Zod no validator.
191
+
192
+ **Resposta exemplo:**
193
+ ```json
194
+ {
195
+ "statusCode": 400,
196
+ "message": "Dados enviados inválidos",
197
+ "errors": [
198
+ "name is required",
199
+ "email invalid email"
200
+ ]
201
+ }
202
+ ```
203
+
204
+ ### 4. Global Exception Filter
205
+
206
+ Captura todas as exceções não tratadas.
207
+
208
+ **Resposta exemplo:**
209
+ ```json
210
+ {
211
+ "statusCode": 500,
212
+ "message": "Internal server error",
213
+ "timestamp": "2024-01-01T10:00:00.000Z",
214
+ "path": "/users"
215
+ }
216
+ ```
217
+
218
+ ## Exemplo Completo
219
+
220
+ ```typescript
221
+ // src/application/user/read/read-user.handler.ts
222
+ import { Injectable } from '@nestjs/common'
223
+ import { ResourceNotFoundError } from '@koalarx/nest/core/errors/resource-not-found.error'
224
+ import { failure, ok, RequestResult } from '@koalarx/nest/core/request-overflow/request-result'
225
+ import { AutoMappingService } from '@koalarx/nest/core/mapping/auto-mapping.service'
226
+ import { User } from '@/domain/entities/user/user'
227
+ import { IUserRepository } from '@/domain/repositories/iuser.repository'
228
+ import { ReadUserResponse } from './read-user.response'
229
+
230
+ @Injectable()
231
+ export class ReadUserHandler extends RequestHandlerBase<
232
+ number,
233
+ RequestResult<ResourceNotFoundError, ReadUserResponse>
234
+ > {
235
+ constructor(
236
+ private readonly repository: IUserRepository,
237
+ private readonly mapper: AutoMappingService,
238
+ ) {
239
+ super()
240
+ }
241
+
242
+ async handle(
243
+ id: number,
244
+ ): Promise<RequestResult<ResourceNotFoundError, ReadUserResponse>> {
245
+ // Buscar usuário
246
+ const user = await this.repository.read(id)
247
+
248
+ // Retornar erro se não encontrar
249
+ if (!user) {
250
+ return failure(new ResourceNotFoundError('Usuário não encontrado'))
251
+ }
252
+
253
+ // Mapear e retornar sucesso
254
+ return ok(this.mapper.map(user, User, ReadUserResponse))
255
+ }
256
+ }
257
+ ```
258
+
259
+ ```typescript
260
+ // src/host/controllers/user/read-user.controller.ts
261
+ @Get(':id')
262
+ @ApiResponse({ type: ReadUserResponse })
263
+ async handle(@Param('id') id: number): Promise<ReadUserResponse> {
264
+ const response = await this.handler.handle(id)
265
+
266
+ // Se falhou, lança exceção (capturada pelos filtros)
267
+ if (response.isFailure()) {
268
+ throw response.value
269
+ }
270
+
271
+ return response.value
272
+ }
273
+ ```
274
+
275
+ ## Tratamento de Erros do Validator (Zod)
276
+
277
+ Erros de validação são automaticamente capturados pelo ZodErrorsFilter:
278
+
279
+ ```typescript
280
+ export class CreateUserValidator extends RequestValidatorBase<CreateUserRequest> {
281
+ protected get schema(): ZodType<any, ZodTypeDef, any> {
282
+ return z.object({
283
+ name: z.string().min(1, 'Name is required'),
284
+ email: z.string().email('Valid email is required'),
285
+ })
286
+ }
287
+ }
288
+
289
+ // Se dados inválidos, ZodErrorsFilter captura e retorna 400
290
+ const validated = new CreateUserValidator(req).validate()
291
+ ```
292
+
293
+ ## Fluxo de Tratamento de Erros
294
+
295
+ ```
296
+ Handler retorna failure(error)
297
+ └─ Controller verifica isFailure()
298
+ └─ throws error
299
+ └─ DomainErrorsFilter captura
300
+ └─ Retorna resposta HTTP com statusCode apropriado
301
+ ```
302
+
303
+ Todos os erros são tratados de forma centralizada e segura!