---
title: "API REST: O que É e Como Funciona | Python Brasil"
url: "https://python.dev.br/glossario/api-rest/"
markdown_url: "https://python.dev.br/glossario/api-rest.MD"
description: "Guia completo sobre API REST: princípios REST, HATEOAS, Richardson Maturity Model, autenticação JWT, paginação, versionamento e OpenAPI."
date: "2025-08-12"
author: ""
---

# API REST: O que É e Como Funciona | Python Brasil

Guia completo sobre API REST: princípios REST, HATEOAS, Richardson Maturity Model, autenticação JWT, paginação, versionamento e OpenAPI.


## O que é uma API REST?

Uma **API REST** (Representational State Transfer) é um estilo de arquitetura para comunicação entre sistemas via **protocolo HTTP**. O termo foi definido por **Roy Fielding** em sua tese de doutorado em 2000, descrevendo um conjunto de restrições que, quando aplicadas, resultam em sistemas escaláveis, simples e interoperáveis.

APIs REST são o padrão mais usado para comunicação entre frontend e backend, aplicações mobile, microsserviços e integrações entre sistemas.

## Os 6 Princípios REST

### 1. Cliente-Servidor

A interface de usuário é separada do armazenamento de dados. O cliente não precisa conhecer os detalhes do servidor, e o servidor não conhece o estado da interface do cliente.

### 2. Stateless (Sem Estado)

Cada requisição deve conter todas as informações necessárias para ser processada. O servidor não guarda estado do cliente entre requisições. Isso facilita escalonamento horizontal, pois qualquer servidor pode atender qualquer requisição.

### 3. Cacheable (Cacheável)

Respostas devem indicar se podem ser armazenadas em cache. Isso reduz carga no servidor e melhora a performance do cliente.

### 4. Interface Uniforme

Quatro sub-restrições: identificação de recursos via URI, manipulação via representações, mensagens autodescritivas e HATEOAS.

### 5. Sistema em Camadas

O cliente não precisa saber se está falando diretamente com o servidor ou com um intermediário (proxy, load balancer, CDN).

### 6. Code-On-Demand (Opcional)

Servidores podem enviar código executável ao cliente (como JavaScript), mas isso é opcional e raramente aplicado em APIs REST modernas.

## Richardson Maturity Model

O modelo de maturidade de Richardson classifica APIs REST em 4 níveis:

- **Nível 0**: Uso do HTTP apenas como transporte (RPC via POST)
- **Nível 1**: Recursos (URIs diferentes para cada entidade)
- **Nível 2**: Métodos HTTP corretos (GET, POST, PUT, DELETE) e status codes
- **Nível 3**: HATEOAS — respostas incluem links para ações possíveis

A maioria das "APIs REST" na prática atinge o nível 2. O nível 3 é o REST "maduro" segundo Fielding, mas é raramente implementado.

## HATEOAS

**HATEOAS** (Hypermedia as the Engine of Application State) significa que a resposta da API inclui links para as próximas ações possíveis:

```json
{
  "id": 1,
  "titulo": "Aprendendo Python",
  "status": "ativo",
  "_links": {
    "self": { "href": "/artigos/1" },
    "editar": { "href": "/artigos/1", "method": "PUT" },
    "deletar": { "href": "/artigos/1", "method": "DELETE" },
    "comentarios": { "href": "/artigos/1/comentarios" }
  }
}
```

## Métodos HTTP e Status Codes

### Métodos HTTP

- **GET**: busca dados, sem efeitos colaterais (idempotente)
- **POST**: cria um novo recurso
- **PUT**: substitui um recurso completo (idempotente)
- **PATCH**: atualiza parcialmente um recurso
- **DELETE**: remove um recurso (idempotente)

### Status Codes Mais Comuns

- **200 OK**: sucesso genérico
- **201 Created**: recurso criado com sucesso
- **204 No Content**: sucesso sem corpo de resposta (ex: DELETE)
- **400 Bad Request**: dados inválidos enviados pelo cliente
- **401 Unauthorized**: não autenticado
- **403 Forbidden**: autenticado, mas sem permissão
- **404 Not Found**: recurso não encontrado
- **409 Conflict**: conflito (ex: e-mail já cadastrado)
- **422 Unprocessable Entity**: dados sintaticamente corretos, mas semanticamente inválidos
- **429 Too Many Requests**: rate limit atingido
- **500 Internal Server Error**: erro no servidor

## Exemplo Completo com FastAPI

```python
from fastapi import FastAPI, HTTPException, Query, Header
from pydantic import BaseModel
from typing import Optional
from datetime import datetime

app = FastAPI(title="API de Artigos", version="1.0.0")

class ArtigoCreate(BaseModel):
    titulo: str
    conteudo: str
    categoria: str

class ArtigoResponse(BaseModel):
    id: int
    titulo: str
    categoria: str
    criado_em: datetime
    visualizacoes: int

class RespostaPaginada(BaseModel):
    dados: list[ArtigoResponse]
    total: int
    pagina: int
    tamanho: int

@app.get("/api/v1/artigos", response_model=RespostaPaginada)
async def listar_artigos(
    pagina: int = Query(default=1, ge=1, description="Número da página"),
    tamanho: int = Query(default=20, ge=1, le=100, description="Itens por página"),
    categoria: Optional[str] = Query(default=None),
    busca: Optional[str] = Query(default=None),
):
    # Simulação de paginação
    artigos = buscar_artigos(pagina, tamanho, categoria, busca)
    return RespostaPaginada(
        dados=artigos,
        total=200,
        pagina=pagina,
        tamanho=tamanho
    )

@app.post("/api/v1/artigos", response_model=ArtigoResponse, status_code=201)
async def criar_artigo(artigo: ArtigoCreate):
    novo = salvar_artigo(artigo)
    return novo
```

