Skip to main content

WeltenHub Client Framework — typed REST client and Pydantic schemas for the WeltenHub Story Universe API

Project description

weltenfw — v0.3.0

WeltenHub Client Framework — typed REST client, Pydantic v2 schemas, and a pluggable storage-backend pattern for the WeltenHub Story Universe API.

CI PyPI Python License: MIT

Installation

pip install iil-weltenfw                  # core (httpx + pydantic)
pip install iil-weltenfw[django]          # + Django AppConfig + DjangoCache

Quick Start — Low-Level Client

from weltenfw import WeltenClient

with WeltenClient(
    base_url="https://weltenforger.com/api/v1",
    token="your-token",
) as client:
    world = client.worlds.create(WorldCreateInput(
        name="Aldoria", setting_era="medieval",
    ))
    chars = client.characters.list(world=str(world.id))
    locs  = client.locations.list(world=str(world.id))
    stories = client.stories.list(world=str(world.id))
    scenes  = client.scenes.list(story=str(stories.results[0].id))

Async

async with WeltenClient(base_url=..., token=...) as client:
    world = await client.worlds.aget(world_id)
    locs  = await client.locations.alist(world=world_id)

Django Integration

# settings.py
INSTALLED_APPS  = [..., "weltenfw.django"]
WELTENHUB_URL   = "https://weltenforger.com/api/v1"
WELTENHUB_TOKEN = env("WELTENHUB_TOKEN")

# services.py
from weltenfw.django import get_client
client = get_client()   # lazy singleton, one per worker

Storage Backend Pattern (ADR-117)

weltenfw ships WeltenhubBackend — a higher-level write/read facade on top of WeltenClient. Consumer apps (bfagent, travel-beat, …) use this to keep Weltenhub as the single source of truth without duplicating data.

Two Scenarios — same API

from weltenfw.backends import WeltenhubBackend

backend = WeltenhubBackend(
    base_url="https://weltenforger.com/api/v1",
    token=token,   # user token (A) or service token (B)
)

Scenario A — user has Weltenhub account: token = user.weltenhub_token → data visible in Weltenhub UI immediately.

Scenario B — user not yet linked: token = WELTENHUB_API_KEY (service token) → data stored, UUID returned, UI locked until user links their account. No duplication; consumer stores only UUID.


Backend API Reference

Worlds

Method Signature Returns
create_world (name, description, setting_era, **kw) WorldResult
get_world (world_id) WorldResult
list_worlds (search, page) WorldPage
update_world (world_id, **fields) WorldResult
result = backend.create_world(name="Aldoria", description="Kingdom of runes")
result.id       # Weltenhub UUID
result.ok       # True on success
result.error    # str | None
result.backend  # "weltenhub"

Characters

Method Signature Returns
create_character (world_id, name, personality, backstory, is_protagonist, **kw) CharacterResult
get_character (character_id) CharacterResult
list_characters (world_id, page) CharacterPage
chars = backend.list_characters(world_id="<uuid>")
for c in chars.results:
    print(c.name, c.role_name)

Locations

Method Signature Returns
create_location (world_id, name, description, parent_id, **kw) LocationResult
list_locations (world_id, page, page_size) LocationPage
locs = backend.list_locations(world_id="<uuid>")
for loc in locs.results:
    print(loc.name, loc.location_type_name, loc.full_path)

new_loc = backend.create_location(
    world_id="<uuid>", name="Eisenhain",
    description="A fortress city in the northern mountains.",
)

Stories

Method Signature Returns
create_story (world_id, title, synopsis, **kw) StoryResult
list_stories (world_id, page, page_size) StoryPage
stories = backend.list_stories(world_id="<uuid>")
for s in stories.results:
    print(s.title, s.status)

story = backend.create_story(world_id="<uuid>", title="Der Ruf der Runen")

Scenes

