main.py - Define the BookServer
docs to write: notes on this design. question: Why is there an empty module named dependencies.py
?
Imports
These are listed in the order prescribed by PEP 8.
Standard library
Third-party imports
Local application imports
from .applogger import rslogger
from .config import settings
from .crud import create_traceback
from .db import init_models, term_models
from .internal.feedback import init_graders
from .routers import assessment
from .routers import auth
from .routers import books
from .routers import rslogging
from .routers import discuss
from .session import auth_manager
FastAPI setup
setting root_path: see root_path; this approach comes from github.
Install the auth_manager as middleware This will make the user
part of the request request.state.user
See FastAPI_Login Advanced
Routing
Included
Defined here
Check/create paths used by the server.
os.makedirs(settings.book_path, exist_ok=True)
os.makedirs(settings.error_path, exist_ok=True)
assert (
settings.runestone_path.exists()
), f"Runestone appplication in web2py path {settings.runestone_path} does not exist."
await init_models()
init_graders()
@app.on_event("shutdown")
async def shutdown():
await term_models()
If the user supplies a timezone offset we’ll store it in the RS_info cookie lots of API calls need this so rather than having each process the cookie we’ll drop the value into request.state this will make it generally avilable
@app.middleware("http")
async def get_session_object(request: Request, call_next):
tz_cookie = request.cookies.get("RS_info")
rslogger.debug(f"In timezone middleware cookie is {tz_cookie}")
if tz_cookie:
try:
vals = json.loads(tz_cookie)
request.state.tz_offset = vals["tz_offset"]
rslogger.info(f"Timzone offset: {request.state.tz_offset}")
except Exception as e:
rslogger.error(f"Failed to parse cookie data {tz_cookie} error was {e}")
response = await call_next(request)
return response
@app.get("/")
def read_root():
return {"Hello": "World"}
class NotAuthenticatedException(Exception):
pass
auth_manager.not_authenticated_exception = NotAuthenticatedException
Fast API makes it very easy to handle different error types in an elegant way through the use of middleware to catch particular exception types.
Redirect the user to the login page if not logged in
See: https://fastapi.tiangolo.com/tutorial/handling-errors/#use-the-requestvalidationerror-body for more details on validation errors.
Most validation errors are caught immediately, but we do some secondary validation when populating our xxx_answers tables this catches those and returns a 422
Most validation errors are caught immediately, but we do some secondary validation when populating our xxx_answers tables this catches those and returns a 422
alternatively lets write the traceback info to the database! TODO: get local variable information find a way to get the request body without throwing an error on await request.json()