jmri_server.envelope

The JMRI JSON message envelope.

Wire format (see contracts/json-schema/schema/json-client.json):

  • Client → server: {type, data?, list?, method?, id?}
  • Server → client: {type, data, method?, id?}

Where method ∈ {"get", "put", "post", "delete", "list"}. id is echoed unchanged on responses. The list shorthand {type: "list", list: "<topic>"} is equivalent to {type: "<topic>", method: "list"}.

 1"""The JMRI JSON message envelope.
 2
 3Wire format (see ``contracts/json-schema/schema/json-client.json``):
 4
 5* Client → server: ``{type, data?, list?, method?, id?}``
 6* Server → client: ``{type, data, method?, id?}``
 7
 8Where ``method`` ∈ ``{"get", "put", "post", "delete", "list"}``. ``id`` is
 9echoed unchanged on responses. The ``list`` shorthand ``{type: "list",
10list: "<topic>"}`` is equivalent to ``{type: "<topic>", method: "list"}``.
11"""
12from __future__ import annotations
13
14from typing import Any, Literal
15
16from pydantic import BaseModel, ConfigDict, Field
17
18Method = Literal["get", "put", "post", "delete", "list"]
19
20
21class JmriRequest(BaseModel):
22    """A single client → server message."""
23    model_config = ConfigDict(extra="forbid")
24
25    type: str
26    data: dict[str, Any] | None = None
27    method: Method | None = None
28    list: str | None = None
29    id: int | None = None
30
31
32class JmriResponse(BaseModel):
33    """A single server → client message with payload."""
34    model_config = ConfigDict(extra="forbid")
35
36    type: str
37    data: dict[str, Any] | list[dict[str, Any]] = Field(default_factory=dict)
38    method: Method | None = None
39    id: int | None = None
40
41
42def normalize_request(req: JmriRequest) -> tuple[str, Method, dict[str, Any] | None]:
43    """Resolve the ``list`` shorthand and apply the default method.
44
45    Returns ``(type, method, data)`` ready for dispatch.
46    """
47    if req.type == "list" and req.list is not None:
48        # ``{type: "list", list: "<topic>"}`` shorthand → list of the topic.
49        return req.list, "list", req.data
50    method: Method = req.method if req.method is not None else "get"
51    return req.type, method, req.data
Method = typing.Literal['get', 'put', 'post', 'delete', 'list']
class JmriRequest(pydantic.main.BaseModel):
22class JmriRequest(BaseModel):
23    """A single client → server message."""
24    model_config = ConfigDict(extra="forbid")
25
26    type: str
27    data: dict[str, Any] | None = None
28    method: Method | None = None
29    list: str | None = None
30    id: int | None = None

A single client → server message.

type: str = PydanticUndefined
data: dict[str, typing.Any] | None = None
method: Optional[Literal['get', 'put', 'post', 'delete', 'list']] = None
list: str | None = None
id: int | None = None
class JmriResponse(pydantic.main.BaseModel):
33class JmriResponse(BaseModel):
34    """A single server → client message with payload."""
35    model_config = ConfigDict(extra="forbid")
36
37    type: str
38    data: dict[str, Any] | list[dict[str, Any]] = Field(default_factory=dict)
39    method: Method | None = None
40    id: int | None = None

A single server → client message with payload.

type: str = PydanticUndefined
data: dict[str, typing.Any] | list[dict[str, typing.Any]] = PydanticUndefined
method: Optional[Literal['get', 'put', 'post', 'delete', 'list']] = None
id: int | None = None
def normalize_request( req: JmriRequest) -> tuple[str, typing.Literal['get', 'put', 'post', 'delete', 'list'], dict[str, typing.Any] | None]:
43def normalize_request(req: JmriRequest) -> tuple[str, Method, dict[str, Any] | None]:
44    """Resolve the ``list`` shorthand and apply the default method.
45
46    Returns ``(type, method, data)`` ready for dispatch.
47    """
48    if req.type == "list" and req.list is not None:
49        # ``{type: "list", list: "<topic>"}`` shorthand → list of the topic.
50        return req.list, "list", req.data
51    method: Method = req.method if req.method is not None else "get"
52    return req.type, method, req.data

Resolve the list shorthand and apply the default method.

Returns (type, method, data) ready for dispatch.