I'm trying to create a simple pluggable FastAPI application where plugins can add, or not, API endpoints
This is my folder structure:
server.py
import importlib
import pkgutil
from pathlib import Path
import uvicorn
from fastapi import FastAPI
PLUGINS_PATH = Path(__file__).parent.joinpath("plugins")
app = FastAPI()
def import_module(module_name):
"""Imports a module by it's name from plugins folder."""
module = f"plugins.{module_name}"
return importlib.import_module(module, ".")
def load_plugins() -> list:
"""Import plugins from plugins folder."""
loaded_apps = []
for _, application, _ in pkgutil.iter_modules([str(PLUGINS_PATH)]):
module = import_module(application)
print(
f"Loaded app: {module.__meta__['plugin_name']} -- version: {module.__meta__['version']}"
)
loaded_apps.append(module)
return loaded_apps
@app.get("/")
def main():
return "Hello World!"
if __name__ == "__main__":
plugins = load_plugins()
for plugin in plugins:
"""Register the plugins router."""
if "router" in plugin.__dir__():
app_router = plugin.router
app.include_router(app_router)
uvicorn.run("server:app", host="localhost", port=8000, reload=True)
And in my plugins folder I have:
The plugins/non_api_plugin/__init__.py:
__meta__ = {"plugin_name": "NON API plugin", "version": "0.0.1"}
The plugins/<v1|v2>/__init__.py
from .routes import routes as router
__meta__ = {"plugin_name": "API <v1|v2>", "version": "0.0.1"}
And routes.py files:
from fastapi import APIRouter
routes = APIRouter(prefix="/<v1|v2>")
@routes.get("/")
def novels():
return "Hello World from <v1|v2>"
When I run the server, the plugins are loaded and log their information, but the API endpoints are not loaded.
What I'm missing here? My best guess is that my plugin load system is wrong at some point.
