diff --git a/.gitignore b/.gitignore index 658edd2..066276e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,8 @@ job_review.py check_missing.py **/auth/* **/radio_api/* +**/test/* test/db_stats.py test/report/* .gitignore -.env \ No newline at end of file +.env diff --git a/README.md b/README.md index 3d0fc9f..84e7103 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ A modern FastAPI-based backend providing various endpoints for media, authentica ## Overview -This server is built with [FastAPI](https://fastapi.tiangolo.com/) and provides a comprehensive API for multiple services. The interactive API documentation is available at the [Swagger UI](https://api.codey.lol/docs). +This server is built with [FastAPI](https://fastapi.tiangolo.com/) and provides a comprehensive API for multiple services. API documentation is available in three formats: +- **Swagger UI**: [https://api.codey.lol/docs](https://api.codey.lol/docs) - Classic interactive API explorer with "Try it out" functionality +- **Scalar**: [https://api.codey.lol/scalar](https://api.codey.lol/scalar) - Modern, fast interactive API documentation (recommended) +- **ReDoc**: [https://api.codey.lol/redoc](https://api.codey.lol/redoc) - Clean, read-only documentation with better visual design ## API Endpoints diff --git a/base.py b/base.py index 5ecb0ee..ffa3562 100644 --- a/base.py +++ b/base.py @@ -7,6 +7,7 @@ import asyncio from typing import Any from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware +from scalar_fastapi import get_scalar_api_reference from lyric_search.sources import redis_cache logging.basicConfig(level=logging.INFO) @@ -21,6 +22,8 @@ app = FastAPI( contact={"name": "codey"}, redirect_slashes=False, loop=loop, + docs_url="/docs", # Swagger UI (default) + redoc_url="/redoc", # ReDoc UI (default, but explicitly set) ) constants = importlib.import_module("constants").Constants() @@ -43,6 +46,13 @@ app.add_middleware( allow_headers=["*"], ) # type: ignore +# Add Scalar API documentation endpoint (before blacklist routes) +@app.get("/scalar", include_in_schema=False) +def scalar_docs(): + return get_scalar_api_reference( + openapi_url="/openapi.json", + title="codey.lol API" + ) """ Blacklisted routes @@ -62,10 +72,13 @@ def base_head(): @app.get("/{path}", include_in_schema=False) def disallow_get_any(request: Request, var: Any = None): path = request.path_params["path"] + allowed_paths = ["widget", "misc/no", "docs", "redoc", "scalar", "openapi.json"] + logging.info(f"Checking path: {path}, allowed: {path in allowed_paths or path.split('/', maxsplit=1)[0] in allowed_paths}") if not ( isinstance(path, str) - and (path.split("/", maxsplit=1) == "widget" or path == "misc/no") + and (path.split("/", maxsplit=1)[0] in allowed_paths or path in allowed_paths) ): + logging.error(f"BLOCKED path: {path}") return util.get_blocked_response() else: logging.info("OK, %s", path) @@ -117,7 +130,6 @@ if radio_endpoint: End Actionable Routes """ - """ Startup """