<< All versions
Skill v1.0.1
currentAutomated scan100/100diegosouzapw/awesome-omni-skill/flask-api-development-aj-geddes
1 files
──Details
PublishedMay 19, 2026 at 07:27 AM
Content Hashsha256:3010ce579d8bf595...
Git SHAa6b3c3005ced
Bump Typepatch
──Files
Files (1 file, 13.0 KB)
SKILL.md13.0 KBactive
SKILL.md · 454 lines · 13.0 KB
version: "1.0.1" name: flask-api-development description: Develop lightweight Flask APIs with routing, blueprints, database integration, authentication, and request/response handling. Use when building RESTful APIs, microservices, or lightweight web services with Flask.
Flask API Development
Overview
Create efficient Flask APIs with blueprints for modular organization, SQLAlchemy for ORM, JWT authentication, comprehensive error handling, and proper request validation following REST principles.
When to Use
- Building RESTful APIs with Flask
- Creating microservices with minimal overhead
- Implementing lightweight authentication systems
- Designing API endpoints with proper validation
- Integrating with relational databases
- Building request/response handling systems
Instructions
1. Flask Application Setup
python
# app.pyfrom flask import Flask, request, jsonifyfrom flask_cors import CORSfrom flask_sqlalchemy import SQLAlchemyfrom flask_jwt_extended import JWTManagerimport osapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')app.config['JWT_SECRET_KEY'] = os.getenv('JWT_SECRET_KEY', 'dev-secret')app.config['JSON_SORT_KEYS'] = Falsedb = SQLAlchemy(app)jwt = JWTManager(app)CORS(app)# Request ID middleware@app.before_requestdef assign_request_id():import uuidrequest.request_id = str(uuid.uuid4())# Error handlers@app.errorhandler(400)def bad_request(error):return jsonify({'error': 'Bad Request','message': str(error),'request_id': request.request_id}), 400@app.errorhandler(404)def not_found(error):return jsonify({'error': 'Not Found','message': 'Resource does not exist','request_id': request.request_id}), 404@app.errorhandler(500)def internal_error(error):db.session.rollback()return jsonify({'error': 'Internal Server Error','request_id': request.request_id}), 500if __name__ == '__main__':app.run(debug=os.getenv('ENV') != 'production')
2. Database Models with SQLAlchemy
python
# models.pyfrom datetime import datetimefrom flask_sqlalchemy import SQLAlchemyfrom sqlalchemy.dialects.postgresql import UUIDimport uuiddb = SQLAlchemy()class User(db.Model):__tablename__ = 'users'id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)email = db.Column(db.String(255), unique=True, nullable=False, index=True)password_hash = db.Column(db.String(255), nullable=False)first_name = db.Column(db.String(100))last_name = db.Column(db.String(100))role = db.Column(db.String(20), default='user', index=True)is_active = db.Column(db.Boolean, default=True)created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)# Relationshipsposts = db.relationship('Post', backref='author', lazy='dynamic', cascade='all, delete-orphan')def __repr__(self):return f'<User {self.email}>'def set_password(self, password):from werkzeug.security import generate_password_hashself.password_hash = generate_password_hash(password)def verify_password(self, password):from werkzeug.security import check_password_hashreturn check_password_hash(self.password_hash, password)def to_dict(self):return {'id': str(self.id),'email': self.email,'first_name': self.first_name,'last_name': self.last_name,'role': self.role,'created_at': self.created_at.isoformat()}class Post(db.Model):__tablename__ = 'posts'id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)title = db.Column(db.String(255), nullable=False, index=True)content = db.Column(db.Text, nullable=False)published = db.Column(db.Boolean, default=False)user_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False)created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)def to_dict(self):return {'id': str(self.id),'title': self.title,'content': self.content,'published': self.published,'author_id': str(self.user_id),'created_at': self.created_at.isoformat()}
3. Authentication and JWT
python
# auth.pyfrom flask import request, jsonifyfrom flask_jwt_extended import create_access_token, jwt_required, get_jwt_identityfrom functools import wrapsfrom models import User, dbdef authenticate_user(email, password):user = User.query.filter_by(email=email).first()if user and user.verify_password(password):return userreturn Nonedef login_required(f):@wraps(f)@jwt_required()def decorated_function(*args, **kwargs):identity = get_jwt_identity()user = User.query.get(identity)if not user or not user.is_active:return jsonify({'error': 'User not found or inactive'}), 401request.current_user = userreturn f(*args, **kwargs)return decorated_functiondef admin_required(f):@wraps(f)@login_requireddef decorated_function(*args, **kwargs):if request.current_user.role != 'admin':return jsonify({'error': 'Admin access required'}), 403return f(*args, **kwargs)return decorated_function# routes/auth.pyfrom flask import Blueprint, request, jsonifyfrom auth import authenticate_user, login_requiredfrom models import User, dbfrom flask_jwt_extended import create_access_tokenauth_bp = Blueprint('auth', __name__, url_prefix='/api/auth')@auth_bp.route('/login', methods=['POST'])def login():data = request.get_json()if not data or not data.get('email') or not data.get('password'):return jsonify({'error': 'Missing credentials'}), 400user = authenticate_user(data['email'], data['password'])if not user:return jsonify({'error': 'Invalid credentials'}), 401access_token = create_access_token(identity=str(user.id))return jsonify({'access_token': access_token,'user': user.to_dict()}), 200@auth_bp.route('/register', methods=['POST'])def register():data = request.get_json()if User.query.filter_by(email=data['email']).first():return jsonify({'error': 'Email already exists'}), 409user = User(email=data['email'], first_name=data.get('first_name'))user.set_password(data['password'])db.session.add(user)db.session.commit()return jsonify({'user': user.to_dict()}), 201@auth_bp.route('/profile', methods=['GET'])@login_requireddef get_profile():return jsonify({'user': request.current_user.to_dict()}), 200
4. Blueprints for Modular API Design
python
# routes/users.pyfrom flask import Blueprint, request, jsonifyfrom auth import login_required, admin_requiredfrom models import User, dbfrom sqlalchemy import or_users_bp = Blueprint('users', __name__, url_prefix='/api/users')@users_bp.route('', methods=['GET'])@login_requireddef list_users():page = request.args.get('page', 1, type=int)limit = request.args.get('limit', 20, type=int)search = request.args.get('q', '', type=str)query = User.queryif search:query = query.filter(or_(User.email.ilike(f'%{search}%'),User.first_name.ilike(f'%{search}%')))paginated = query.paginate(page=page, per_page=limit)return jsonify({'data': [user.to_dict() for user in paginated.items],'pagination': {'page': page,'limit': limit,'total': paginated.total,'pages': paginated.pages}}), 200@users_bp.route('/<user_id>', methods=['GET'])@login_requireddef get_user(user_id):user = User.query.get(user_id)if not user:return jsonify({'error': 'User not found'}), 404return jsonify({'user': user.to_dict()}), 200@users_bp.route('/<user_id>', methods=['PATCH'])@login_requireddef update_user(user_id):if str(request.current_user.id) != user_id:return jsonify({'error': 'Unauthorized'}), 403user = User.query.get(user_id)if not user:return jsonify({'error': 'User not found'}), 404data = request.get_json()if 'first_name' in data:user.first_name = data['first_name']if 'last_name' in data:user.last_name = data['last_name']db.session.commit()return jsonify({'user': user.to_dict()}), 200@users_bp.route('/<user_id>', methods=['DELETE'])@admin_requireddef delete_user(user_id):user = User.query.get(user_id)if not user:return jsonify({'error': 'User not found'}), 404db.session.delete(user)db.session.commit()return '', 204
5. Request Validation
python
# validators.pyfrom flask import request, jsonifyfrom functools import wrapsdef validate_json(*required_fields):def decorator(f):@wraps(f)def decorated_function(*args, **kwargs):if not request.is_json:return jsonify({'error': 'Request body must be JSON'}), 400data = request.get_json()missing = [field for field in required_fields if field not in data]if missing:return jsonify({'error': 'Missing required fields','missing_fields': missing}), 400return f(*args, **kwargs)return decorated_functionreturn decoratordef validate_email(email):import repattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'return re.match(pattern, email) is not None# Usage@users_bp.route('', methods=['POST'])@validate_json('email', 'password', 'first_name')def create_user():data = request.get_json()if not validate_email(data['email']):return jsonify({'error': 'Invalid email format'}), 400# ... rest of logic
6. Application Factory and Configuration
python
# config.pyimport osclass Config:SQLALCHEMY_TRACK_MODIFICATIONS = FalseJSON_SORT_KEYS = Falseclass DevelopmentConfig(Config):DEBUG = TrueTESTING = FalseSQLALCHEMY_DATABASE_URI = 'sqlite:///app.db'class ProductionConfig(Config):DEBUG = FalseTESTING = FalseSQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL')JWT_SECRET_KEY = os.getenv('JWT_SECRET_KEY')class TestingConfig(Config):TESTING = TrueSQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'# factory.pyfrom flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom flask_jwt_extended import JWTManagerdef create_app(config_name='development'):app = Flask(__name__)if config_name == 'production':from config import ProductionConfigapp.config.from_object(ProductionConfig)else:from config import DevelopmentConfigapp.config.from_object(DevelopmentConfig)db = SQLAlchemy(app)jwt = JWTManager(app)# Register blueprintsfrom routes.auth import auth_bpfrom routes.users import users_bpapp.register_blueprint(auth_bp)app.register_blueprint(users_bp)return app
Best Practices
✅ DO
- Use blueprints for modular organization
- Implement proper authentication with JWT
- Validate all user input
- Use SQLAlchemy ORM for database operations
- Implement comprehensive error handling
- Use pagination for collection endpoints
- Log errors and important events
- Return appropriate HTTP status codes
- Implement CORS properly
- Use environment variables for configuration
❌ DON'T
- Store secrets in code
- Use global variables for shared state
- Ignore database transactions
- Trust user input without validation
- Return stack traces in production
- Use mutable default arguments
- Forget to handle database connection errors
- Implement authentication in route handlers
Complete Example
python
from flask import Flask, request, jsonifyfrom flask_sqlalchemy import SQLAlchemyfrom flask_jwt_extended import JWTManager, create_access_tokenapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/db'db = SQLAlchemy(app)jwt = JWTManager(app)class User(db.Model):id = db.Column(db.Integer, primary_key=True)email = db.Column(db.String, unique=True)password = db.Column(db.String)@app.route('/api/login', methods=['POST'])def login():data = request.jsonuser = User.query.filter_by(email=data['email']).first()if user:token = create_access_token(identity=user.id)return jsonify({'token': token}), 200return jsonify({'error': 'Invalid'}), 401@app.route('/api/users', methods=['GET'])def get_users():users = User.query.all()return jsonify([{'id': u.id, 'email': u.email} for u in users]), 200if __name__ == '__main__':app.run()