Skip to main content

Four packages, one platform, one command

A plugin platform is composed by an application, not by its plugins. Each plugin package in examples/music ships its own standalone create_app for running it alone; datalayer_music_example is the host that runs them together, in dependency order, on one PluginPlatform — which is what the frontend's Plugins panel talks to.

datalayer_music_example is a real distribution — it depends on the four plugin packages, ships the built interface in its wheel, and exposes a console script:

pip install datalayer_music_example
datalayer-music-example

See the host for the construct that makes that one command serve both tiers.

def create_app() -> FastAPI:
reactor = PluginPlatform()
register_catalog(reactor)
register_checkout(reactor)
register_playlist(reactor)
register_mood(reactor)
reactor.start()

app = create_reactor_app(reactor)
app.include_router(catalog_router)
app.include_router(build_checkout_router(reactor))
# Built from the platform rather than imported: the playlist routes read
# their rules per request, so toggling `mood` changes the answer live.
app.include_router(build_playlist_router(reactor))
return app

Registration order is the dependency order the platform enforces: it refuses a plugin whose declared dependencies are not registered yet, so checkout and playlist follow catalog, and mood follows playlist.

The four manifests

PluginDepends onDeclares about the frontendServes
catalogGET /api/catalog/songs
checkoutcatalogrequires @music/checkoutPOST /api/checkout
playlistcataloglikes @music/playlistGET /api/playlist/rules, GET /api/playlist?rule=…
moodplaylistlikes @music/moodnothing — it contributes rules

checkout declares its frontend dependency as required because the endpoint it serves is only ever called by the checkout UI: a backend without it is reachable but unused. playlist and mood declare theirs as optional — those routes answer curl perfectly well on their own.

Ask the server what is missing:

curl -s 'localhost:8799/plugins/frontend-requirements?active=@music/playlist'

The pair, again — on the server

playlist defines the music.playlistRule contribution point and serves whatever is contributed to it. mood contributes three rules from provide_contributions and serves nothing.

The playlist plugin never imports the mood plugin, does not know it exists, and works without it — the same lesson as on the frontend, in a different language.

Each package alone

Every plugin package also builds a standalone app, which is the honest test that a plugin is a plugin rather than a module of the host:

uvicorn catalog_plugin.app:app --reload --port 8799