## Autenticação

### API Key

```python
from fastapi import Security, HTTPException, status
from fastapi.security import APIKeyHeader

api_key_header = APIKeyHeader(name="X-API-Key")

async def verificar_api_key(api_key: str = Security(api_key_header)):
    if api_key != CHAVE_VALIDA:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Chave de API inválida"
        )
    return api_key
```

### JWT (JSON Web Token)

```python
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")

async def usuario_atual(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        email = payload.get("sub")
        if not email:
            raise HTTPException(status_code=401, detail="Token inválido")
        return email
    except JWTError:
        raise HTTPException(status_code=401, detail="Token inválido ou expirado")
```

## Paginação

Existem três estratégias principais de paginação:

**Baseada em página (offset)**: simples, mas pode ter resultados inconsistentes em dados que mudam rapidamente.

```
GET /artigos?pagina=2&tamanho=20
```

**Baseada em cursor**: mais eficiente para grandes volumes de dados.

```
GET /artigos?cursor=eyJpZCI6MTAwfQ&tamanho=20
```

**Baseada em keyset**: usa o valor do último item para buscar o próximo lote.

```
GET /artigos?ultimo_id=100&tamanho=20
```

## Versionamento

Estratégias de versionamento de APIs:

**URI**: mais comum e explícito.
```
GET /api/v1/artigos
GET /api/v2/artigos
```

**Header**: mais "puro" em termos REST, mas menos visível.
```
Accept: application/vnd.minhapi.v2+json
```

**Query param**: simples, mas mistura versão com dados.
```
GET /artigos?version=2
```

## Rate Limiting

Rate limiting protege a API de abusos. A resposta deve incluir headers informativos:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1710000000
Retry-After: 60
```

Implementação simples com Redis (usando `slowapi`):

```python
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.get("/artigos")
@limiter.limit("100/minute")
async def listar_artigos(request: Request):
    return {"artigos": []}
```

## OpenAPI e Swagger

O **OpenAPI** (antigo Swagger) é a especificação padrão para documentar APIs REST. O FastAPI gera o schema OpenAPI automaticamente:

- Acesse `/docs` para a interface Swagger UI interativa
- Acesse `/redoc` para a documentação ReDoc
- Acesse `/openapi.json` para o schema em JSON

Você pode enriquecer a documentação:

```python
@app.get(
    "/artigos/{artigo_id}",
    response_model=ArtigoResponse,
    summary="Buscar artigo por ID",
    description="Retorna os detalhes completos de um artigo.",
    responses={
        404: {"description": "Artigo não encontrado"},
        200: {"description": "Artigo encontrado com sucesso"}
    }
)
async def buscar_artigo(artigo_id: int):
    ...
```

## REST vs GraphQL

| Aspecto | REST | GraphQL |
|---|---|---|
| Estrutura | Múltiplos endpoints | Um único endpoint |
| Dados | Resposta fixa | Cliente define os campos |
| Over-fetching | Comum | Resolvido |
| Under-fetching | Requer múltiplas chamadas | Resolvido |
| Cache | Simples (HTTP cache) | Mais complexo |
| Adoção | Universal | Crescente |

REST é mais simples e universal. GraphQL brilha quando há muitos tipos de clientes (mobile, web, TV) com necessidades diferentes de dados.

## Boas Práticas

- Use **substantivos no plural** nos endpoints: `/usuarios`, não `/getUsuario`
- Retorne **status codes corretos** — 201 para criação, 204 para deleção sem corpo
- Inclua **paginação** em todas as rotas que retornam listas
- Use **versionamento** desde o início: `/api/v1/`
- Documente com **OpenAPI** e mantenha a documentação atualizada
- Implemente **rate limiting** para proteger a API
- Use **HTTPS** sempre em produção

## Erros Comuns

- Usar POST para todas as operações (nível 0 de maturidade)
- Retornar sempre 200 mesmo em erros
- Colocar verbos na URL: `/getArtigos`, `/deletarUsuario`
- Não implementar paginação em listas que podem crescer

## Termos Relacionados

- [FastAPI](/glossario/fastapi/) - Framework moderno para APIs REST em Python
- [Flask](/glossario/flask/) - Microframework para APIs
- [Django](/glossario/django/) - Framework web completo com suporte a APIs via DRF
- [Pydantic](/glossario/pydantic/) - Validação de dados essencial para APIs

> **APIs REST em outras linguagens**: <a href="https://golang.com.br/blog/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', {source: 'python.dev.br', target: 'golang.com.br', content: 'glossario-api-rest'})">Go é referência em APIs de alta performance</a> com frameworks como Gin e Echo, e <a href="https://kotlin.dev.br/blog/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', {source: 'python.dev.br', target: 'kotlin.dev.br', content: 'glossario-api-rest'})">Kotlin com Spring Boot</a> oferece APIs robustas no ecossistema JVM.
