Para que uma API seja considerada RESTful, ela deve aderir aos princípios e restrições
do estilo de arquitetura REST (Representational State Transfer). Aqui estão os principais
requisitos que uma API precisa cumprir para ser considerada RESTful:
1. Interface Uniforme (Uniform Interface)
Uso adequado dos métodos HTTP: A API deve usar os métodos HTTP de forma
padronizada para representar as operações CRUD (Create, Read, Update, Delete)
sobre os recursos:
GET: Para recuperar representações de um recurso.
POST: Para criar um novo recurso.
PUT/PATCH: Para atualizar um recurso existente.
DELETE: Para remover um recurso.
Identificação dos Recursos (Resource Identification): Cada recurso deve ser
identificado por uma URL única. Por exemplo,
[Link] identifica um recurso específico (usuário com
ID 123).
Representação dos Recursos (Resource Representation): Os dados dos recursos
devem ser representados em formatos padronizados, como JSON ou XML. A
resposta da API deve incluir uma representação atual do recurso, e o cliente pode
enviar representações de novos recursos para criação ou atualização.
Self-descriptive Messages (Mensagens Autodescritivas): Cada mensagem HTTP
deve ter informações suficientes para ser entendida e processada. Por exemplo, os
cabeçalhos HTTP devem indicar o tipo de mídia (Content-Type), o status da
resposta (Status Code), etc.
HATEOAS (Hypermedia As The Engine Of Application State): As respostas da API
devem incluir links (hipermídia) para outras operações relacionadas, permitindo que
o cliente navegue pelos recursos sem precisar de conhecimento prévio da estrutura
da API.
2. Stateless (Sem Estado)
Cada requisição do cliente ao servidor deve ser independente e autônoma,
contendo todas as informações necessárias para o servidor entender e processar a
requisição. O servidor não deve manter o estado da sessão entre as requisições.
3. Cacheable (Cacheável)
As respostas das requisições devem ser explicitamente marcadas como
cacheáveis ou não. Isso permite que clientes e intermediários armazenem as
respostas para evitar chamadas repetitivas ao servidor, melhorando a eficiência.
4. Cliente-Servidor (Client-Server)
A arquitetura deve seguir a separação entre cliente e servidor. O cliente faz as
requisições e o servidor as processa, sem que ambos compartilhem a lógica de
negócios. Isso permite que o frontend e o backend evoluam de forma
independente.
5. Sistema em Camadas (Layered System)
A arquitetura pode ser composta por múltiplas camadas, como servidores de
autenticação, cache, proxies, etc. O cliente interage apenas com a camada
imediata, sem saber ou precisar conhecer as camadas subjacentes.
6. Código Sob Demanda (Opcional)
Embora não seja obrigatório, a API RESTful pode incluir a capacidade de enviar
código executável para o cliente, como scripts JavaScript, para aumentar a
funcionalidade do cliente.
Exemplos de uma API RESTful:
Endpoints significativos: As URLs refletem a estrutura dos recursos, por exemplo,
GET /usuarios, POST /usuarios, GET /usuarios/123, PUT /usuarios/123.
Uso correto de códigos de status HTTP: A API deve retornar códigos de status
apropriados, como 200 OK para sucesso, 201 Created para criação de um recurso,
400 Bad Request para erros do cliente, 404 Not Found quando um recurso não é
encontrado, etc.
Hipermídia: Respostas da API podem incluir links para operações relacionadas,
como {"self": "/usuarios/123", "delete": "/usuarios/123/delete"}.
Idempotência dos verbos HTTP
metodos idempotentes são metodos que ao ter um requisicao executada várias
vezes o resultado sempre terá o mesmo resultados
Métodos idempotentes:
Get
Put
Delete
Métodos não idempotentes:
Post
Patch
Middlewares
São funções intermediárias que podem ser inseridas em uma aplicação para
processar requisições e respostas entre o cliente e o servidor. São basicamentes
funcções de rota que vão interceptar,processar e ate mesmo alterar as requisições
e respostas da [Link] como a função da rota ela contém o req,res mas com
um novo parâmetro o next que serve para pular para o próximo middleware ou
função de rota.
ex: [Link](‘/user’,middlewareAutenticacao,funcao da rota)
Prisma
Prisma é uma biblioteca ORM (Object-Relational Mapping) para [Link] e
TypeScript que facilita a interação com bancos de dados. Ele proporciona uma
camada de abstração sobre o banco de dados, permitindo que você trabalhe com
dados de forma mais intuitiva, utilizando TypeScript e JavaScript em vez de
escrever SQL manualmente.
Comandos
1. prisma init
Descrição: Inicializa um novo projeto Prisma. Cria a estrutura básica do projeto,
incluindo o arquivo [Link] e um diretório prisma.
2. prisma db push
Descrição: Atualiza o banco de dados com base no esquema definido no arquivo
[Link]. Esse comando é útil para aplicar alterações no banco de dados
sem criar uma migração.
3. prisma migrate dev
Descrição: Cria e aplica migrações ao banco de dados de desenvolvimento.
Também atualiza o Prisma Client para refletir as mudanças no esquema.
4. prisma migrate deploy
Descrição: Aplica migrações pendentes ao banco de dados de produção. Esse
comando é usado para aplicar migrações em ambientes de produção.
5. prisma migrate reset
Descrição: Reseta o banco de dados, aplicando todas as migrações desde o início
e limpando todos os dados. Isso é útil para desenvolvimento e testes.
6. prisma generate
Descrição: Gera o Prisma Client com base no esquema do banco de dados
definido no [Link]. Necessário sempre que o esquema do banco de dados
for alterado.
7. prisma studio
Descrição: Abre o Prisma Studio, uma interface gráfica para visualizar e editar
dados no banco de dados.
8. prisma db pull
Descrição: Sincroniza o esquema do Prisma com o esquema atual do banco de
dados. Atualiza o arquivo [Link] com base no banco de dados existente.
9. prisma db seed
Descrição: Executa scripts de seed para popular o banco de dados com dados
iniciais. Normalmente é configurado no arquivo prisma/[Link] ou prisma/[Link].
10. prisma --version
Descrição: Exibe a versão do Prisma CLI instalada.
11. prisma format
Descrição: Formata o arquivo [Link] para seguir o estilo padrão do
Prisma.
12. prisma introspect
Descrição: Analisa um banco de dados existente e gera o esquema Prisma
correspondente no arquivo [Link].
13. prisma validate
Descrição: Valida o arquivo [Link] para garantir que está correto e não
contém erros.
14. prisma migrate status
Descrição: Exibe o status das migrações no banco de dados, mostrando quais
migrações foram aplicadas e quais ainda estão pendentes.
15. prisma migrate resolve
Descrição: Marca uma migração como aplicada ou não aplicada sem realmente
executá-la. Usado para resolver conflitos de migração ou sincronizar o estado das
migrações.
Autenticação JWT
Estrutura do JWT
Um JWT é composto por três partes principais, separadas por pontos (.):
1. Header (Cabeçalho)
2. Payload (Corpo)
3. Signature (Assinatura)
1. Header (Cabeçalho)
O cabeçalho do JWT geralmente especifica o tipo de token e o algoritmo usado para
assinar o token. Um exemplo de cabeçalho é:
json
{
"alg": "HS256",
"typ": "JWT"
}
alg: O algoritmo de assinatura usado, como HMAC SHA256 (HS256) ou RSA
(RS256).
typ: O tipo de token, que é sempre JWT.
O cabeçalho é codificado em Base64Url para formar a primeira parte do JWT.
2. Payload (Corpo)
O corpo do JWT contém as "declarações" (claims). Existem três tipos de claims:
Registered Claims (Claims Registradas): São um conjunto de claims pré-definidos
que não são obrigatórios, mas recomendados para garantir interoperabilidade.
Exemplos incluem:
sub (Subject): Identificador do usuário.
iat (Issued At): Data e hora em que o token foi emitido.
exp (Expiration Time): Data e hora em que o token expira.
Public Claims (Claims Públicas): Claims definidas para compartilhar informações
entre partes, mas que não são pré-definidas. Estas devem ser definidas em um
namespace para evitar colisões.
Private Claims (Claims Privadas): Claims criadas para compartilhar informações
entre partes que possuem um acordo sobre como usar essas claims. Não são
pré-definidas nem registradas.
Um exemplo de payload é:
json
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
O payload também é codificado em Base64Url para formar a segunda parte do JWT.
3. Signature (Assinatura)
A assinatura é usada para verificar se o token não foi alterado e, em alguns casos, para
garantir a autenticidade do token. Para criar a assinatura, você combina o cabeçalho e o
payload codificados em Base64Url com uma chave secreta (ou chave privada, se usar um
algoritmo de assinatura assimétrica).
A assinatura é criada da seguinte forma:
text
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Onde secret é a chave secreta compartilhada usada para HMAC, ou uma chave privada
usada para algoritmos assimétricos.
Como Funciona o JWT
1. Geração do Token:
O servidor gera um JWT quando o usuário se autentica com sucesso. O
JWT contém informações sobre o usuário e uma assinatura que garante a
integridade do token.
2. Envio ao Cliente:
O JWT é enviado ao cliente (geralmente no cabeçalho Authorization ou em
um cookie).
3. Uso do Token:
O cliente inclui o JWT em requisições subsequentes para acessar recursos
protegidos.
4. Verificação do Token:
O servidor verifica a assinatura do JWT para garantir que não foi alterado.
Se a assinatura for válida e o token não estiver expirado, o servidor permite
o acesso aos recursos solicitados.
Vantagens e Desvantagens do JWT
Vantagens
Autossuficiente: Contém todas as informações necessárias para autenticação e
autorização, o que elimina a necessidade de consultar um banco de dados para
cada requisição.
Escalabilidade: Funciona bem em sistemas distribuídos, pois o token pode ser
verificado independentemente pelo servidor.
Compacto e Portátil: O JWT é compactado e pode ser transmitido facilmente em
URLs, cabeçalhos HTTP, ou cookies.
Desvantagens
Tamanho do Token: O JWT pode se tornar grande se contiver muitas informações,
o que pode aumentar o tamanho das requisições e respostas.
Revogação: Se um JWT for comprometido, ele não pode ser facilmente revogado
até que expire, a menos que se use uma lista de revogação no servidor.
Exposição de Dados: O conteúdo do JWT é visível para qualquer pessoa que tenha
o token, o que pode ser um problema se informações sensíveis forem incluídas no
payload. A assinatura garante integridade, mas não criptografia.