Skip to content

API

paystone.api is intended to serve as a base for all APIs created as part of the datascience repository. This includes the serving applications of machine learning services, as well as all auxiliary services.

It provides consistency through scaffolding and tooling for the following areas:

  1. Documentation.
  2. Middleware.
  3. Logging.
  4. Clients.

Its main exports are:

  • The PSAPI class, which augments the third-party FastAPI class.
  • The PSAPIClient class, which wraps async requests to our APIs.

Documentation

The base PSFastAPI class, from which all serving applications inherit, augments FastAPI with an add_documentation method.

The purpose of this add_documentation method is to translate Markdown documentation -- which can be housed alongside our other documentation in Notion -- into docstrings coupled with the FastAPI object itself. In this way, documentation remains centralized while simultaneously becoming baked into our APIs, and we lend additional structure to the documentation of endpoints.

More specifically, add_documentation works by parsing the relevant directory for the serving application in search of *.md files. The structure of the directory is expected to be as follows:

  • All files contained at one level of hierarchy, i.e. no nested directories.
  • An index.md which holds the documentation that is intended to appear at the root of the API.
    • This is the documentation that appears at the top of the page when viewing the /docs page of a FastAPI application.
  • One .md file for each route in the API, named after the route.
    • This is effectively the "docstring" of each route.
    • It does not need to document the request and response parameters; this is done via the associated data models.
    • It should document how the route works and what it does.

Middleware

PSFastAPI also augments FastAPI with an add_middlewares method, and paystone.api.middleware contains the base class for that middleware.

The base middleware functionality that this package provides is the usage of requests without consuming them. By default, the Starlette Request object can only be read once; this means that no middleware can read the contents of a request body, because it would consume that request body before the endpoint handler received it, and the request would break. PSFastAPI fixes this by reading the request body without consuming it.

Logging

When this package is imported, its logging submodule is run, which sets up loggers using the Python logging package.

Logging is configured such that none of the basic Gunicorn logging is present, and all of our custom logging has the same format. This results in a cleaner, easier to parse log stream.

For example, you won't see the establishment and termination of individual connections by Gunicorn, but you will see a line summarizing the request, response, duration, etc. of each request after it completes.

Clients

All clients have one authentication method in common: authentication via service account. This means including the "Authorization" header in a request with a "Bearer" token that is, in one way or another, authenticated by a service account.

For all of our services, that service account is the datascience service account. For machine learning services, the required method of authentication is for that service account to sign and provide a JWT. For auxiliary services, an ID token is provided.

The PSAPIClient class handles all the aforementioned authentication.

To make requests it wraps, not the synchronous requests library, but the asynchronous aiohttp library. Asynchronous requests allow users to make much more efficient use of our APIs, particularly the machine learning services where requests may take some time to complete.

Only the GET and POST HTTP methods are exposed as methods of the class.