Manual Routes¶
flarchitect can wrap your own Flask view functions with the same machinery it uses for generated endpoints. This is helpful when you hand‑craft a route but still want consistent authentication, schema validation/serialisation, rate limiting and OpenAPI documentation.
Use architect.schema_constructor
to decorate a view and describe how it
should be treated. The decorator applies input/output Marshmallow schemas,
honours auth/roles config, attaches rate limiting, and registers the route for
documentation generation.
Basic usage¶
from flask import Flask
from marshmallow import Schema, fields
from flarchitect import Architect
app = Flask(__name__)
app.config.update(
API_TITLE="My API",
API_VERSION="1.0",
# Enable JWT (or your chosen method) if you want auth enforced
API_AUTHENTICATE_METHOD=["jwt"],
)
architect = Architect(app)
class HelloOut(Schema):
message = fields.String(required=True)
@app.get("/hello")
@architect.schema_constructor(
output_schema=HelloOut, # serialise the return value with this schema
group_tag="Custom", # group in docs
auth=True, # enforce configured auth on this route
)
def hello():
return {"message": "world"}
The decorator automatically:
Validates/serialises using the provided schemas.
Enforces authentication (unless
auth=False
is set).Applies any configured rate limit (see
API_RATE_LIMIT
and model/method overrides).Registers the route so it appears in the OpenAPI spec and docs.
Input and output schemas¶
You can validate request bodies and serialise responses with Marshmallow
schemas. Use input_schema
for inbound data and output_schema
for the
response. For endpoints returning a list, pass many=True
to control how
serialisation is applied.
If you don’t want flarchitect to serialise the response, set
output_schema=None
. In this mode the wrapper skips field selection and
Marshmallow dumping entirely and your handler’s return value (dict or list)
is wrapped unchanged in the standard JSON envelope.
class ItemIn(Schema):
name = fields.String(required=True)
class ItemOut(Schema):
id = fields.Integer(required=True)
name = fields.String(required=True)
@app.post("/items")
@architect.schema_constructor(input_schema=ItemIn, output_schema=ItemOut)
def create_item():
# Access validated input via Flask's request.json in your handler
...
return {"id": 1, "name": "example"}
Route handler signature¶
Decorated handlers may optionally accept deserialized_data
to receive the
validated request body when input_schema
is provided. Extra wrapper kwargs
such as model
are filtered and only arguments declared in your function
signature are passed, so both of the following are valid:
@app.post("/echo")
@architect.schema_constructor(input_schema=ItemIn, output_schema=None)
def echo(deserialized_data=None):
return deserialized_data
# or
@app.post("/echo2")
@architect.schema_constructor(input_schema=ItemIn, output_schema=None)
def echo2(deserialized_data=None, **kwargs): # kwargs may include 'model'
return deserialized_data
Roles and authentication¶
If your application uses role‑based access control, supply roles
to require
users to have specific roles on this route. By default, when authentication is
enabled globally, roles are enforced automatically for decorated routes.
@app.get("/admin/stats")
@architect.schema_constructor(output_schema=HelloOut, roles=["admin"]) # require the "admin" role
def admin_stats():
return {"message": "ok"}
To allow access when the user has any of multiple roles, either set
roles_any_of=True
or pass a dict with {"roles": [...], "any_of": True}
:
@app.get("/content/edit")
@architect.schema_constructor(output_schema=HelloOut, roles=["editor", "admin"], roles_any_of=True)
def edit_content():
return {"message": "ok"}
# equivalent
@app.get("/content/edit-alt")
@architect.schema_constructor(output_schema=HelloOut, roles={"roles": ["editor", "admin"], "any_of": True})
def edit_content_alt():
return {"message": "ok"}
To opt out of authentication for a specific manual route, set auth=False
:
@app.get("/public/ping")
@architect.schema_constructor(output_schema=HelloOut, auth=False)
def public_ping():
return {"message": "pong"}
Documentation metadata¶
schema_constructor
records metadata so your manual routes show up in the
OpenAPI document and UI. Useful kwargs include:
group_tag
: Group name used for sectioning in docs.summary
: Short summary for the operation.tag
: Additional tag label if needed.error_responses
: Mapping of error codes to descriptions used in docs.
Additional helpers¶
If you only need to protect a manual route with JWT and don’t require schema
wrapping or documentation, you can use jwt_authentication
directly:
from flarchitect.core.architect import jwt_authentication
@app.get("/profile")
@jwt_authentication
def profile():
return {"status": "ok"}
This decorator validates the Authorization: Bearer <token>
header and sets
the current user context.