REST: os verbos e os códigos de status
Dois programas precisam conversar pela rede. REST é o combinado que faz um entender o outro sem manual próprio: o endereço diz de qual coisa você está falando, o verbo diz o que fazer com ela, e um número de três dígitos diz o que aconteceu.
O que REST resolve
Sem um combinado, cada API inventa o próprio vocabulário. Uma expõe /buscarUsuario, outra /usuario/get, uma terceira manda tudo por POST e devolve sempre 200 com um campo "erro" escondido no corpo da resposta. Quem consome três APIs assim lê três manuais e decora três jeitos diferentes de descobrir se a chamada deu certo.
REST corta esse trabalho reaproveitando o que o HTTP já tinha desde os anos 90: um endereço para cada coisa, um verbo para cada operação e um código numérico para o resultado. Com o combinado no lugar, você lê DELETE /tarefas/7 e já sabe o que aquilo faz, sem abrir documentação nenhuma.
Os conceitos que você precisa antes da primeira linha
- Recurso e endereço. Recurso é uma coisa do seu sistema: uma tarefa, um usuário, um pedido. O endereço nomeia essa coisa com substantivo.
/tarefasé a coleção inteira,/tarefas/1é a tarefa de número 1. Ação na URL, como/buscarTarefa, joga fora metade do combinado. - Verbo, ou método HTTP. A ação mora aqui. Pela documentação da MDN: GET pede a representação de um recurso, POST submete dados a um recurso e costuma mudar o estado do servidor, PUT substitui todas as representações atuais do recurso, PATCH aplica modificações parciais, DELETE remove o recurso.
- Código de status. Três dígitos na primeira linha da resposta, em cinco faixas: 1xx informativo, 2xx deu certo, 3xx redirecionamento, 4xx erro de quem chamou, 5xx erro do servidor. O código responde sobre o resultado antes de você olhar o corpo, e é justamente essa a parte que a API do exemplo anterior jogava fora ao responder 200 para tudo.
- Seguro e idempotente. A RFC 9110 chama de seguro o método que só lê, sem alterar o estado do recurso (GET e HEAD), e de idempotente aquele em que várias requisições idênticas têm o mesmo efeito de uma só (GET, HEAD, PUT, DELETE, OPTIONS, TRACE). POST fica fora das duas listas. É por isso que recarregar a página depois de enviar um formulário cria o registro duas vezes.
- Sem estado. Cada requisição chega completa. O servidor não guarda o que você pediu na chamada anterior para entender a chamada de agora. Quem precisa de identidade manda a credencial em toda requisição, e é essa restrição que permite colocar dez cópias da mesma API atrás de um balanceador sem ninguém perceber.
O contrato por dentro: recursos, verbos e códigos de status
REST organiza a API em torno de recursos: cada coisa do sistema tem um endereço. /clientes é a coleção, /clientes/42 é um cliente. O que você quer fazer com o recurso não vai na URL, vai no verbo HTTP, e cada verbo tem um contrato que o cliente da API pode assumir.
- Os cinco verbos do dia a dia:
GETlê e não altera nada (pode repetir à vontade).POSTcria.PUTsubstitui o recurso inteiro.PATCHaltera parte.DELETEremove. Repetir umDELETEdá o mesmo resultado que fazer uma vez. Repetir umPOSTcria dois. Essa diferença tem nome, idempotência, e aparece em entrevista. - O status é a resposta em uma palavra, por família:
2xxdeu certo (200ok,201criado,204sem corpo),4xxo erro é do cliente (400pedido malformado,404não existe,401/403autenticação e permissão),5xxo erro é do servidor. O hello world desta página devolve200e404de verdade. - O corpo é JSON e a conversa não tem memória: cada requisição carrega tudo que o servidor precisa (inclusive o token de autenticação, num header), porque REST é stateless: o servidor não guarda o "onde paramos" entre uma chamada e outra.
POST /clientes HTTP/1.1
Content-Type: application/json
{ "nome": "Ana" }
HTTP/1.1 201 Created
Location: /clientes/42
{ "id": 42, "nome": "Ana" }
Requisição em cima, resposta embaixo: verbo + recurso, status + corpo. Toda API REST que você consumir na carreira é variação desse quadro.
Hello world: uma API que devolve 200 e 404
Você precisa do Node.js e do curl, sem instalar pacote nenhum. O servidor inteiro usa só o módulo node:http, que já vem junto.
-
Confira que o Node.js está na máquina. Qualquer versão 18 ou mais nova serve.
node --version -
Crie a pasta do exercício e entre nela.
mkdir -p hello-rest && cd hello-rest -
Crie um arquivo chamado
servidor.jse cole isto dentro:const http = require('node:http'); const tarefas = new Map([ [1, { id: 1, titulo: 'Estudar os verbos do HTTP', feita: false }] ]); let proximoId = 2; const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json; charset=utf-8'); const url = new URL(req.url, `http://${req.headers.host}`); const partes = url.pathname.split('/').filter(Boolean); if (partes[0] !== 'tarefas') { res.writeHead(404); res.end(JSON.stringify({ erro: 'rota inexistente' })); return; } // coleção: /tarefas if (partes.length === 1) { if (req.method === 'GET') { res.writeHead(200); res.end(JSON.stringify([...tarefas.values()])); return; } if (req.method === 'POST') { let corpo = ''; req.on('data', (p) => { corpo += p; }); req.on('end', () => { let dados; try { dados = JSON.parse(corpo || '{}'); } catch { res.writeHead(400); res.end(JSON.stringify({ erro: 'corpo nao e JSON valido' })); return; } if (typeof dados.titulo !== 'string' || dados.titulo.trim() === '') { res.writeHead(400); res.end(JSON.stringify({ erro: 'campo titulo e obrigatorio' })); return; } const nova = { id: proximoId++, titulo: dados.titulo, feita: false }; tarefas.set(nova.id, nova); res.writeHead(201, { Location: `/tarefas/${nova.id}` }); res.end(JSON.stringify(nova)); }); return; } res.writeHead(405, { Allow: 'GET, POST' }); res.end(JSON.stringify({ erro: 'metodo nao permitido nesta rota' })); return; } // item: /tarefas/:id const id = Number(partes[1]); if (req.method === 'GET') { if (!tarefas.has(id)) { res.writeHead(404); res.end(JSON.stringify({ erro: 'tarefa nao encontrada', id })); return; } res.writeHead(200); res.end(JSON.stringify(tarefas.get(id))); return; } if (req.method === 'DELETE') { if (!tarefas.has(id)) { res.writeHead(404); res.end(JSON.stringify({ erro: 'tarefa nao encontrada', id })); return; } tarefas.delete(id); res.removeHeader('Content-Type'); res.writeHead(204); res.end(); return; } res.writeHead(405, { Allow: 'GET, DELETE' }); res.end(JSON.stringify({ erro: 'metodo nao permitido nesta rota' })); }); server.listen(3000, () => { console.log('API no ar em http://localhost:3000'); }); -
Suba o servidor. O terminal imprime uma linha e fica ocupado, o que é o comportamento certo.
node servidor.js -
Abra um segundo terminal, deixando o primeiro rodando, e faça a chamada de um recurso que existe. A opção
-imanda o curl mostrar os cabeçalhos da resposta, que é onde mora o código de status. A opção-stira a barra de progresso.curl -i -s http://localhost:3000/tarefas/1 -
Agora peça uma tarefa que não existe, no mesmo servidor e no mesmo formato de rota. Só o número muda.
curl -i -s http://localhost:3000/tarefas/999 -
Exercite os outros verbos, ainda no segundo terminal. O POST cria e responde 201 com o cabeçalho
Location. O DELETE apaga e responde 204, sem corpo.curl -i -s -X POST http://localhost:3000/tarefas \ -H "Content-Type: application/json" \ -d '{"titulo":"Testar o 201"}' curl -i -s -X DELETE http://localhost:3000/tarefas/2 -
Volte ao primeiro terminal e pare o servidor com Ctrl + C. As tarefas moram na memória do processo, então tudo que você criou some junto.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":1,"titulo":"Estudar os verbos do HTTP","feita":false}
E o passo 6, com a mesma rota e outro número:
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
{"erro":"tarefa nao encontrada","id":999}
Esses dois blocos na tela são o combinado inteiro funcionando: quem chamou não precisou ler o corpo para saber que a segunda deu errado, o 404 já disse. Se aparecer Connection refused, o servidor do passo 4 não está rodando ou você fechou o primeiro terminal. Se aparecer o JSON sem nenhuma linha HTTP/1.1 em cima, faltou o -i no comando.O que REST não é
A confusão mais comum é tratar "REST" e "API que devolve JSON por HTTP" como sinônimos. REST é um estilo de arquitetura descrito por Roy Fielding no capítulo 5 da tese de doutorado dele, em 2000, e vem com seis restrições nomeadas: cliente-servidor, sem estado, cache, interface uniforme, sistema em camadas e código sob demanda, essa última opcional. JSON não aparece na lista. Uma API REST pode responder XML, HTML ou texto puro sem deixar de ser REST.
O caminho inverso também engana. Trocar o formato para JSON e usar os verbos certos ainda deixa de fora boa parte da interface uniforme. Em outubro de 2008, o próprio Fielding publicou um texto chamado "REST APIs must be hypertext-driven" que abre com a reclamação de que ele estava ficando frustrado com a quantidade de gente chamando qualquer interface sobre HTTP de API REST. No mercado, "API REST" virou o nome de HTTP com verbo e status, e é isso que vai estar escrito na vaga que você quer. Saber de onde vem a palavra evita discussão vazia em revisão de código.
Fontes
- MDN Web Docs, Métodos de requisição HTTP, de onde saíram as definições de GET, POST, PUT, PATCH e DELETE. Conferida em 15/08/2026.
- MDN Web Docs, Códigos de status de respostas HTTP, com as cinco faixas e o significado de 200, 201, 204, 400, 404 e 405. Conferida em 15/08/2026.
- RFC 9110, HTTP Semantics (junho de 2022), seções 9.2.1 e 9.2.2, que definem método seguro e método idempotente. Conferida em 15/08/2026.
- Roy T. Fielding, capítulo 5 "Representational State Transfer (REST)" da tese de 2000, onde as seis restrições do estilo estão descritas uma a uma. Conferida em 15/08/2026.
- Roy T. Fielding, "REST APIs must be hypertext-driven" (20/10/2008), o texto citado na seção sobre o mito. Conferida em 15/08/2026.
- Node.js, documentação do módulo
http, de onde vieramhttp.createServer,res.writeHead,req.methodereq.url. Conferida em 15/08/2026.
O hello world desta página foi executado em 15/08/2026, no Node.js v22.23.0 com curl 8.18.0. As oito etapas rodaram na ordem descrita. GET /tarefas/1 respondeu HTTP/1.1 200 OK com o JSON da tarefa, GET /tarefas/999 respondeu HTTP/1.1 404 Not Found, o POST respondeu HTTP/1.1 201 Created com Location: /tarefas/2, o DELETE respondeu HTTP/1.1 204 No Content sem corpo, o mesmo DELETE repetido respondeu 404, o POST sem título respondeu 400 Bad Request e o DELETE /tarefas na coleção respondeu 405 Method Not Allowed com Allow: GET, POST. Os dois blocos mostrados no quadro da prova são a saída literal do terminal.
Para continuar
O contraponto direto é GraphQL, que resolve o mesmo problema por outro caminho: em vez de vários endereços com formato fixo, um endereço só onde quem chama descreve os campos que quer. Do lado de quem constrói, Node.js é a plataforma que rodou o servidor desta página, e vale conhecer o resto dela antes de trocar o node:http cru por um framework. O caminho completo, com as vinte tecnologias e a ordem sugerida, está no mapa da stack web.
O curso desta trilha está em preparação. A lista paga menos.
Os tutoriais daqui continuam gratuitos. O que está a caminho é um curso pago que transforma esse mapa em formação guiada, na ordem certa e com projeto. Deixe seu e-mail: você recebe os estudos novos gratuitos e, no lançamento, o desconto de quem entrou na lista primeiro.