A typical request

What happens during a typical request? Here is a concrete example. Hopefully this helps the reader to understand which technologies are used and how they work together. We will gloss over some details to arrive at the big picture without too many detours, so be prepared to find some more intricacies if you look closer.

We will take as an example the request:

https://db.cde-ev.de/db/cde/past/event/42/show

It is received by the Apache Web Server on the CdEDB virtual machine running on the CdE server. Apache then delegates this to the WSGI application cdedb.frontend.Application found in cdedb/frontend/application.py. The URL is matched against the available patterns in cdedb/frontend/paths.py and the result is the endpoint cde/show_past_event. This contains a realm (cde) and an action (show_past_event). Now a cdedb.common.RequestState object is constructed; it contains the session information for the current request. Most notably it contains a cdedb.common.User object describing the person doing the request (enabling us for example to check whether she is authorized to access the URL). This request state object is handed around encapsulating all state of the session, the other parts of the python code are state-less (except for the actual SQL-database queries of course). Another important attribute of the request state object is the ambience dict, which contains informations about the objects referenced by id in the URL path. In this case it has an entry pevent containing the data of the concluded event with id 42.

We have frontends for each realm, in this case the cdedb.frontend.cde.CdEFrontend from cdedb/frontend/cde.py. The method corresponding to the action is called, that is cdedb.frontend.cde.CdEFrontend.show_past_event(). This function is annotated with the cdedb.frontend.common.access() decorated which in this case triggers a check whether the accessing user has privileges to view cde content (this corresponds to the boolean is_cde_realm in the database entry of the user in the table core.personas, more on this later). Only things annotated with this decorator are accessible, anything else is private. Now the frontend function acquires the data to be displayed from the backends. We exemplary take the call to cdedb.backend.pastevent.PastEventBackend.list_past_courses() from the cdedb.backend.pastevent.PastEventBackend in cdedb/backend/past_event.py. Note that the backend is present as a proxy attribute pasteventproxy in the frontend. The idea is that it should mostly be possible to replace the direct call of a method of the backend object by a remote procedure call over the network, with the backend residing on an entirely different computer. This separation forces a clean design, but not actually doing network transparency has some development/maintenance upsides (e.g. less moving parts as we have only a single Python process).

The backends are responsible for accessing the actual PostgreSQL database, which stores all state. The cdedb.backend.pastevent.PastEventBackend.list_past_courses() method first does some validation (the frontend function we looked at did not have any inputs requiring validation, but if you look at a frontend function receiving inputs via the cdedb.frontend.common.REQUESTdata() decorator you will see those arguments validated too). In this case the parameter pevent_id is checked with the validation function cdedb.validation._id() from cdedb/validation.py (which by some magic is actually accessed as cdedb.validation.affirm_id()). It proceeds to extract the list of courses of a concluded event from the table past_event.courses with help of the method cdedb.backend.common.AbstractBackend.sql_select(), which essentially formulates an SQL query and submits it to the PostgreSQL server. The database layout is stored in cdedb/database/cdedb-tables.sql, where each schema roughly corresponds to one realm.

Returning to the frontend we skip over most of the logic in cdedb.frontend.cde.CdEFrontend.show_past_event() and come to the final call to cdedb.frontend.common.AbstractFrontend.render() which takes all the data from the backend and creates a nice HTML page. For this it uses the template cdedb/frontend/templates/web/de/cde/show_past_event.tmpl. The templates utilize the jinja2 syntax. The finished page is then returned to the Apache server which delivers it to the user.