diff --git a/backend/btrixcloud/main.py b/backend/btrixcloud/main.py index 015972ef..3fa96f87 100644 --- a/backend/btrixcloud/main.py +++ b/backend/btrixcloud/main.py @@ -11,6 +11,9 @@ from fastapi import FastAPI, HTTPException from fastapi.responses import JSONResponse from fastapi.routing import APIRouter +from fastapi.openapi.utils import get_openapi +from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html + from .db import init_db, await_db_and_migrations, update_and_prepare_db from .emailsender import EmailSender @@ -34,18 +37,45 @@ from .subs import init_subs_api from .crawlmanager import CrawlManager from .utils import run_once_lock, register_exit_handler, is_bool - +from .version import __version__ API_PREFIX = "/api" -app_root = FastAPI( - docs_url=API_PREFIX + "/docs", - redoc_url=API_PREFIX + "/redoc", - openapi_url=API_PREFIX + "/openapi.json", -) + +OPENAPI_URL = API_PREFIX + "/openapi.json" + +app_root = FastAPI(docs_url=None, redoc_url=None, OPENAPI_URL=OPENAPI_URL) db_inited = {"inited": False} +# ============================================================================ +def make_schema(): + """make custom openapi schema""" + schema = get_openapi( + title="Browsertrix", + description="""\ +The Browsertrix API provides access to all aspects of the Browsertrix app. + +See [https://docs.browsertrix.com/](https://docs.browsertrix.com/) for more info on deploying Browsertrix\ + """, + summary="Browsertrix Crawling System API", + version=__version__, + terms_of_service="http://browsertrix.com/terms", + contact={ + "name": "Browsertrix", + "url": "https://browsertrix.com/", + "email": "info@webrecorder.net", + }, + license_info={ + "name": "AGPL v3", + "url": "https://www.gnu.org/licenses/agpl-3.0.en.html", + }, + routes=app_root.routes, + ) + schema["info"]["x-logo"] = {"url": "/docs-logo.svg"} + return schema + + # ============================================================================ # pylint: disable=too-many-locals, duplicate-code def main(): @@ -200,7 +230,6 @@ def main(): return settings # internal routes - @app.get("/openapi.json", include_in_schema=False) async def openapi() -> JSONResponse: return JSONResponse(app_root.openapi()) @@ -221,6 +250,31 @@ def main(): app_root.include_router(app, prefix=API_PREFIX) + # API Configurations -- needed to provide custom favicon + @app_root.get(API_PREFIX + "/docs", include_in_schema=False) + def overridden_swagger(): + return get_swagger_ui_html( + openapi_url=OPENAPI_URL, + title="Browsertrix API", + swagger_favicon_url="/favicon.ico", + ) + + @app_root.get(API_PREFIX + "/redoc", include_in_schema=False) + def overridden_redoc(): + return get_redoc_html( + openapi_url=OPENAPI_URL, + title="Browsertrix API", + redoc_favicon_url="/favicon.ico", + ) + + def get_api_schema(): + if not app_root.openapi_schema: + app_root.openapi_schema = make_schema() + + return app_root.openapi_schema + + app_root.openapi = get_api_schema # type: ignore + # ============================================================================ @app_root.on_event("startup") diff --git a/backend/test/test_api.py b/backend/test/test_api.py new file mode 100644 index 00000000..ef4d7c11 --- /dev/null +++ b/backend/test/test_api.py @@ -0,0 +1,32 @@ +import requests + +from .conftest import API_PREFIX + + +def test_api_docs(): + r = requests.get(f"{API_PREFIX}/docs") + assert r.status_code == 200 + + text = r.text + assert "