Router Extensions
A router extension refers to API endpoints, paths, and the namespaces within the Python Interface. They are the exposed, user-facing, functions and power all of the interfaces - REST API, MCP, Notebook, etc.
Under the hood, router extension modules are instances of fastapi.APIRouter.
Folder structure
router_example
├── README.md
├── openbb_empty_router
│ └── __init__.py
│ └── empty_router.py
├── poetry.lock
└── pyproject.toml
Extension code will go in the empty_router.py file, and __init__.py contains no code.
TOML File
The entry point for the extension is specified as a Poetry plugin, near the bottom of the file.
pyproject.toml
[tool.poetry]
name = "openbb-empty-router"
version = "0.0.0"
description = "An empty OpenBB Router extension"
authors = ["Hello <hello@world.com>"]
readme = "README.md"
packages = [{ include = "openbb_empty_router" }]
[tool.poetry.dependencies]
python = "^3.10,<3.14"
openbb-core = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.plugins."openbb_core_extension"]
empty = "openbb_empty_router.empty_router:router"
Imports
Here's how to import the Router class, and initialize it.
from openbb_core.app.model.obbject import OBBject
from openbb_core.app.router import Router
router = Router(prefix="", description="An Empty OpenBB Router Extension.")
The prefix will be determined by pyproject.toml
[tool.poetry.plugins."openbb_core_extension"]
empty = "openbb_empty_router.empty_router:router"
Router commands will be available under the namepsace, obb.empty
Provider Interface Imports
Routing an endpoint to the Provider Interface requires other imports, and a distinct function signature.
from openbb_core.app.model.command_context import CommandContext
from openbb_core.app.model.example import APIEx, PythonEx
from openbb_core.app.model.obbject import OBBject
from openbb_core.app.provider_interface import (
ExtraParams,
ProviderChoices,
StandardParams,
)
from openbb_core.app.query import Query
Endpoints
The Router instance is applied as a decorator, using @router.command.
There are two varities of endpoint, and endpoint's path will be the name of the function.
Provider Interface
To implement a Provider metamodel, define the function as:
# This uses the Provider Interface to call the empty provider fetcher.
@router.command(
model="Empty", # This is the metamodel defined in the Provider's `fetcher_dict`.
examples=[
APIEx(parameters={"provider": "empty"}),
PythonEx(
description="Say Hello.",
code=[
"result = obb.empty.hello()",
],
),
],
)
async def empty_function(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject:
"""An empty function using the Provider Interface."""
return await OBBject.from_query(Query(**locals()))
Basic - GET
A basic endpoint, where all business logic occurs within, will look like:
# This is a standard router "get" command.
@router.command(methods=["GET"])
async def hello() -> (
OBBject[str]
):
"""OpenBB Hello World."""
return OBBject(results="Hello from the Empty Router extension!")
Basic - POST
from openbb_core.provider.abstract.data import Data
# This is a standard router "post" command.
@router.command(methods=["POST"])
async def hello(
data: Data, # Body parameter
some_param: str # Query parameter
) -> OBBject:
"""OpenBB Hello World."""
return OBBject(results=data.model_dump())
Decorator Parameters
The @router.command decorator will accept:
methods: List of HTTP methods - typicallyGETorPOST.model: A metamodel associated with aProviderextension endpoint.deprecated: Instance ofDeprecated.examples: List of API or Python Examples.exclude_from_api: Include endpoint only in Python Interface.no_validate: Set asTrueto ignore response validation and treat asAny.openapi_extra: Dictionary of additional metadata to include inopenapi.json.- Use this as an entrypoint for inline configurations of
widget_configormcp_config
- Use this as an entrypoint for inline configurations of
Using fastapi.APIRouter
The instance of fastapi.APIRouter can be accessed from the router._api_router attribute, and can be used directly as a normal, FastAPI, decorator.
@router._api_router.get("/also_empty")
async def also_empty(param: str) -> str:
"""Also Emmpty"""
return "Hello world!"