Skip to main content

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
from flask_more_smorest.perms import init_fms
from flask_more_smorest.perms.models.defaults import (
    Domain,
    Token,
    User,
    UserRole,
    UserSetting,
)

# Register default models explicitly
init_fms(
    user=User,
    role=UserRole,
    token=Token,
    domain=Domain,
    setting=UserSetting,
)

# Instant login and profile endpoints
user_bp = UserBlueprint(register=False)  # 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 UserBlueprint
from flask_more_smorest.perms import init_fms
from flask_more_smorest.perms.models.abstract_user import AbstractUser
from flask_more_smorest.sqla import db
from sqlalchemy.orm import Mapped, mapped_column

class Employee(AbstractUser):
    email: Mapped[str] = mapped_column(db.String(128), unique=True, nullable=False)
    password: Mapped[bytes | None] = mapped_column(db.LargeBinary(128), nullable=True)
    is_enabled: Mapped[bool] = mapped_column(db.Boolean(), default=True)
    employee_id: Mapped[str] = mapped_column(db.String(32), unique=True)
    department: Mapped[str] = mapped_column(db.String(100))

# Register custom user model
init_fms(user=Employee)

# Use custom user model in blueprint
employee_bp = UserBlueprint(model=Employee, register=False)

Enable public registration

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

public_bp = UserBlueprint(model=PublicUser, register=False)

Getting the current user

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

from flask_more_smorest.perms.models.defaults import User
from flask_more_smorest.perms import get_current_user

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

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

user = get_current_user()
if isinstance(user, MyUser):
    print(f"User {user.email} is logged in")

Or use the class method on your user model:

from flask_more_smorest.perms.models.defaults import User

user = User.get_current_user()  # Returns User | None
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 init_fms
from my_app.auth import get_current_user

init_fms(user=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.9.2",
  "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

Testing

Flask-More-Smorest provides testing helpers for authenticated endpoints:

from flask_more_smorest.perms.models.defaults import User, UserRole, BaseRoleEnum
from flask_more_smorest.testing import as_user, as_admin

# Create test user
with User.bypass_perms():
    user = User(email="test@example.com", password="password123")
    user.save()

# Test authenticated endpoint
with as_user(client, str(user.id)):
    response = client.get("/api/users/me/")
    assert response.status_code == 200

# Test admin endpoint
admin = User(email="admin@example.com", password="password123")
admin.roles.append(UserRole(user=admin, role=BaseRoleEnum.ADMIN))

with as_admin(client, str(admin.id)):
    response = client.get("/api/users/")
    assert response.status_code == 200

See the Testing Guide for more examples.

Learn more

Contributing

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

Metadata

Release files for flask-more-smorest 0.13.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flask-more-smorest 0.13.1
File Size Uploaded
flask_more_smorest-0.13.1.tar.gz 71.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-more-smorest 0.13.1
File Interpreter ABI Platform
flask_more_smorest-0.13.1-py3-none-any.whl Python 3 none any Details

Total release size: 158.1 kB

Release files / flask_more_smorest-0.13.1.tar.gz

Download URL flask_more_smorest-0.13.1.tar.gz
Size 71.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e413a235f028cf438c7e25cc5fede6c2523355b1bd0416e6ac0ab052dbc89352
BLAKE2b-256 checksum
How to use checksums
c2b5c9c8276611317d9e1d829b2b0e6132d3a5c4bbfda0a875e5c83d74a43b38
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release files / flask_more_smorest-0.13.1-py3-none-any.whl

Download URL flask_more_smorest-0.13.1-py3-none-any.whl
Size 86.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f02b28f538cf6f97e00ee11de97cf1f3a928bce2206350c8f3791ce8e7fa12d6
BLAKE2b-256 checksum
How to use checksums
dc73d04805545b5cd3049406d8ecf521fcd2e2daef2cb4c188a27ec5eace7a1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.15.1

2 release files

0.15.0

2 release files

0.14.0

2 release files

This release

0.13.1 This release

2 release files

0.13.0

2 release files

0.12.2

2 release files

0.12.1

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.4

2 release files

0.10.3

2 release files

0.10.2

2 release files

0.10.1

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page