132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
import os
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.responses import RedirectResponse
|
|
from scalar_fastapi import get_scalar_api_reference
|
|
from app.routes import discovery, reviews, stats
|
|
|
|
ROOT_PATH = os.environ.get("ROOT_PATH", "")
|
|
|
|
DESCRIPTION = """
|
|
Hi, this is a read-only API exposing 20+ years of my personal media reviews of movies, books,
|
|
and television since 2001.
|
|
|
|
This API provides structured access to a personal media review database. Every
|
|
review includes a date, category, title, creator, genre, rating, and optional
|
|
written commentary.
|
|
|
|
## Rating scale
|
|
|
|
Ratings use a **-3.0 to 3.0** scale:
|
|
|
|
| Rating | Meaning |
|
|
|--------|---------|
|
|
| 3.0 | Masterpiece, tears flowed |
|
|
| 2.0 | Great, I was glowing for a day |
|
|
| 1.0 | Good enough use of my time |
|
|
| 0.0 | Meh, a void of space |
|
|
| -1.0 | Below average, should have spent this time knitting |
|
|
| -2.0 | Bad, I want someone to pay me for this |
|
|
| -3.0 | Terrible, I felt like I needed to use toilet paper after |
|
|
|
|
## Getting started
|
|
|
|
- Browse available categories, genres, and creators via the **Discovery**
|
|
endpoints
|
|
- Fetch reviews with filtering and pagination via **GET /reviews**
|
|
- Explore aggregate statistics via the **Statistics** endpoints
|
|
- Get a surprise recommendation via **GET /reviews/random**
|
|
|
|
## About
|
|
|
|
This API is a portfolio project demonstrating API design and documentation
|
|
skills. Built with [FastAPI](https://fastapi.tiangolo.com/) and documented
|
|
with [Scalar](https://scalar.com/). To see release notes, go to the
|
|
[Releases](https://gugulet.hu/technical/git/g_it/api/releases) page.
|
|
"""
|
|
|
|
CUSTOM_CSS = """
|
|
.darklight-reference-promo { display: none !important; }
|
|
|
|
.light-mode {
|
|
--scalar-color-1: #343434;
|
|
--scalar-color-2: #666666;
|
|
--scalar-color-3: #979797;
|
|
--scalar-color-accent: #C9C9C9;
|
|
--scalar-background-1: #FAFAFA;
|
|
--scalar-background-2: #FFFFFF;
|
|
--scalar-background-3: #FFFFFF;
|
|
--scalar-background-accent: #FFFFFF;
|
|
--scalar-border-color: transparent;
|
|
}
|
|
|
|
@font-face {
|
|
font-display: swap;
|
|
font-family: 'DM Sans';
|
|
font-style: normal;
|
|
font-weight: 100 700;
|
|
src: url('https://gugulet.hu/technical/git/g_it/site/raw/branch/main/content/assets/fonts/dm-sans.ttf') format('truetype');
|
|
}
|
|
|
|
@font-face {
|
|
font-display: swap;
|
|
font-family: 'DM Mono';
|
|
font-style: normal;
|
|
font-weight: 100 700;
|
|
src: url('https://gugulet.hu/technical/git/g_it/site/raw/branch/main/content/assets/fonts/dm-mono.ttf') format('truetype');
|
|
}
|
|
|
|
:root {
|
|
--scalar-font: 'DM Sans', sans-serif;
|
|
--scalar-font-code: 'DM Mono', monospace;
|
|
}
|
|
|
|
.darklight-reference > * {
|
|
display: none !important;
|
|
}
|
|
.darklight-reference {
|
|
padding: 0.75rem !important;
|
|
display: flex !important;
|
|
}
|
|
.darklight-reference::before {
|
|
content: '';
|
|
display: block;
|
|
width: 32px;
|
|
height: 32px;
|
|
background: url('https://gugulet.hu/technical/git/g_it/site/raw/branch/main/content/assets/media/g-logo-250x250.webp') no-repeat center / contain;
|
|
}
|
|
"""
|
|
|
|
app = FastAPI(
|
|
title="Reviews API",
|
|
description=DESCRIPTION,
|
|
version="1.1",
|
|
docs_url=None,
|
|
redoc_url=None,
|
|
)
|
|
|
|
@app.get("/ref", include_in_schema=False)
|
|
async def scalar_docs():
|
|
return get_scalar_api_reference(
|
|
openapi_url=f"{ROOT_PATH}/openapi.json",
|
|
title=app.title,
|
|
force_dark_mode_state="light",
|
|
hide_dark_mode_toggle=True,
|
|
with_default_fonts=False,
|
|
scalar_favicon_url="https://gugulet.hu/technical/git/g_it/site/raw/branch/main/content/assets/media/face-favicon-512x512.png",
|
|
default_open_all_tags=False,
|
|
custom_css=CUSTOM_CSS,
|
|
)
|
|
|
|
app.include_router(reviews.router)
|
|
app.include_router(discovery.router)
|
|
app.include_router(stats.router)
|
|
|
|
@app.get("/", include_in_schema=False)
|
|
def root_redirect():
|
|
return RedirectResponse(url=f"{ROOT_PATH}/ref")
|
|
|
|
@app.get("/health", tags=["System"])
|
|
def health_check():
|
|
"""Verify the API is running."""
|
|
return {"status": "ok"}
|