Versionamento
Parte da seção APIs REST do Journey de Node.js da Coddy. Lição 22 de 25.
Alterar o formato de uma resposta quebra todos os clientes que já a utilizam. Uma versão no caminho permite que clientes antigos e novos coexistam: /api/v1/orders hoje, /api/v2/orders quando o formato mudar. Quando um caminho muda, o caminho antigo responde com um redirecionamento para o novo:
GET /api/orders/5 → 308 Location: /api/v1/orders/5
POST /api/orders → 308 Location: /api/v1/orders301 e 302 permitem que os clientes repitam um POST como GET, o que descarta o corpo. 308 diz "repita a mesma solicitação nesse endereço", incluindo o método e o corpo. Dentro de um middleware montado, req.url perdeu o caminho de montagem, enquanto req.originalUrl o mantém inteiro:
// em app.use('/api/orders', ...) para GET /api/orders/5?full=1
req.url // '/5?full=1'
req.originalUrl // '/api/orders/5?full=1'Desafio
FácilSua API vai mudar de maneiras que os clientes antigos não esperam, então coloque um número de versão nos caminhos. A API de hoje passa a ser a versão 1, em /api/v1/tasks, e os endereços antigos redirecionam os clientes para lá.
- Em
server.js, monte o roteador de tarefas em/api/v1/tasksem vez de/api/tasks. - Também em
server.js, adicione um middleware montado em/api/tasksque apenas redirecione. Ele responde com o status 308 para o mesmo endereço sob/api/v1, mantendo o restante do caminho e a string de consulta. Dentro de um middleware montado,req.originalUrlcontém o endereço antigo completo. Por exemplo:GET /api/tasks/2redireciona para/api/v1/tasks/2.POST /api/tasksredireciona para/api/v1/tasks.GET /api/tasks?done=false&sort=titleredireciona para/api/v1/tasks?done=false&sort=title.
Use 308, não 301: após um 308, o cliente repete um POST como POST, incluindo o corpo.
- Em
routes/tasks.js, a rota POST defineLocationcomo o novo endereço, por exemplo,/api/v1/tasks/4para a tarefa 4.
Experimente: GET /api/tasks/2 retorna 308, e a aba Headers mostra Location: /api/v1/tasks/2. A barra de requisição mostra o próprio redirecionamento; ela não o segue. Envie POST { "title": "Order new chairs" } para /api/tasks: você recebe 308 com Location: /api/v1/tasks, e nenhuma tarefa é criada. Envie o mesmo corpo com POST para /api/v1/tasks: 201 com Location: /api/v1/tasks/4. GET /api/v1/tasks/2 retorna a tarefa 2.
Experimente você mesmo
import express from 'express';
import { sendError } from './errors.js';
import taskRoutes from './routes/tasks.js';
const BOARD_ORIGIN = 'https://board.example.com';
const app = express();
// Permite que páginas em BOARD_ORIGIN chamem esta API pelo navegador.
app.use((req, res, next) => {
res.set('Access-Control-Allow-Origin', BOARD_ORIGIN);
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
res.set('Access-Control-Allow-Headers', 'Content-Type');
return res.status(204).end();
}
next();
});
app.use(express.json());
app.use(express.static('public'));
app.use('/api/tasks', taskRoutes);
// Os erros das rotas chegam aqui. Um corpo que não é um JSON válido é um
// erro do cliente (400); qualquer outro erro é nosso (500).
app.use((err, req, res, next) => {
if (err.type === 'entity.parse.failed') {
return sendError(res, 400, 'invalid_json', 'The body is not valid JSON');
}
console.error(err);
sendError(res, 500, 'server_error', 'Something went wrong');
});
app.listen(3000, () => {
console.log('Task tracker API on port 3000');
});
Todas as lições de APIs REST
1Recursos e verbos
Recursos e URLsCriando com POST4Navegadores, versões e configuração
O que é uma origemPermitindo outra origemCORSUma página que chama a APIPratique por conta própria: Playground de Express