Skip to content
Jennings Zhang edited this page Jan 19, 2023 · 2 revisions

There is a lot of metaprogramming magic in the module chris.link which enables the code everywhere else to be declarative. The modules chris.client and chris.models are mostly type definitions, using the decorators of chris.link.http to "code itself."

Linked Objects and the @http decorators

Everything in CUBE has links: on the base URL there are collection_links, things like plugin instances have a link to their feed, etc. Linked is the superclass of most classes in aiochris.

Subclasses of Linked can make HTTP requests to their links easily by defining methods decorated by parameterized decorators defined in the chris.link.http module. For example:

import serde
import dataclasses
from typing import Optional
from chris.link import http
from chris.link.linked import LinkedModel


@serde.deserialize
@dataclasses.dataclass(frozen=True)
class PluginInstance(LinkedModel):

    url: str   # URL link of this plugin instance
    feed: str  # URL link to plugin instance's feed
    id: int    # plugin instance ID number
    title: str
    previous_id: Optional[int]

    @http.get("feed")
    async def get_feed(self) -> "Feed":
        ...

    @http.put("url")
    async def set(
        self, title: Optional[str] = None, status: Optional[str] = None
    ) -> "PluginInstance":
        ...

    @http.delete("url")
    def delete(self) -> None:
        ...

The example above differs from the real chris.models.logged_in.PluginInstance in how its fields are defined in a superclass chris.models.data.PluginInstanceData.

The parameter to the @http.* decorator is the name of a link in the class. These values are validated by the metaclass chris.link.linked.LinkedMeta at the time of class definition, so that typos are caught early.

Class Hierarchy Diagram

                                           ┌──────┐
                                           │Linked│
                                           └──┬───┘
                                              │
                           ┌──────────────────┴─────────────────────┐
                           │                                        │
               ┌───────────▼───────────┐                       ┌────▼──────┐
               │CollectionJsonApiClient│                       │LinkedModel│
               └──┬───────────────┬────┘                       └────┬──────┘
                  │               │                                 │
                  │               │                                 │
         ┌────────▼──────┐    ┌───▼───────────┐    ┌────────────────┴───┬───────────────┬──────────┐
         │BaseChrisClient│    │_AdminApiClient│    │                    │               │          │
         └──┬──────────┬─┘    └───────────────┘    │                    │               │          │
            │          │                       ┌───▼────────┐  ┌────────▼─────────┐ ┌───▼────┐   ┌─▼─┐
            │          │                       │PublicPlugin│  │PluginInstanceData│ │FeedData│   │...│
┌───────────▼───┐  ┌───▼───────────────┐       └─────┬──────┘  └────────┬─────────┘ └───┬────┘   └─┬─┘
│AnonChrisClient│  │AuthenticatedClient│             │                  │               │          │
└───────────────┘  └───┬───────────┬───┘             │                  │               │          │
                       │           │              ┌──▼───┐       ┌──────▼───────┐     ┌─▼──┐     ┌─▼─┐
                       │           │              │Plugin│       │PluginInstance│     │Feed│     │...│
                 ┌─────▼─────┐ ┌───▼────────────┐ └──────┘       └──────────────┘     └────┘     └───┘
                 │ChrisClient│ │ChrisAdminClient│
                 └───────────┘ └────────────────┘
Clone this wiki locally