API REST para processar arquivos de pedidos legados e normalizar dados.
- Node.js + TypeScript
- Fastify (framework web)
- SQLite (banco de dados)
- Zod (validação de schemas)
- Swagger (documentação)
- Jest (testes)
- Esbuild (build)
- ESLint + Prettier (qualidade de código)
O projeto segue uma arquitetura em camadas, onde cada camada tem responsabilidades específicas e se comunica através de interfaces:
orders.routes.ts: Define as rotas HTTP e configura a injeção de dependências- Responsabilidade: Configuração de endpoints, schemas de validação e documentação Swagger
- Fluxo: Recebe requisições HTTP → Injeta dependências → Delega para Controllers
orders.controller.ts: Controlador que gerencia requisições HTTP- Responsabilidade: Validação de entrada, extração de dados do request, tratamento de erros HTTP
- Dependências: Recebe
IOrderProcessorvia injeção de dependência - Fluxo: Valida arquivo → Extrai conteúdo → Chama service → Retorna resposta HTTP
upload.schema.ts: Schemas Zod para validação de dados- Responsabilidade: Definição de contratos de entrada e saída da API
Contém a lógica de negócio principal, cada service implementa uma responsabilidade específica:
-
order-processor.service.ts: Orquestrador principal- Implementa:
IOrderProcessor - Dependências:
IOrderParser,IOrderFilter,IOrderCalculator,IPersistenceService - Responsabilidade: Coordena todo o fluxo de processamento
- Implementa:
-
order-filter.service.ts: Filtros de dados- Implementa:
IOrderFilter - Responsabilidade: Aplicação de regras de filtro nos pedidos
- Implementa:
-
order-calculator.service.ts: Cálculos de totais- Implementa:
IOrderCalculator - Responsabilidade: Cálculo de totais de pedidos
- Implementa:
-
persistence.service.ts: Persistência de dados- Implementa:
IPersistenceService - Dependências:
Database(Singleton) - Responsabilidade: Salvar dados processados no banco
- Implementa:
parser.ts: Utilitário de parsing- Implementa:
IOrderParser - Responsabilidade: Análise e validação de linhas do arquivo
- Implementa:
constants.ts: Constantes da aplicação
database.ts: Classe Singleton para acesso ao SQLite- Responsabilidade: Conexão com banco, criação de tabelas, operações CRUD
- Padrão: Singleton para garantir uma única instância de conexão
Define abstrações que permitem baixo acoplamento entre camadas:
orders.interface.ts: Contratos para processamento de pedidosIOrderProcessor,IOrderFilter,IOrderCalculator
parser.interface.ts: Contratos para parsingIOrderParser,IFieldValidator
persistence.interface.ts: Contrato para persistênciaIPersistenceService
order.model.ts: Definição de tipos e modelos de dados- Responsabilidade: DTOs e estruturas de dados compartilhadas
- Arquitetura em Camadas: Controllers → Services → Database
- Princípios SOLID:
- S - Single Responsibility Principle: Cada classe tem uma única responsabilidade (ex:
OrderParserapenas analisa linhas,OrderCalculatorapenas calcula totais) - O - Open/Closed Principle: Classes abertas para extensão via interfaces (ex:
IOrderProcessor,IOrderFilter) - L - Liskov Substitution Principle: Implementações podem ser substituídas sem quebrar o código (ex: qualquer implementação de
IOrderParser) - I - Interface Segregation Principle: Interfaces específicas e focadas (ex:
IOrderCalculator,IOrderFilter,IFieldValidator) - D - Dependency Inversion Principle: Dependências via abstrações/interfaces, não implementações concretas (ex:
OrdersControllerdepende deIOrderProcessor,OrderProcessorServicerecebe dependências via construtor)
- S - Single Responsibility Principle: Cada classe tem uma única responsabilidade (ex:
- Dependency Injection: Injeção de dependências via interfaces (ex:
OrdersControllerconstructor,OrderProcessorServiceconstructor) - Singleton: Classe
Databasecom instância única (ex:Database.getInstance()emdatabase.ts,app.ts,persistence.service.ts) - Strategy: Diferentes estratégias de processamento via interfaces (ex:
OrderParserimplementaIOrderParser,OrderFilterServiceimplementaIOrderFilter,OrderCalculatorServiceimplementaIOrderCalculator) - Repository: Abstração de acesso a dados via
IPersistenceService(ex:PersistenceServiceimplementaIPersistenceService, métodopersistData()empersistence.service.ts)
npm install
# Desenvolvimento
npm run dev
# Build
npm run build
# Testes
npm test
npm run test:watch
npm run test:coverage
# Qualidade
npm run lint
npm run lint:fix
npm run formatA API foi implantada na plataforma Fly.io e está disponível no seguinte endereço: https://legacy-api-normalizer-bitter-dust-7197.fly.dev/
Endpoint para upload de arquivo .txt com dados de pedidos legados e retorna dados normalizados em JSON.
- Abra o Postman ou Insomnia
- Crie uma nova requisição do tipo POST
- Insira a URL:
https://legacy-api-normalizer-bitter-dust-7197.fly.dev/orders/upload(caso esteja rodando localmente, usehttp://localhost:3000/orders/upload) - Na seção "Body", selecione a opção "form-data" (Postman) ou "Multipart Form" (Insomnia)
- Adicione um campo com a chave
filee selecione o tipo "File" - Clique no botão para selecionar o arquivo e escolha seu arquivo .txt
- Envie a requisição
Cada linha do arquivo deve ter exatamente 95 caracteres com campos de tamanho fixo:
000000058 Dewey Crona00000005670000000001 1328.520211001
0000000118 Robena Raynor00000010950000000006 1544.6620211212
0000000180 Judi Lowe00000016750000000004 359.9820210820[
{
"user_id": 1,
"name": "João Silva",
"orders": [
{
"order_id": 1,
"total": "180.23",
"date": "2023-01-01",
"products": [
{
"product_id": 1,
"value": "123.45"
},
{
"product_id": 2,
"value": "56.78"
}
]
}
]
},
{
"user_id": 2,
"name": "Maria Souza",
"orders": [
{
"order_id": 2,
"total": "99.99",
"date": "2023-02-02",
"products": [
{
"product_id": 3,
"value": "99.99"
}
]
}
]
}
]- 200: Array de usuários com pedidos normalizados
- 400: Erro de validação ou processamento
A documentação da API está disponível via Swagger em /docs quando o servidor estiver rodando.
Utiliza SQLite com as seguintes tabelas:
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT
)CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
total TEXT,
date TEXT,
FOREIGN KEY (user_id) REFERENCES users(id)
)CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER,
product_id INTEGER,
value TEXT,
FOREIGN KEY (order_id) REFERENCES orders(id)
)