Siren hypermedia and OpenAPI integration for Modwire.
Project description
modwire-siren
Typed Siren documents projected from OpenAPI without application-owned route maps.
Every external boundary is behind a package interface: catalog, href resolution, field policy,
field creation, link creation, resource hrefs, and serialization. ModwireSirenFactory is the
standard composition root; ModwireSiren is the small public façade.
Public API
The supported root imports below are generated from modwire_siren.__all__.
| Symbol | Purpose | Primary API |
|---|---|---|
ModwireSiren |
Project validated entity requests into serialized Siren documents. | document(request: modwire_siren.contracts.entity.SirenEntityRequest) -> dict[str, typing.Any] |
ModwireSirenFactory |
Build the standard OpenAPI-backed Siren façade. | standard(schema: dict[str, typing.Any], base_url: str) -> modwire_siren.facade.ModwireSiren |
NinjaExtraSirenController |
Framework-light base for Ninja Extra controllers that emit Siren documents. | siren_document(resource_name: str, properties: collections.abc.Mapping[str, typing.Any], operation_ids: tuple[str, ...], path_values: collections.abc.Mapping[str, typing.Any], entities: tuple[modwire_siren.contracts.entity.SirenEmbeddedEntity, ...] = ()) -> dict[str, typing.Any] |
OpenApiError |
Report invalid or incomplete OpenAPI data used for Siren projection. | — |
SirenEntityDecorator |
Turn a controller method's property mapping into a Siren entity document. | — |
SirenEntityRequest |
Describe the resource data and allowed operations projected into one entity. | — |
__version__ |
Installed distribution version. | — |
Executable example
Source: build_document.py. This file is executed by the test suite.
from modwire_siren import ModwireSirenFactory, SirenEntityRequest
openapi_schema = {
"openapi": "3.1.0",
"paths": {
"/records/{record_slug}": {
"x-siren-resource": {
"name": "record",
"class": "record",
"identifier": "slug",
"path-parameters": {"record_slug": "slug"},
"relations": {},
},
"get": {"operationId": "get_record", "summary": "Get record"},
}
},
}
siren = ModwireSirenFactory.standard(openapi_schema, "https://api.example.com/")
document = siren.document(
SirenEntityRequest(
resource_name="record",
properties={"slug": "architecture/aggregate", "title": "Architecture"},
operation_ids=("get_record",),
path_values={},
entities=(),
)
)
OpenAPI contract
paths:
/records/{record_slug}:
x-siren-resource:
name: record
class: record
identifier: slug
path-parameters:
record_slug: slug
relations:
section_slug:
rel: section
resource: section
many: false
patch:
operationId: revise_record
summary: Revise record
The strict OpenApiResourceExtension validates the extension. Unknown resources, incomplete path
mappings, absent operation IDs, and unknown schema references fail while building the catalog.
The Pydantic Siren contracts own wire aliases such as class, type, and schema.
PydanticSirenSerializer implements the SirenSerializer interface with one model dump; it does
not redeclare the wire schema.
Django Ninja Extra
The controller adapter does not import Django or Ninja Extra, so the core package keeps no framework dependency. It composes directly with Ninja Extra's controller and route decorators:
from ninja_extra import ControllerBase, api_controller, route
from modwire_siren import ModwireSiren, NinjaExtraSirenController, SirenEntityDecorator
@api_controller("/records")
class RecordController(ControllerBase, NinjaExtraSirenController):
def __init__(self, records: RecordService, siren: ModwireSiren):
NinjaExtraSirenController.__init__(self, siren)
self.records = records
@route.get("/{record_slug}", operation_id="get_record")
@SirenEntityDecorator("record", operations=("revise_record",))
def get_record(self, record_slug: str):
return self.records.get(record_slug)
The method returns only resource properties. @SirenEntityDecorator(...) retains its signature for
Ninja's parameter inspection, supplies route arguments as path values, supports sync and async
handlers, and projects the result through the standard ModwireSiren composition root.
Development and release
Run uv sync --all-groups and make verify. Releases use strict SemVer tags and PyPI Trusted
Publishing configured for repository 9orky/modwire-siren, workflow release.yml, and environment
pypi.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modwire_siren-0.1.0.tar.gz.
File metadata
- Download URL: modwire_siren-0.1.0.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea95f4effb4893b9a1ec9133eb48f79a8689ef69325833c1f38f0ff8b880f59a
|
|
| MD5 |
8d2423aa082b0ac7fc185fafc4325691
|
|
| BLAKE2b-256 |
e1f534ae6caeffec6e50343ca6e8887b606f06e96300d0a6c606974758ddd0fb
|
Provenance
The following attestation bundles were made for modwire_siren-0.1.0.tar.gz:
Publisher:
release.yml on 9orky/modwire-siren
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modwire_siren-0.1.0.tar.gz -
Subject digest:
ea95f4effb4893b9a1ec9133eb48f79a8689ef69325833c1f38f0ff8b880f59a - Sigstore transparency entry: 2140112185
- Sigstore integration time:
-
Permalink:
9orky/modwire-siren@c73792f2710d93c5a9a446fc10da38addc210e70 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/9orky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c73792f2710d93c5a9a446fc10da38addc210e70 -
Trigger Event:
release
-
Statement type:
File details
Details for the file modwire_siren-0.1.0-py3-none-any.whl.
File metadata
- Download URL: modwire_siren-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9706a358d2fae87962d854daf7567c4e582af2645675ac242ea3ff5234cbafc3
|
|
| MD5 |
01a6434fd18014a8f6f70158d61aae3f
|
|
| BLAKE2b-256 |
e2f1bc0edfa016319c239e5a561eb482c88effe7631bae2bc25e74f316a4bbd3
|
Provenance
The following attestation bundles were made for modwire_siren-0.1.0-py3-none-any.whl:
Publisher:
release.yml on 9orky/modwire-siren
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modwire_siren-0.1.0-py3-none-any.whl -
Subject digest:
9706a358d2fae87962d854daf7567c4e582af2645675ac242ea3ff5234cbafc3 - Sigstore transparency entry: 2140112194
- Sigstore integration time:
-
Permalink:
9orky/modwire-siren@c73792f2710d93c5a9a446fc10da38addc210e70 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/9orky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c73792f2710d93c5a9a446fc10da38addc210e70 -
Trigger Event:
release
-
Statement type: