Desafio Essentials Projetos
[English | Portuguese]
Serão basicamente 2 partes que vamos focar nesse teste:
- Sua habilidade de desenvolvimento.
- Sua habilidade de colocar o código para rodar usando específicas tecnologias.
Alguns passos terão requerimentos vagos ou erros. Não há resposta certa ou errada, queremos avaliar sua postura diante do desafio assim o modo como você o desenvolverá.
Parte 1 - Desenvolvimento
Pre-requisitos
- Git
- Conta no Github
Como fazer
O projeto deve usar controle de versão no git e armazenado/subido para o Github em um repositório privado na sua conta.
Quando terminar o desafio, convide o usuário mbergo
para colaborador do seu repositório do desafio para que possamos fazer a avaliação.
A tarefa
Usando Go, Python3 ou NodeJS ou Rails sua tarefa, será implementar um API REST que faça CRUD em produtos armazenados em um banco de dados MySQL 5.7.
A API terá que fazer a validação dos dados de entrada. Exemplo: SKU é único em POST e PUT.
Requisitos
-
Kubernetes deployment manifests para rodar, balancear, limitar requests e escalar utilizando HPA no Minikube v1.13.0
-
Script para popular o banco de dados com dummy data.
-
Testes unitários
Bibliotecas de terceiros
Você poderá usar bibliotecas de terceiros, como por exemplo o driver para falar com o banco de dados, mas encorajamos que use o menor número de bibliotecas possíveis.
API de Produtos
Response codes
- 200 OK
- 201 Created
- 400 Bad Request
- 404 Not Found
- 500 Internal Server Error
Todas as respostas de erro (400, 404, 500) devem retornar um objeto único com uma única chave chamada "errorText" e o valor (string) descrevendo o erro.
Exemplo:
{
"errorText": "The error message"
}
Definição do "produto"
{
"productId": <int>, (readonly, unique)
"title": <string>, (required for POST)
"sku": <string>, (required for POST, unique)
"barcodes": [<string>], (unique)
"description": <string|null>, (default null)
"attributes": [<attribute>],
"price": <money>, (default "0.00")
"created": <timestamp>, (readonly)
"lastUpdated": <timestamp|null> (readonly)
}
Endpoints
GET /api/products
Parâmetros de query
Todos os parâmetros são opcionais
Parâmetro | Descrição | Tipo | Default |
---|---|---|---|
start | Inicio do index | int | 0 |
num | Numero de indexes retornados | int | 10 |
sku | Filtrar por sku | string | --- |
barcode | Filtrar por barcode | string | |
fields | Campos do produto que serão retornados da resposta | string, separado por vírgulas | --- |
- Exemplo da URL
http://127.0.0.1:8080/api/products?start=40&num=2&fields=productId,title
- Retorno sucesso
{
"totalCount": <int>,
"items": [<product>]
}
- Exemplo de retorno
{
"totalCount": 126,
"items": [
{
"productId": 45,
"title": "Awesome socks"
},
{
"productId": 46,
"title": "Batman socks"
}
]
}
GET
GET /api/products/{productId}
Parâmetros de query
Todos os parâmetros são opcionais
Parâmetro | Descrição | Tipo | Default |
---|---|---|---|
fields | Campos do produto que serão retornados da resposta | string, separado por vírgulas | --- |
Exemplo Retorno sucesso
{
"productId": 45,
"title": "Awesome socks",
"sku": "SCK-4511",
"barcodes": ["7410852096307"],
"description": null,
"attributes": [
{
"name": "color",
"value": "Red"
},
{
"name": "size",
"value": "39-41"
},
],
"price": "89.00",
"created": 1554472112,
"lastUpdated": null
}
Retorno erro
{
"errorText": "Can’t find product (<productId>)"
}
POST
POST /api/products
Para POST, um subset de produto é permitido, porém todos os campos requeridos para criação devem estar presentes.
Body content
{
"title": "Awesome socks",
"sku": "SCK-4511",
"barcodes": ["7410852096307"],
"description": null,
"attributes": [
{
"name": "color",
"value": "Red",
},
{
"name": "size",
"value": "39-41",
},
],
"price": "89.00",
}
- Resposta sucesso (int)
45
- Resposta erro
{
"errorText": "SKU 'SCK-4511' already exists"
}
PUT
PUT /api/products/{productId}
Novamente, um subset de produto é permitido.
Retorno sucesso (bool)
true
Retorno erro
{
"errorText": " Invalid sku, can not be null"
}
DELETE
DELETE /api/products/{productId}
Retorno sucesso (bool)
true
Retorno erro
{
"errorText": "Product with productId (<productId>) does not exist"
}
Definições
Tipos API
Atributos
{
"name": <string>, (required)
"value": <string> (required)
}
Mysql schema
CREATE SCHEMA IF NOT EXISTS `glb_test_assignment`
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `glb_test_assignment`.`product` (
`product_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(32) NOT NULL,
`sku` VARCHAR(32) NOT NULL,
`description` VARCHAR(1024) NULL,
`price` DECIMAL(12,2)NOT NULL DEFAULT 0.00,
`created` DATETIME NOT NULL,
`last_updated` DATETIME NULL,
PRIMARY KEY (`product_id`),
UNIQUE INDEX (`sku` ASC),
INDEX (
`created`
),
INDEX (`last_updated`)
);
CREATE TABLE IF NOT EXISTS `glb_test_assignment`.`product_barcode` (
`product_id` INT UNSIGNED NOT NULL,
`barcode` VARCHAR(32) NOT NULL,
PRIMARY KEY (`product_id`, `barcode`),
UNIQUE INDEX (`barcode`)
);
CREATE TABLE IF NOT EXISTS `glb_test_assignment`.`product_attribute` (
`product_id` INT UNSIGNED NOT NULL,
`name` VARCHAR(16) NOT NULL,
`value` VARCHAR(32) NOT NULL,
PRIMARY KEY (`product_id`, `name`)
);
Parte 2 - Entrega da aplicação
- Sua aplicação deve rodar no Minikube v1.25.0 + kubectl
- Você deve escrever os manifestos do Kubernetes para criar o Ingresso para expor sua app, 1 container para rodar sua aplicação e 1 container para rodar o Banco de dados. Você deve utilizar Serviços e deployments do K8s assim como HPA setando limites de requests e uso de recursos do sistema. Os números desses limites devem ser baixos o suficiente para ser possivel ver o HPA entrar em ação a partir de requisições da máquina local.
-
Todos os logs devem ser visiveis a partir do
kubectl logs -f <pod>
-
A segurança do cluster será levada em consideração.
-
O projeto deve rodar utilizando apenas 1 comando (assumindo que a pessoa já tenha o minikube instalado e rodando).
-
A submissão do desafio será feita com você criando um repo privado em sua conta e adicionando o usuário
mbergo
para acesso. O link do seu repositório deve ser postado no issues do desafio.
Critério de avaliação
- Organização do código: Separação de módulos - código app e infra.
- Clareza: O README explica de forma resumida qual é o problema e como pode rodar a aplicação?
- Assertividade: A aplicação está fazendo o que é esperado? Se tem algo faltando, o README explica o porquê? Isso será discutido na próxima fase da entrevista.
- Legibilidade do código (incluindo comentários)
- Segurança: Existe alguma vulnerabilidade clara que não tenha sido endereçada?
- Cobertura de testes Teste unitários
- Histórico de commits (estrutura e qualidade, titulos e descrição)
- Escolhas técnicas: A escolha das bibliotecas, arquitetura, etc, é a melhor escolha para a aplicação?
- Comunicação: Se você não conseguiu completar todo o teste, o README contém o que ficou faltando? Isso será discutido na próxima fase da entrevista.
Dúvidas
Quaisquer dúvidas que você venha a ter, abra uma issue que responderemos assim que marcado o mbergo
na mesma.
Boa sorte.