APIs REST e GraphQL¶
TLDR: REST e GraphQL reutilizam os mesmos command/query handlers, só a camada de apresentação é duplicada. Pipeline HTTP real: middleware de correlation id, guard que extrai o ator autenticado, ZodGlobalValidationPipe, controller, TransactionInterceptor, ApplicationErrorFilter. GraphQL é Apollo Server v5, code-first. Os conceitos gerais (REST, GraphQL, DTO) estão em REST, GraphQL e DTO.
| Termo | Vá pra |
|---|---|
| A esteira real de uma requisição HTTP | Pipeline de uma requisição |
| Validação automática de DTO | ZodGlobalValidationPipe |
| Erro de domínio para status HTTP | ApplicationErrorFilter |
| Configuração do Apollo Server, code-first | GraphQL |
| Quais módulos têm GraphQL | Módulos com GraphQL vs. apenas REST |
Pipeline de uma requisição¶
flowchart LR
REQ["Requisição HTTP"] --> MW["Middleware\ncorrelationIdMiddleware"]
MW --> GD["Guard\nextrai Bearer token, valida JWT"]
GD --> PP["Pipe\nZodGlobalValidationPipe"]
PP --> CTRL["Controller\ndelega pro handler"]
CTRL --> INT["Interceptor\nTransactionInterceptor"]
INT --> HANDLER["Handler"]
HANDLER --> INT2["Interceptor\ncommit ou rollback"]
INT2 --> RESP["Resposta HTTP"]
HANDLER -.->|erro| FT["Filter\nApplicationErrorFilter"]
FT --> RESP
| Etapa | Implementação real |
|---|---|
| Middleware | correlationIdMiddleware, gera ID único por requisição pra rastreamento em log (src/infrastructure.logging/) |
| Rate Limiting | AppThrottlerGuard global (@nestjs/throttler), configurável via RATE_LIMIT_TTL e RATE_LIMIT_LIMIT (padrão: 200 req/60s), com limites dedicados em endpoints críticos |
| Guard | Valida Bearer token via JWKS (ou mock token em dev), popula RequestActor (src/server/nest/auth/), ver Autenticação e autorização |
| Pipe | ZodGlobalValidationPipe, valida body contra static schema do DTO |
| Controller | Extrai o ator (@AccessContextHttp()), delega pro handler |
| Interceptor | TransactionInterceptor, abre transação antes do handler, commit/rollback depois, ver Banco de dados e transações |
| Filter | ApplicationErrorFilter, converte erro de domínio/aplicação em resposta HTTP |
ZodGlobalValidationPipe¶
export class ZodGlobalValidationPipe implements PipeTransform {
transform(value: unknown, metadata: ArgumentMetadata) {
const metatype = metadata.metatype;
if (!hasSchema(metatype)) return value;
const result = metatype.schema.safeParse(value);
if (!result.success) {
throw new BadRequestException(
result.error.issues.map((issue) => ({ field: issue.path.join("."), message: issue.message })),
);
}
return result.data;
}
}
Se o DTO não declara static schema, o pipe deixa o valor passar sem validar.
ApplicationErrorFilter¶
@Catch(ApplicationError, DomainError)
export class ApplicationErrorFilter implements ExceptionFilter {
catch(exception: ApplicationError | DomainError, host: ArgumentsHost) {
const errorResponse = buildHttpErrorResponse(exception, request.url);
response.status(errorResponse.statusCode).json(errorResponse);
}
}
| Código do erro | HTTP status |
|---|---|
APP.RESOURCE_NOT_FOUND |
404 |
APP.FORBIDDEN |
403 |
APP.UNAUTHORIZED |
401 |
APP.VALIDATION |
422 |
APP.CONFLICT |
409 |
APP.INTERNAL |
500 |
APP.SERVICE_UNAVAILABLE |
503 |
DOMAIN.ENTITY_VALIDATION |
422 |
DOMAIN.BUSINESS_RULE_VIOLATION |
422 |
GraphQL¶
Apollo Server v5.4 com driver NestJS, endpoint /api/graphql, GraphiQL habilitado em desenvolvimento, cache LRU (100 MB, TTL de 5 minutos), schema code-first (autoSchemaFile: true, gerado a partir de classes @ObjectType()/@Field(), sem arquivo .graphql escrito à mão).
flowchart TD
subgraph "REST"
REST_CTRL["Controller"] --> REST_DTO["DTO REST"]
end
subgraph "GraphQL"
GQL_RES["Resolver"] --> GQL_DTO["DTO GraphQL"]
end
REST_DTO --> HANDLER["Mesmo command/query handler"]
GQL_DTO --> HANDLER
Resolvers (presentation.graphql/) reutilizam os mesmos command/query handlers da API REST, a lógica de negócio, validação e autorização são idênticas nos dois protocolos. O projeto não usa DataLoader pra resolver o problema N+1 do GraphQL, queries que buscam relação fazem JOIN no repositório TypeORM, relations declaradas no paginateConfig de cada repositório.
Módulos com GraphQL vs. apenas REST¶
18 módulos têm REST e GraphQL: campus, bloco, ambiente, usuario, perfil, curso, disciplina, turma, diario, modalidade, nivel-formacao, oferta-formacao, estado, cidade, endereco, calendario-letivo, empresa, imagem-arquivo. Só REST: autenticacao (login, refresh), arquivo (upload), estagiario/estagio/responsavel-empresa, gerar-horario/horario-edicao/horario-consulta, relatorio/notificacao.
Importação em lote: o módulo de usuário expõe POST /usuarios/importar/csv (multipart/form-data), criando usuário com o campo E-mail Pessoal, sem exigir senha inicial.