O Soccer Ranking Dashboard
é um site informativo sobre partidas e classificações de futebol! ⚽️
Foi desenvolvida uma API (utilizando o método TDD
) integrada através do docker-compose.
Construí um back-end dockerizado utilizando modelagem de dados através do Sequelize.
Para adicionar uma partida é necessário ter um token, portanto a pessoa deverá estar logada para fazer as alterações. Há um relacionamento entre as tabelas teams
e matches
para fazer as atualizações das partidas.
O back-end popula adequadamente a tabela disponível no front-end que será exibida para a pessoa usuária do sistema.
O projeto é composto de 4 entidades importantes para sua estrutura:
1️⃣ Banco de dados:
- Um container docker MySQL já configurado no docker-compose através de um serviço definido como
db
. - Tem o papel de fornecer dados para o serviço de backend.
- Durante a execução dos testes sempre vai ser acessado pelo
sequelize
e via porta3002
dolocalhost
; - Você também pode conectar a um Cliente MySQL (Workbench, Beekeeper, DBeaver e etc), colocando as credenciais configuradas no docker-compose no serviço
db
.
2️⃣ Back-end:
- Deve rodar na porta
3001
, pois o front-end faz requisições para ele nessa porta por padrão; - Sua aplicação deve ser inicializada a partir do arquivo
app/backend/src/server.ts
; - Garanta que o
express
é executado e a aplicação ouve a porta que vem das variáveis de ambiente;
3️⃣ Front-end:
- O front se comunica com serviço de back-end pela url
http://localhost:3001
4️⃣ Docker:
- O
docker-compose
tem a responsabilidade de unir todos os serviços conteinerizados (backend, frontend e db) e subir o projeto completo com o comandonpm run compose:up
ounpm run compose:up:dev
;
🔰 Rodando o projeto
- Clone o repositório
Usar link SSH
-
Entre na pasta do repositório que você acabou de clonar:
cd pasta-do-repositório
- Instale as dependências [Caso existam]
*
npm install
🕵️ Linter
Este projeto já vem com as dependências relacionadas ao linter configuradas nos arquivos package.json
nos seguintes caminhos:
sd-022-a-trybe-futebol-clube/app/backend/package.json
Para rodar o 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 ir em extensions e baixar o plugin ESLint
.
⚠️ Configurações mínimas para execução do projeto
Na sua máquina você deve ter:
- Sistema Operacional Distribuição Unix
- Node versão 16
- Docker
- Docker-compose versão >=1.29.2
➡️ O node
deve ter versão igual ou superior à 16.14.0 LTS
:
- Para instalar o nvm, acesse esse link;
- Rode os comandos abaixo para instalar a versão correta de
node
e usá-la:nvm install 16.14 --lts
nvm use 16.14
nvm alias default 16.14
➡️ Odocker-compose
deve ter versão igual ou superior àˆ1.29.2
:
- Acesse o link da documentação oficial com passos para desinstalar caso necessário.
🐳 Configuração Docker
⚠ O seu docker-compose precisa estar na versão 1.29 ou superior. ⚠ Veja aqui a documentação para atualizar o docker-compose.
- O arquivo
docker-compose.yml
também pode ser utilizado para executar a aplicação na sua máquina local, para isso é necessário executar o comandonpm run compose:up
na raiz do projeto. - Para o desenvolvimento do projeto, usei o comando
npm run compose:up:dev
pois, diferente do comando anterior, este está configurado para compartilhar volumes com o docker e também utiliza o script que realiza o live-reload ao modificar o código do back-end. Somente quando instalar uma nova dependência ou alterar algum arquivo na raiz do backend, você deverá parar o docker-compose com o comandonpm run compose:down:dev
e executar novamentenpm run compose:up:dev
, pois o volume está mapeando somente alterações dentro da pastasrc
. Você pode verificar essas configurações explorando o arquivodocker-compose.dev.yml
e comparar comdocker-compose.yml
⚠️ Inicialização do compose e verificação dos logs das aplicações
-
Considerando o uso do parâmetro
healthcheck
em cada container dodocker-compose.yml
, a inicialização dos containers deve aguardar o comando de status de saúde (o que valida se aquele container está operacional ou não):- No container
db
, representado por um comandoping
no banco de dados; - No back-end, representado por um comando
lsof
, que vai procurar aplicações ativas na porta definida (por padrão, no caso3001
); - No front-end, representado por um comando
lsof
, que vai procurar aplicações ativas na porta definida (por padrão, no caso3000
).
- No container
-
Caso os containers respeitem as premissas anteriores, os mesmos devem ser criados sem maiores problemas:
- Em caso de algum problema (no back-end, por exemplo), você deve se deparar com alguma mensagem do tipo:
- Nesse caso, a partir da pasta
./app
(onde está seu docker-compose), é possível rodar o comandodocker-compose logs
(Para ver todos os status) oudocker-compose logs <nome-do-seu-serviço>
(Para mostrar somente o de um escopo específico).⚠️ é indicado remover o parâmetrorestart: 'always'
do seu serviço, para que o mesmo não polua seus logs;- Nesse contexto, rodando o comando
docker-compose logs backend
:
⚙️ Variáveis de ambiente
No diretório app/backend/
renomeie o arquivo .env.example
para .env
e configure os valores de acordo com o cenário do seu ambiente (credenciais de banco de dados, secrets desejadas e etc). Isso vai permitir que você inicialize a aplicação fora do container e ela se conecte com seu banco local caso deseje.
./app/backend/.env.example
JWT_SECRET=jwt_secret
APP_PORT=3001
DB_USER=seu_user
DB_PASS=sua_senha
DB_HOST=localhost
DB_PORT=3306
TRYBE_FUTEBOL_CLUBE
.
🎲 Sequelize
Para o desenvolvimento, foi criado um Diagrama de Entidade-Relacionamento (DER) para construir a modelagem do banco de dados.
![Exemplo banco de dados](assets/diagrama-er.png)
package.json
do diretório app/backend
contém um script db:reset
que é responsável por "dropar" o banco, recriar e executar as migrations e seeders. Você pode executá-lo com o commando npm run db:reset
se por algum motivo precisar recriar a base de dados;
app/backend/src/database/seeders
.
app/backend
. Certifique-se de que antes de rodar comandos do sequelize já exista uma versão compilada do back-end (diretório app/build
), caso contrário basta executar npm run build
para compilar. O sequelize só funcionará corretamente se o projeto estiver compilado.
sequelize init
novamente
Testes de cobertura
A construção de testes de cobertura no back-end foi feita em TypeScript, utilizando mocha
, chai
e sinon
, na pasta app/backend/src/tests/
.
Para rodar os testes de cobertura no back-end, utilize o comando: npm run test:coverage
.
🛠 Execução de testes localmente
ℹ️ IMPORTANTE
Para que os testes do projeto sejam executados localmente é necessário que todos os seus containers estejam no ar e saudáveis.
Com os containers do Banco de dados, Back-end e Front-end rodando e saudáveis:
-
Para executar todos os testes, execute na raiz do seu projeto:
npm test
-
Para executar apenas um arquivo específico de testes, basta colocar no final do comando anterior o nome do arquivo de teste. Execute na raiz do seu projeto, por exemplo:
npm test teams.test.js
👀 Dicas e comandos úteis
- Quando um Workspace é inicializado na raiz do projeto, são apresentados alguns erros no Typescript. Para que o editor consiga sincronizar corretamente as configurações do
tsconfig.json
, é necessário iniciar um novo Workspace dentro do diretóriobackend
. Sempre que o VSCode apresentar algum erro de configuração do Typescript, certifique-se de que está usando o Workspace correto. - Ao rodar o comando
npm install
na pasta raiz do projeto você automaticamente estará instalando as aplicações (front e back); - Você pode instalar as aplicações (front e back) rodando o comando
npm run install:apps
na pasta raiz do projeto; - Você pode subir ou descer uma aplicação do compose, utilizando
npm run
com os scriptscompose:up
,compose:down
, oucompose:up:dev
,compose:down:dev
; - Os comando de compose anteriores estão configurados para executar o docker-compose com o terminal desanexado (detached mode
-d
). Caso queira acompanhar os logs de um serviço em tempo real pelo terminal, basta executarnpm run logs [nome_do_servico]
onde nome_do_servico é opcional e pode receber os serviços backend, frontend ou db
Esse projeto é composto de 4 seções principais:
- Users e Login
- Times
- Partidas
- Placar
- Comece rodando o comando
npm run build
na pasta doback-end
para fazer o build da aplicação; - Nessa seção temos o diagrama de entidades;
Introdução
-
A rota utilizada deve ser (
/login
); -
A rota deve receber os campos
email
epassword
e esses campos devem ser validados no banco de dados:- O campo
email
deve receber um email válido; - O Campo
password
deve ter mais de 6 caracteres.
- O campo
-
O body da requisição deve conter o seguinte formato:
{ "email": "string", "password": "string" }
Requisitos
1 - Desenvolva em /app/backend/src/database
nas pastas correspondentes, uma migration e um model para a tabela users
- O avaliador consultará os dados da tabela
users
, verificando se ela contém os dados iniciais corretos. Nessa seção temos o diagrama de entidades;
2 - (TDD
) Desenvolva testes que cubram no mínimo 5% dos arquivos back-end em /src
, com um mínimo de 7 linhas cobertas
Sugestões:
- Baseando-se no contrato do endpoint
/login
do próximo requisito, inicie um teste de integração utilizando a metodologiaTDD
com a implementação do requisito seguinte; - Nesse primeiro momento, foque em desenvolver o que pede o requisito, progredindo gradualmente a partir disso;
- Para tanto, utilize/altere o arquivo de referência
app/backend/src/tests/change.me.test.ts
; - Veja a seção de Testes de cobertura para mais detalhes.
3 - Desenvolva o endpoint /login
no back-end de maneira que ele permita o acesso com dados válidos no front-end
-
A rota de ser do tipo
POST
; -
O avaliador verificará se é possível fazer o login com dados corretos e que, após o acesso, será redirecionado para a tela de jogos.
-
As senhas que existem no banco de dados estão encriptadas. Veja a seção de Criptografia de Senhas para mais detalhes de como comparar a senha do banco com a senha do corpo da requisição.
-
Se o login foi feito com sucesso, o resultado retornado deverá ser similar ao exibido abaixo, com um status http
200
:{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjU0NTI3MTg5fQ.XS_9AA82iNoiVaASi0NtJpqOQ_gHSHhxrpIdigiT-fc" // Aqui deve ser o token gerado pelo backend. }
4 - (TDD
) Desenvolva testes que cubram no mínimo 10% dos arquivos back-end em /src
, com um mínimo de 19 linhas cobertas
Sugestão:
- Evolua os testes de integração da sua rota
/login
, utilizando o métodoTDD
, agora considerando o contrato do próximo requisito.
5 - Desenvolva o endpoint /login
no back-end de maneira que ele não permita o acesso sem informar um email no front-end
-
O avaliador verificará se fazer o login sem um email, haverá o retorno de status bad request.
-
Se o login não tiver o campo "email", o resultado retornado deverá ser a mensagem abaixo, com um status http
400
:
{ "message": "All fields must be filled" }
6 - (TDD
) Desenvolva testes que cubram no mínimo 15% dos arquivos back-end em /src
, com um mínimo de 25 linhas cobertas
Sugestão:
- Evolua os testes de integração da sua rota
/login
, utilizando o métodoTDD
, agora considerando o contrato do próximo requisito.
7 - Desenvolva o endpoint /login
no back-end de maneira que ele não permita o acesso sem informar uma senha no front-end
-
O avaliador verificará se fazer login sem senha, o retorno será status bad request.
-
Se o login não tiver o campo "password", o resultado retornado deverá ser conforme exibido abaixo, com um status http
400
:
{ "message": "All fields must be filled" }
8 - (TDD
) Desenvolva testes que cubram no mínimo 20% dos arquivos back-end em /src
, com um mínimo de 35 linhas cobertas
Sugestão:
- Evolua os testes de integração da sua rota
/login
, utilizando o métodoTDD
, agora considerando o contrato do próximo requisito.
9 - Desenvolva o endpoint /login
no back-end de maneira que ele não permita o acesso com um email inválido no front-end
-
O avaliador verificará se fazer o login com um email incorreto retornará status não-autorizado.
-
Se o login tiver o "email" inválido, o resultado retornado será similar ao exibido abaixo, com um status http
401
:
{ "message": "Incorrect email or password" }
10 - (TDD
) Desenvolva testes que cubram no mínimo 30% dos arquivos back-end em /src
, com um mínimo de 45 linhas cobertas
Sugestão:
- Evolua os testes de integração da sua rota
/login
, utilizando o métodoTDD
, agora considerando os contratos dos próximos dois requisitos.
11 - Desenvolva o endpoint /login
no back-end de maneira que ele não permita o acesso com uma senha inválida no front-end
-
O avaliador verificará se fazer o login com uma senha incorreta retornará status não-autorizado.
-
Se o login tiver a "senha" inválida, o resultado retornado deverá ser conforme exibido abaixo, com um status http
401
:
{ "message": "Incorrect email or password" }
12 - Desenvolva o endpoint /login/validate
no back-end de maneira que ele retorne os dados corretamente no front-end
-
Deve ser uma rota
GET
que receba umheader
com parâmetroauthorization
, onde ficará armazenado o token gerado no login; -
O avaliador verificará se ao tentar bater na rota com um token válido, o mesmo retornará o tipo de usuário.
A resposta deve ser de status 200
com um objeto
contendo a role
do user:
{ "role": "admin" }
Introdução
- Os requisitos a seguir consideram o consumo da rota
/teams
para retornar os nomes dos times associados à partida na renderização do front-end
Requisitos
13 - (TDD
) Desenvolva testes que cubram no mínimo 45% dos arquivos back-end em /src
, com um mínimo de 70 linhas cobertas
Sugestão:
- Crie um novo teste de integração, agora da sua rota
/teams
, utilizando o métodoTDD
, considerando os contratos dos próximos dois requisitos. Nessa seção temos o diagrama de entidades.
14 - Desenvolva em /app/backend/src/database
nas pastas correspondentes, uma migration e um model para a tabela de teams
- O avaliador consultará os dados da tabela
teams
, verificando se ela contém os dados iniciais corretos. Nessa seção temos o diagrama de entidades.
15 - Desenvolva o endpoint /teams
no back-end de forma que ele possa retornar todos os times corretamente
- Deve ser uma rota
GET
com resposta com status200
e com umjson
contendo o retorno no seguinte modelo:
[
{
"id": 1,
"teamName": "Avaí/Kindermann"
},
{
"id": 2,
"teamName": "Bahia"
},
{
"id": 3,
"teamName": "Botafogo"
},
...
]
16 - Desenvolva o endpoint /teams/:id
no back-end de forma que ele possa retornar dados de um time específico
- Deve ser uma rota
GET
com resposta com status200
e com umjson
contendo o retorno no seguinte modelo:
{
"id": 5,
"teamName": "Cruzeiro"
}
17 - (TDD
) Desenvolva testes que cubram no mínimo 60% dos arquivos back-end em /src
, com um mínimo de 80 linhas cobertas
Sugestão:
- Crie um novo teste de integração, agora da sua rota
/matches
, utilizando o métodoTDD
, agora considerando os contratos dos próximos três requisitos.
Introdução
- Para os requisitos de criação de partidas, será necessário implementar o model e algumas rotas relacionadas a entidade Match.
Requisitos
18 - Desenvolva em /app/backend/src/database
nas pastas correspondentes, uma migration e um model para a tabela de matches
- O avaliador consultará os dados da tabela
matches
, verificando se ela contém os dados iniciais corretos. Nessa seção temos o diagrama de entidades.
19 - Desenvolva o endpoint /matches
de forma que os dados apareçam corretamente na tela de partidas no front-end.
-
A rota deve ser um
GET
e retorna uma lista de partidas; -
Será validado que a página apresentará todos os dados de partidas sem nenhum filtro.
Exemplo de retorno:
[ { "id": 1, "homeTeam": 16, "homeTeamGoals": 1, "awayTeam": 8, "awayTeamGoals": 1, "inProgress": false, "teamHome": { "teamName": "São Paulo" }, "teamAway": { "teamName": "Grêmio" } }, ... { "id": 41, "homeTeam": 16, "homeTeamGoals": 2, "awayTeam": 9, "awayTeamGoals": 0, "inProgress": true, "teamHome": { "teamName": "São Paulo" }, "teamAway": { "teamName": "Internacional" } } ]
-
OBS: Você deverá definir os relacionamentos para
teamHome
eteamAway
somente na model de partidas.
20 - Desenvolva o endpoint /matches
de forma que seja possível filtrar as partidas em andamento na tela de partidas do front-end
-
A rota deverá ser do tipo
GET
e retornar uma lista de partidas filtradas; -
Será validado que, ao escolher a opção de partidas em andamento, serão filtradas todas as partidas em andamento;
-
Essa requisição deverá usar
query string
para definir o parâmetro: ex:matches?inProgress=true
Exemplo de retorno da requisição:
[
{
"id": 41,
"homeTeam": 16,
"homeTeamGoals": 2,
"awayTeam": 9,
"awayTeamGoals": 0,
"inProgress": true,
"teamHome": {
"teamName": "São Paulo"
},
"teamAway": {
"teamName": "Internacional"
}
},
{
"id": 42,
"homeTeam": 6,
"homeTeamGoals": 1,
"awayTeam": 1,
"awayTeamGoals": 0,
"inProgress": true,
"teamHome": {
"teamName": "Ferroviária"
},
"teamAway": {
"teamName": "Avaí/Kindermann"
}
}
]
21 - Desenvolva o endpoint /matches
de forma que seja possível filtrar as partidas finalizadas na tela de partidas do front-end
-
A rota deverá ser do tipo
GET
e retornar uma lista de partidas filtradas; -
Será validado que,ao escolher a opção de partidas finalizadas, serão filtradas todas as partidas finalizadas;
-
Essa requisição deverá usar
query string
para definir o parâmetro. ex:matches?inProgress=false
Exemplo de retorno da requisição:
[
{
"id": 1,
"homeTeam": 16,
"homeTeamGoals": 1,
"awayTeam": 8,
"awayTeamGoals": 1,
"inProgress": false,
"teamHome": {
"teamName": "São Paulo"
},
"teamAway": {
"teamName": "Grêmio"
}
},
{
"id": 2,
"homeTeam": 9,
"homeTeamGoals": 1,
"awayTeam": 14,
"awayTeamGoals": 1,
"inProgress": false,
"teamHome": {
"teamName": "Internacional"
},
"teamAway": {
"teamName": "Santos"
}
}
]
22 - (Bônus
; TDD
) Desenvolva testes que cubram no mínimo 80% dos arquivos back-end em /src
, com um mínimo de 100 linhas cobertas
Sugestão:
- Evolua os testes de integração da sua rota
/matches
, utilizando o métodoTDD
, agora considerando o contrato dos próximos requisitos.
23 - Desenvolva o endpoint /matches
de modo que seja possível salvar uma partida com o status de inProgress como true no banco de dados
-
A rota deverá ser do tipo
POST
e retornar a partida inserida no banco de dados; -
Será validado que é possível salvar um jogo no banco de dados e ver o jogo na página de jogos;
-
A partida só pode ser criada com token JWT validado;
-
O corpo da requisição terá o seguinte formato:
{
"homeTeam": 16, // O valor deve ser o id do time
"awayTeam": 8, // O valor deve ser o id do time
"homeTeamGoals": 2,
"awayTeamGoals": 2,
}
- Caso a partida seja inserida com sucesso, deve-se retornar os dados da partida, com status
201
:
{
"id": 1,
"homeTeam": 16,
"homeTeamGoals": 2,
"awayTeam": 8,
"awayTeamGoals": 2,
"inProgress": true,
}
24 - Desenvolva o endpoint /matches/:id/finish
de modo que seja possível alterar o status inProgress de uma partida para false no banco de dados
-
A rota deve ser do tipo
PATCH
; -
Será recebido o
id
pelo parâmetro da URL; -
Será validado que, ao finalizar uma partida, a alteração é feita no banco de dados e na página.
-
Deve-se retornar, com um status
200
, a seguinte mensagem:
{ "message": "Finished" }
25 - Desenvolva o endpoint /matches
de forma que não seja possível inserir uma partida com times iguais
-
Será validado que não é possível inserir uma partida em que o
homeTeam
e oawayTeam
sejam iguais, por exemplo: Barcelona x Barcelona; -
Caso isso ocorra, deve-se retornar, com um status
422
, a seguinte mensagem::
{ "message": "It is not possible to create a match with two equal teams" }
26 - Desenvolva o endpoint /matches
de forma que não seja possível inserir uma partida com um time que não existe na tabela teams
-
Será validado que não é possível inserir uma partida com um time que não existe na tabela teams;
-
Caso algum dos times não esteja cadastrado no banco de dados, deve-se retornar, com um status
404,
a seguinte mensagem:
{ "message": "There is no team with such id!" }
27 - Desenvolva o endpoint /matches
de forma que não seja possível inserir uma partida sem um token válido
-
Será validado que não é possível inserir uma partida com um token inválido;
-
Caso o token informado não seja válido, deve-se retornar, com um status
401
, a seguinte mensagem:
{ "message": "Token must be a valid token" }
-
O endpoint deve ser do tipo
PATCH
; -
Será recebido o
id
pelo parâmetro da URL; -
Será avaliado que é possível alterar o resultado de uma partida.
-
O corpo da requisição terá o seguinte formato:
{
"homeTeamGoals": 3,
"awayTeamGoals": 1
}
- Será avaliado que é o endpoint responde à requisição com um status
200
e qualquer corpo.
Introdução
- `Classificação`: Posição na classificação;
- `Time`: Nome do time;
- `P`: Total de Pontos;
- `J`: Total de Jogos;
- `V`: Total de Vitórias;
- `E`: Total de Empates;
- `D`: Total de Derrotas;
- `GP`: Gols marcados a favor;
- `GC`: Gols sofridos;
- `SG`: Saldo total de gols;
- `%`: Aproveitamento do time.
-
Todas as regras de negócio e cálculos necessários deverão ser realizados no seu back-end. A aplicação front-end apenas renderizará essas informações.
-
Para calcular o
Total de Pontos
, você deve levar em consideração que:- O time
vitorioso
: marcará +3 pontos; - O time
perdedor
: marcará 0 pontos; - Em caso de
empate
: ambos os times marcam +1 ponto.
- O time
-
Para o campo
Aproveitamento do time (%)
, que é a porcentagem de jogos ganhos, use a seguinte fórmula:[P / (J * 3)] * 100
, onde:P
: Total de Pontos;J
: Total de Jogos.
Obs.: O seu resultado deverá ser limitado a
duas casas decimais
. -
Para calcular
Saldo de Gols
use a seguinte fórmula:GP - GC
, onde:GP
: Gols marcados a favor;GC
: Gols sofridos.
-
O resultado deverá ser ordenado sempre de forma decrescente, levando em consideração a quantidade de pontos que o time acumulou. Em caso de empate no
Total de Pontos
, você deve levar em consideração os seguintes critérios para desempate:
Ordem para desempate
1º Total de Vitórias; 2º Saldo de gols; 3º Gols a favor; 4º Gols sofridos.
- Por padrão, as respostas de todos os seus endpoints deverão estar em inglês, mesmo que a renderização no front-end seja em português.
- A sua tabela deverá renderizar somente as PARTIDAS que já foram FINALIZADAS! Os seguintes pontos serão avaliados:
- Se a lista de classificação está correta;
- Se a regra de classificação se mantém mesmo com mudanças na classificação;
- Se a tabela de classificação tem 10 colunas;
- Se a tabela tem uma linha para cada time.
Exemplo de retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 13,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 17,
"goalsOwn": 5,
"goalsBalance": 12,
"efficiency": 86.67
},
{
"name": "Corinthians",
"totalPoints": 12,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 12,
"goalsOwn": 3,
"goalsBalance": 9,
"efficiency": 80
},
{
"name": "Santos",
"totalPoints": 11,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 12,
"goalsOwn": 6,
"goalsBalance": 6,
"efficiency": 73.33
},
...
]
-
Os endpoints dessa seção, irão alimentar uma tabela idêntica ao exemplo abaixo no front-end:
Classificação Time P J V E D GP GC SG % 1 Ferroviária 38 15 12 2 1 44 13 31 84.4
Requisitos
29 - Desenvolva o endpoint /leaderboard/home
de forma que seja possível filtrar as classificações dos times da casa
na tela de classificação do front-end com os dados iniciais do banco de dados
-
O endpoint deverá ser do tipo
GET
; -
Será avaliado que ao fazer a requisição ao endpoint
/leaderboard/home
serão retornados os campos e valores corretos, considerando os dados iniciais do banco de dados; -
Partidas que estiverem em andamento (não foram finalizadas) não devem ser consideradas.
Retorno esperado:
[
{
"name": "Santos",
"totalPoints": 9,
"totalGames": 3,
"totalVictories": 3,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 9,
"goalsOwn": 3,
"goalsBalance": 6,
"efficiency": "100.00"
},
{
"name": "Palmeiras",
"totalPoints": 7,
"totalGames": 3,
"totalVictories": 2,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 10,
"goalsOwn": 5,
"goalsBalance": 5,
"efficiency": "77.78"
},
{
"name": "Corinthians",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 6,
"goalsOwn": 1,
"goalsBalance": 5,
"efficiency": "100.00"
},
{
"name": "Grêmio",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 4,
"goalsOwn": 1,
"goalsBalance": 3,
"efficiency": "100.00"
},
{
"name": "Real Brasília",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 0,
"goalsBalance": 2,
"efficiency": "100.00"
},
{
"name": "São Paulo",
"totalPoints": 4,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 4,
"goalsOwn": 1,
"goalsBalance": 3,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 4,
"goalsOwn": 6,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Botafogo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 2,
"goalsOwn": 4,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Ferroviária",
"totalPoints": 3,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 3,
"goalsOwn": 2,
"goalsBalance": 1,
"efficiency": "50.00"
},
{
"name": "Napoli-SC",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 2,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Cruzeiro",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 2,
"goalsOwn": 3,
"goalsBalance": -1,
"efficiency": "16.67"
},
{
"name": "Flamengo",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 2,
"goalsBalance": -1,
"efficiency": "16.67"
},
{
"name": "Minas Brasília",
"totalPoints": 1,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 3,
"goalsOwn": 6,
"goalsBalance": -3,
"efficiency": "11.11"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 1,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 3,
"goalsOwn": 7,
"goalsBalance": -4,
"efficiency": "11.11"
},
{
"name": "São José-SP",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 2,
"goalsOwn": 5,
"goalsBalance": -3,
"efficiency": "0.00"
},
{
"name": "Bahia",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 0,
"goalsOwn": 4,
"goalsBalance": -4,
"efficiency": "0.00"
}
]
30 - Desenvolva o endpoint /leaderboard/home
de forma que seja possível filtrar as classificações dos times da casa na tela de classificação do front-end, e atualizar a tabela ao inserir a partida Corinthians 2 X 1 Internacional
- Será avaliado que após acrescentar a partida Corinthians 2 X 1 Internacional e fazer a requisição ao endpoint
/leaderboard/home
, serão retornados os campos e valores corretos.
Retorno esperado:
[
{
"name": "Santos",
"totalPoints": 9,
"totalGames": 3,
"totalVictories": 3,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 9,
"goalsOwn": 3,
"goalsBalance": 6,
"efficiency": "100.00"
},
{
"name": "Corinthians",
"totalPoints": 9,
"totalGames": 3,
"totalVictories": 3,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 8,
"goalsOwn": 2,
"goalsBalance": 6,
"efficiency": "100.00"
},
{
"name": "Palmeiras",
"totalPoints": 7,
"totalGames": 3,
"totalVictories": 2,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 10,
"goalsOwn": 5,
"goalsBalance": 5,
"efficiency": "77.78"
},
{
"name": "Grêmio",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 4,
"goalsOwn": 1,
"goalsBalance": 3,
"efficiency": "100.00"
},
{
"name": "Real Brasília",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 0,
"goalsBalance": 2,
"efficiency": "100.00"
},
{
"name": "São Paulo",
"totalPoints": 4,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 4,
"goalsOwn": 1,
"goalsBalance": 3,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 4,
"goalsOwn": 6,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Botafogo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 2,
"goalsOwn": 4,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Ferroviária",
"totalPoints": 3,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 3,
"goalsOwn": 2,
"goalsBalance": 1,
"efficiency": "50.00"
},
{
"name": "Napoli-SC",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 2,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Cruzeiro",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 2,
"goalsOwn": 3,
"goalsBalance": -1,
"efficiency": "16.67"
},
{
"name": "Flamengo",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 2,
"goalsBalance": -1,
"efficiency": "16.67"
},
{
"name": "Minas Brasília",
"totalPoints": 1,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 3,
"goalsOwn": 6,
"goalsBalance": -3,
"efficiency": "11.11"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 1,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 3,
"goalsOwn": 7,
"goalsBalance": -4,
"efficiency": "11.11"
},
{
"name": "São José-SP",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 2,
"goalsOwn": 5,
"goalsBalance": -3,
"efficiency": "0.00"
},
{
"name": "Bahia",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 0,
"goalsOwn": 4,
"goalsBalance": -4,
"efficiency": "0.00"
}
]
31 - Desenvolva o endpoint /leaderboard/away
, de forma que seja possível filtrar as classificações dos times quando visitantes na tela de classificação do front-end, com os dados iniciais do banco de dados
-
O endpoint deverá ser do tipo
GET
; -
Será avaliado que ao fazer a requisição ao endpoint
/leaderboard/away
, serão retornados os campos e valores corretos considerando os dados iniciais do banco de dados; -
Partidas que estiverem em andamento (não foram finalizadas) não devem ser consideradas.
Retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 7,
"goalsOwn": 0,
"goalsBalance": 7,
"efficiency": "100.00"
},
{
"name": "Corinthians",
"totalPoints": 6,
"totalGames": 3,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 6,
"goalsOwn": 2,
"goalsBalance": 4,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 3,
"goalsOwn": 0,
"goalsBalance": 3,
"efficiency": "100.00"
},
{
"name": "São José-SP",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 3,
"goalsOwn": 1,
"goalsBalance": 2,
"efficiency": "100.00"
},
{
"name": "São Paulo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 5,
"goalsBalance": 0,
"efficiency": "44.44"
},
{
"name": "Ferroviária",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 4,
"goalsOwn": 5,
"goalsBalance": -1,
"efficiency": "44.44"
},
{
"name": "Real Brasília",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 3,
"goalsOwn": 4,
"goalsBalance": -1,
"efficiency": "44.44"
},
{
"name": "Grêmio",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 7,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Flamengo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 3,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 3,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 1,
"goalsBalance": 0,
"efficiency": "50.00"
},
{
"name": "Cruzeiro",
"totalPoints": 3,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 2,
"goalsFavor": 6,
"goalsOwn": 7,
"goalsBalance": -1,
"efficiency": "33.33"
},
{
"name": "Santos",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 3,
"goalsOwn": 3,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Bahia",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 2,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Minas Brasília",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 3,
"goalsBalance": -2,
"efficiency": "16.67"
},
{
"name": "Botafogo",
"totalPoints": 0,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 2,
"goalsFavor": 1,
"goalsOwn": 4,
"goalsBalance": -3,
"efficiency": "0.00"
},
{
"name": "Napoli-SC",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 1,
"goalsOwn": 10,
"goalsBalance": -9,
"efficiency": "0.00"
}
]
32 - Desenvolva o endpoint /leaderboard/away
de forma que seja possível filtrar as classificações dos times quando visitantes na tela de classificação do front-end e atualizar a tabela ao inserir a partida Corinthians 2 X 1 Internacional
- Será avaliado que após acrescentar a partida Corinthians 2 X 1 Internacional e fazer a requisição ao endpoint
/leaderboard/away
, serão retornados os campos e valores corretos.
Retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 7,
"goalsOwn": 0,
"goalsBalance": 7,
"efficiency": "100.00"
},
{
"name": "Corinthians",
"totalPoints": 6,
"totalGames": 3,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 6,
"goalsOwn": 2,
"goalsBalance": 4,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 6,
"totalGames": 3,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 4,
"goalsOwn": 2,
"goalsBalance": 2,
"efficiency": "66.67"
},
{
"name": "São José-SP",
"totalPoints": 6,
"totalGames": 2,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 0,
"goalsFavor": 3,
"goalsOwn": 1,
"goalsBalance": 2,
"efficiency": "100.00"
},
{
"name": "São Paulo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 5,
"goalsBalance": 0,
"efficiency": "44.44"
},
{
"name": "Ferroviária",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 4,
"goalsOwn": 5,
"goalsBalance": -1,
"efficiency": "44.44"
},
{
"name": "Real Brasília",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 3,
"goalsOwn": 4,
"goalsBalance": -1,
"efficiency": "44.44"
},
{
"name": "Grêmio",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 7,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Flamengo",
"totalPoints": 4,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 3,
"goalsBalance": -2,
"efficiency": "44.44"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 3,
"totalGames": 2,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 1,
"goalsBalance": 0,
"efficiency": "50.00"
},
{
"name": "Cruzeiro",
"totalPoints": 3,
"totalGames": 3,
"totalVictories": 1,
"totalDraws": 0,
"totalLosses": 2,
"goalsFavor": 6,
"goalsOwn": 7,
"goalsBalance": -1,
"efficiency": "33.33"
},
{
"name": "Santos",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 3,
"goalsOwn": 3,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Bahia",
"totalPoints": 2,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 2,
"goalsOwn": 2,
"goalsBalance": 0,
"efficiency": "33.33"
},
{
"name": "Minas Brasília",
"totalPoints": 1,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 1,
"goalsOwn": 3,
"goalsBalance": -2,
"efficiency": "16.67"
},
{
"name": "Botafogo",
"totalPoints": 0,
"totalGames": 2,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 2,
"goalsFavor": 1,
"goalsOwn": 4,
"goalsBalance": -3,
"efficiency": "0.00"
},
{
"name": "Napoli-SC",
"totalPoints": 0,
"totalGames": 3,
"totalVictories": 0,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 1,
"goalsOwn": 10,
"goalsBalance": -9,
"efficiency": "0.00"
}
]
33 - Desenvolva o endpoint /leaderboard
de forma que seja possível filtrar a classificação geral dos times na tela de classificação do front-end com os dados iniciais do banco de dados
-
O endpoint deverá ser do tipo
GET
; -
Será avaliado que ao fazer a requisição ao endpoint
/leaderboard
, serão retornados os campos e valores corretos considerando os dados iniciais do banco de dados. -
Partidas que estiverem em andamento (não foram finalizadas) não devem ser consideradas.
Retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 13,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 17,
"goalsOwn": 5,
"goalsBalance": 12,
"efficiency": "86.67"
},
{
"name": "Corinthians",
"totalPoints": 12,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 12,
"goalsOwn": 3,
"goalsBalance": 9,
"efficiency": "80.00"
},
{
"name": "Santos",
"totalPoints": 11,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 12,
"goalsOwn": 6,
"goalsBalance": 6,
"efficiency": "73.33"
},
{
"name": "Grêmio",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 8,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 7,
"goalsOwn": 6,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Real Brasília",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 4,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "São Paulo",
"totalPoints": 8,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 2,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 6,
"goalsBalance": 3,
"efficiency": "53.33"
},
{
"name": "Ferroviária",
"totalPoints": 7,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 7,
"goalsOwn": 7,
"goalsBalance": 0,
"efficiency": "46.67"
},
{
"name": "São José-SP",
"totalPoints": 6,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 5,
"goalsOwn": 6,
"goalsBalance": -1,
"efficiency": "40.00"
},
{
"name": "Flamengo",
"totalPoints": 5,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 2,
"totalLosses": 2,
"goalsFavor": 2,
"goalsOwn": 5,
"goalsBalance": -3,
"efficiency": "33.33"
},
{
"name": "Cruzeiro",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 8,
"goalsOwn": 10,
"goalsBalance": -2,
"efficiency": "26.67"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 4,
"goalsOwn": 8,
"goalsBalance": -4,
"efficiency": "26.67"
},
{
"name": "Botafogo",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 3,
"goalsOwn": 8,
"goalsBalance": -5,
"efficiency": "26.67"
},
{
"name": "Bahia",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 2,
"goalsOwn": 6,
"goalsBalance": -4,
"efficiency": "13.33"
},
{
"name": "Minas Brasília",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 4,
"goalsOwn": 9,
"goalsBalance": -5,
"efficiency": "13.33"
},
{
"name": "Napoli-SC",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 3,
"goalsOwn": 12,
"goalsBalance": -9,
"efficiency": "13.33"
}
]
34 - Desenvolva o endpoint /leaderboard de forma que seja possível filtrar a classificação geral dos times na tela de classificação do front-end e atualizar a tabela ao inserir a partida Flamengo 3 X 0 Napoli-SC
- Será avaliado que após acrescentar a partida Flamengo 3 X 0 Napoli-SC e fazer a requisição ao endpoint /leaderboard, serão retornados os campos e valores corretos.
Retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 13,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 17,
"goalsOwn": 5,
"goalsBalance": 12,
"efficiency": "86.67"
},
{
"name": "Corinthians",
"totalPoints": 12,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 12,
"goalsOwn": 3,
"goalsBalance": 9,
"efficiency": "80.00"
},
{
"name": "Santos",
"totalPoints": 11,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 12,
"goalsOwn": 6,
"goalsBalance": 6,
"efficiency": "73.33"
},
{
"name": "Grêmio",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 8,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 7,
"goalsOwn": 6,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Real Brasília",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 4,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "São Paulo",
"totalPoints": 8,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 2,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 6,
"goalsBalance": 3,
"efficiency": "53.33"
},
{
"name": "Flamengo",
"totalPoints": 8,
"totalGames": 6,
"totalVictories": 2,
"totalDraws": 2,
"totalLosses": 2,
"goalsFavor": 5,
"goalsOwn": 5,
"goalsBalance": 0,
"efficiency": "44.44"
},
{
"name": "Ferroviária",
"totalPoints": 7,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 1,
"totalLosses": 2,
"goalsFavor": 7,
"goalsOwn": 7,
"goalsBalance": 0,
"efficiency": "46.67"
},
{
"name": "São José-SP",
"totalPoints": 6,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 5,
"goalsOwn": 6,
"goalsBalance": -1,
"efficiency": "40.00"
},
{
"name": "Cruzeiro",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 8,
"goalsOwn": 10,
"goalsBalance": -2,
"efficiency": "26.67"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 4,
"goalsOwn": 8,
"goalsBalance": -4,
"efficiency": "26.67"
},
{
"name": "Botafogo",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 3,
"goalsOwn": 8,
"goalsBalance": -5,
"efficiency": "26.67"
},
{
"name": "Bahia",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 2,
"goalsOwn": 6,
"goalsBalance": -4,
"efficiency": "13.33"
},
{
"name": "Minas Brasília",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 4,
"goalsOwn": 9,
"goalsBalance": -5,
"efficiency": "13.33"
},
{
"name": "Napoli-SC",
"totalPoints": 2,
"totalGames": 6,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 4,
"goalsFavor": 3,
"goalsOwn": 15,
"goalsBalance": -12,
"efficiency": "11.11"
}
]
35 - Desenvolva o endpoint /leaderboard de forma que seja possível filtrar a classificação geral dos times na tela de classificação do front-end e atualizar a tabela ao inserir a partida Minas Brasília 1 X 0 Ferroviária
- Será avaliado que após acrescentar a partida Minas Brasília 1 X 0 Ferroviária e fazer a requisição ao endpoint /leaderboard, serão retornados os campos e valores corretos.
Retorno esperado:
[
{
"name": "Palmeiras",
"totalPoints": 13,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 1,
"totalLosses": 0,
"goalsFavor": 17,
"goalsOwn": 5,
"goalsBalance": 12,
"efficiency": "86.67"
},
{
"name": "Corinthians",
"totalPoints": 12,
"totalGames": 5,
"totalVictories": 4,
"totalDraws": 0,
"totalLosses": 1,
"goalsFavor": 12,
"goalsOwn": 3,
"goalsBalance": 9,
"efficiency": "80.00"
},
{
"name": "Santos",
"totalPoints": 11,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 2,
"totalLosses": 0,
"goalsFavor": 12,
"goalsOwn": 6,
"goalsBalance": 6,
"efficiency": "73.33"
},
{
"name": "Grêmio",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 8,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Internacional",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 7,
"goalsOwn": 6,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "Real Brasília",
"totalPoints": 10,
"totalGames": 5,
"totalVictories": 3,
"totalDraws": 1,
"totalLosses": 1,
"goalsFavor": 5,
"goalsOwn": 4,
"goalsBalance": 1,
"efficiency": "66.67"
},
{
"name": "São Paulo",
"totalPoints": 8,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 2,
"totalLosses": 1,
"goalsFavor": 9,
"goalsOwn": 6,
"goalsBalance": 3,
"efficiency": "53.33"
},
{
"name": "Ferroviária",
"totalPoints": 7,
"totalGames": 6,
"totalVictories": 2,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 7,
"goalsOwn": 8,
"goalsBalance": -1,
"efficiency": "38.89"
},
{
"name": "São José-SP",
"totalPoints": 6,
"totalGames": 5,
"totalVictories": 2,
"totalDraws": 0,
"totalLosses": 3,
"goalsFavor": 5,
"goalsOwn": 6,
"goalsBalance": -1,
"efficiency": "40.00"
},
{
"name": "Flamengo",
"totalPoints": 5,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 2,
"totalLosses": 2,
"goalsFavor": 2,
"goalsOwn": 5,
"goalsBalance": -3,
"efficiency": "33.33"
},
{
"name": "Minas Brasília",
"totalPoints": 5,
"totalGames": 6,
"totalVictories": 1,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 5,
"goalsOwn": 9,
"goalsBalance": -4,
"efficiency": "27.78"
},
{
"name": "Cruzeiro",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 8,
"goalsOwn": 10,
"goalsBalance": -2,
"efficiency": "26.67"
},
{
"name": "Avaí/Kindermann",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 4,
"goalsOwn": 8,
"goalsBalance": -4,
"efficiency": "26.67"
},
{
"name": "Botafogo",
"totalPoints": 4,
"totalGames": 5,
"totalVictories": 1,
"totalDraws": 1,
"totalLosses": 3,
"goalsFavor": 3,
"goalsOwn": 8,
"goalsBalance": -5,
"efficiency": "26.67"
},
{
"name": "Bahia",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 2,
"goalsOwn": 6,
"goalsBalance": -4,
"efficiency": "13.33"
},
{
"name": "Napoli-SC",
"totalPoints": 2,
"totalGames": 5,
"totalVictories": 0,
"totalDraws": 2,
"totalLosses": 3,
"goalsFavor": 3,
"goalsOwn": 12,
"goalsBalance": -9,
"efficiency": "13.33"
}
]