Skip to main content

Enhanced Flask-Smorest blueprints with automatic CRUD operations

Project description

Flask-More-Smorest

PyPI version Python Support Documentation Status Documentation Status License: MIT Downloads

Flask-More-Smorest extends Flask-Smorest with a number of enhancements and goodies, with the sole goal of drastically reducing boilerplate and complexity when creating a new REST API with Flask and Flask-Smorest.

Links:

Highlights

  • Automatic CRUD endpoints with filtering and pagination
  • SQLAlchemy base model with auto-generated Marshmallow schemas
  • Built-in user authentication with JWT and role-based permissions
  • UserBlueprint for instant login/profile endpoints
  • Resource-based permission management
  • Health check endpoint for load balancers and monitoring
  • RFC 7807 error responses for standardized error handling
  • SQLAlchemy performance monitoring for identifying slow queries

Quick Start

from flask import Flask
from flask_more_smorest import BaseModel, CRUDBlueprint, init_db
from flask_more_smorest.perms import Api
from flask_more_smorest.sqla import db
from sqlalchemy.orm import Mapped, mapped_column

app = Flask(__name__)
app.config.update(
    API_TITLE="Example API",
    API_VERSION="v1",
    OPENAPI_VERSION="3.0.2",
    SQLALCHEMY_DATABASE_URI="sqlite:///example.db",
    SECRET_KEY="change-me",
    JWT_SECRET_KEY="change-me-too",
)

# Define your model
class Critter(BaseModel):
    name: Mapped[str] = mapped_column(db.String(100))
    species: Mapped[str] = mapped_column(db.String(50))
    cuteness_level: Mapped[int] = mapped_column(db.Integer, default=10)

init_db(app)          # sets up SQLAlchemy
api = Api(app)        # registers JWT + permission hooks

# Create CRUD blueprint using model class directly
critters = CRUDBlueprint(
    "critters",
    __name__,
    model=Critter,           # Use class (preferred over string)
    schema=Critter.Schema,   # Auto-generated schema
    url_prefix="/api/critters/",
)

api.register_blueprint(critters)

This automatically creates RESTful endpoints: GET /api/critters/, GET /api/critters/<id>, POST /api/critters/, PATCH /api/critters/<id>, DELETE /api/critters/<id>, plus automatic filtering (?created_at__from=..., ?species=...) and a health check endpoint at /health.

Controlling endpoints

By default, all CRUD methods are enabled. Control which endpoints are generated:

from flask_more_smorest.crud.crud_blueprint import CRUDMethod

# Enable only specific methods
read_only = CRUDBlueprint(
    "critters",
    __name__,
    model=Critter,
    schema=Critter.Schema,
    methods=[CRUDMethod.INDEX, CRUDMethod.GET],  # Only list and get
)

# Disable specific methods
no_delete = CRUDBlueprint(
    "critters",
    __name__,
    model=Critter,
    schema=Critter.Schema,
    skip_methods=[CRUDMethod.DELETE],  # All except delete
)

For advanced configuration (custom schemas, admin-only endpoints, etc.), see the full documentation.

Working with models

Use BaseModel for simple models with UUID keys, timestamp tracking, and auto-generated Marshmallow schemas:

from flask_more_smorest import BaseModel
from flask_more_smorest.sqla import db
from sqlalchemy.orm import Mapped, mapped_column

class Critter(BaseModel):
    name: Mapped[str] = mapped_column(db.String(100), nullable=False)
    species: Mapped[str] = mapped_column(db.String(50), nullable=False)
    cuteness_level: Mapped[int] = mapped_column(db.Integer, default=10)

Auto-generated schema: Critter.Schema is automatically created with all fields. Use it directly in blueprints—no need to define custom schemas unless you need special validation.

Adding permission checks

Use BasePermsModel when you need permission hooks:

from flask_more_smorest.perms import BasePermsModel
from flask_more_smorest.sqla import db
from sqlalchemy.orm import Mapped, mapped_column

class Critter(BasePermsModel):
    name: Mapped[str] = mapped_column(db.String(100), nullable=False)
    species: Mapped[str] = mapped_column(db.String(50), nullable=False)

    def _can_write(self, current_user) -> bool:
        return current_user is not None and current_user.has_role("admin")

    def _can_read(self, current_user) -> bool:
        return True  # Anyone can read

BasePermsModel adds _can_read(), _can_write(), and _can_create() hooks that are checked automatically on CRUD operations. The current_user argument contains the authenticated user (or None).

Built-in user authentication

Get instant authentication with UserBlueprint:

from flask_more_smorest import UserBlueprint

