Skip to content

FastAPI with versioning

Wout De Nolf requested to merge use_fastapi into main

Closes #2 (closed), #28 (closed)

Switch from Flask to FastAPI because of:

  • easier route management (useful for versioning)
  • Flask needs lots of extra libraries for basic functionality while the FastApi functionality is more complete
  • easier for production deployment (security, authentication, etc.): not included in this MR (#15 (closed))

Before we used flask-restful to avoid code duplication when defining the end-points for tasks, workflows and icons (these end-points are very similar, except for the content that is being get/put/post). However I avoided using fastapi-restful so that the end-points are defined as just plain FastApi end-points. This way other developers don't have to learn another library. I'm pretty sure we could avoid code duplication in a more pythonic way (e.g. compare app.routers.tasks.router with app.routers.workflows.router and app.routers.icons.router). Edit: fastapi's Depends can probably be used for that.

API changes

The REST API is kept the same as much as possible except for adding the prefix /api. In addition two GET end-points which were expecting a body (which is not allowed) now expect query parameters:

  • GET /api/workflows: use query for keyword parameters (e.g. /api/workflows?kw=instrument_name:ID00&kw=scan_type:ct)
  • GET /api/workflows/descriptions: use query for keyword parameters (e.g. /api/workflows/descriptions?kw=instrument_name:ID00&kw=scan_type:ct)

FYI the keyword value is json deserialized when possible (e.g. kw=tags:["XRPD", "ID00"] results in {"tags": ["XRPD", "ID00"]}).

Port change

uvicorn provides port 8000 by default instead of port 5000. (Remark: in the ewoks tutorial we warn about problems with port 5000 on macOS)

CLI changes

Old

  -h, --help            show this help message and exit
  -l {DEBUG,INFO,WARNING,ERROR,CRITICAL}, --log {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                        Set the logging level
  --host HOST           Host name
  -p PORT, --port PORT  Port number
  -c CONFIGURATION, --config CONFIGURATION
                        Path to a python script (equivalent to the environment variable 'EWOKSSERVER_SETTINGS')
  -d RESOURCE_DIRECTORY, --dir RESOURCE_DIRECTORY
                        Root directory for resources (e.g. workflows, tasks, icons descriptions)
  -s SPEC_FILENAME, --spec-filename SPEC_FILENAME
                        Save the Swagger docs as JSON
  --without-events      Without websocket events
  --frontend-tests      Load frontend test configuration
  -r, --rediscover-tasks
                        Run task discovery on start up

New

  --host TEXT                     Bind socket to this host.  [default:
                                  127.0.0.1]
  --port INTEGER                  Bind socket to this port. If 0, an available
                                  port will be picked.  [default: 8000]
  --log-level [critical|error|warning|info|debug|trace]
                                  Log level. [default: info]
  --config TEXT                   Path to the config python script (equivalent
                                  to the environment variable
                                  'EWOKSSERVER_SETTINGS')
  --dir TEXT                      Root directory for resources (e.g.
                                  workflows, tasks, icons descriptions)
  --without-events                Disable Socket.IO app for event stream
  --frontend-tests                Load frontend test configuration
  --rediscover-tasks              Run task discovery on start up
  --no-older-versions             Do not provide end-points for older versions
                                  of the Ewoks API
  --help                          Show this message and exit.

Websocket

In the flask alternative we didn't just use websockets, we used socket.io

WebSocket is a technology that enables two-way realtime communication between client and server. In contrast, Socket.IO is a library that provides an abstraction layer on top of WebSockets, making it easier to create realtime applications.

There is no socket.io support for fastApi. There is fastapi-socketio but this is incomplete (e.g. missing test utilities). So we use python-socketio directly and make it work with with fastapi and testing.

Versioning

The normal REST end-points default to the latest version (e.g. GET /api/workflows). In addition there are end points for every strict version and every major version. For example

  • GET /api/workflows # same as v2_0_0
  • GET /api/v2/workflows # same as v2_0_0
  • GET /api/v2_0_0/workflows
  • GET /api/v1/workflows # same as v1_1_0
  • GET /api/v1_1_0/workflows
  • GET /api/v1_0_0/workflows

FastApi allows a path to be deprecated which shows up in the docs but I'm not sure the client gets deprecation warnings.

Versioning is done semantically: major (breaking API changes), minor (API has extra stuff), patch (same API, only bug fix).

Edited by Wout De Nolf

Merge request reports