Set up Flask REST API with flask-smorest, OpenAPI docs, blueprint architecture, and dataclass models. Use when creating a new Flask API server, building REST endpoints, or setting up a production API.
Sets up a production-ready Flask REST API with flask-smorest for automatic OpenAPI/Swagger documentation. Creates a modular blueprint architecture with dataclass models for type-safe request/response handling. Use when starting a new Flask API project that needs clean structure, automatic docs, and scalable endpoint organization.
/plugin marketplace add jmazzahacks/byteforge-claude-skills/plugin install byteforge-skills@byteforge-claude-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill helps you set up a Flask REST API following a standardized pattern with flask-smorest for OpenAPI documentation, blueprint architecture, and dataclass models for request/response handling.
Use this skill when:
IMPORTANT: Before creating files, ask the user these questions:
"What is your project name?" (e.g., "materia-server", "trading-api", "myapp")
{project_name}.py (e.g., materia_server.py)"What features/endpoints do you need?" (e.g., "users", "tokens", "orders")
"Do you need database integration?" (yes/no)
"What port should the server run on?" (default: 5000)
Create these directories if they don't exist:
{project_root}/
├── blueprints/ # Blueprint modules (one per feature)
│ ├── __init__.py
│ └── {feature}.py
├── models/ # Dataclass models with to_dict/from_dict
│ ├── __init__.py
│ └── {feature}.py
└── {project_name}.py # Main application file
Create {project_name}.py using this template:
import os
import logging
from flask import Flask
from flask_cors import CORS
from flask_smorest import Api
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def create_app():
app = Flask(__name__)
app.config['API_TITLE'] = '{Project Name} API'
app.config['API_VERSION'] = 'v1'
app.config['OPENAPI_VERSION'] = '3.0.2'
app.config['OPENAPI_URL_PREFIX'] = '/'
app.config['OPENAPI_SWAGGER_UI_PATH'] = '/swagger'
app.config['OPENAPI_SWAGGER_UI_URL'] = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist/'
CORS(app)
api = Api(app)
from blueprints.{feature} import blp as {feature}_blp
api.register_blueprint({feature}_blp)
logger.info("Flask app initialized")
return app
if __name__ == '__main__':
port = int(os.environ.get('PORT', {port_number}))
app = create_app()
logger.info(f"Swagger UI: http://localhost:{port}/swagger")
app.run(host='0.0.0.0', port=port)
CRITICAL: Replace:
{Project Name} → Human-readable project name (e.g., "Materia Server"){project_name} → Snake case project name (e.g., "materia_server"){port_number} → Actual port number (e.g., 5151){feature} → Feature name from user's responseFor each feature, create a models file with dataclasses that include to_dict and from_dict methods:
models/{feature}.pyfrom dataclasses import dataclass
from typing import Optional
@dataclass
class {Feature}:
"""
{Feature} data model.
Includes validation in from_dict and serialization via to_dict.
"""
id: str
name: str
created_at: int
updated_at: Optional[int] = None
def to_dict(self) -> dict:
"""Serialize to dictionary for JSON response."""
return {
"id": self.id,
"name": self.name,
"created_at": self.created_at,
"updated_at": self.updated_at
}
@classmethod
def from_dict(cls, data: dict) -> "{Feature}":
"""
Create instance from dictionary with validation.
Args:
data: Dictionary with {feature} data
Returns:
{Feature} instance
Raises:
ValueError: If required fields are missing or invalid
"""
if "id" not in data:
raise ValueError("id is required")
if "name" not in data:
raise ValueError("name is required")
if "created_at" not in data:
raise ValueError("created_at is required")
return cls(
id=str(data["id"]),
name=str(data["name"]),
created_at=int(data["created_at"]),
updated_at=int(data["updated_at"]) if data.get("updated_at") else None
)
CRITICAL: Replace:
{Feature} → PascalCase feature name (e.g., "TradableToken"){feature} → Snake case feature name (e.g., "tradable_token")For each feature/endpoint, create a blueprint file:
blueprints/{feature}.pyimport logging
from flask import request, jsonify
from flask.views import MethodView
from flask_smorest import Blueprint, abort
from models.{feature} import {Feature}
logger = logging.getLogger(__name__)
blp = Blueprint('{feature}', __name__, url_prefix='/api', description='{Feature} API')
@blp.route('/{feature}')
class {Feature}ListResource(MethodView):
def get(self):
"""Get list of {feature}s."""
try:
limit = request.args.get('limit', 100, type=int)
offset = request.args.get('offset', 0, type=int)
# TODO: Implement logic to fetch {feature}s
items = []
return jsonify({
"data": [item.to_dict() for item in items],
"limit": limit,
"offset": offset
})
except ValueError as e:
logger.warning(f"Bad request: {e}")
abort(400, message=str(e))
except Exception as e:
logger.exception(f"Error fetching {feature}s: {e}")
abort(500, message="Internal server error")
def post(self):
"""Create a new {feature}."""
try:
data = request.get_json()
if not data:
abort(400, message="Request body is required")
item = {Feature}.from_dict(data)
# TODO: Implement logic to save {feature}
return jsonify(item.to_dict()), 201
except ValueError as e:
logger.warning(f"Validation error: {e}")
abort(400, message=str(e))
except Exception as e:
logger.exception(f"Error creating {feature}: {e}")
abort(500, message="Internal server error")
@blp.route('/{feature}/<string:item_id>')
class {Feature}Resource(MethodView):
def get(self, item_id: str):
"""Get a single {feature} by ID."""
try:
# TODO: Implement logic to fetch {feature} by ID
item = None
if not item:
abort(404, message=f"{Feature} not found: {item_id}")
return jsonify(item.to_dict())
except Exception as e:
logger.exception(f"Error fetching {feature}: {e}")
abort(500, message="Internal server error")
def put(self, item_id: str):
"""Update a {feature}."""
try:
data = request.get_json()
if not data:
abort(400, message="Request body is required")
# TODO: Implement logic to update {feature}
return jsonify({"message": "Updated"})
except ValueError as e:
logger.warning(f"Validation error: {e}")
abort(400, message=str(e))
except Exception as e:
logger.exception(f"Error updating {feature}: {e}")
abort(500, message="Internal server error")
def delete(self, item_id: str):
"""Delete a {feature}."""
try:
# TODO: Implement logic to delete {feature}
return jsonify({"message": "Deleted"})
except Exception as e:
logger.exception(f"Error deleting {feature}: {e}")
abort(500, message="Internal server error")
CRITICAL: Replace:
{Feature} → PascalCase feature name (e.g., "TradableToken"){feature} → Snake case feature name (e.g., "tradable_token")If the project needs shared services (database, API clients, etc.), create a singleton manager:
common.py"""
Singleton manager for shared service instances.
Provides centralized initialization of database connections, API clients,
and other shared resources.
"""
import os
import logging
logger = logging.getLogger(__name__)
class ServiceManager:
"""
Singleton manager for shared service instances.
Ensures only one instance of each service is created and reused
across all blueprints.
"""
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(ServiceManager, cls).__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if self._initialized:
return
# Initialize services
self._db = None
self._initialized = True
logger.info("ServiceManager initialized")
def get_database(self):
"""
Get database connection instance.
Returns:
Database connection instance (lazy initialization)
"""
if self._db is None:
# Import database driver
from src.{project_name}.database import Database
# Get connection parameters from environment
db_host = os.environ.get('{PROJECT_NAME}_DB_HOST', 'localhost')
db_name = os.environ.get('{PROJECT_NAME}_DB_NAME', '{project_name}')
db_user = os.environ.get('{PROJECT_NAME}_DB_USER', '{project_name}')
db_passwd = os.environ.get('{PROJECT_NAME}_DB_PASSWORD')
if not db_passwd:
raise ValueError("{PROJECT_NAME}_DB_PASSWORD environment variable required")
self._db = Database(db_host, db_name, db_user, db_passwd)
logger.info("Database connection initialized")
return self._db
# Global singleton instance
service_manager = ServiceManager()
CRITICAL: Replace:
{PROJECT_NAME} → Uppercase project name (e.g., "MATERIA_SERVER"){project_name} → Snake case project name (e.g., "materia_server")example.envCreate or update example.env with required environment variables:
# Server Configuration
PORT={port_number}
DEBUG=False
# Database Configuration (if applicable)
{PROJECT_NAME}_DB_HOST=localhost
{PROJECT_NAME}_DB_NAME={project_name}
{PROJECT_NAME}_DB_USER={project_name}
{PROJECT_NAME}_DB_PASSWORD=your_password_here
# Optional: CORS Configuration
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8080
CRITICAL: Replace:
{port_number} → Actual port number (e.g., 5151){PROJECT_NAME} → Uppercase project name (e.g., "MATERIA_SERVER"){project_name} → Snake case project name (e.g., "materia_server").env (gitignored)Instruct the user to copy example.env to .env and fill in actual values:
# Copy example.env to .env and update with actual values
cp example.env .env
Add .env to .gitignore if not already present:
# Environment variables
.env
Create requirements.txt with dependencies (no version pinning):
# Flask and API framework
Flask
flask-smorest
flask-cors
# Environment variable management
python-dotenv
# Production server (optional but recommended)
gunicorn
# Database (if needed)
psycopg2-binary
Create blueprints/__init__.py:
"""
Blueprint modules for {Project Name} API.
Each blueprint represents a distinct feature or resource endpoint.
"""
Create or update README.md with:
# Copy example environment file
cp example.env .env
# Edit .env and fill in actual values
# Then install dependencies
pip install -r requirements.txt
# Development mode
python {project_name}.py
# Production mode with Gunicorn
gunicorn -w 4 -b 0.0.0.0:{port_number} '{project_name}:create_app()'
Copy example.env to .env and configure:
Server Configuration:
PORT - Server port (default: {port_number})DEBUG - Enable debug mode (default: False)Database (if applicable):
{PROJECT_NAME}_DB_HOST - Database host (default: localhost){PROJECT_NAME}_DB_NAME - Database name (default: {project_name}){PROJECT_NAME}_DB_USER - Database user (default: {project_name}){PROJECT_NAME}_DB_PASSWORD - Database password (REQUIRED)Once running, access Swagger UI at:
http://localhost:{port_number}/swagger
This pattern follows these principles:
create_app() pattern for testing and flexibilityIf database is needed, use postgres-setup skill first:
User: "Set up postgres database for my project"
Then reference the database in your blueprints via the singleton manager:
from common import service_manager
db = service_manager.get_database()
If publishing as a package, use python-pypi-setup skill:
User: "Set up Python package for PyPI"
User: "Set up Flask API server for my project"
Claude: "What is your project name?"
User: "crypto-tracker"
Claude: "What features/endpoints do you need?"
User: "prices, tokens, portfolio"
Claude: "Do you need database integration?"
User: "yes"
Claude: "What port should the server run on?"
User: "8080"
Claude:
crypto_tracker.py with Flask appmodels/ directory with dataclass models:
prices.py, tokens.py, portfolio.pyblueprints/ directory with endpoint handlers:
prices.py, tokens.py, portfolio.pycommon.py with ServiceManager singletonrequirements.txt with dependenciesIf user requests Docker, reference the flask-docker-deployment skill for production-ready containerization with automated versioning and health checks.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.