Desafio técnico do processo seletivo da Luiza Labs. Trata-se de um serviço de consulta de CEP, cujo objetivo é permitir que o usuário obtenha seu endereço a partir do CEP.
[Prática]
Serviço de Consulta de CEP[Teórica]
Resposta
Este projeto é um serviço de consulta de CEP (Código de Endereçamento Postal) que permite aos usuários obter informações de seu endereço (rua, bairro, cidade e estado) a partir de um CEP fornecido. O sistema inclui autenticação de usuários, conferindo que apenas usuários registrados possam acessar as funcionalidades do serviço.
A linguagem escolhida para o desafio foi Javascript, interpretado por Node.js e integrado com Typescript para segurança de tipo em tempo de desenvolvimento. Essa escolha foi feita devido a:
- É a linguagem que melhor domino atualmente;
- Seu código possui fácil entendimento, melhorando a manutenção da aplicação;
- A linguagem consegue estar presente tanto no lado do cliente, quanto no lado do servidor;
- O event loop do Node.js, que permite uma execução não bloqueante, se mostra eficiente em uma aplicação onde várias requisições precisam ser atendidas simultaneamente;
- Em conjunto com o Typescript, se torna uma linguagem com tipagem de dados, melhorando a segurança no tempo de execução, diminuindo erros inesperados.
A arquitetura escolhida se baseia na utilização de conceitos de Clean Code e principalmente SOLID como por exemplo a Injeção de Dependência e o Princípio da Responsabilidade Única. De forma geral, permite implementação de testes, tanto das funções mais básicas (testes unitários), quanto de testes de funções completas(testes end-to-end).
Os padrões principais são:
- Use Case: É a camada responsável pela abstração de toda a lógica principal e regras de negócio da aplicação;
- Repository: É uma camada responsável pela interação da aplicação com o mundo exterior, sejam serviços externos ou aplicações de armazenamento de dados, como os próprios bancos de dados e cache;
- Factory: Padrão responsável por "construir" as funcionalidades, integrando os use cases aos repositories.
Por mais que o projeto tenha um pequeno escopo, foquei em dois principais fatores, organização e performance. Pois, mesmo com poucas funcionalidades, qualquer descuido pode gerar efeitos indesejados.
- Organização: utilizando os padrões já citados, organizei a aplicação para cada parte ter sua função e que as mais internas não sofressem impacto ou interferência das mais externas;
- Performance: algumas pequenas medidas foram tomadas para diminuir a quantidade de consultas no banco de dados, como:
- Antes de buscar o endereço no banco de dados, uma consulta é feita no cache. Se as informações estiverem no cache, a busca no banco não é realizada. Caso o endereço não seja encontrado no cache, a busca é feita no banco de dados, e os dados obtidos são inseridos no cache para consultas futuras;
- Em vez de, a cada vez que o endereço não for encontrado no banco, gerar um novo CEP possível e buscar novamente (caso não esteja no cache), a aplicação gera todos os possíveis CEPs de uma vez e os busca utilizando um
WHERE IN
, ordenando para que sempre retorne o CEP mais próximo do original.
As tecnologias usadas, tanto na aplicação, como nos serviços com os quais ela interage.
- Aplicação:
- Node.js: O interpretador de Javascript para o lado do servidor;
- Typescript: O superset que adiciona tipagem de dados ao Javascript;
- Fastify: O framework responsável por subir a API e gerenciar as rotas;
- Prisma: O ORM com integração direta com Typescript responsável pela comunicação com o banco de dados PostgreSQL;
- Zod: O pacote de validação de dados, usado para validar a entrada de dados na aplicação, seja pelas rotas, como variáveis de ambiente;
- JWT: O método de validação de segurança entre cliente e servidor;
- Swagger: A ferramenta de documentação de APIs;
- Vitest: O framework para execução de testes automatizados;
- Faker: O pacote para mock de dados para testes.
- Externos:
- Docker: Uma plataforma para gerenciamento de containers;
- PostgreSQL: Um banco de dados robusto e ope-source;
- Redis: Um banco de dados em memória, usado para cache;
- Sentry: Uma plataforma para registro de erros não tratados da aplicação;
- New Relic: Uma plataforma para registro de logs da aplicação e monitoramento de recursos;
- ViaCEP: API externa para consulta de CEPs, uma opção a mais para responder ao usuário caso o CEP não exista na base de dados;
- Postman: A ferramento para testar aplicação através de requisições HTTP.
Todas as rotas disponibilizadas pelo serviço:
- Públicas:
GET /api
: Health Check da API;GET /api-docs
: Documentação de todas as rotas disponibilizadas pela API;POST /api/register
: Criação de um novo usuário;POST /api/authenticate
: Autenticação de usuário existente;
- Autenticadas:
GET /api/cep/:cep
: Busca dados de endereço pelo CEP;
Para executar a aplicação localmente, é necessário ter o Docker instalado. Para instalar de acordo com o sistema operacional usado, clique aqui. Então rode no terminal os seguintes comandos:
cd server-api # Ou o caminho completo até a aplicação
docker-compose up -d # Subirá todos os serviços necessários
Isso fará com que a aplicação rode na porta configurada no Dockerfile
e docker-compose.yml
.
Observação: As variáveis de ambiente ficaram expostas no código para melhor visualização da aplicação.
Para executar os testes da aplicação, é necessário ter o Node.js instalado. Para executar os testes, rode no terminal os seguintes comandos:
cd server-api # Ou o caminho completo até a aplicação
npm install # Instalar as dependências, incluindo o Vitest
npm run test # Executará os testes unitários
# ou
npm run test:coverage # Executará a cobertura de testes
A aplicação, para mérito demonstrativo, foi hospedada no Render. Para acessar a aplicação, acesso uns dos links abaixo:
Quando você digita a URL de um site (http://www.netshoes.com.br) no browser e pressiona enter, explique da forma que preferir, o que ocorre nesse processo do protocolo HTTP entre o Client e o Server.
Para responder a essa questão, levei em consideração exatamente a URL "http://www.netshoes.com.br" e utilizei a CLI curl do Windows para acompanhar as etapas do comportamento de todo o cenário, desde o pressionar da tecla "Enter", até o carregamento da página inicial do site propriamente dito.
-
Ao pressionar em "Enter", o cliente (browser) envia o domínio "netshoes.com.br" para um servidor de resolução de DNS para obter o IP do servidor. Ao receber o IP, realiza uma requisição HTTP através do método GET para o servidor web.
-
O servidor processa a requisição e retorna um status code 301 (Moved Permanently) indicando que o conteúdo da página foi movido permanentemente para outra. Nos cabeçalhos de resposta, existe o header "Location", que contém a nova URL a ser seguida, neste caso "https://www.netshoes.com.br":
- Possuindo a nova URL, que agora utiliza o protocolo HTTPS, realiza uma nova requisição GET para o servidor web (não precisa resolver o DNS novamente, pois o domínio não mudou), que, por sua vez, processa a requisição e retorna um status code 200 e o HTML completo da página no body;
- O cliente renderiza o HTML em tela, exibindo a tela inicial do site para o usuário.