This guide covers development practices, tools, and workflows for contributing to the Flask API Boilerplate.
Before you begin, ensure you have:
- Python 3.10 or higher
- PostgreSQL 14 or higher
- Redis 6 or higher
- Docker and docker-compose (optional, but recommended)
- Clone and setup:
git clone https://github.com/julianfleck/flask-structured-api.git
cd flask-structured-api
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/macOS
# or
venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt
- Install pre-commit hooks:
pre-commit install
app/core/
: Framework components (don't modify)app/custom/
: Your custom implementationsapp/api/core/
: Core API endpointsapp/api/custom/
: Your custom endpoints
- Create new endpoint in
app/api/custom/v1/
:
# app/api/custom/v1/hello.py
from flask import Blueprint
from flask_structured_api.core.auth import require_auth
bp = Blueprint('hello', name)
@bp.route('/hello')
@require_auth
def hello():
return {"message": "Hello, World!"}
- Register the endpoint in your custom module:
# app/custom/init.py
def init_custom_routes(app):
from app.api.custom.v1.hello import bp
app.register_blueprint(bp, url_prefix='/api/v1')
We use several tools to maintain code quality:
- Black for code formatting
- isort for import sorting
- flake8 for linting
- mypy for type checking
Configuration is in pyproject.toml
:
[tool.black]
line-length = 88
target-version = ['py310']
include = '\.pyi?$'
[tool.isort]
profile = "black"
multi_line_output = 3
# Run all tests
pytest
# Run with coverage
pytest --cov=app
# Run specific test file
pytest tests/test_api/test_auth.py
# Run tests matching pattern
pytest -k "test_auth"
Example test structure:
# tests/test_api/test_auth.py
import pytest
from app.models import User
@pytest.fixture
def test_user(db_session):
user = User(
email="test@example.com",
hashed_password="hashed_pwd"
)
db_session.add(user)
db_session.commit()
return user
def test_login_success(client, test_user):
response = client.post("/api/v1/auth/login", json={
"email": "test@example.com",
"password": "password123"
})
assert response.status_code == 200
assert "access_token" in response.json["data"]
# Create new migration
flask db revision --autogenerate -m "description"
# Apply migrations
flask db upgrade
# Rollback migration
flask db downgrade
The API documentation is automatically generated using Flask-OpenAPI:
# app/core/openapi.py
from flask_openapi3 import OpenAPI
from app.models.requests import UserCreateRequest
from app.models.responses import UserResponse
app = OpenAPI(__name__)
@app.post("/users", responses={"200": UserResponse})
def create_user(body: UserCreateRequest):
"""Create a new user"""
return create_user_logic(body)
Access the documentation at /docs
or /redoc
when running the API.
Here's the updated CLI commands section for docs/development/README.md
:
The API provides CLI commands for common management tasks:
# Authentication
flask tokens create --email user@example.com --expires 60 # Create JWT token
flask api-keys create --email user@example.com --name "API" # Create API key
flask api-keys list --email user@example.com # List API keys
flask api-keys revoke --email user@example.com --key-id 1 # Revoke API key
# User Management
flask users create-admin # Create admin user
# Database
flask db upgrade # Run migrations
flask db downgrade # Rollback migration
flask db revision --autogenerate -m "description" # Create migration
For detailed usage of any command:
flask <command> --help
Example outputs:
# Creating a JWT token
$ flask tokens create --email admin@example.com
Access Token (expires in 60 minutes):
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Refresh Token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
# Creating an API key
$ flask api-keys create --email admin@example.com --name "Production API"
API Key (save this, it won't be shown again):
sk_live_abc123...
# Listing API keys
$ flask api-keys list --email admin@example.com
ID: 1
Name: Production API
Created: 2024-03-15 10:30:00
Last used: 2024-03-15 12:45:00
Expires: Never
Active: True
Scopes: read:items, write:items
The API uses Click to create CLI commands. Here's how to add your own commands:
- Create a new file in
app/cli/your_commands.py
:
import click
from flask.cli import AppGroup
# Create a command group
your_cli = AppGroup('your-group', help='Description of your commands')
# Add a command to the group
@your_cli.command('command-name')
@click.option('--required-arg', prompt=True, help='Argument description')
@click.option('--optional-arg', default='default', help='Optional argument')
def your_command(required_arg: str, optional_arg: str):
"""Command description shown in --help"""
# Your command logic here
click.echo(f"Doing something with {required_arg}")
- Register your commands in
app/cli/__init__.py
:
from flask import Flask
from app.cli.your_commands import your_cli
def init_cli(app: Flask):
app.cli.add_command(your_cli)
- Use your command:
# Show help
flask your-group --help
# Run command
flask your-group command-name --required-arg value
Key points:
- Use
AppGroup
to group related commands - Add
@click.option()
for command arguments - Provide help text for commands and options
- Use
click.echo()
for output - Register commands in
init_cli()
# Set breakpoint in code
breakpoint()
# Or use VSCode debugger configuration
{
"name": "Flask API",
"type": "python",
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "src.flask_structured_api.main:create_app",
"FLASK_ENV": "development"
},
"args": [
"run",
"--debug"
]
}
We use type hints throughout the codebase:
from typing import Optional, List
src.flask_structured_api.models import User
def get_users(active_only: bool = False) -> List[User]:
"""Get list of users"""
query = User.query
if active_only:
query = query.filter_by(is_active=True)
return query.all()
def get_user_by_id(user_id: int) -> Optional[User]:
"""Get user by ID"""
return User.query.get(user_id)
- Create feature branch
git checkout -b feature/your-feature
- Make changes and commit
git add .
git commit -m "feat: add new feature"
- Push and create PR
git push origin feature/your-feature
- Use docstrings for functions and classes
- Keep README files up to date
- Document API changes in CHANGELOG.md
- Add type hints to all functions
### Database Connection Failed
- Check if PostgreSQL is running
- Verify DATABASE_URL in .env
- Ensure database exists
### Redis Connection Failed
- Check if Redis is running
- Verify REDIS_URL in .env
- Check Redis port availability
### Token Issues
- Verify SECRET_KEY and JWT_SECRET_KEY are set
- Check token expiration
- Ensure proper Authorization header format
For more details on specific topics: