FastAPI with versioning
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).