Python Flask API: Tutorial Completo 2026

📚 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

  1. ChatGPT API Python - Integrar GPT-4 em Flask
  2. API Telegram Bot - Webhooks Telegram
  3. API WhatsApp Node.js - Alternativa Node.js
  4. Bot Discord Python - Discord bots
  5. Chatbot IA - Backend chatbots
  6. 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:

💡 Consultoria inicial gratuita para avaliar seu caso e propor uma solução personalizada.