misc: Set prefix and tags to API routers

Improve OpenAPI documentation by setting tags to each API router. Also,
set a prefix to each router to group the endpoints by their
functionality.
This commit is contained in:
Michael Manganiello
2025-02-09 11:29:05 -03:00
parent 0ea6b3d8ee
commit 70825830c4
16 changed files with 117 additions and 76 deletions

View File

@@ -23,7 +23,9 @@ from utils.router import APIRouter
ACCESS_TOKEN_EXPIRE_MINUTES: Final = 30
REFRESH_TOKEN_EXPIRE_DAYS: Final = 7
router = APIRouter()
router = APIRouter(
tags=["auth"],
)
# Session authentication endpoints

View File

@@ -23,10 +23,13 @@ from PIL import Image
from sqlalchemy.inspection import inspect
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/collections",
tags=["collections"],
)
@protected_route(router.post, "/collections", [Scope.COLLECTIONS_WRITE])
@protected_route(router.post, "/", [Scope.COLLECTIONS_WRITE])
async def add_collection(
request: Request,
artwork: UploadFile | None = None,
@@ -95,7 +98,7 @@ async def add_collection(
return CollectionSchema.model_validate(created_collection)
@protected_route(router.get, "/collections", [Scope.COLLECTIONS_READ])
@protected_route(router.get, "/", [Scope.COLLECTIONS_READ])
def get_collections(request: Request) -> list[CollectionSchema]:
"""Get collections endpoint
@@ -111,7 +114,7 @@ def get_collections(request: Request) -> list[CollectionSchema]:
return CollectionSchema.for_user(request.user.id, [c for c in collections])
@protected_route(router.get, "/collections/{id}", [Scope.COLLECTIONS_READ])
@protected_route(router.get, "/{id}", [Scope.COLLECTIONS_READ])
def get_collection(request: Request, id: int) -> CollectionSchema:
"""Get collections endpoint
@@ -131,7 +134,7 @@ def get_collection(request: Request, id: int) -> CollectionSchema:
return CollectionSchema.model_validate(collection)
@protected_route(router.put, "/collections/{id}", [Scope.COLLECTIONS_WRITE])
@protected_route(router.put, "/{id}", [Scope.COLLECTIONS_WRITE])
async def update_collection(
request: Request,
id: int,
@@ -221,7 +224,7 @@ async def update_collection(
return CollectionSchema.model_validate(updated_collection)
@protected_route(router.delete, "/collections/{id}", [Scope.COLLECTIONS_WRITE])
@protected_route(router.delete, "/{id}", [Scope.COLLECTIONS_WRITE])
async def delete_collections(request: Request, id: int) -> MessageResponse:
"""Delete collections endpoint

View File

@@ -11,10 +11,13 @@ from handler.auth.constants import Scope
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/config",
tags=["config"],
)
@router.get("/config")
@router.get("/")
def get_config() -> ConfigResponse:
"""Get config endpoint
@@ -41,7 +44,7 @@ def get_config() -> ConfigResponse:
) from exc
@protected_route(router.post, "/config/system/platforms", [Scope.PLATFORMS_WRITE])
@protected_route(router.post, "/system/platforms", [Scope.PLATFORMS_WRITE])
async def add_platform_binding(request: Request) -> MessageResponse:
"""Add platform binding to the configuration"""
@@ -60,9 +63,7 @@ async def add_platform_binding(request: Request) -> MessageResponse:
return {"msg": f"{fs_slug} binded to: {slug} successfully!"}
@protected_route(
router.delete, "/config/system/platforms/{fs_slug}", [Scope.PLATFORMS_WRITE]
)
@protected_route(router.delete, "/system/platforms/{fs_slug}", [Scope.PLATFORMS_WRITE])
async def delete_platform_binding(request: Request, fs_slug: str) -> MessageResponse:
"""Delete platform binding from the configuration"""
@@ -77,7 +78,7 @@ async def delete_platform_binding(request: Request, fs_slug: str) -> MessageResp
return {"msg": f"{fs_slug} bind removed successfully!"}
@protected_route(router.post, "/config/system/versions", [Scope.PLATFORMS_WRITE])
@protected_route(router.post, "/system/versions", [Scope.PLATFORMS_WRITE])
async def add_platform_version(request: Request) -> MessageResponse:
"""Add platform version to the configuration"""
@@ -96,9 +97,7 @@ async def add_platform_version(request: Request) -> MessageResponse:
return {"msg": f"Added {fs_slug} as version of: {slug} successfully!"}
@protected_route(
router.delete, "/config/system/versions/{fs_slug}", [Scope.PLATFORMS_WRITE]
)
@protected_route(router.delete, "/system/versions/{fs_slug}", [Scope.PLATFORMS_WRITE])
async def delete_platform_version(request: Request, fs_slug: str) -> MessageResponse:
"""Delete platform version from the configuration"""
@@ -113,7 +112,7 @@ async def delete_platform_version(request: Request, fs_slug: str) -> MessageResp
return {"msg": f"{fs_slug} version removed successfully!"}
@protected_route(router.post, "/config/exclude", [Scope.PLATFORMS_WRITE])
@protected_route(router.post, "/exclude", [Scope.PLATFORMS_WRITE])
async def add_exclusion(request: Request) -> MessageResponse:
"""Add platform exclusion to the configuration"""
@@ -135,7 +134,7 @@ async def add_exclusion(request: Request) -> MessageResponse:
@protected_route(
router.delete,
"/config/exclude/{exclusion_type}/{exclusion_value}",
"/exclude/{exclusion_type}/{exclusion_value}",
[Scope.PLATFORMS_WRITE],
)
async def delete_exclusion(

View File

@@ -22,7 +22,9 @@ from models.rom import Rom
from starlette.datastructures import URLPath
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
tags=["feeds"],
)
@protected_route(

View File

@@ -11,10 +11,13 @@ from handler.scan_handler import scan_firmware
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/firmware",
tags=["firmware"],
)
@protected_route(router.post, "/firmware", [Scope.FIRMWARE_WRITE])
@protected_route(router.post, "/", [Scope.FIRMWARE_WRITE])
def add_firmware(
request: Request,
platform_id: int,
@@ -81,7 +84,7 @@ def add_firmware(
}
@protected_route(router.get, "/firmware", [Scope.FIRMWARE_READ])
@protected_route(router.get, "/", [Scope.FIRMWARE_READ])
def get_platform_firmware(
request: Request,
platform_id: int | None = None,
@@ -102,7 +105,7 @@ def get_platform_firmware(
@protected_route(
router.get,
"/firmware/{id}",
"/{id}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.FIRMWARE_READ],
)
def get_firmware(request: Request, id: int) -> FirmwareSchema:
@@ -126,7 +129,7 @@ def get_firmware(request: Request, id: int) -> FirmwareSchema:
@protected_route(
router.head,
"/firmware/{id}/content/{file_name}",
"/{id}/content/{file_name}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.FIRMWARE_READ],
)
def head_firmware_content(request: Request, id: int, file_name: str):
@@ -160,7 +163,7 @@ def head_firmware_content(request: Request, id: int, file_name: str):
@protected_route(
router.get,
"/firmware/{id}/content/{file_name}",
"/{id}/content/{file_name}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.FIRMWARE_READ],
)
def get_firmware_content(
@@ -190,7 +193,7 @@ def get_firmware_content(
return FileResponse(path=firmware_path, filename=firmware.file_name)
@protected_route(router.post, "/firmware/delete", [Scope.FIRMWARE_WRITE])
@protected_route(router.post, "/delete", [Scope.FIRMWARE_WRITE])
async def delete_firmware(
request: Request,
) -> MessageResponse:

View File

@@ -21,7 +21,9 @@ from handler.metadata.sgdb_handler import STEAMGRIDDB_API_ENABLED
from utils import get_version
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
tags=["system"],
)
@router.get("/heartbeat")

View File

@@ -14,10 +14,13 @@ from handler.scan_handler import scan_platform
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/platforms",
tags=["platforms"],
)
@protected_route(router.post, "/platforms", [Scope.PLATFORMS_WRITE])
@protected_route(router.post, "/", [Scope.PLATFORMS_WRITE])
async def add_platforms(request: Request) -> PlatformSchema:
"""Create platform endpoint
@@ -40,7 +43,7 @@ async def add_platforms(request: Request) -> PlatformSchema:
)
@protected_route(router.get, "/platforms", [Scope.PLATFORMS_READ])
@protected_route(router.get, "/", [Scope.PLATFORMS_READ])
def get_platforms(request: Request) -> list[PlatformSchema]:
"""Get platforms endpoint
@@ -57,7 +60,7 @@ def get_platforms(request: Request) -> list[PlatformSchema]:
]
@protected_route(router.get, "/platforms/supported", [Scope.PLATFORMS_READ])
@protected_route(router.get, "/supported", [Scope.PLATFORMS_READ])
def get_supported_platforms(request: Request) -> list[PlatformSchema]:
"""Get list of supported platforms endpoint
@@ -94,7 +97,7 @@ def get_supported_platforms(request: Request) -> list[PlatformSchema]:
return supported_platforms
@protected_route(router.get, "/platforms/{id}", [Scope.PLATFORMS_READ])
@protected_route(router.get, "/{id}", [Scope.PLATFORMS_READ])
def get_platform(request: Request, id: int) -> PlatformSchema:
"""Get platforms endpoint
@@ -114,7 +117,7 @@ def get_platform(request: Request, id: int) -> PlatformSchema:
return PlatformSchema.model_validate(platform)
@protected_route(router.put, "/platforms/{id}", [Scope.PLATFORMS_WRITE])
@protected_route(router.put, "/{id}", [Scope.PLATFORMS_WRITE])
async def update_platform(request: Request, id: int) -> PlatformSchema:
"""Update platform endpoint
@@ -138,7 +141,7 @@ async def update_platform(request: Request, id: int) -> PlatformSchema:
return PlatformSchema.model_validate(platform_db)
@protected_route(router.delete, "/platforms/{id}", [Scope.PLATFORMS_WRITE])
@protected_route(router.delete, "/{id}", [Scope.PLATFORMS_WRITE])
async def delete_platforms(request: Request, id: int) -> MessageResponse:
"""Delete platforms endpoint

View File

@@ -5,16 +5,19 @@ from fastapi.responses import FileResponse
from handler.auth.constants import Scope
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/raw",
tags=["raw"],
)
@protected_route(router.head, "/raw/assets/{path:path}", [Scope.ASSETS_READ])
@protected_route(router.head, "/assets/{path:path}", [Scope.ASSETS_READ])
def head_raw_asset(request: Request, path: str):
asset_path = f"{ASSETS_BASE_PATH}/{path}"
return FileResponse(path=asset_path, filename=path.split("/")[-1])
@protected_route(router.get, "/raw/assets/{path:path}", [Scope.ASSETS_READ])
@protected_route(router.get, "/assets/{path:path}", [Scope.ASSETS_READ])
def get_raw_asset(request: Request, path: str):
"""Download a single asset file

View File

@@ -42,10 +42,13 @@ from utils.hashing import crc32_to_hex
from utils.nginx import FileRedirectResponse, ZipContentLine, ZipResponse
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/roms",
tags=["roms"],
)
@protected_route(router.post, "/roms", [Scope.ROMS_WRITE])
@protected_route(router.post, "/", [Scope.ROMS_WRITE])
async def add_rom(request: Request):
"""Upload single rom endpoint
@@ -107,7 +110,7 @@ async def add_rom(request: Request):
return Response(status_code=status.HTTP_201_CREATED)
@protected_route(router.get, "/roms", [Scope.ROMS_READ])
@protected_route(router.get, "/", [Scope.ROMS_READ])
def get_roms(
request: Request,
platform_id: int | None = None,
@@ -170,7 +173,7 @@ def get_roms(
@protected_route(
router.get,
"/roms/{id}",
"/{id}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.ROMS_READ],
)
def get_rom(request: Request, id: int) -> DetailedRomSchema:
@@ -194,7 +197,7 @@ def get_rom(request: Request, id: int) -> DetailedRomSchema:
@protected_route(
router.head,
"/roms/{id}/content/{file_name}",
"/{id}/content/{file_name}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.ROMS_READ],
)
async def head_rom_content(
@@ -280,7 +283,7 @@ async def head_rom_content(
@protected_route(
router.get,
"/roms/{id}/content/{file_name}",
"/{id}/content/{file_name}",
[] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.ROMS_READ],
)
async def get_rom_content(
@@ -396,7 +399,7 @@ async def get_rom_content(
)
@protected_route(router.put, "/roms/{id}", [Scope.ROMS_WRITE])
@protected_route(router.put, "/{id}", [Scope.ROMS_WRITE])
async def update_rom(
request: Request,
id: int,
@@ -572,7 +575,7 @@ async def update_rom(
return DetailedRomSchema.from_orm_with_request(rom, request)
@protected_route(router.post, "/roms/delete", [Scope.ROMS_WRITE])
@protected_route(router.post, "/delete", [Scope.ROMS_WRITE])
async def delete_roms(
request: Request,
) -> MessageResponse:
@@ -631,7 +634,7 @@ async def delete_roms(
return {"msg": f"{len(roms_ids)} roms deleted successfully!"}
@protected_route(router.put, "/roms/{id}/props", [Scope.ROMS_USER_WRITE])
@protected_route(router.put, "/{id}/props", [Scope.ROMS_USER_WRITE])
async def update_rom_user(request: Request, id: int) -> RomUserSchema:
data = await request.json()
rom_user_data = data.get("data", {})

View File

@@ -12,10 +12,13 @@ from handler.scan_handler import scan_save
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/saves",
tags=["saves"],
)
@protected_route(router.post, "/saves", [Scope.ASSETS_WRITE])
@protected_route(router.post, "/", [Scope.ASSETS_WRITE])
def add_saves(
request: Request,
rom_id: int,
@@ -84,17 +87,17 @@ def add_saves(
}
# @protected_route(router.get, "/saves", [Scope.ASSETS_READ])
# @protected_route(router.get, "/", [Scope.ASSETS_READ])
# def get_saves(request: Request) -> MessageResponse:
# pass
# @protected_route(router.get, "/saves/{id}", [Scope.ASSETS_READ])
# @protected_route(router.get, "/{id}", [Scope.ASSETS_READ])
# def get_save(request: Request, id: int) -> MessageResponse:
# pass
@protected_route(router.put, "/saves/{id}", [Scope.ASSETS_WRITE])
@protected_route(router.put, "/{id}", [Scope.ASSETS_WRITE])
async def update_save(request: Request, id: int) -> SaveSchema:
data = await request.form()
@@ -128,7 +131,7 @@ async def update_save(request: Request, id: int) -> SaveSchema:
return SaveSchema.model_validate(db_save)
@protected_route(router.post, "/saves/delete", [Scope.ASSETS_WRITE])
@protected_route(router.post, "/delete", [Scope.ASSETS_WRITE])
async def delete_saves(request: Request) -> MessageResponse:
data: dict = await request.json()
save_ids: list = data["saves"]

View File

@@ -9,10 +9,13 @@ from handler.scan_handler import scan_screenshot
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/screenshots",
tags=["screenshots"],
)
@protected_route(router.post, "/screenshots", [Scope.ASSETS_WRITE])
@protected_route(router.post, "/", [Scope.ASSETS_WRITE])
def add_screenshots(
request: Request,
rom_id: int,

View File

@@ -12,10 +12,13 @@ from handler.scan_handler import _get_main_platform_igdb_id
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/search",
tags=["search"],
)
@protected_route(router.get, "/search/roms", [Scope.ROMS_READ])
@protected_route(router.get, "/roms", [Scope.ROMS_READ])
async def search_rom(
request: Request,
rom_id: int,
@@ -117,7 +120,7 @@ async def search_rom(
return matched_roms
@protected_route(router.get, "/search/cover", [Scope.ROMS_READ])
@protected_route(router.get, "/cover", [Scope.ROMS_READ])
async def search_cover(
request: Request,
search_term: str = "",

View File

@@ -12,10 +12,13 @@ from handler.scan_handler import scan_state
from logger.logger import log
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/states",
tags=["states"],
)
@protected_route(router.post, "/states", [Scope.ASSETS_WRITE])
@protected_route(router.post, "/", [Scope.ASSETS_WRITE])
def add_states(
request: Request,
rom_id: int,
@@ -83,17 +86,17 @@ def add_states(
}
# @protected_route(router.get, "/states", [Scope.ASSETS_READ])
# @protected_route(router.get, "/", [Scope.ASSETS_READ])
# def get_states(request: Request) -> MessageResponse:
# pass
# @protected_route(router.get, "/states/{id}", [Scope.ASSETS_READ])
# @protected_route(router.get, "/{id}", [Scope.ASSETS_READ])
# def get_state(request: Request, id: int) -> MessageResponse:
# pass
@protected_route(router.put, "/states/{id}", [Scope.ASSETS_WRITE])
@protected_route(router.put, "/{id}", [Scope.ASSETS_WRITE])
async def update_state(request: Request, id: int) -> StateSchema:
data = await request.form()
@@ -126,7 +129,7 @@ async def update_state(request: Request, id: int) -> StateSchema:
return StateSchema.model_validate(db_state)
@protected_route(router.post, "/states/delete", [Scope.ASSETS_WRITE])
@protected_route(router.post, "/delete", [Scope.ASSETS_WRITE])
async def delete_states(request: Request) -> MessageResponse:
data: dict = await request.json()
state_ids: list = data["states"]

View File

@@ -2,10 +2,13 @@ from endpoints.responses.stats import StatsReturn
from handler.database import db_stats_handler
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/stats",
tags=["stats"],
)
@router.get("/stats")
@router.get("/")
def stats() -> StatsReturn:
"""Endpoint to return the current RomM stats

View File

@@ -5,10 +5,13 @@ from handler.auth.constants import Scope
from tasks.update_switch_titledb import update_switch_titledb_task
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/tasks",
tags=["tasks"],
)
@protected_route(router.post, "/tasks/run", [Scope.TASKS_RUN])
@protected_route(router.post, "/run", [Scope.TASKS_RUN])
async def run_tasks(request: Request) -> MessageResponse:
"""Run all tasks endpoint
@@ -22,7 +25,7 @@ async def run_tasks(request: Request) -> MessageResponse:
return {"msg": "All tasks ran successfully!"}
@protected_route(router.post, "/tasks/{task}/run", [Scope.TASKS_RUN])
@protected_route(router.post, "/{task}/run", [Scope.TASKS_RUN])
async def run_task(request: Request, task: str) -> MessageResponse:
"""Run all tasks endpoint

View File

@@ -16,12 +16,15 @@ from logger.logger import log
from models.user import Role, User
from utils.router import APIRouter
router = APIRouter()
router = APIRouter(
prefix="/users",
tags=["users"],
)
@protected_route(
router.post,
"/users",
"/",
[],
status_code=status.HTTP_201_CREATED,
)
@@ -77,7 +80,7 @@ def add_user(
return UserSchema.model_validate(db_user_handler.add_user(user))
@protected_route(router.get, "/users", [Scope.USERS_READ])
@protected_route(router.get, "/", [Scope.USERS_READ])
def get_users(request: Request) -> list[UserSchema]:
"""Get all users endpoint
@@ -91,7 +94,7 @@ def get_users(request: Request) -> list[UserSchema]:
return [UserSchema.model_validate(u) for u in db_user_handler.get_users()]
@protected_route(router.get, "/users/me", [Scope.ME_READ])
@protected_route(router.get, "/me", [Scope.ME_READ])
def get_current_user(request: Request) -> UserSchema | None:
"""Get current user endpoint
@@ -105,7 +108,7 @@ def get_current_user(request: Request) -> UserSchema | None:
return request.user
@protected_route(router.get, "/users/{id}", [Scope.USERS_READ])
@protected_route(router.get, "/{id}", [Scope.USERS_READ])
def get_user(request: Request, id: int) -> UserSchema:
"""Get user endpoint
@@ -123,7 +126,7 @@ def get_user(request: Request, id: int) -> UserSchema:
return UserSchema.model_validate(user)
@protected_route(router.put, "/users/{id}", [Scope.ME_WRITE])
@protected_route(router.put, "/{id}", [Scope.ME_WRITE])
async def update_user(
request: Request, id: int, form_data: Annotated[UserForm, Depends()]
) -> UserSchema:
@@ -220,7 +223,7 @@ async def update_user(
return UserSchema.model_validate(db_user)
@protected_route(router.delete, "/users/{id}", [Scope.USERS_WRITE])
@protected_route(router.delete, "/{id}", [Scope.USERS_WRITE])
def delete_user(request: Request, id: int) -> MessageResponse:
"""Delete user endpoint