aboutsummaryrefslogtreecommitdiffstats
path: root/fatcat_scholar/web.py
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@archive.org>2020-05-12 12:19:49 -0700
committerBryan Newbold <bnewbold@archive.org>2020-05-12 12:19:51 -0700
commit221fe40a0440b86773ad17db967ed4335d9e4da9 (patch)
tree2f5b98ce74c4a49845f51a3edda5638b71aa153c /fatcat_scholar/web.py
parentc3b83184948711d285a9898f7bb901e0231cd0a9 (diff)
downloadfatcat-scholar-221fe40a0440b86773ad17db967ed4335d9e4da9.tar.gz
fatcat-scholar-221fe40a0440b86773ad17db967ed4335d9e4da9.zip
fastapi infrastructure
- API/web distrinction - language code prefixes - content negotiation for endpoints
Diffstat (limited to 'fatcat_scholar/web.py')
-rw-r--r--fatcat_scholar/web.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/fatcat_scholar/web.py b/fatcat_scholar/web.py
new file mode 100644
index 0000000..dfebe01
--- /dev/null
+++ b/fatcat_scholar/web.py
@@ -0,0 +1,79 @@
+
+"""
+This file is the FastAPI web application.
+"""
+
+from enum import Enum
+
+from fastapi import FastAPI, APIRouter, Request, Depends
+from fastapi.staticfiles import StaticFiles
+from fastapi.templating import Jinja2Templates
+from fastapi.responses import HTMLResponse
+
+I18N_LANG_DEFAULT = "en"
+I18N_LANG_OPTIONS = ["en", "de", "zh"]
+
+class LangPrefix:
+ """
+ Looks for a two-character language prefix.
+
+ If there is no such prefix, in the future it could also look at the
+ Accept-Language header and try to infer a language from that, while not
+ setting the prefix code.
+ """
+
+ def __init__(self, request: Request):
+ self.prefix : str = ""
+ self.code : str = I18N_LANG_DEFAULT
+ for lang_option in I18N_LANG_OPTIONS:
+ if request.url.path.startswith(f"/{lang_option}/"):
+ self.prefix = f"/{lang_option}"
+ self.code = lang_option
+ break
+
+class ContentNegotiation:
+ """
+ Choses a mimetype to return based on Accept header.
+
+ Intended to be used for RESTful content negotiation from web endpoints to API.
+ """
+
+ def __init__(self, request: Request):
+ self.mimetype = "text/html"
+ if request.headers.get('accept', '').startswith('application/json'):
+ self.mimetype = "application/json"
+
+api = APIRouter()
+
+@api.get("/", operation_id="get_home")
+async def home(request: Request):
+ return {"endpoints": {"/": "this", "/search": "fulltext search"}}
+
+@api.get("/search", operation_id="get_search")
+async def search(request: Request):
+ return {"message": "search results would go here, I guess"}
+
+web = APIRouter()
+templates = Jinja2Templates(directory="fatcat_scholar/templates")
+
+@web.get("/", include_in_schema=False)
+async def web_home(request: Request, lang: LangPrefix = Depends(LangPrefix), content: ContentNegotiation = Depends(ContentNegotiation)):
+ if content.mimetype == "application/json":
+ return await api_home(request)
+ return templates.TemplateResponse("home.html", {"request": request})
+
+@web.get("/search", include_in_schema=False)
+async def web_search(request: Request):
+ if content.mimetype == "application/json":
+ return await api_search(request)
+ return templates.TemplateResponse("search.html", {"request": request})
+
+app = FastAPI()
+
+
+app.include_router(web)
+for lang_option in I18N_LANG_OPTIONS:
+ app.include_router(web, prefix=f"/{lang_option}")
+app.include_router(api)
+app.mount("/static", StaticFiles(directory="fatcat_scholar/static"), name="static")
+