OpenAPI Support¶
AppKernel generates a live OpenAPI 3.1.0 specification from your registered
services. Call enable_openapi() after
registering all services:
from appkernel import AppKernelEngine, HttpClientConfig
kernel = AppKernelEngine('my-app', cfg_dir='./config')
kernel.register(User, methods=['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
kernel.enable_openapi(title='My API', version='1.0.0')
kernel.run()
This exposes three endpoints:
/openapi.json— the machine-readable OpenAPI 3.1.0 specification./docs— Swagger UI (interactive browser)./redoc— ReDoc documentation browser.
To suppress the UI endpoints and serve only the raw spec:
kernel.enable_openapi(include_docs=False)
The tags parameter on register() applies
a tag to every endpoint of that registration, which is useful for grouping
all endpoints of an API version together:
kernel.register(UserV1Service(), url_base='/v1/', tags=['v1'])
kernel.register(UserV2Service(), url_base='/v2/', tags=['v2'])
Registration tags are merged with per-decorator tags, with registration tags listed first. See API Versioning for a full walkthrough.
enable_openapi returns self and can be chained:
kernel.register(User).deny_all().require(Role('user'), methods='GET')
kernel.enable_openapi(title='My API').run()
Decorator metadata¶
All @action and @resource decorators accept optional OpenAPI kwargs.
They do not affect runtime behaviour — they are used only for documentation.
Kwarg |
Purpose |
|---|---|
|
Short operation summary (shown as the title in Swagger UI). |
|
List of tag strings used to group operations (e.g. |
|
Explicit |
|
Explicit |
|
List of query parameter names to document (e.g. |
|
|
Example:
class PaymentService:
@resource(
method='POST',
summary='Authorise a payment',
tags=['Payments'],
request_model=Payment,
response_model=Payment,
)
def authorise(self, payload):
...
@resource(
method='GET',
query_params=['start', 'stop'],
summary='List payments in a date range',
tags=['Payments'],
)
def list_payments(self, start=None, stop=None):
...
@resource(
method='POST',
path='/legacy-pay',
deprecated=True,
summary='Deprecated — use POST /payments/pay instead',
)
def legacy_pay(self, payload):
...
Type-hint inference¶
When request_model or response_model are omitted, AppKernel inspects
the method’s type annotations to infer schemas automatically:
class UserService:
@resource(method='POST')
def create_user(self, user: User) -> User:
...
The first non-self parameter typed as a Model subclass
becomes the request body schema. The -> ReturnType annotation becomes the
200/201 response schema.
When a method has no type hints, the schema falls back to
{"type": "object"}. Add type hints or use explicit request_model /
response_model kwargs to get precise documentation.
Priority order for schema resolution:
Explicit
request_model/response_modeldecorator kwarg.Type-hint inference from the method signature.
Model class (for CRUD routes registered with
register()).{"type": "object"}fallback.
Validator constraints¶
Model field schemas are built by get_json_schema() and
include constraints derived from validator metadata:
Validator |
OpenAPI constraint |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Response envelope¶
Collection responses (GET /resources/) are wrapped in the AppKernel
envelope:
{
"_type": "list",
"_items": [ { ... }, { ... } ],
"_links": { "self": { "href": "/resources/" } }
}
The generated spec documents collection GET responses with an inline schema:
{
"type": "object",
"properties": {
"_type": { "type": "string" },
"_items": { "type": "array", "items": { "$ref": "#/components/schemas/User" } },
"_links": { "type": "object" }
}
}
Single-item GET, POST, and PUT responses reference the model schema directly
({"$ref": "#/components/schemas/User"}). DELETE responses document the
OperationResult shape with a result count field.
Query DSL¶
AppKernel supports a rich URL query DSL for collection endpoints that cannot be fully expressed as standard OpenAPI parameters:
GET /users/?name=~john # name contains 'john'
GET /users/?sequence=>10 # sequence greater than 10
GET /users/?roles:[Admin,User] # roles in the given list
These are documented as freeform string query parameters. The standard
pagination and query parameters (page, page_size, sort_by,
sort_order, query) are added automatically to every collection GET
route.
Full DSL syntax is described in Repositories.
Programmatic usage¶
The generator can also be invoked directly without registering HTTP routes:
from appkernel.openapi import OpenAPISchemaGenerator
generator = OpenAPISchemaGenerator(title='My API', version='1.0.0')
spec = generator.generate()
import json
print(json.dumps(spec, indent=2))