API REST: Boas Práticas de Design e Testes

Testes Automatizados · 4 de julho de 2026

📖 4 min de leitura

Princípios REST

Constraints REST

  1. Client-Server: Separação de interesses
  2. Stateless: Cada requisição contém toda informação
  3. Cacheable: Respostas podem ser cacheadas
  4. Uniform Interface: Interface consistente
  5. Layered System: Arquitetura em camadas

HTTP Methods

Método Semântica Idempotente Safe
GET Ler recurso Sim Sim
POST Criar recurso Não Não
PUT Substituir recurso Sim Não
PATCH Atualizar parcialmente Não Não
DELETE Remover recurso Sim Não
HEAD Ler headers Sim Sim
OPTIONS Verbos suportados Sim Sim

Status Codes

2xx Success

Código Significado Uso
200 OK GET, PUT, PATCH bem-sucedido
201 Created POST que cria recurso
202 Accepted Async processing
204 No Content DELETE bem-sucedido

3xx Redirection

Código Significado Uso
301 Moved Permanently Redirect permanente
302 Found Redirect temporário
304 Not Modified Cache válido

4xx Client Error

Código Significado Uso
400 Bad Request Dados inválidos
401 Unauthorized Não autenticado
403 Forbidden Sem permissão
404 Not Found Recurso não existe
409 Conflict Conflito de estado
422 Unprocessable Validação falhou
429 Too Many Requests Rate limit

5xx Server Error

Código Significado Uso
500 Internal Server Error Erro genérico
502 Bad Gateway Gateway inválido
503 Service Unavailable Manutenção
504 Gateway Timeout Timeout

Design de Endpoints

Resource Naming

# BOAS PRÁTICAS

# Recursos (substantivos, não verbos)
GET /users # Lista usuários
GET /users/{id} # Busca usuário
POST /users # Cria usuário
PUT /users/{id} # Atualiza usuário
DELETE /users/{id} # Remove usuário

# Sub-recursos
GET /users/{id}/orders # Pedidos do usuário
GET /users/{id}/orders/{orderId} # Pedido específico
POST /users/{id}/orders # Cria pedido para usuário

# Evite:
GET /getUsers
POST /createUser
PUT /updateUserData

Versionamento

# Via URL (mais comum)
GET /v1/users
GET /v2/users

# Via Header
Accept: application/vnd.api.v2+json

# Via Query Param (evite)
GET /users?version=2


Autenticação e Autorização

Bearer Token (JWT)

# Flask API
from flask import Flask, request, jsonify
import jwt

app = Flask(__name__)
SECRET_KEY = "your-secret-key"

@app.route("/protected")
def protected():
token = request.headers.get("Authorization", "").replace("Bearer ", "")

if not token:
return jsonify({"error": "Token required"}), 401

try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return jsonify({
"user_id": payload["sub"],
"role": payload["role"]
})
except jwt.ExpiredSignatureError:
return jsonify({"error": "Token expired"}), 401
except jwt.InvalidTokenError:
return jsonify({"error": "Invalid token"}), 401

@app.route("/login", methods=["POST"])
def login():
# Validate credentials
user = validate_credentials(request.json)

token = jwt.encode({
"sub": user.id,
"role": user.role,
"exp": datetime.utcnow() + timedelta(hours=1)
}, SECRET_KEY, algorithm="HS256")

return jsonify({"token": token})

OAuth 2.0

# Flask + OAuth
from authlib.integrations.flask_client import OAuth

oauth = OAuth(app)
google = oauth.register(name='google')

@app.route("/login/google")
def login_google():
return google.authorize_redirect(redirect_uri=url_for("callback", _external=True))

@app.route("/callback/google")
def callback():
token = google.authorize_access_token()
user_info = google.get("userinfo").json()
# Create session
return jsonify(user_info)


Documentação OpenAPI

# openapi.yaml
openapi: 3.0.3
info:
  title: E-commerce API
  version: 1.0.0
  description: API for e-commerce platform

servers:
- url: https://api.exemplo.com/v1
description: Production
- url: https://staging.exemplo.com/v1
description: Staging

paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: List of users
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
'401':
$ref: '#/components/responses/Unauthorized'

post:
summary: Create user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUser'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'422':
$ref: '#/components/responses/ValidationError'

components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
format: email
created_at:
type: string
format: date-time

CreateUser:
type: object
required:
- name
- email
- password
properties:
name:
type: string
minLength: 1
email:
type: string
format: email
password:
type: string
minLength: 8

responses:
Unauthorized:
description: Authentication required
content:
application/json:
schema:
type: object
properties:
error:
type: string

ValidationError:
description: Validation failed
content:
application/json:
schema:
type: object
properties:
errors:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string


Conclusão

API REST bem desenhada é crucial para integrações. As chaves são:

  1. HTTP semantics corretas – Métodos e status codes
  2. Recursos bem nomeados – Substantivos, não verbos
  3. Documentação completa – OpenAPI/Swagger
  4. Autenticação segura – JWT/OAuth
  5. Versionamento – Para evoluir sem quebrar