Menu
CoddyTech

Versionamento

Parte da seção APIs REST do Journey de Node.js da Coddy. Lição 15 de 18.

Mudar 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. Caminhos que mudam respondem com um redirecionamento:

GET  /api/orders/5   →  308  Location: /api/v1/orders/5
POST /api/orders     →  308  Location: /api/v1/orders

301 e 302 permitem que os clientes repitam um POST como GET, o que descarta o corpo. 308 diz "repita a mesma solicitação lá", 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'
challenge icon

Desafio

Fácil
  • Monte o roteador de tarefas em /api/v1/tasks.
  • Cada caminho antigo /api/tasks responde com 308 para o mesmo caminho em /api/v1, incluindo a consulta.
  • As novas tarefas recebem Location: /api/v1/tasks/<id>.

Envie GET /api/tasks/2, POST /api/tasks com { "title": "Order new chairs" }, depois GET /api/v1/tasks/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();
app.use(express.json());

// 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);
    res.set('Access-Control-Allow-Credentials', 'true');
    if (req.method === 'OPTIONS') {
        res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');
        res.set('Access-Control-Allow-Headers', 'Content-Type');
        return res.status(204).end();
    }
    next();
});

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