Para realizar o projeto, atente-se a cada passo descrito a seguir, e se tiver qualquer dúvida, nos envie por Slack! #vqv 🚀
Aqui você vai encontrar os detalhes de como estruturar o desenvolvimento do seu projeto a partir deste repositório, utilizando uma branch específica e um Pull Request para colocar seus códigos.
Ao iniciar este projeto você concorda com as diretrizes do Código de Conduta e do Manual da Pessoa Estudante da Trybe.
🤷🏽♀️ Como entregar
Para entregar o seu projeto você deverá criar um Pull Request neste repositório.
Lembre-se que você pode consultar nosso conteúdo sobre Git & GitHub e nosso Blog - Git & GitHub sempre que precisar!
👨💻 O que deverá ser desenvolvido
Neste projeto você vai desenvolver uma API e um banco de dados para a produção de conteúdo para um blog!
Você deverá desenvolver uma aplicação em Node.js
usando o pacote sequelize
para fazer um CRUD
de posts.
-
Você deverá desenvolver endpoints que estarão conectados ao seu banco de dados seguindo os princípios do REST;
-
Para fazer um post é necessário usuário e login, portanto será trabalhada a relação entre
user
epost
; -
Será necessária a utilização de categorias para os posts, trabalhando, assim, a relação de
posts
paracategories
e decategories
paraposts
.
🗓 Data de Entrega
- Projeto individual.
- Serão
6
dias de projeto. - Data de entrega para avaliação final do projeto:
04/07/2022 14:10
.
🐋 Rodando no Docker vs Localmente
1.26.0
por 1.29.2
.
ℹ️ Rode os serviços
node
edb
com o comandodocker-compose up -d --build
.
-
Lembre-se de parar o
mysql
se estiver usando localmente na porta padrão (3306
), ou adapte, caso queria fazer uso da aplicação em containers; -
Esses serviços irão inicializar um container chamado
blogs_api
e outro chamadoblogs_api_db
; -
A partir daqui você pode rodar o container
blogs_api
via CLI ou abri-lo no VS Code;
ℹ️ Use o comando
docker exec -it blogs_api bash
.
- Ele te dará acesso ao terminal interativo do container criado pelo compose, que está rodando em segundo plano.
ℹ️ Instale as dependências [Caso existam] com
npm install
. (Instale dentro do container)
-
⚠️ Atenção: Caso opte por utilizar o Docker, TODOS os comandos disponíveis nopackage.json
(npm start, npm test, npm run dev, ...) devem ser executados DENTRO do container, ou seja, no terminal que aparece após a execução do comandodocker exec
citado acima. -
⚠️ Atenção: O git dentro do container não vem configurado com suas credenciais. Ou faça os commits fora do container, ou configure as suas credenciais do git dentro do container. -
⚠️ Atenção: Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador. -
✨ Dica: A extensão
Remote - Containers
(que estará na seção de extensões recomendadas do VS Code) é indicada para que você possa desenvolver sua aplicação no container Docker direto no VS Code, como você faz com seus arquivos locais.
ℹ️ Instale as dependências [Caso existam] com
npm install
-
⚠️ Atenção: Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador. -
✨ Dica: Para rodar o projeto desta forma, obrigatoriamente você deve ter o
node
instalado em seu computador. -
✨ Dica: O avaliador espera que a versão do
node
utilizada seja a 16.
‼️ Antes de começar a desenvolver
- Clone o repositório
git clone https://github.com/tryber/sd-018-b-project-blogs-api.git
.- Entre na pasta do repositório que você acabou de clonar:
cd sd-018-b-project-blogs-api
- Instale as dependências [Caso existam]
npm install
- Crie uma branch a partir da branch
master
- Verifique que você está na branch
master
- Exemplo:
git branch
- Exemplo:
- Se não estiver, mude para a branch
master
- Exemplo:
git checkout master
- Exemplo:
- Agora crie uma branch à qual você vai submeter os
commits
do seu projeto- Você deve criar uma branch no seguinte formato:
nome-de-usuario-nome-do-projeto
- Exemplo:
git checkout -b joaozinho-sd-018-b-project-blogs-api
- Você deve criar uma branch no seguinte formato:
- Adicione as mudanças ao stage do Git e faça um
commit
- Verifique que as mudanças ainda não estão no stage
- Exemplo:
git status
(deve aparecer listada a pasta joaozinho em vermelho)
- Exemplo:
- Adicione o novo arquivo ao stage do Git
- Exemplo:
git add .
(adicionando todas as mudanças - que estavam em vermelho - ao stage do Git)git status
(deve aparecer listado o arquivo joaozinho/README.md em verde)
- Exemplo:
- Faça o
commit
inicial- Exemplo:
git commit -m 'iniciando o projeto x'
(fazendo o primeiro commit)git status
(deve aparecer uma mensagem tipo nothing to commit )
- Exemplo:
- Adicione a sua branch com o novo
commit
ao repositório remoto
- Usando o exemplo anterior:
git push -u origin joaozinho-sd-018-b-project-blogs-api
- Crie um novo
Pull Request
(PR)
- Vá até a página de Pull Requests do repositório no GitHub
- Clique no botão verde "New pull request"
- Clique na caixa de seleção "Compare" e escolha a sua branch com atenção
- Clique no botão verde "Create pull request"
- Adicione uma descrição para o Pull Request e clique no botão verde "Create pull request"
- Não se preocupe em preencher mais nada por enquanto!
- Volte até a página de Pull Requests do repositório e confira que o seu Pull Request está criado
⌨️ Durante o desenvolvimento
-
Faça
commits
das alterações que você fizer no código regularmente -
Lembre-se de sempre após um (ou alguns)
commits
atualizar o repositório remoto -
Os comandos que você utilizará com mais frequência são:
git status
(para verificar o que está em vermelho - fora do stage - e o que está em verde - no stage)git add
(para adicionar arquivos ao stage do Git)git commit
(para criar um commit com os arquivos que estão no stage do Git)git push -u nome-da-branch
(para enviar o commit para o repositório remoto na primeira vez que fizer opush
de uma nova branch)git push
(para enviar o commit para o repositório remoto após o passo anterior)
🤝 Depois de terminar o desenvolvimento (opcional)
Para "entregar" seu projeto, siga os passos a seguir:
- Vá até a página DO SEU Pull Request, adicione a label de "code-review" e marque seus colegas
- No menu à direita, clique no link "Labels" e escolha a label code-review
- No menu à direita, clique no link "Assignees" e escolha o seu usuário
- No menu à direita, clique no link "Reviewers" e digite students, selecione o time tryber/students-sd-00
Se ainda houver alguma dúvida sobre como entregar seu projeto, aqui tem um video explicativo.
🕵🏿 Revisando um pull request
À medida que você e as outras pessoas que estudam na Trybe forem entregando os projetos, vocês receberão um alerta via Slack para também fazer a revisão dos Pull Requests de colegas. Fique atento às mensagens do "Pull Reminders" no Slack!
Use o material que você já viu sobre Code Review para te ajudar a revisar os projetos que chegaram para você.
🛠 Execução de testes localmente
ℹ️ IMPORTANTE
-
O teste local deve rodar o script
npm run start:test
, que vai iniciar e depois encerrar, em segundo plano outra instância da sua API, na porta3030
. Dessa forma, o teste conseguira consumir sua API e validar os requisitos. -
Sua API deve estar funcionando minimamente para que o teste comece, dado que ele aguarda o estabelecimento da mesma para começar o teste.
-
Todos os testes vão gerar e consumir um banco de dados próprio com final
*-test
, que é gerado através da configuração do arquivosrc/database/config/config.js
. -
Isso vai garantir que durante seu desenvolvimento, o teste não manipule ou derrube sua API na porta padrão (
3000
) ou seu banco de dados padrão (final*-dev
), isolando os mesmos. -
Caso ocorra algum problema, encerre o teste com
[CTRL] + [C]
e utilize o scriptnpm run kill:test
O teste local já é configurado, internamente, com a variável de ambiente NODE_ENV=test
para indicar o banco a ser utilizado pelo Sequelize, o que deve resultar na criação de um banco, somente para o teste:
Sem essa variável (modo padrão de desenvolvimento), sua API deve resultar algo como:
ℹ️ Scripts para executar os testes locais:
Vamos usar o Jest para executar os testes, use o comando a seguir para executar todos os testes:
npm test
Caso queira executar só um arquivo de test use o seguinte comando, considerado que quer testar o arquivo tests/req07-createPost.test.js
:
npm test tests/req07-createPost.test.js
ou
npm test req07
Caso queira omitir dados de debug nos testes, utilize a variável de ambiente DEBUG=false
, como em DEBUG=false npm test
.
🎛 Linter
Para garantir a qualidade do código, usaremos o ESLint para fazer a sua análise estática.
Este projeto já vem com as dependências relacionadas ao linter configuradas nos arquivos package.json
nos seguintes caminhos:
sd-018-b-project-blogs-api/package.json
Para poder rodar os ESLint
em um projeto basta executar o comando npm install
dentro do projeto e depois npm run lint
. Se a análise do ESLint
encontrar problemas no seu código, tais problemas serão mostrados no seu terminal. Se não houver problema no seu código, nada será impresso no seu terminal.
Você também pode instalar o plugin do ESLint
no VSCode
, bastar baixar o plugin ESLint
e instalá-lo
⚠️ Informações importantes sobre o projeto
Em cada requisito você encontrará uma imagem demonstrando como sua API deverá se comportar, dada a requisição específica.
O não cumprimento de um requisito, total ou parcialmente, impactará em sua avaliação.
O projeto possui uma pasta src
, e é fortemente recomendável que você construa sua aplicação dentro dessa pasta.
Não é necessário usar o comando npx sequelize-cli init
uma vez que já é fornecido no projeto.
src/api.js
const express = require('express');
// ...
const app = express();
app.use(express.json());
// ...
// É importante exportar a constante `app`,
// para que possa ser utilizada pelo arquivo `src/server.js`
module.exports = app;
Que ficará responsável por receber as definições de middlewares e rotas de sua API
👉
src/server.js
const app = require('./api');
// não remova a variável `API_PORT` ou o `listen`
const port = process.env.API_PORT || 3000;
// não remova esse endpoint
app.get('/', (request, response) => {
response.send();
});
app.listen(port, () => console.log('ouvindo porta', port));
Que ficará responsável por iniciar sua API
👉
src/database/config/config.js
require('dotenv').config();
const environment = process.env.NODE_ENV || 'test';
const suffix = {
dev: '-dev',
development: '-dev',
test: '-test',
};
const options = {
host: process.env.HOSTNAME || process.env.MYSQL_HOST || 'localhost',
port: process.env.MYSQL_PORT || '3306',
database:
`${process.env.MYSQL_DB_NAME || 'blogs-api'}${suffix[environment] || suffix.test}`,
username: process.env.MYSQL_USER || 'root',
password: process.env.MYSQL_PASSWORD || '1234',
dialect: 'mysql',
dialectOptions: {
timezone: 'Z',
},
logging: process.env.DEBUG !== 'false',
};
module.exports = {
development: {
...options,
},
test: {
...options,
},
};
Que é o arquivo de configuração principal do Sequelize
👉
.sequelizerc
const path = require('path');
module.exports = {
'config': path.resolve('src', 'database', 'config', 'config.js'),
'models-path': path.resolve('src', 'database', 'models'),
'seeders-path': path.resolve('src', 'database', 'seeders'),
'migrations-path': path.resolve('src', 'database', 'migrations'),
};
Responsável por identificar os caminhos dos recursos do Sequelize
Você irá precisar configurar as variáveis de ambiente para uso do MySQL. Você pode usar esse Conteúdo de variáveis de ambiente com NodeJS como referência.
O arquivo a seguir, contém um modelo das variáveis de ambiente utilizadas no projeto. Para o contexto de teste local, é importante configurar as variáveis: MYSQL_HOST
, MYSQL_PORT
, MYSQL_USER
, MYSQL_PASSWORD
:
👉
.env.example
#### SERVER VARS
NODE_ENV=development
API_PORT=3000
#### DATABASE VARS
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DB_NAME=blogs-api
MYSQL_USER=root
MYSQL_PASSWORD=password
#### SECRECT VARS
JWT_SECRET=suaSenhaSecreta
Esta variável de ambiente deverá ser utilizada tanto para criar o token quanto para verificá-lo. Os teste locais e o avaliador vão utilizar a variável de ambiente JWT_SECRET
para testar os requisitos
👀 Dicas
Tenha em mente que todas as "respostas" devem respeitar os status do protocolo HTTP com base no que o REST prega.
Alguns exemplos:
-
Requisições que precisam de token mas não o receberam devem retornar um código de
status 401
; -
Requisições que não seguem o formato pedido pelo servidor devem retornar um código de
status 400
; -
Um problema inesperado no servidor deve retornar um código de
status 500
; -
Um acesso ao criar um recurso, no nosso caso usuário ou post, deve retornar um código de
status 201
.
🎲 Diagrama ER e Entidades
Para orientar a construção das tabelas através do ORM, utilize o DER a seguir:
O seu projeto deverá usar o ORM Sequelize
para criar e atualizar o seu banco de dados.
Os primeiros requisitos do projeto devem orientar a produção de suas migrations para gerar:
-
Uma tabela chamada Users, contendo dados com a seguinte estrutura:
{ "id": 1, "displayName": "Brett Wiltshire", "email": "brett@email.com", // tem quer ser único "password": "123456", "image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png" }
-
Uma tabela chamada Categories, contendo dados com a seguinte estrutura:
{ "id": 18, "name": "News" }
-
Uma tabela chamada BlogPosts, contendo dados com a seguinte estrutura:
{ "id": 21, "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key", "userId": 14, // Chave estrangeira, referenciando o id de `Users` "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.947Z", }
-
Uma tabela chamada PostCategories, contendo uma chave primária composta utilizando os dois atributos da estrutura:
{ "postId": 50, // Chave primária e estrangeira, referenciando o id de `BlogPosts` "categoryId": 20 // Chave primária e estrangeira, referenciando o id de `Categories` }
Os dados acima são fictícios, e estão aqui apenas como exemplo
⚠️ ️ Em caso de dúvidas, consulte os conteúdos:- Transformando ideias em um modelo de banco de dados (Em
Database Design - Como modelar um banco de dados
>4) Criando e modelando tabelas de acordo com um diagrama ER
) - ORM - Interface da aplicação com o banco de dados (Em
Migrações
) - ORM - Associations (Em
Relacionamentos N:N
)
- Deleta o banco de dados:
"drop": "npx sequelize-cli db:drop"
- Cria o banco e gera as tabelas:
"prestart": "npx sequelize-cli db:create && npx sequelize-cli db:migrate"
- Insere dados/Popula a tabela:
"seed": "npx sequelize-cli db:seed:all"
👀 OBS: Os testes irão rodar através do seu migrate usando os scripts acima, também listados no
package.json
.⚠️ Preste bastante atenção, pois a alteração desses scripts pode impedir o avaliador de funcionar corretamente⚠️ ️ Haverá um arquivo na pasta/seeders
, que irá conter as queries para inserção no banco de dados.Não a remova, pois o avaliador depende dela
. - Transformando ideias em um modelo de banco de dados (Em
🗣 Nos dê feedbacks sobre o projeto!
Ao finalizar e submeter o projeto, não se esqueça de avaliar sua experiência preenchendo o formulário. Leva menos de 3 minutos!
FORMULÁRIO DE AVALIAÇÃO DE PROJETO
🗂 Compartilhe seu portfólio!
Você sabia que o LinkedIn é a principal rede social profissional e compartilhar o seu aprendizado lá é muito importante para quem deseja construir uma carreira de sucesso? Compartilhe esse projeto no seu LinkedIn, marque o perfil da Trybe (@trybe) e mostre para a sua rede toda a sua evolução.
- Esse teste fará uma conexão no banco utilizando a configuração de teste do arquivo
src/database/config/config.js
; - Suas
migrations
devem estar no diretório correto e respeitar a nomenclatura pedida no requisito; - Suas
migrations
devem respeitar o diagrama de Entidade-Relacionamento e o formato das entidades, como descrito na seção de Diagrama ER e Entidades. - Exclua na pasta
./src/database/migrations/
, o arquivoremove-me.js
.
Os seguintes pontos serão avaliados:
-
[Será validado que é possível fazer um INSERT e um SELECT na tabela User]
- O avaliador irá inserir um dado de exemplo na tabela
Users
; - O avaliador irá fazer um select, desse mesmo dado, na tabela
Users
.
- O avaliador irá inserir um dado de exemplo na tabela
-
[Será validado que é possível fazer um INSERT e um SELECT na tabela Categories]
- O avaliador irá inserir um dado de exemplo na tabela
Categories
; - O avaliador irá fazer um select, desse mesmo dado, na tabela
Categories
.
- O avaliador irá inserir um dado de exemplo na tabela
-
[Será validado que, a partir de um INSERT em User, é possível fazer um INSERT e um SELECT na tabela BlogPosts]
- Dado que
BlogPosts
possui uma chave estrangeirauserId
:- O avaliador irá inserir um dado de exemplo na tabela
Users
;
- O avaliador irá inserir um dado de exemplo na tabela
- Desse modo:
- O avaliador irá inserir um dado de exemplo na tabela
BlogPosts
; - O avaliador irá fazer um select, desse mesmo dado, na tabela
BlogPosts
.
- O avaliador irá inserir um dado de exemplo na tabela
- Dado que
-
[Será validado que, a partir de INSERTs em User, Categories e BlogPosts, é possível fazer um INSERT e um SELECT na tabela PostCategories]
- Dado que
PostCategories
possui uma chave primária composta de duas chaves estrangeiras, respectivamente,postId
,categoryId
:- O avaliador irá inserir um dado de exemplo na tabela
Users
; - O avaliador irá inserir um dado de exemplo na tabela
Categories
; - O avaliador irá inserir um dado de exemplo na tabela
BlogPosts
;
- O avaliador irá inserir um dado de exemplo na tabela
- Desse modo:
- O avaliador irá inserir um dado de exemplo na tabela
PostCategories
; - O avaliador irá fazer um select, desse mesmo dado, na tabela
PostCategories
.
- O avaliador irá inserir um dado de exemplo na tabela
- Dado que
- Sua
model
deve estar no diretório correto e respeitar a nomenclatura pedida no requisito; - Sua
model
deve respeitar o diagrama de Entidade-Relacionamento e o formato das entidades, como descrito na seção de Diagrama ER e Entidades.
Os seguintes pontos serão avaliados:
-
[Será validado que existe o arquivo 'user.js']
-
[Será validado que o modelo possui o nome 'User']
-
[Será validado que o modelo possui a propriedade 'id']
-
[Será validado que o modelo possui a propriedade 'displayName']
-
[Será validado que o modelo possui a propriedade 'email']
-
[Será validado que o modelo possui a propriedade 'password']
-
[Será validado que o modelo possui a propriedade 'image']
- O endpoint deve ser acessível através do URL
/login
; - O corpo da requisição deverá seguir o formato abaixo:
{ "email": "lewishamilton@gmail.com", "password": "123456" }
Os seguintes pontos serão avaliados:
-
[Será validado que não é possível fazer login sem todos os campos preenchidos]
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
400
:
{ "message": "Some required fields are missing" }
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível fazer login com um usuário que não existe]
- Se a requisição receber um par de
email
epassword
errados/inexistentes, o resultado retornado deverá ser conforme exibido abaixo, com um status http400
:
{ "message": "Invalid fields" }
- Se a requisição receber um par de
-
[Será validado que é possível fazer login com sucesso]
- Se o login foi feito com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7ImlkIjo1LCJkaXNwbGF5TmFtZSI6InVzdWFyaW8gZGUgdGVzdGUiLCJlbWFpbCI6InRlc3RlQGVtYWlsLmNvbSIsImltYWdlIjoibnVsbCJ9LCJpYXQiOjE2MjAyNDQxODcsImV4cCI6MTYyMDY3NjE4N30.Roc4byj6mYakYqd9LTCozU1hd9k_Vw5IWKGL4hcCVG8" }
⚠️ O token anterior é fictício, seu token deve ser gerado a partir da variável de ambienteJWT_SECRET
, dopayload
da requisição e não deve conter o atributopassword
em sua construção. - Se o login foi feito com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- O endpoint deve ser acessível através do URL
/user
; - O endpoint deve ser capaz de adicionar um novo
user
a sua tabela no banco de dados; - O corpo da requisição deverá seguir o formato abaixo:
{ "displayName": "Brett Wiltshire", "email": "brett@email.com", "password": "123456", "image": "http://4.bp.blogspot.com/_YA50adQ-7vQ/S1gfR_6ufpI/AAAAAAAAAAk/1ErJGgRWZDg/S45/brett.png" }
Os seguintes pontos serão avaliados
-
[Será validado que não é possível cadastrar com o campo
displayName
menor que 8 caracteres]- Se a requisição não tiver o campo
displayName
devidamente preenchido com 8 caracteres ou mais, o resultado retornado deverá ser conforme exibido abaixo, com um status http400
:
{ "message": "\"displayName\" length must be at least 8 characters long" }
- Se a requisição não tiver o campo
-
[Será validado que não é possível cadastrar com o campo
email
com formato inválido]- Se a requisição não tiver o campo
email
devidamente preenchido com o formato<prefixo@dominio>
, o resultado retornado deverá ser conforme exibido abaixo, com um status http400
:
{ "message": "\"email\" must be a valid email" }
- Se a requisição não tiver o campo
-
[Será validado que não é possível cadastrar com o campo
password
menor que 6 caracteres]- Se a requisição não tiver o campo
password
devidamente preenchido com 6 caracteres ou mais, o resultado retornado deverá ser conforme exibido abaixo, com um status http400
:
{ "message": "\"password\" length must be at least 6 characters long" }
- Se a requisição não tiver o campo
-
[Será validado que não é possível cadastrar com um email já existente]
- Se a requisição enviar o campo
email
com um email que já existe, o resultado retornado deverá ser conforme exibido abaixo, com um status http409
:
{ "message": "User already registered" }
- Se a requisição enviar o campo
-
[Será validado que é possível cadastrar um pessoa usuária com sucesso]
- Se o user for criado com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
201
:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7ImlkIjo1LCJkaXNwbGF5TmFtZSI6InVzdWFyaW8gZGUgdGVzdGUiLCJlbWFpbCI6InRlc3RlQGVtYWlsLmNvbSIsImltYWdlIjoibnVsbCJ9LCJpYXQiOjE2MjAyNDQxODcsImV4cCI6MTYyMDY3NjE4N30.Roc4byj6mYakYqd9LTCozU1hd9k_Vw5IWKGL4hcCVG8" }
⚠️ O token anterior é fictício, seu token deve ser gerado a partir da variável de ambienteJWT_SECRET
, dopayload
da requisição e não deve conter o atributopassword
em sua construção. - Se o user for criado com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- Após termos feito o requisito de criação de
users
e o requisito delogin
, alguns requisitos abaixo vão precisar desta autenticação prévia, para que seja possível consumir o endpoint; - Todo requisito que precisar validar o
token
terá o símbolo ☝; - ✨ Dica: Se é algo que vamos utilizar em mais de uma rota, será que podemos separa-lo em algum lugar que comece com
M
demiddleware
? 😜
Os seguintes pontos serão avaliados
-
[Será validado que não é possível fazer uma operação sem o token na requisição]
- Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
401
:
{ "message": "Token not found" }
- Se o token for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível fazer uma operação com o token inválido]
- Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http
401
:
{ "message": "Expired or invalid token" }
- Se o token for inválido o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/user
; - O endpoint deve ser capaz de trazer todos
users
do banco de dados;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível listar todos os usuários]
- Ao listar usuários com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
[ { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, /* ... */ ]
- Ao listar usuários com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/user/:id
; - O endpoint deve ser capaz de trazer o
user
baseado noid
do banco de dados se ele existir;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível listar um usuário específico com sucesso]
- Ao listar um usuário com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
{ "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }
- Ao listar um usuário com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível listar um usuário inexistente]
- Se o usuário for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
404
:
{ "message": "User does not exist" }
- Se o usuário for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
- Sua
model
deve estar no diretório correto e respeitar a nomenclatura pedida no requisito; - Sua
model
deve respeitar o diagrama de Entidade-Relacionamento e o formato das entidades, como descrito na seção de Diagrama ER e Entidades.
Os seguintes pontos serão avaliados
-
[Será validado que existe o arquivo 'category.js']
-
[Será validado que o modelo possui o nome 'Category']
-
[Será validado que o modelo possui a propriedade 'id']
-
[Será validado que o modelo possui a propriedade 'name']
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/categories
; - O endpoint deve ser capaz de adicionar uma nova categoria a sua tabela no banco de dados;
- O corpo da requisição deverá seguir o formato abaixo:
{ "name": "Typescript" }
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que não é possível cadastrar uma categoria sem o campo
name
]- Se a requisição não tiver o campo
name
devidamente preenchidos(não pode haver campo em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http400
:
{ "message": "\"name\" is required" }
- Se a requisição não tiver o campo
-
[Será validado que é possível cadastrar uma categoria com sucesso]
- Se a categoria for criada com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
201
:
{ "id": 3, "name": "Typescript" }
- Se a categoria for criada com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/categories
; - O endpoint deve ser capaz de trazer todas categorias do banco de dados;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível listar todas as categoria com sucesso]
- Ao listar categorias com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
[ { "id": 1, "name": "Inovação" }, { "id": 2, "name": "Escola" }, /* ... */ ]
- Ao listar categorias com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
10 - Crie o modelo 'BlogPost' em 'src/database/models/blogPost.js' com as propriedades e associações corretas
-
Sua
model
deve estar no diretório correto e respeitar a nomenclatura pedida no requisito; -
Sua
model
deve respeitar o diagrama de Entidade-Relacionamento e o formato das entidades, como descrito na seção de Diagrama ER e Entidades; -
Sua
model
deve respeitar a associação correta (N:1) com o modeloUser
; -
✨ Dica:
- Explore como renomear campos no Sequelize;
Os seguintes pontos serão avaliados
-
[Será validado que existe o arquivo 'blogPost.js']
-
[Será validado que o modelo possui o nome 'BlogPost']
-
[Será validado que o modelo possui a propriedade 'id']
-
[Será validado que o modelo possui a propriedade 'title']
-
[Será validado que o modelo possui a propriedade 'content']
-
[Será validado que o modelo possui a propriedade 'userId']
-
[Será validado que o modelo possui a propriedade 'published']
-
[Será validado que o modelo possui a propriedade 'updated']
-
[Será validado que o modelo em 'blogPost.js', define a associação 'belongsTo', com a entidade de nome 'User']
-
[Será validado que o modelo em 'user.js', define a associação 'hasMany', com a entidade de nome 'BlogPost']
11 - Crie o modelo 'PostCategory' em 'src/database/models/postCategory.js' com as propriedades e associações corretas
- Sua
model
deve estar no diretório correto e respeitar a nomenclatura pedida no requisito; - Sua
model
deve respeitar o diagrama de Entidade-Relacionamento e o formato das entidades, como descrito na seção de Diagrama ER e Entidades; - Sua
model
deve respeitar a associação correta (N:N) entre o modeloBlogPost
e o modeloCategory
;
Os seguintes pontos serão avaliados
-
[Será validado que existe o arquivo 'postCategory.js']
-
[Será validado que o modelo possui o nome 'PostCategory']
-
[Será validado que o modelo possui a propriedade 'postId']
-
[Será validado que o modelo possui a propriedade 'categoryId']
-
[Será validado que o modelo em 'postCategory.js', através do(s) modelos(s) de nome(s) 'Category; BlogPost', define a associação 'belongsToMany' respectivamente, com o(s) modelo(s) de nome(s) 'BlogPost, Category']
-
☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; -
O endpoint deve ser acessível através do URL
/post
; -
O endpoint deve ser capaz de adicionar um novo blog post e vinculá-lo as categorias em suas tabelas no banco de dados;
-
O corpo da requisição deverá seguir o formato abaixo:
{ "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key", "categoryIds": [1, 2] }
-
✨ Dicas:
- Explore outros find na documentação do Sequelize;
- Explore outros insert na documentação do Sequelize;
- Explore a seção Transações do dia 24.2 no course, essa seção vai deixar suas aplicações com mais confiablidade e atomicidade, quando o assunto for transações de banco de dados;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que não é possível cadastrar sem todos os campos preenchidos]
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
400
:
{ "message": "Some required fields are missing" }
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível cadastrar um blogpost com uma
categoryIds
inexistente]- Se a requisição não tiver o campo
categoryIds
devidamente preenchido com um array com pelo menos uma categoria que exista, o resultado retornado deverá ser conforme exibido abaixo, com um status http `400``:
{ "message": "\"categoryIds\" not found" }
- Se a requisição não tiver o campo
-
[Será validado que é possível cadastrar um blogpost com sucesso]
- Se o blog post for criado com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
201
:
{
"id": 3,
"title": "Latest updates, August 1st",
"content": "The whole text for the blog post goes here in this key",
"userId": 1,
"updated": "2022-05-18T18:00:01.196Z",
"published": "2022-05-18T18:00:01.196Z"
}
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/post
; - O endpoint deve ser capaz de trazer todos os bogs post, user dono dele e as categorias do banco de dados;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível listar blogpost com sucesso]
- Ao listar posts com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
[ { "id": 1, "title": "Post do Ano", "content": "Melhor post do ano", "userId": 1, "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 1, "name": "Inovação" } ] }, /* ... */ ]
- Ao listar posts com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/post/:id
; - O endpoint deve ser capaz de trazer o blog post baseado no
id
do banco de dados se ele existir;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível listar um blogpost com sucesso]
- Ao listar um post com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
{ "id": 1, "title": "Post do Ano", "content": "Melhor post do ano", "userId": 1, "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 1, "name": "Inovação" } ] }
- Ao listar um post com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível listar um blogpost inexistente]
- Se o post for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
404
:
{ "message": "Post does not exist" }
- Se o post for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/post/:id
; - O endpoint deve ser capaz de alterar um post do banco de dados, se ele existir;
- Sua aplicação só deve permitir a alteração de um blog post caso a pessoa seja dona dele;
- Sua aplicação não deve permitir a alteração das categorias do post, somente os atributos
title
econtent
podem ser alterados; - O corpo da requisição deverá seguir o formato abaixo:
{ "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key" }
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que não é possível editar um blogpost com outro usuário]
- Somente o user que criou o blog post poderá editá-lo, o resultado retornado deverá ser conforme exibido abaixo, com um status http
401
{ "message": "Unauthorized user" }
- Somente o user que criou o blog post poderá editá-lo, o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que não é possível editar sem todos os campos preenchidos]
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
400
:
{ "message": "Some required fields are missing" }
- Se a requisição não tiver todos os campos devidamente preenchidos(não pode haver campos em branco), o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que é possível editar um blogpost com sucesso]
- Se o blog post for alterado com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
{ "id": 3, "title": "Latest updates, August 1st", "content": "The whole text for the blog post goes here in this key", "userId": 1, "published": "2022-05-18T18:00:01.000Z", "updated": "2022-05-18T18:07:32.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 1, "name": "Inovação" }, { "id": 2, "name": "Escola" } ] }
- Se o blog post for alterado com sucesso o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/post/:id
; - O endpoint deve ser capaz de deletar um blog post baseado no
id
do banco de dados se ele existir; - Sua aplicação só deve permitir a deleção de um blog post caso a pessoa seja dona dele;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que não é possível deletar um blogpost com outro usuário]
- Somente o user que criou o blog post poderá deletá-lo, o resultado retornado deverá ser conforme exibido abaixo, com um status http
401
{ "message": "Unauthorized user" }
- Somente o user que criou o blog post poderá deletá-lo, o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que é possível deletar um blogpost com sucesso]
- Se o blog post for deletado com sucesso não deve ser retornada nenhuma resposta, apenas um status http
204
:
- Se o blog post for deletado com sucesso não deve ser retornada nenhuma resposta, apenas um status http
-
[Será validado que não é possível deletar um blogpost inexistente]
- Se o post for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
404
:
{ "message": "Post does not exist" }
- Se o post for inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
- ☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; - O endpoint deve ser acessível através do URL
/user/me
; - O endpoint deve ser capaz de deletar você do banco de dados, baseado no
id
que esta dentro do seutoken
; - Sua aplicação deve ser capaz de utilizar o token de autenticação nos headers, para saber o user logado correspondente á ser apagado;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível excluir meu usuário com sucesso]
- Se o user for deletado com sucesso não deve ser retornada nenhuma resposta, apenas um status http
204
:
- Se o user for deletado com sucesso não deve ser retornada nenhuma resposta, apenas um status http
-
☝ Não esqueça de validar o
token
neste requisito, como descrito na seção de Validando token nas requisições; -
O endpoint deve ser acessível através do URL
/post/search
; -
O endpoint deve ser capaz de trazer os blogs post baseados no
q
do banco de dados, se ele existir; -
Sua aplicação deve ser capaz de retornar um array de blogs post que contenham em seu título ou conteúdo o termo passado na URL;
-
Sua aplicação deve ser capaz de retornar um array vázio caso nenhum blog post satisfaça a busca;
-
O query params da requisição deverá seguir o formato abaixo:
http://localhost:PORT/post/search?q=vamos
-
✨ Dica:
- Explore como fazer LIKE no Sequelize igual aprendemos no dia 20.3 - Pesquisas mais dinâmicas e maleáveis com LIKE do course;
Os seguintes pontos serão avaliados
-
☝ [Será validado o token, como descrito na seção de Validando token nas requisições]
-
[Será validado que é possível buscar um blogpost pelo
title
]- Se a buscar for pelo
title
o resultado retornado deverá ser conforme exibido abaixo, com um status http200
:
// GET /post/search?q=Vamos que vamos [ { "id": 2, "title": "Vamos que vamos", "content": "Foguete não tem ré", "userId": 1, "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 2, "name": "Escola" } ] } ]
- Se a buscar for pelo
-
[Será validado que é possível buscar um blogpost pelo
content
]- Se a buscar for pelo
content
o resultado retornado deverá ser conforme exibido abaixo, com um status http200
:
// GET /post/search?q=Foguete não tem ré [ { "id": 2, "title": "Vamos que vamos", "content": "Foguete não tem ré", "userId": 1, "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 2, "name": "Escola" } ] } ]
- Se a buscar for pelo
-
[Será validado que é possível buscar todos os blogpost quando passa a busca vazia]
- Se a buscar for vazia o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
// GET /post/search?q= [ { "id": 1, "title": "Post do Ano", "content": "Melhor post do ano", "userId": 1, "published": "2011-08-01T19:58:00.000Z", "updated": "2011-08-01T19:58:51.000Z", "user": { "id": 1, "displayName": "Lewis Hamilton", "email": "lewishamilton@gmail.com", "image": "https://upload.wikimedia.org/wikipedia/commons/1/18/Lewis_Hamilton_2016_Malaysia_2.jpg" }, "categories": [ { "id": 1, "name": "Inovação" } ] }, /* ... */ ]
- Se a buscar for vazia o resultado retornado deverá ser conforme exibido abaixo, com um status http
-
[Será validado que é possível buscar um blogpost inexistente e retornar array vazio]
- Se a buscar um post inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http
200
:
// GET /post/search?q=BATATA []
- Se a buscar um post inexistente o resultado retornado deverá ser conforme exibido abaixo, com um status http