03 - PUT - Atualiza Recurso
video: https://youtu.be/... no frontmatter da nota.PUT - Atualiza Recurso
1. Definição e Semântica
O método HTTP PUT é definido pela RFC 7231 (seção 4.3.4) como o método que solicita a criação ou substituição completa do estado do recurso identificado pela URL alvo. Sua semântica é de "store" (armazenar): o servidor deve guardar o corpo da requisição como representação canônica do recurso naquela URL.
Características Formais
- Método:
PUT - Seguro: Não (modifica estado do servidor)
- Idempotente: Sim (múltiplas execuções produzem o mesmo estado)
- Cacheável: Não (por padrão; apenas se houver header
Content-Locationexplícito) - Corpo na requisição: Sim, obrigatório (representação completa do recurso)
- Corpo na resposta: Opcional
- RFC de referência: RFC 7231 (HTTP/1.1 Semantics), RFC 9110 (HTTP Semantics, obsoleta a 7231)
Idempotência
A idempotência é a propriedade central do PUT. Se o cliente enviar a mesma requisição PUT 1, 10 ou 1000 vezes, o estado final do recurso deve ser idêntico. Isso difere do POST, onde múltiplas execuções podem criar múltiplos recursos (ex: múltiplas ordens de compra).
PUT /users/42 HTTP/1.1
Host: api.exemplo.com
Content-Type: application/json
Authorization: Bearer eyJ...
{"id": 42, "name": "Alice", "email": "alice@exemplo.com", "age": 30}
Se a requisição acima for retransmitida pelo cliente (ex: timeout), o resultado final será o mesmo: o recurso /users/42 conterá exatamente os campos enviados.
2. Criação vs Atualização
O PUT pode ser usado tanto para criar quanto para atualizar um recurso, desde que o cliente controle a URL alvo. Isso é diferente do POST, em que tipicamente o servidor gera a URL (ex: POST /users retorna 201 Created com Location: /users/42).
Criação com PUT
PUT /users/42 HTTP/1.1
Content-Type: application/json
{"name": "Alice", "email": "alice@exemplo.com"}
Resposta: 201 Created se o recurso não existia; 200 OK ou 204 No Content se já existia e foi substituído.
Atualização com PUT
A semântica é de substituição completa. Se o recurso existia com 5 campos e o PUT envia apenas 2, o resultado é um recurso com apenas esses 2 campos — os demais são removidos.
Estado inicial: {"id":42, "name":"Alice", "email":"alice@x.com", "age":30, "city":"SP"}
PUT enviado: {"id":42, "name":"Alice Silva"}
Estado final: {"id":42, "name":"Alice Silva"}
Esta é a principal diferença em relação ao PATCH, que faz atualização parcial preservando campos não enviados.
3. PUT vs POST vs PATCH
| Critério | POST | PUT | PATCH |
|---|---|---|---|
| Semântica | Criar/ação genérica | Substituir recurso | Atualização parcial |
| Idempotente | Não | Sim | Não (por padrão) |
| Cliente define URL | Geralmente não | Sim | Sim |
| Corpo completo | Sim, para criação | Sim, obrigatório | Não, apenas deltas |
| RFC | 7231 §4.3.3 | 7231 §4.3.4 | 5789 |
Exemplo Comparativo
Recurso: {"id":1, "name":"Bob", "email":"bob@x.com"}
POST /users/1— não usual (POST é para criar novo, não operar sobre existente).PUT /users/1com{"name":"Robert"}— resultado:{"name":"Robert"}(email removido).PATCH /users/1com{"name":"Robert"}— resultado:{"id":1, "name":"Robert", "email":"bob@x.com"}.
4. Headers Importantes
Content-Type
Indica o formato do corpo enviado. Para APIs REST modernas, application/json é padrão. Outros comuns: application/xml, application/x-www-form-urlencoded, text/plain.
Content-Length
Obrigatório quando o corpo é enviado de uma vez. Para uploads chunked, usa-se Transfer-Encoding: chunked.
If-Match (Controle de Concorrência)
Implementa optimistic locking via ETag. O servidor só aplica o PUT se a ETag do recurso atual casar com a informada; caso contrário, retorna 412 Precondition Failed.
PUT /users/42 HTTP/1.1
If-Match: "abc123"
Content-Type: application/json
{"name":"Alice 2.0"}
Expect: 100-continue
Cliente anuncia que tem um corpo grande para enviar e aguarda o servidor concordar antes de transmitir. Evita desperdiçar banda em uploads que seriam rejeitados (ex: arquivo muito grande).
5. Códigos de Resposta Típicos
| Status | Significado | Quando |
|---|---|---|
| 200 OK | Sucesso com corpo | Atualização bem-sucedida, retorna recurso |
| 201 Created | Recurso criado | PUT criou novo recurso na URL |
| 204 No Content | Sucesso sem corpo | Atualização bem-sucedida, sem payload de retorno |
| 400 Bad Request | Sintaxe inválida | JSON malformado, campos obrigatórios faltando |
| 401 Unauthorized | Falta autenticação | Token ausente ou inválido |
| 403 Forbidden | Sem permissão | Autenticado, mas sem direito de escrita |
| 404 Not Found | Recurso não existe | PUT em coleção inexistente |
| 409 Conflict | Conflito de estado | Versão/ETag incompatível, locks |
| 412 Precondition Failed | If-Match falhou | ETag não corresponde |
| 415 Unsupported Media Type | Content-Type não suportado | Servidor só aceita JSON, recebeu XML |
6. Exemplos Práticos
curl — Atualizar Usuário
curl -X PUT https://api.exemplo.com/users/42 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"Alice Silva","email":"alice.silva@exemplo.com"}'
curl — Criar Recurso com PUT (Upsert)
curl -X PUT https://api.exemplo.com/articles/tech-http-put \
-H "Content-Type: application/json" \
-d '{"title":"Entendendo PUT","author":"Alice"}'
Python (requests)
import requests
r = requests.put(
"https://api.exemplo.com/users/42",
json={"name": "Alice Silva", "email": "alice.silva@exemplo.com"},
headers={"Authorization": "Bearer " + token},
)
print(r.status_code, r.json())
7. Boas Práticas em APIs REST
Versionamento de Recurso
Inclua a versão na URL ou no header (Accept: application/vnd.api+json;version=1):
PUT /v1/users/42
Validação de Schema
Valide o corpo antes de persistir. Use JSON Schema (draft 2020-12) para definir o formato esperado do payload.
Retorno Padronizado
Retorne o recurso atualizado em respostas 200 OK para que o cliente confirme o estado persistido. Para 204 No Content, o cliente precisa confiar no sucesso silencioso.
Controle de Concorrência
Sempre implemente ETag + If-Match em recursos editáveis por múltiplos clientes. Isso evita "lost updates" quando dois usuários editam o mesmo recurso simultaneamente.
Idempotência na Prática
Se o servidor usa um identificador de requisição (Idempotency-Key), guarde o resultado por algumas horas. Retornar a mesma resposta para a mesma chave evita duplicações acidentais em retries.
8. Erros Comuns
| Erro | Causa | Correção |
|---|---|---|
| Substituição perde campos | PUT enviado com payload parcial | Usar PATCH para atualização parcial |
| Criação acidental | PUT em URL inexistente cria recurso | Validar existência antes, ou usar POST para criar |
| Duplicação em retries | Falta de Idempotency-Key | Gerar UUID por requisição e validar no servidor |
| 415 Unsupported Media Type | Content-Type incompatível | Padronizar JSON na API |
9. Resumo Técnico
| Atributo | Valor |
|---|---|
| Método | PUT |
| RFC | 7231 §4.3.4 (obsoleta por 9110) |
| Idempotente | Sim |
| Seguro | Não |
| Cacheável | Não (sem Content-Location) |
| Corpo obrigatório | Sim |
| Sucessos típicos | 200, 201, 204 |
| Concorrência | ETag + If-Match |
10. Conclusão
O método PUT é o mecanismo HTTP para substituição idempotente de recursos. Sua característica de idempotência o torna seguro para retries em redes instáveis, mas sua semântica de substituição completa exige que o cliente envie o estado integral do recurso. Em APIs REST modernas, PUT coexiste com PATCH (para atualizações parciais) e POST (para criação não idempotente). O uso correto de headers como If-Match e Idempotency-Key é essencial para garantir consistência em ambientes distribuídos com múltiplos clientes concorrentes.