📚 Série: Backend Python → ChatGPT API Python | API Telegram Bot | API WhatsApp Node.js | Bot Discord Python
O que é Python Flask API?
Python Flask API é micro-framework (flask.palletsprojects.com) minimalista e flexível para criar REST APIs: rotas HTTP (GET, POST, PUT, DELETE), JSON request/response, autenticação JWT, integração bancos (PostgreSQL, MongoDB), middlewares, blueprints modularização, extensões (SQLAlchemy ORM, Flask-CORS, Flask-Limiter), deploy simples (Heroku, Railway, Render). Diferente Django (full-stack pesado), Flask oferece apenas essenciais permitindo controle total arquitetura, ideal para APIs microservices, backends mobile, integrações IA (GPT-4, webhooks), prototipagem rápida com produção robusta escalando 10k+ requests/segundo com configuração correta.
Diferença: Flask (micro, flexível, você escolhe tudo) vs Django (batteries-included, opinionado, mais setup inicial).
Setup Projeto Flask Produção
Estrutura Recomendada
meu-projeto/
├── app/
│ ├── __init__.py # Criar app Flask
│ ├── models.py # SQLAlchemy models
│ ├── routes/ # Blueprints
│ │ ├── auth.py
│ │ ├── users.py
│ │ └── produtos.py
│ ├── utils/
│ │ ├── auth.py # JWT helpers
│ │ └── validators.py
│ └── config.py # Configurações
├── tests/ # Testes pytest
├── migrations/ # Flask-Migrate
├── requirements.txt
├── .env
└── run.py # Entry point
Instalação Dependências
pip install flask flask-sqlalchemy flask-cors flask-jwt-extended python-dotenv psycopg2-binary
requirements.txt:
Flask==3.0.0
Flask-SQLAlchemy==3.0.5
Flask-CORS==4.0.0
Flask-JWT-Extended==4.5.3
Flask-Migrate==4.0.5
python-dotenv==1.0.0
psycopg2-binary==2.9.9
gunicorn==21.2.0
API REST Completa: Exemplo Prático
1. Configuração (app/config.py)
import os
from datetime import timedelta
class Config:
# Database
SQLALCHEMY_DATABASE_URI = os.getenv(
'DATABASE_URL',
'postgresql://user:pass@localhost/meudb'
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
# JWT
JWT_SECRET_KEY = os.getenv('JWT_SECRET', 'super-secret-change-me')
JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1)
JWT_REFRESH_TOKEN_EXPIRES = timedelta(days=30)
# CORS
CORS_ORIGINS = os.getenv('CORS_ORIGINS', '*').split(',')
class DevelopmentConfig(Config):
DEBUG = True
class ProductionConfig(Config):
DEBUG = False
config = {
'development': DevelopmentConfig,
'production': ProductionConfig
}
2. Inicialização (app/__init__.py)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from flask_jwt_extended import JWTManager
from flask_migrate import Migrate
db = SQLAlchemy()
jwt = JWTManager()
migrate = Migrate()
def create_app(config_name='development'):
app = Flask(__name__)
app.config.from_object(f'app.config.{config_name}')
# Inicializar extensões
db.init_app(app)
CORS(app, resources={r"/api/*": {"origins": app.config['CORS_ORIGINS']}})
jwt.init_app(app)
migrate.init_app(app, db)
# Registrar blueprints
from app.routes.auth import auth_bp
from app.routes.users import users_bp
from app.routes.produtos import produtos_bp
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(users_bp, url_prefix='/api/users')
app.register_blueprint(produtos_bp, url_prefix='/api/produtos')
# Health check
@app.route('/health')
def health():
return {'status': 'ok'}, 200
return app
3. Models (app/models.py)
from app import db
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
nome = db.Column(db.String(100))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def to_dict(self):
return {
'id': self.id,
'email': self.email,
'nome': self.nome,
'created_at': self.created_at.isoformat()
}
class Produto(db.Model):
__tablename__ = 'produtos'
id = db.Column(db.Integer, primary_key=True)
nome = db.Column(db.String(200), nullable=False)
descricao = db.Column(db.Text)
preco = db.Column(db.Numeric(10, 2), nullable=False)
estoque = db.Column(db.Integer, default=0)
ativo = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'nome': self.nome,
'descricao': self.descricao,
'preco': float(self.preco),
'estoque': self.estoque,
'ativo': self.ativo
}
4. Autenticação (app/routes/auth.py)
from flask import Blueprint, request, jsonify
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_required, get_jwt_identity
from app import db
from app.models import User
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/register', methods=['POST'])
def register():
data = request.get_json()
# Validar campos
if not data.get('email') or not data.get('password'):
return {'error': 'Email e senha obrigatórios'}, 400
# Verificar se existe
if User.query.filter_by(email=data['email']).first():
return {'error': 'Email já cadastrado'}, 409
# Criar usuário
user = User(
email=data['email'],
nome=data.get('nome')
)
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
return {'message': 'Usuário criado com sucesso', 'user': user.to_dict()}, 201
@auth_bp.route('/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(email=data.get('email')).first()
if not user or not user.check_password(data.get('password')):
return {'error': 'Credenciais inválidas'}, 401
# Gerar tokens
access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(identity=user.id)
return {
'access_token': access_token,
'refresh_token': refresh_token,
'user': user.to_dict()
}, 200
@auth_bp.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
user_id = get_jwt_identity()
access_token = create_access_token(identity=user_id)
return {'access_token': access_token}, 200
@auth_bp.route('/me', methods=['GET'])
@jwt_required()
def me():
user_id = get_jwt_identity()
user = User.query.get(user_id)
if not user:
return {'error': 'Usuário não encontrado'}, 404
return user.to_dict(), 200
5. CRUD Produtos (app/routes/produtos.py)
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from app import db
from app.models import Produto
produtos_bp = Blueprint('produtos', __name__)
# Listar produtos
@produtos_bp.route('/', methods=['GET'])
def list_produtos():
# Query params
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
search = request.args.get('search', '')
# Query
query = Produto.query
if search:
query = query.filter(Produto.nome.ilike(f'%{search}%'))
# Paginação
produtos = query.paginate(page=page, per_page=per_page)
return {
'produtos': [p.to_dict() for p in produtos.items],
'total': produtos.total,
'pages': produtos.pages,
'current_page': page
}, 200
# Obter produto
@produtos_bp.route('/<int:id>', methods=['GET'])
def get_produto(id):
produto = Produto.query.get_or_404(id)
return produto.to_dict(), 200
# Criar produto (protegido)
@produtos_bp.route('/', methods=['POST'])
@jwt_required()
def create_produto():
data = request.get_json()
# Validar
if not data.get('nome') or not data.get('preco'):
return {'error': 'Nome e preço obrigatórios'}, 400
produto = Produto(
nome=data['nome'],
descricao=data.get('descricao'),
preco=data['preco'],
estoque=data.get('estoque', 0)
)
db.session.add(produto)
db.session.commit()
return produto.to_dict(), 201
# Atualizar produto
@produtos_bp.route('/<int:id>', methods=['PUT'])
@jwt_required()
def update_produto(id):
produto = Produto.query.get_or_404(id)
data = request.get_json()
# Atualizar campos
if 'nome' in data:
produto.nome = data['nome']
if 'descricao' in data:
produto.descricao = data['descricao']
if 'preco' in data:
produto.preco = data['preco']
if 'estoque' in data:
produto.estoque = data['estoque']
if 'ativo' in data:
produto.ativo = data['ativo']
db.session.commit()
return produto.to_dict(), 200
# Deletar produto
@produtos_bp.route('/<int:id>', methods=['DELETE'])
@jwt_required()
def delete_produto(id):
produto = Produto.query.get_or_404(id)
db.session.delete(produto)
db.session.commit()
return {'message': 'Produto deletado'}, 200
6. Entry Point (run.py)
from app import create_app, db
import os
app = create_app(os.getenv('FLASK_ENV', 'development'))
if __name__ == '__main__':
with app.app_context():
db.create_all() # Criar tabelas
app.run(
host='0.0.0.0',
port=int(os.getenv('PORT', 5000)),
debug=app.config['DEBUG']
)
Rodar Localmente
# Configurar env
export DATABASE_URL="postgresql://user:pass@localhost/meudb"
export JWT_SECRET="seu-secret-aqui"
export FLASK_ENV="development"
# Criar banco
python
>>> from app import create_app, db
>>> app = create_app()
>>> with app.app_context():
... db.create_all()
>>> exit()
# Rodar
python run.py
Testar API:
# Register
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "teste@email.com", "password": "senha123", "nome": "João"}'
# Login
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "teste@email.com", "password": "senha123"}'
# Criar produto (com token)
curl -X POST http://localhost:5000/api/produtos \
-H "Content-Type: application/json" \
-H "Authorization: Bearer SEU_TOKEN_AQUI" \
-d '{"nome": "Notebook", "preco": 2500, "estoque": 10}'
# Listar produtos
curl http://localhost:5000/api/produtos?page=1&per_page=20
Validação Dados (Marshmallow)
Instalar:
pip install marshmallow
Schema (app/schemas.py):
from marshmallow import Schema, fields, validate, ValidationError
class ProdutoSchema(Schema):
id = fields.Int(dump_only=True)
nome = fields.Str(required=True, validate=validate.Length(min=3, max=200))
descricao = fields.Str()
preco = fields.Decimal(required=True, places=2, validate=validate.Range(min=0))
estoque = fields.Int(validate=validate.Range(min=0))
ativo = fields.Bool()
produto_schema = ProdutoSchema()
produtos_schema = ProdutoSchema(many=True)
Usar em route:
from app.schemas import produto_schema
from marshmallow import ValidationError
@produtos_bp.route('/', methods=['POST'])
@jwt_required()
def create_produto():
try:
# Validar dados
data = produto_schema.load(request.get_json())
except ValidationError as err:
return {'errors': err.messages}, 400
produto = Produto(**data)
db.session.add(produto)
db.session.commit()
return produto_schema.dump(produto), 201
Rate Limiting
Instalar:
pip install Flask-Limiter
Setup:
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
# Por rota
@auth_bp.route('/login', methods=['POST'])
@limiter.limit("5 per minute")
def login():
...
Testes (pytest)
Instalar:
pip install pytest pytest-flask
Teste (tests/test_auth.py):
import pytest
from app import create_app, db
from app.models import User
@pytest.fixture
def client():
app = create_app('testing')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
with app.test_client() as client:
with app.app_context():
db.create_all()
yield client
with app.app_context():
db.drop_all()
def test_register(client):
response = client.post('/api/auth/register', json={
'email': 'teste@test.com',
'password': 'senha123',
'nome': 'Teste'
})
assert response.status_code == 201
assert 'user' in response.json
def test_login(client):
# Criar usuário
client.post('/api/auth/register', json={
'email': 'teste@test.com',
'password': 'senha123'
})
# Login
response = client.post('/api/auth/login', json={
'email': 'teste@test.com',
'password': 'senha123'
})
assert response.status_code == 200
assert 'access_token' in response.json
def test_login_invalido(client):
response = client.post('/api/auth/login', json={
'email': 'naoexiste@test.com',
'password': 'errado'
})
assert response.status_code == 401
Rodar:
pytest tests/
Deploy Produção
Railway (Recomendado)
1. Criar Procfile:
web: gunicorn run:app
2. railway.json:
{
"build": {
"builder": "NIXPACKS"
},
"deploy": {
"restartPolicyType": "ON_FAILURE"
}
}
3. Deploy:
# Instalar CLI
npm i -g @railway/cli
# Login
railway login
# Criar projeto
railway init
# Adicionar PostgreSQL
railway add
# Deploy
railway up
4. Variáveis ambiente:
railway variables set JWT_SECRET=seu-secret-aqui
railway variables set FLASK_ENV=production
Render
1. render.yaml:
services:
- type: web
name: minha-api
env: python
buildCommand: pip install -r requirements.txt
startCommand: gunicorn run:app
envVars:
- key: DATABASE_URL
fromDatabase:
name: postgres
property: connectionString
- key: JWT_SECRET
generateValue: true
- key: FLASK_ENV
value: production
databases:
- name: postgres
databaseName: meudb
user: postgres
2. Push GitHub → Auto deploy
Casos Reais Flask API
Caso 1: Backend Mobile App
App: E-commerce 50k usuários
Features API:
- Auth JWT (login, register, refresh)
- Produtos (CRUD, busca, filtros)
- Carrinho (add, remove, checkout)
- Pedidos (criar, rastrear)
- Pagamentos (Stripe webhook)
Infra:
- Railway (app)
- PostgreSQL (banco)
- Redis (cache)
- S3 (imagens)
Performance:
- 500 req/s pico
- Latência média: 180ms
- Uptime: 99.8%
Caso 2: API IA Chatbot
Bot WhatsApp + GPT-4
Endpoints:
# Webhook WhatsApp
@app.route('/webhook/whatsapp', methods=['POST'])
def webhook_whatsapp():
data = request.json
mensagem = data['message']['text']
numero = data['from']
# Processar com GPT-4
resposta = processar_ia(mensagem, numero)
# Enviar resposta
evolution_api.send_text(numero, resposta)
return {'status': 'ok'}, 200
# Histórico conversa
@app.route('/api/conversas/<numero>', methods=['GET'])
@jwt_required()
def historico(numero):
msgs = Mensagem.query.filter_by(
numero=numero
).order_by(Mensagem.created_at.desc()).limit(50).all()
return {
'mensagens': [m.to_dict() for m in msgs]
}, 200
Volume:
- 10k mensagens/dia
- 300 conversas ativas/dia
Próximos passos
- ChatGPT API Python - Integrar GPT-4 em Flask
- API Telegram Bot - Webhooks Telegram
- API WhatsApp Node.js - Alternativa Node.js
- Bot Discord Python - Discord bots
- Chatbot IA - Backend chatbots
- Automação IA - APIs workflows
Precisa desenvolver API Python profissional? A Agência Café Online já desenvolveu para 60+ empresas (ROI médio 800%). Consultoria grátis.
Sobre o autor: Felipe Zanoni desenvolve Flask APIs processando 5M+ requests/mês com autenticação JWT, PostgreSQL e deploy produção-ready para startups e empresas.
💬 Precisa de Ajuda para Implementar?
A Agência Café Online já ajudou dezenas de empresas a implementarem soluções de automação e IA, com resultados reais e mensuráveis.
Fale comigo:
- 📱 WhatsApp: Clique aqui para conversar
- 📸 Instagram: @fe_leads
- 🌐 Site: agenciacafeonline.com.br
💡 Consultoria inicial gratuita para avaliar seu caso e propor uma solução personalizada.