Skip to main content

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


Download files

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

Source Distribution

modwire_siren-1.0.0.tar.gz (13.3 kB view details)

Uploaded Source

Built Distribution

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

modwire_siren-1.0.0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file modwire_siren-1.0.0.tar.gz.

File metadata

  • Download URL: modwire_siren-1.0.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

Hashes for modwire_siren-1.0.0.tar.gz
Algorithm Hash digest
SHA256 429f2d07d9e69737a45fd9ab96eb51bcb8051c6b92cd9d304a9afc24c29a159e
MD5 c03e9ec84f6147f0f47ce20ec88fbd3a
BLAKE2b-256 f22689c0631d9077b6c67fe51d48ea89e3f6e695b35d819acac9a998c09a2298

See more details on using hashes here.

Provenance

The following attestation bundles were made for modwire_siren-1.0.0.tar.gz:

Publisher: release.yml on 9orky/modwire-siren

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

File details

Details for the file modwire_siren-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: modwire_siren-1.0.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

Hashes for modwire_siren-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 915a29b472e9b103423f59933a07cf2f270bb7e1bc6c55a73b0aa4d5d331b942
MD5 f98303fc660ca36607adb0670de9b705
BLAKE2b-256 213585a6527d95bb2d84c2fa8d07b042b1122a1c3f5576a23a4e9133683b582f

See more details on using hashes here.

Provenance

The following attestation bundles were made for modwire_siren-1.0.0-py3-none-any.whl:

Publisher: release.yml on 9orky/modwire-siren

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