O Desenvolvimento de APIs Python tornou-se uma habilidade fundamental para programadores modernos. Com sua sintaxe clara e poderosas bibliotecas, o Python estabeleceu-se como uma das melhores linguagens para criar APIs RESTful robustas e escaláveis. Este artigo explora o Desenvolvimento de APIs Python, comparando os principais frameworks e apresentando as melhores práticas.
O Python consolidou sua posição como linguagem preferida para o Desenvolvimento de APIs Python por diversas razões:
Essas vantagens tornaram-se ainda mais evidentes, com os frameworks Python para APIs evoluindo para atender às demandas crescentes de desempenho e escalabilidade.
O ecossistema Python oferece diversos frameworks para o Desenvolvimento de APIs Python, cada um com seus pontos fortes. Vamos explorar os três mais populares.
O FastAPI revolucionou o Desenvolvimento de APIs Python com seu foco em desempenho e facilidade de uso:
Este exemplo de código demonstra a criação de uma API RESTful completa para gerenciamento de produtos usando FastAPI. Ele inclui a definição de um modelo de dados (Produto), simulação de um banco de dados em memória, e rotas para operações CRUD (Criar, Ler, Atualizar, Deletar) de produtos. Além disso, um middleware simples é adicionado para logar as requisições.
# Exemplo de API com FastAPI
from fastapi import FastAPI, HTTPException, Depends, status
from pydantic import BaseModel
from typing import List, Optional
import uvicorn
# Inicializar aplicação
app = FastAPI(
title="API de Produtos",
description="API RESTful para gerenciamento de produtos",
version="1.0.0"
)
# Modelo de dados com validação
class Produto(BaseModel):
id: Optional[int] = None
nome: str
descricao: str
preco: float
disponivel: bool = True
class Config:
schema_extra = {
"example": {
"nome": "Smartphone XYZ",
"descricao": "Smartphone de última geração",
"preco": 1999.90,
"disponivel": True
}
}
# Simulação de banco de dados
db_produtos = {}
contador_id = 1
# Rotas CRUD
@app.post("/produtos/", response_model=Produto, status_code=status.HTTP_201_CREATED)
async def criar_produto(produto: Produto):
global contador_id
produto.id = contador_id
db_produtos[contador_id] = produto
contador_id += 1
return produto
@app.get("/produtos/", response_model=List[Produto])
async def listar_produtos(skip: int = 0, limit: int = 100):
return list(db_produtos.values())[skip : skip + limit]
@app.get("/produtos/{produto_id}", response_model=Produto)
async def obter_produto(produto_id: int):
if produto_id not in db_produtos:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Produto com ID {produto_id} não encontrado"
)
return db_produtos[produto_id]
@app.put("/produtos/{produto_id}", response_model=Produto)
async def atualizar_produto(produto_id: int, produto: Produto):
if produto_id not in db_produtos:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Produto com ID {produto_id} não encontrado"
)
produto.id = produto_id
db_produtos[produto_id] = produto
return produto
@app.delete("/produtos/{produto_id}", status_code=status.HTTP_204_NO_CONTENT)
async def deletar_produto(produto_id: int):
if produto_id not in db_produtos:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Produto com ID {produto_id} não encontrado"
)
del db_produtos[produto_id]
return None
# Middleware para logging
@app.middleware("http")
async def log_requests(request, call_next):
print(f"Requisição para: {request.url.path}")
response = await call_next(request)
return response
# Executar servidor
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
Vantagens do FastAPI:
O Flask continua sendo uma escolha popular para APIs devido à sua simplicidade e flexibilidade:
Este exemplo de código demonstra a criação de uma API RESTful para gerenciamento de produtos usando Flask e Flask-RESTful. Ele utiliza Marshmallow para validação de dados e simula um banco de dados em memória. As rotas para listar, criar, obter, atualizar e deletar produtos são definidas como recursos RESTful.
# Exemplo de API RESTful com Flask
from flask import Flask, request, jsonify
from flask_restful import Api, Resource
from marshmallow import Schema, fields, validate, ValidationError
import uuid
app = Flask(__name__)
api = Api(app)
# Esquema de validação com Marshmallow
class ProdutoSchema(Schema):
id = fields.Str(dump_only=True) # Apenas para resposta, não para entrada
nome = fields.Str(required=True, validate=validate.Length(min=1))
descricao = fields.Str(required=True)
preco = fields.Float(required=True, validate=validate.Range(min=0.01))
disponivel = fields.Bool(missing=True) # Valor padrão se não fornecido
produto_schema = ProdutoSchema()
produtos_schema = ProdutoSchema(many=True)
# Simulação de banco de dados
produtos = {}
# Recurso para coleção de produtos
class ProdutoListResource(Resource):
def get(self):
return jsonify(produtos_schema.dump(list(produtos.values())))
def post(self):
try:
# Validar dados de entrada
produto_data = produto_schema.load(request.json)
# Gerar ID único
produto_id = str(uuid.uuid4())
produto_data["id"] = produto_id
# Salvar no "banco de dados"
produtos[produto_id] = produto_data
return produto_schema.dump(produto_data), 201
except ValidationError as err:
return {"errors": err.messages}, 400
# Recurso para produto individual
class ProdutoResource(Resource):
def get(self, produto_id):
produto = produtos.get(produto_id)
if not produto:
return {"error": "Produto não encontrado"}, 404
return produto_schema.dump(produto)
def put(self, produto_id):
if produto_id not in produtos:
return {"error": "Produto não encontrado"}, 404
try:
# Validar dados de entrada
produto_data = produto_schema.load(request.json)
produto_data["id"] = produto_id
# Atualizar no "banco de dados"
produtos[produto_id] = produto_data
return produto_schema.dump(produto_data)
except ValidationError as err:
return {"errors": err.messages}, 400
def delete(self, produto_id):
if produto_id not in produtos:
return {"error": "Produto não encontrado"}, 404
del produtos[produto_id]
return "", 204
# Registrar recursos
api.add_resource(ProdutoListResource,
'/produtos')
api.add_resource(ProdutoResource,
'/produtos/<string:produto_id>')
# Executar servidor
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
Vantagens do Flask:
Para projetos maiores e mais complexos, o Django REST Framework (DRF) oferece uma solução robusta para o Desenvolvimento de APIs Python:
Este conjunto de exemplos de código mostra como construir uma API RESTful completa usando Django REST Framework. Ele inclui a definição de um modelo Django (Produto), um serializador para converter dados do modelo para JSON e vice-versa (ProdutoSerializer), um ViewSet para lidar com as operações CRUD e filtragem de produtos, e a configuração de URLs para rotear as requisições para o ViewSet.
# Exemplo de API com Django REST Framework
# arquivo: models.py
from django.db import models
class Produto(models.Model):
nome = models.CharField(max_length=100)
descricao = models.TextField()
preco = models.DecimalField(max_digits=10, decimal_places=2)
disponivel = models.BooleanField(default=True)
data_criacao = models.DateTimeField(auto_now_add=True)
data_atualizacao = models.DateTimeField(auto_now=True)
def __str__(self):
return self.nome
# arquivo: serializers.py
from rest_framework import serializers
from .models import Produto
class ProdutoSerializer(serializers.ModelSerializer):
class Meta:
model = Produto
fields = ['id', 'nome', 'descricao', 'preco', 'disponivel',
'data_criacao', 'data_atualizacao']
read_only_fields = ['id', 'data_criacao', 'data_atualizacao']
# arquivo: views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.pagination import PageNumberPagination
from .models import Produto
from .serializers import ProdutoSerializer
class ProdutoPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
class ProdutoViewSet(viewsets.ModelViewSet):
queryset = Produto.objects.all().order_by('-data_atualizacao')
serializer_class = ProdutoSerializer
pagination_class = ProdutoPagination
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
queryset = Produto.objects.all()
# Filtrar por disponibilidade
disponivel = self.request.query_params.get('disponivel')
if disponivel is not None:
queryset = queryset.filter(disponivel=disponivel.lower() == 'true')
# Filtrar por preço mínimo
preco_min = self.request.query_params.get('preco_min')
if preco_min is not None:
queryset = queryset.filter(preco__gte=float(preco_min))
# Filtrar por preço máximo
preco_max = self.request.query_params.get('preco_max')
if preco_max is not None:
queryset = queryset.filter(preco__lte=float(preco_max))
return queryset
# arquivo: urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProdutoViewSet
router = DefaultRouter()
router.register(r'produtos', ProdutoViewSet)
urlpatterns = [
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls')),
]
Vantagens do Django REST Framework:
O desempenho é uma consideração crucial ao escolher um framework para o Desenvolvimento de APIs Python. Os benchmarks mostram diferenças significativas:
Framework | Requisições/segundo | Latência média | Uso de memória |
---|---|---|---|
FastAPI | ~10,000 | ~2ms | Médio |
Flask | ~2,500 | ~8ms | Baixo |
Django RF | ~1,200 | ~15ms | Alto |
Estes números são aproximados e variam dependendo da complexidade da API, hardware e configuração. O FastAPI mantém sua vantagem de desempenho, mas os outros frameworks também evoluíram significativamente.
Independentemente do framework escolhido, algumas práticas se consolidaram como essenciais para APIs RESTful de qualidade:
Mantenha um padrão consistente para seus endpoints:
# Padrão recomendado para endpoints RESTful
GET /recursos # Listar recursos
POST /recursos # Criar novo recurso
GET /recursos/{id} # Obter recurso específico
PUT /recursos/{id} # Atualizar recurso (completo)
PATCH /recursos/{id} # Atualizar recurso (parcial)
DELETE /recursos/{id} # Excluir recurso
# Para relacionamentos
GET /recursos/{id}/subrecursos # Listar subrecursos
POST /recursos/{id}/subrecursos # Criar subrecurso
Implemente versionamento para evitar quebrar clientes existentes:
Este exemplo de código demonstra como implementar versionamento de API usando FastAPI. Ele define duas versões da API (v1 e v2) com rotas separadas, permitindo que diferentes versões da API coexistam e sejam acessadas por diferentes prefixos de URL.
# Exemplo com FastAPI
from fastapi import FastAPI, APIRouter
app = FastAPI()
# Funções de exemplo para as diferentes versões da API
def get_recursos_v1():
return {"message": "Recursos da API v1"}
def get_recursos_v2():
return {"message": "Recursos da API v2 com dados adicionais"}
# API v1
v1_router = APIRouter(prefix="/api/v1")
v1_router.add_api_route("/recursos", get_recursos_v1, methods=["GET"])
app.include_router(v1_router)
# API v2
v2_router = APIRouter(prefix="/api/v2")
v2_router.add_api_route("/recursos", get_recursos_v2, methods=["GET"])
app.include_router(v2_router)
Sempre valide dados de entrada para evitar problemas de segurança e integridade:
Este exemplo de código mostra como realizar validação robusta de dados de entrada usando Pydantic, comumente utilizado com FastAPI. Ele define um modelo UsuarioCreate com campos obrigatórios e validações personalizadas para formato de e-mail e força da senha, garantindo que os dados recebidos estejam em conformidade com as regras de negócio.
# Exemplo com Pydantic (FastAPI)
from pydantic import BaseModel, Field, validator
from typing import Optional
import re
class UsuarioCreate(BaseModel):
nome: str = Field(..., min_length=2, max_length=50)
email: str = Field(..., max_length=100)
senha: str = Field(..., min_length=8)
telefone: Optional[str] = Field(None)
@validator('email')
def email_valido(cls, v):
if not re.match(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", v):
raise ValueError('Email inválido')
return v
@validator('senha')
def senha_forte(cls, v):
if not re.search(r"[A-Z]", v):
raise ValueError('Senha deve conter pelo menos uma letra maiúscula')
if not re.search(r"[a-z]", v):
raise ValueError('Senha deve conter pelo menos uma letra minúscula')
if not re.search(r"[0-9]", v):
raise ValueError('Senha deve conter pelo menos um número')
return v
Implemente autenticação robusta para proteger seus endpoints:
Este exemplo de código demonstra um sistema de autenticação baseado em JWT (JSON Web Tokens) para FastAPI. Ele inclui funções para criar tokens de acesso e para obter o usuário atual a partir de um token, protegendo assim os endpoints da API e garantindo que apenas usuários autenticados possam acessá-los.
# Exemplo com FastAPI e JWT
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from datetime import datetime, timedelta
from typing import Optional
# Configuração
SECRET_KEY = "sua_chave_secreta_muito_segura"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def criar_token_acesso(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def obter_usuario_atual(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Credenciais inválidas",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = get_user(username) # Função para buscar usuário no banco
if user is None:
raise credentials_exception
return user
# Uso em um endpoint protegido
@app.get("/usuarios/me")
async def ler_usuarios_me(current_user = Depends(obter_usuario_atual)):
return current_user
Mantenha sua API bem documentada para facilitar a adoção:
Este exemplo de código simples mostra como configurar a documentação automática no FastAPI. Ao inicializar a aplicação FastAPI com title, description e version, o framework gera automaticamente interfaces interativas de documentação (Swagger UI e ReDoc) que podem ser acessadas diretamente pelo navegador, facilitando o uso e teste da API.
# Exemplo com FastAPI (documentação automática)
from fastapi import FastAPI
app = FastAPI(
title="Minha API",
description="API para gerenciamento de recursos",
version="1.0.0",
openapi_tags=[
{
"name": "usuarios",
"description": "Operações relacionadas a usuários"
},
{
"name": "produtos",
"description": "Operações relacionadas a produtos"
}
]
)
# ... (suas rotas e lógica de API aqui)
# A documentação interativa (Swagger UI) estará disponível em /docs
# A documentação alternativa (ReDoc) estará disponível em /redoc
O Python continua sendo uma excelente escolha para o Desenvolvimento de APIs Python, oferecendo uma gama de frameworks que atendem a diferentes necessidades e escalas de projeto. Ao seguir as melhores práticas e escolher o framework certo, você pode construir APIs robustas, eficientes e fáceis de manter. Seja com a velocidade do FastAPI, a flexibilidade do Flask ou a robustez do Django REST Framework, o Python oferece as ferramentas necessárias para o sucesso no Desenvolvimento de APIs Python.
A segurança em aplicações Python é uma grande preocupação para desenvolvedores. Com o aumento de…
A análise de dados em tempo real tornou-se um componente crítico para empresas que precisam…
O desenvolvimento web evoluiu significativamente nos últimos anos, e os frameworks Python estão na vanguarda…
A inteligência artificial está revolucionando todos os setores da sociedade, desde aplicações empresariais até soluções…
Nesta aula do minicurso de Python, quero abordar dois tipos de coleção que são usadas…
Entre as estruturas de dados mais versáteis do Python, os dicionários se destacam. Eles nos…
Este blog utiliza cookies. Se você continuar assumiremos que você está satisfeito com ele.
Leia Mais...