Method Signature Returns
create_scene (story_id, title, summary, order, **kw) SceneResult
list_scenes (story_id, page, page_size) ScenePage
scenes = backend.list_scenes(story_id="<uuid>")
for s in scenes.results:
    print(s.title, s.location_name, s.order)

Result Types

All result types are frozen dataclasses with an .ok property:

Type Key fields
WorldResult id, name, description, setting_era, genre_name
CharacterResult id, name, world_id, role_name, description, personality
LocationResult id, name, world_id, parent_id, location_type_name, description, full_path
SceneResult id, title, story_id, summary, location_name, order
StoryResult id, title, world_id, genre_name, status, synopsis

All *Page types have .results: list[*Result] and .count: int.


User Provisioning (S2S, idempotent)

token = WeltenhubBackend.provision_user(
    username="bf_hugo",
    email="hugo@example.com",
    base_url="https://weltenforger.com/api/v1",
    service_token=WELTENHUB_API_KEY,
)
# Returns per-user token (Scenario A) or None on failure

LocalWorldBackend (tests / offline)

from weltenfw.backends.local import LocalWorldBackend

backend = LocalWorldBackend()
result = backend.create_world(name="Test")
# result.id = "" — caller manages local DB
# result.backend = "local"

Custom Backend (Protocol)

Implement AbstractWorldBackend without inheriting — structural subtyping:

from weltenfw.backends.base import AbstractWorldBackend, WorldResult

class MyBackend:
    def create_world(self, name: str, **kw) -> WorldResult: ...
    def get_world(self, world_id: str) -> WorldResult: ...
    def list_worlds(self, search: str = "", page: int = 1): ...
    def update_world(self, world_id: str, **fields): ...
    def create_character(self, world_id, name, **kw): ...
    def get_character(self, character_id): ...
    def list_characters(self, world_id, page=1): ...
    def list_locations(self, world_id, page=1, page_size=100): ...
    def create_location(self, world_id, name, **kw): ...
    def list_stories(self, world_id, page=1, page_size=100): ...
    def create_story(self, world_id, title, **kw): ...
    def list_scenes(self, story_id, page=1, page_size=100): ...
    def create_scene(self, story_id, title, **kw): ...

Architecture

  • 1 Client = 1 Token = 1 Tenant — no global singleton; multi-tenant callers instantiate one client per token.
  • Pydantic v2 — all API responses validated into typed, frozen schemas.
  • Separate Input schemas*CreateInput (POST) / *UpdateInput (PATCH).
  • Lookup cache — pluggable CacheBackend (NullCache → MemoryCache → DjangoCache).
  • Storage Backend Pattern — Weltenhub-DB is SSoT; consumer apps store UUID only.

Changelog

See CHANGELOG.md.

Links

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

iil_weltenfw-0.4.0.tar.gz (35.7 kB view details)

Uploaded Source

Built Distribution

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

iil_weltenfw-0.4.0-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file iil_weltenfw-0.4.0.tar.gz.

File metadata

  • Download URL: iil_weltenfw-0.4.0.tar.gz
  • Upload date:
  • Size: 35.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for iil_weltenfw-0.4.0.tar.gz
Algorithm Hash digest
SHA256 18308564ddadc7e0bf3b7d8f8447da0f25ffc8b37f501f820ac011b6f8cdfcf4
MD5 4146205d2e69855f40698d21f54337fe
BLAKE2b-256 9b262700df195f31aa579b1c256e882cb0869cc5cc08383e7b8e960f2107916a

See more details on using hashes here.

File details

Details for the file iil_weltenfw-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: iil_weltenfw-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 36.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for iil_weltenfw-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 41b53c2e0b38c0f2a1a6cae479d79938e9cf6a9f485ff831dc1024b9ff894ecc
MD5 2bd80ea4c45a68a3de0196e3c331ab33
BLAKE2b-256 bfcdea473df435accfaa24bfeec39055ed34e40a5fcac85a136a94572faa2ee0

See more details on using hashes here.

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