# Instant login and profile endpoints
user_bp = UserBlueprint()  # Creates /api/users/login/ and /api/users/me/
api.register_blueprint(user_bp)

This provides:

  • POST /api/users/login/ - JWT authentication
  • GET /api/users/me/ - Current user profile
  • Full CRUD for user management
  • Role-based permissions

Extending the User model

Add custom fields by inheriting from User:

from flask_more_smorest import User, UserBlueprint
from flask_more_smorest.sqla import db
from sqlalchemy.orm import Mapped, mapped_column

class Employee(User):
    employee_id: Mapped[str] = mapped_column(db.String(32), unique=True)
    department: Mapped[str] = mapped_column(db.String(100))

# Use custom user model in blueprint
employee_bp = UserBlueprint(model=Employee, schema=Employee.Schema)

Enable public registration

class PublicUser(User):
    PUBLIC_REGISTRATION = True  # Allow unauthenticated user creation

public_bp = UserBlueprint(model=PublicUser, schema=PublicUser.Schema)

Getting the current user

Access the authenticated user using the class method for type-safe results:

from flask_more_smorest import User

# In your route or permission check
user = User.get_current_user()  # Returns User | None

# With a custom user class
class MyUser(User):
    employee_id = mapped_column(db.String(32))

user = MyUser.get_current_user()  # Returns MyUser | None (properly typed)

# Check if user is authenticated
if user:
    print(f"User {user.email} is logged in")

The class method provides typed access and is the preferred way to get the current user in application code.

Using your own User model

If you already have a User model, configure flask-more-smorest to use it:

from flask_more_smorest.perms import register_user_class
from my_app.auth import get_current_user

register_user_class(MyUser, get_current_user=get_current_user)
# Permission system now uses your User model

See Custom User Context for details.

Production Features

Health Check Endpoint

Built-in health check for load balancers and monitoring systems:

curl http://localhost:5000/health
{
  "status": "healthy",
  "timestamp": "2026-01-11T08:30:00+00:00",
  "version": "0.6.0",
  "database": "connected"
}

Configure via HEALTH_ENDPOINT_PATH and HEALTH_ENDPOINT_ENABLED.

RFC 7807 Error Responses

Standardized error format following RFC 7807:

{
  "type": "/errors/not_found_error",
  "title": "Not Found",
  "status": 404,
  "detail": "User with id 123 doesn't exist",
  "instance": "/api/users/123"
}

Debug information automatically included in debug/testing mode only.

SQLAlchemy Performance Monitoring

Track and log slow queries:

app.config.update(
    SQLALCHEMY_PERFORMANCE_MONITORING=True,
    SQLALCHEMY_SLOW_QUERY_THRESHOLD=0.5,  # Log queries over 500ms
)

Get per-request statistics:

from flask_more_smorest.sqla import get_request_query_stats

@app.after_request
def log_stats(response):
    stats = get_request_query_stats()
    print(f"Queries: {stats['query_count']}, Time: {stats['total_query_time']:.3f}s")
    return response

Learn more

Contributing

Contributions and feedback are welcome! See CONTRIBUTING.md for guidelines.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask_more_smorest-0.8.0.tar.gz (62.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flask_more_smorest-0.8.0-py3-none-any.whl (69.3 kB view details)

Uploaded Python 3

File details

Details for the file flask_more_smorest-0.8.0.tar.gz.

File metadata

  • Download URL: flask_more_smorest-0.8.0.tar.gz
  • Upload date:
  • Size: 62.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for flask_more_smorest-0.8.0.tar.gz
Algorithm Hash digest
SHA256 9874e8bb40f4833f16c92a1ebdcd2a629df9f21524e5467bb844b19461124c5e
MD5 c6c94c4fa6c1e7b71c8a4f538b9567e1
BLAKE2b-256 b3269a936424935eb787bcd73dcaf274d03295c665279306e8511a2f19c2cc0b

See more details on using hashes here.

Provenance

The following attestation bundles were made for flask_more_smorest-0.8.0.tar.gz:

Publisher: ci-cd.yml on qualisero/flask-more-smorest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file flask_more_smorest-0.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for flask_more_smorest-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 26c4484a3f3e6539b99d1259527f12cc5902d59e55cd4ec9bc6018a435cb4a2d
MD5 505026d3f5c16c40b35ac515a8bb1ca9
BLAKE2b-256 f17ce6b6795be5fc46933bfead110f6147b4f2298d71c5b32a1aa974596fd4be

See more details on using hashes here.

Provenance

The following attestation bundles were made for flask_more_smorest-0.8.0-py3-none-any.whl:

Publisher: ci-cd.yml on qualisero/flask-more-smorest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page