PYREST-FRAMEWORK v2.0.1 - Documentação Técnica
Visão Geral
O PYREST-FRAMEWORK é um framework Python moderno e robusto para criação de APIs REST, inspirado no Express.js do Node.js. Desenvolvido especificamente para projetos acadêmicos de Análise e Desenvolvimento de Sistemas (ADS), oferece uma experiência de desenvolvimento profissional com arquitetura MVC completa.
Características Principais
- ✅ Arquitetura MVC Completa: Controllers, Services, Models e Repositories
- ✅ Integração com Prisma ORM: Suporte a PostgreSQL, MySQL e SQLite
- ✅ Sistema de Validação Robusto: Validação automática de dados
- ✅ CLI Avançado: Criação automática de projetos com estrutura completa
- ✅ Middlewares Avançados: CORS, logging, auth, rate limiting
- ✅ Sintaxe Familiar: Inspirado no Express.js
- ✅ Documentação Extensa: Guias completos e exemplos
- ✅ Sistema de Testes: Cobertura abrangente
- ✅ Exemplos Práticos: Código real e funcional
Índice
- Instalação
- Primeiros Passos
- Conceitos Fundamentais
- Roteamento
- Request e Response
- Middlewares
- Tratamento de Erros
- CLI (Command Line Interface)
- Exemplos Avançados
- Testes
- Deploy
- Referência da API
Instalação
Requisitos do Sistema
- Python: 3.7 ou superior
- Sistema Operacional: Windows, macOS, Linux
- Memória: Mínimo 128MB RAM
- Espaço: Mínimo 50MB de espaço em disco
Instalação via pip
pip install pyrest-framework
Instalação em Desenvolvimento
git clone https://github.com/mamadusamadev/pyrest-framework.git
cd pyrest-framework
pip install -e .
Verificação da Instalação
# Testa a instalação
python install_and_test.py
# Ou usa o CLI
pyrest info
Primeiros Passos
Hello World
from pyrest import create_app
# Cria a aplicação
app = create_app()
# Define uma rota
@app.get('/')
def hello_world(req, res):
res.json({
"message": "Hello, PYREST-FRAMEWORK!",
"version": "2.0.1"
})
# Inicia o servidor
if __name__ == '__main__':
app.listen(port=3000, debug=True)
Usando o CLI
# Cria um novo projeto
pyrest create minha-api
# Entra no projeto
cd minha-api
# Inicia o servidor
pyrest serve --debug
# Ou inicia um servidor de exemplo
pyrest serve --quick
Conceitos Fundamentais
Arquitetura do Framework
O PYREST-FRAMEWORK segue uma arquitetura modular e extensível:
┌─────────────────┐
│ Application │ ← Classe principal
├─────────────────┤
│ Routes │ ← Sistema de roteamento
├─────────────────┤
│ Middlewares │ ← Camada de middlewares
├─────────────────┤
│ Request/Res │ ← Objetos HTTP
└─────────────────┘
Fluxo de Requisição
- Requisição HTTP chega ao servidor
- Middlewares são executados em sequência
- Roteamento encontra o handler correto
- Handler processa a requisição
- Response é enviada de volta
Componentes Principais
PyRestFramework (App)
- Classe principal do framework
- Gerencia rotas, middlewares e configurações
- Responsável pelo ciclo de vida da aplicação
Route
- Representa uma rota HTTP
- Suporte a parâmetros dinâmicos (
:id) - Matching baseado em regex
Request
- Objeto que representa a requisição HTTP
- Parsing automático de JSON e form data
- Acesso a headers, query params, body
Response
- Objeto que representa a resposta HTTP
- Múltiplos formatos de resposta (JSON, HTML, XML)
- Headers de segurança e cache
Roteamento
Métodos HTTP Suportados
@app.get('/users') # GET
@app.post('/users') # POST
@app.put('/users/:id') # PUT
@app.delete('/users/:id') # DELETE
@app.patch('/users/:id') # PATCH
@app.options('/users') # OPTIONS
Parâmetros de Rota
@app.get('/users/:id')
def get_user(req, res):
user_id = req.params['id'] # Acessa o parâmetro
res.json({"id": user_id})
# Requisição: GET /users/123
# Resultado: {"id": "123"}
Query Parameters
@app.get('/users')
def get_users(req, res):
page = req.get_query('page', '1')
limit = req.get_query('limit', '10')
res.json({
"page": page,
"limit": limit
})
# Requisição: GET /users?page=2&limit=20
Múltiplas Rotas
@app.get('/')
@app.get('/home')
def home(req, res):
res.json({"message": "Welcome!"})
Request e Response
Objeto Request
Propriedades Principais
req.method # Método HTTP (GET, POST, etc.)
req.path # Caminho da requisição
req.headers # Headers HTTP (dict)
req.body # Corpo da requisição (string)
req.params # Parâmetros de rota (dict)
req.query # Query parameters (dict)
req.json_data # Dados JSON parseados (dict)
req.form_data # Dados de formulário (dict)
Métodos Úteis
# Headers
user_agent = req.get_header('user-agent', 'Unknown')
# Query Parameters
page = req.get_query('page', '1')
# Route Parameters
user_id = req.get_param('id')
# JSON Data
data = req.get_json()
name = req.get_json('name', 'Default')
# Form Data
form_data = req.get_form()
email = req.get_form('email')
# Verificações
if req.is_json():
data = req.get_json()
if req.is_secure():
# Requisição HTTPS
Objeto Response
Métodos de Resposta
# JSON Response
res.json({"message": "Success"})
# Text Response
res.send("Hello World")
# HTML Response
res.html("<h1>Hello</h1>")
# XML Response
res.xml("<root><message>Hello</message></root>")
# File Response
res.file(content, "file.txt", "text/plain")
# Redirect
res.redirect('/new-page')
Headers e Status
# Status Code
res.status(201).json(data)
# Headers
res.header('Content-Type', 'application/json')
res.header('Authorization', 'Bearer token')
# Multiple Headers
res.headers_dict({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
})
Cookies e CORS
# Cookies
res.cookie('session', 'abc123', max_age=3600, secure=True)
res.clear_cookie('session')
# CORS
res.cors(origin='https://example.com', credentials=True)
Middlewares
Middlewares Incluídos
CORS (Cross-Origin Resource Sharing)
from pyrest import Middlewares
app.use(Middlewares.cors())
app.use(Middlewares.cors(
origin='https://example.com',
credentials=True
))
Logger
app.use(Middlewares.logger()) # combined
app.use(Middlewares.logger('dev')) # desenvolvimento
app.use(Middlewares.logger('common')) # comum
Body Parser
app.use(Middlewares.body_parser())
app.use(Middlewares.json_parser())
app.use(Middlewares.urlencoded())
Security Headers
app.use(Middlewares.security_headers())
Rate Limiting
app.use(Middlewares.rate_limit(
max_requests=100,
window_ms=60000
))
Authentication
app.use(Middlewares.auth_required())
Static Files
app.use(Middlewares.static_files('public', '/static'))
Middleware Personalizado
def custom_middleware(req, res):
# Adiciona timestamp à requisição
req.timestamp = time.time()
# Continua a execução
return True
app.use(custom_middleware)
Middleware que Para a Execução
def auth_middleware(req, res):
token = req.get_header('authorization')
if not token:
res.status(401).json({
"error": "Unauthorized"
})
return False # Para a execução
return True # Continua a execução
app.use(auth_middleware)
Tratamento de Erros
Handlers de Erro Personalizados
@app.error_handler(404)
def not_found(req, res):
res.json({
"error": "Not Found",
"message": f"Route '{req.path}' not found"
})
@app.error_handler(500)
def server_error(req, res):
res.json({
"error": "Internal Server Error",
"message": "Something went wrong"
})
Tratamento de Exceções
@app.get('/users/:id')
def get_user(req, res):
try:
user_id = int(req.params['id'])
user = find_user(user_id)
if not user:
res.status(404).json({
"error": "User not found"
})
return
res.json(user)
except ValueError:
res.status(400).json({
"error": "Invalid ID format"
})
except Exception as e:
res.status(500).json({
"error": "Internal server error",
"message": str(e)
})
Middleware de Tratamento Global
def error_handler_middleware(req, res):
try:
# Continua a execução
pass
except Exception as e:
res.status(500).json({
"error": "Internal Server Error",
"message": str(e)
})
return False
app.use(error_handler_middleware)
CLI (Command Line Interface)
Comandos Disponíveis
pyrest create <nome>
Cria um novo projeto com estrutura completa.
# Criação básica
pyrest create minha-api
# Com diretório específico
pyrest create minha-api -o /path/to/output
Estrutura criada:
minha-api/
├── app.py # Aplicação principal
├── README.md # Documentação
├── requirements.txt # Dependências
├── .gitignore # Git ignore
├── routes/ # Rotas organizadas
├── middlewares/ # Middlewares customizados
├── models/ # Modelos de dados
├── utils/ # Utilitários
└── tests/ # Testes
pyrest serve
Inicia um servidor PyRest.
# Carrega app.py (padrão)
pyrest serve
# Carrega arquivo específico
pyrest serve app.py
# Servidor de exemplo
pyrest serve --quick
# Configurações específicas
pyrest serve --port 8080 --host 0.0.0.0 --debug
pyrest info
Mostra informações sobre o framework.
pyrest info
Opções do Comando Serve
| Opção | Descrição | Padrão |
|---|---|---|
--port |
Porta do servidor | 3000 |
--host |
Host do servidor | localhost |
--debug |
Modo debug | False |
--quick |
Servidor de exemplo | False |
Exemplos Avançados
API REST Completa
from pyrest import create_app, Middlewares
app = create_app()
# Middlewares
app.use(Middlewares.cors())
app.use(Middlewares.logger('dev'))
app.use(Middlewares.json_parser())
# Simula banco de dados
users = []
# GET /users
@app.get('/users')
def get_users(req, res):
page = int(req.get_query('page', '1'))
limit = int(req.get_query('limit', '10'))
start = (page - 1) * limit
end = start + limit
paginated_users = users[start:end]
res.json({
"users": paginated_users,
"pagination": {
"page": page,
"limit": limit,
"total": len(users)
}
})
# POST /users
@app.post('/users')
def create_user(req, res):
data = req.json_data
if not data or 'name' not in data:
res.status(400).json({
"error": "Name is required"
})
return
new_user = {
"id": len(users) + 1,
"name": data['name'],
"email": data.get('email', '')
}
users.append(new_user)
res.status(201).json(new_user)
# GET /users/:id
@app.get('/users/:id')
def get_user(req, res):
try:
user_id = int(req.params['id'])
user = next((u for u in users if u['id'] == user_id), None)
if user:
res.json(user)
else:
res.status(404).json({
"error": "User not found"
})
except ValueError:
res.status(400).json({
"error": "Invalid ID"
})
# PUT /users/:id
@app.put('/users/:id')
def update_user(req, res):
try:
user_id = int(req.params['id'])
data = req.json_data
user_index = next((i for i, u in enumerate(users)
if u['id'] == user_id), None)
if user_index is None:
res.status(404).json({
"error": "User not found"
})
return
users[user_index].update(data)
users[user_index]['id'] = user_id
res.json(users[user_index])
except ValueError:
res.status(400).json({
"error": "Invalid ID"
})
# DELETE /users/:id
@app.delete('/users/:id')
def delete_user(req, res):
try:
user_id = int(req.params['id'])
user_index = next((i for i, u in enumerate(users)
if u['id'] == user_id), None)
if user_index is None:
res.status(404).json({
"error": "User not found"
})
return
deleted_user = users.pop(user_index)
res.json({
"message": "User deleted",
"user": deleted_user
})
except ValueError:
res.status(400).json({
"error": "Invalid ID"
})
if __name__ == '__main__':
app.listen(port=3000, debug=True)
Autenticação com JWT
import jwt
import hashlib
from datetime import datetime, timedelta
from pyrest import create_app, Middlewares
app = create_app()
# Configurações
JWT_SECRET = "your-secret-key"
JWT_EXPIRATION = 3600
# Middleware de autenticação
def auth_middleware(req, res):
# Rotas públicas
public_routes = ['/login', '/register']
if req.path in public_routes:
return True
# Verifica token
auth_header = req.get_header('authorization')
if not auth_header or not auth_header.startswith('Bearer '):
res.status(401).json({
"error": "Token required"
})
return False
token = auth_header[7:]
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
req.user = payload
return True
except:
res.status(401).json({
"error": "Invalid token"
})
return False
app.use(auth_middleware)
# Login
@app.post('/login')
def login(req, res):
data = req.json_data
# Validação básica
if not data or 'username' not in data or 'password' not in data:
res.status(400).json({
"error": "Username and password required"
})
return
# Aqui você faria a validação real
if data['username'] == 'admin' and data['password'] == 'password':
payload = {
'user_id': 1,
'username': data['username'],
'exp': datetime.utcnow() + timedelta(seconds=JWT_EXPIRATION)
}
token = jwt.encode(payload, JWT_SECRET, algorithm='HS256')
res.json({
"message": "Login successful",
"token": token,
"expires_in": JWT_EXPIRATION
})
else:
res.status(401).json({
"error": "Invalid credentials"
})
# Rota protegida
@app.get('/profile')
def get_profile(req, res):
res.json({
"user_id": req.user['user_id'],
"username": req.user['username']
})
if __name__ == '__main__':
app.listen(port=3000, debug=True)
Testes
Executando Testes
# Todos os testes
pytest
# Com cobertura
pytest --cov=pyrest
# Testes específicos
pytest tests/test_core.py -v
# Com relatório HTML
pytest --cov=pyrest --cov-report=html
Escrevendo Testes
import unittest
from unittest.mock import Mock
from pyrest import create_app
class TestAPI(unittest.TestCase):
def setUp(self):
self.app = create_app()
def test_home_route(self):
# Simula requisição
req = Mock()
req.method = 'GET'
req.path = '/'
res = Mock()
res.json = Mock()
# Executa handler
@self.app.get('/')
def home(req, res):
res.json({"message": "Hello"})
# Verifica se rota foi registrada
self.assertEqual(len(self.app.routes), 1)
route = self.app.routes[0]
self.assertEqual(route.method, 'GET')
self.assertEqual(route.path, '/')
Testes de Integração
import requests
def test_api_integration():
# Inicia servidor em thread separada
import threading
import time
def start_server():
app.listen(port=3001)
server_thread = threading.Thread(target=start_server)
server_thread.daemon = True
server_thread.start()
time.sleep(1) # Aguarda servidor iniciar
# Testa API
response = requests.get('http://localhost:3001/')
assert response.status_code == 200
assert response.json()['message'] == 'Hello'
Deploy
Ambiente de Desenvolvimento
# Instalação
pip install -r requirements.txt
# Execução
python app.py
# Ou usando CLI
pyrest serve --debug
Ambiente de Produção
# Instalação
pip install pyrest-framework
# Execução
pyrest serve --host 0.0.0.0 --port 80
Docker
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 3000
CMD ["python", "app.py"]
Nginx (Proxy Reverso)
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Systemd Service
[Unit]
Description=PyRest API
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/api
ExecStart=/usr/bin/python3 app.py
Restart=always
[Install]
WantedBy=multi-user.target
Referência da API
Para documentação completa da API, consulte:
- API Reference - Referência detalhada de todas as classes e métodos
- Changelog - Histórico de versões e mudanças
Classes Principais
PyRestFramework
get(path, handler=None)- Define rota GETpost(path, handler=None)- Define rota POSTput(path, handler=None)- Define rota PUTdelete(path, handler=None)- Define rota DELETEpatch(path, handler=None)- Define rota PATCHoptions(path, handler=None)- Define rota OPTIONSuse(middleware)- Adiciona middlewareerror_handler(status_code)- Define handler de errolisten(port=3000, host='localhost', debug=False)- Inicia servidor
Request
get_header(name, default=None)- Obtém headerget_query(name, default=None)- Obtém query parameterget_param(name, default=None)- Obtém parâmetro de rotaget_json(key=None, default=None)- Obtém dados JSONget_form(key=None, default=None)- Obtém dados de formuláriois_json()- Verifica se é JSONis_form()- Verifica se é form datais_secure()- Verifica se é HTTPS
Response
status(code)- Define status codeheader(key, value)- Define headerjson(data, indent=None, ensure_ascii=False)- Resposta JSONsend(data)- Resposta textohtml(content)- Resposta HTMLxml(content)- Resposta XMLfile(content, filename, mimetype=None)- Resposta arquivoredirect(url, permanent=False)- Redirecionamentocookie(name, value, **options)- Define cookiecors(**options)- Headers CORS
Middlewares
cors(**options)- Middleware CORSlogger(format='combined')- Middleware de loggingbody_parser()- Middleware body parserjson_parser()- Middleware JSON parserurlencoded()- Middleware URL encodedstatic_files(directory, prefix='/static')- Middleware static filesrate_limit(max_requests=100, window_ms=60000)- Middleware rate limitingauth_required()- Middleware de autenticaçãoerror_handler()- Middleware de tratamento de errossecurity_headers()- Middleware de headers de segurança
Suporte e Comunidade
Recursos Adicionais
- GitHub: https://github.com/mamadusamadev/pyrest-framework
- Issues: Para reportar bugs ou solicitar features
- Discussions: Para dúvidas e discussões
- Wiki: Documentação adicional e tutoriais
Contribuindo
- Fork o projeto
- Crie uma branch para sua feature
- Commit suas mudanças
- Push para a branch
- Abra um Pull Request
Licença
Este projeto está licenciado sob a Licença MIT - veja o arquivo LICENSE para detalhes.
Conclusão
O PYREST-FRAMEWORK v2.0.1 oferece uma solução completa e profissional para desenvolvimento de APIs REST em Python. Com sua arquitetura MVC moderna, integração com Prisma ORM, sistema de validação robusto e CLI avançado, é ideal tanto para aprendizado quanto para projetos reais em produção.
Principais Melhorias da v2.0.1
- ✅ Arquitetura MVC Completa: Separação clara entre Controllers, Services, Models e Repositories
- ✅ Integração com Prisma: Suporte nativo a PostgreSQL, MySQL e SQLite
- ✅ Sistema de Validação: Validação automática de dados com múltiplos validadores
- ✅ CLI Avançado: Criação automática de projetos com estrutura profissional
- ✅ Fallback Inteligente: Funciona com ou sem banco de dados
- ✅ Documentação Completa: Guias detalhados para todas as funcionalidades
Para começar rapidamente:
# Instalação básica
pip install pyrest-framework
# Instalação com suporte a banco de dados
pip install pyrest-framework[database]
# Criação de projeto com estrutura MVC completa
pyrest create minha-api
# Execução
cd minha-api
pyrest serve --debug
Happy coding! 🚀
Metadata
Release files for pyrest-framework 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyrest_framework-2.0.1.tar.gz | 76.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyrest_framework-2.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 121.7 kB
Release files / pyrest_framework-2.0.1.tar.gz
| Download URL | pyrest_framework-2.0.1.tar.gz |
|---|---|
| Size | 76.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fe7ab8f363d3788033b96aab92bf9dc03a5d925dbbd9223ca3bace4eceb718ef
|
|
BLAKE2b-256 checksum How to use checksums |
fc91bc555ae291145dcbeed2c42b97c64ce7968b3702948edb32290983778c78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.2
|
Release files / pyrest_framework-2.0.1-py3-none-any.whl
| Download URL | pyrest_framework-2.0.1-py3-none-any.whl |
|---|---|
| Size | 44.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0646b091b3f3f3c97ec25ee6b7e6f106cbb06e3f5d9650446695c0a7492ec13b
|
|
BLAKE2b-256 checksum How to use checksums |
2cd5a116018ade05954c2ca41b753ac6637058ac7262390999b7ec6d285be123
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.2
|