fastapi-mount
fastapi-mount copied to clipboard
A minimal application for prototyping mounting the main FastAPI at a sub path.
FastAPI Mount Demonstration
A minimal application for prototyping mounting the main FastAPI at a sub path.
Rationale
Typically, an application expects to be seated at the root of a domain , for
example, this application defines two endpoints /hello and /bye which you
can hit locally (after a make start command) at localhost:8000/hello and
localhost:8000/bye. However, sometimes we might want to 'mount' an application
at a sub path. This may be the case in a microservice setting where many
services are sitting behind a reverse proxy and should be addressed at the same
domain (see the figure below from https://traefik.io). The FastAPI documentation
explains some
of the problems that occur in such a situation.

As an example, let's assume you have two services user-service and
shopping-cart. Both applications were created in a way that they expect to be
at the root, however, now we want to address them at different paths on the same
domain. This could be api.domain.com/user-service and
api.domain.com/shopping-cart. The application itself should not really be
involved in this. Where it is being deployed is outside of its scope and we
certainly don't want to edit all our route definitions.
It turns out that the SCRIPT_NAME HTTP header was created for exactly this
purpose. Instead of letting the proxy manipulate this header with every request,
it is fairly standard to let it be configurable by an environment variable. A
popular option is
gunicorn in
combination with
Flask.
In Flask this is internally handled by werkzeug as shown
here.
How do we do this with FastAPI (or Starlette)?
-
If you start this service without further actions you can visit the exposed routes and documentation at:
localhost:8000/hellolocalhost:8000/byelocalhost:8000/docslocalhost:8000/redoc
-
In order to switch it up, we can now use a reverse proxy. One has already been defined for you in the docker-compose configuration. When you now try to access your service through the proxy at
http://localhost/demo-service/helloyou will see that this fails with a 404. -
We can rescue the situation by rewriting the URL in the proxy instead. You can try this by instead hitting
http://localhost/demo2-service/hello. This will give you the correct response but if you now visithttp://localhost/demo2-service/docsthat fails because the app itself is unaware of the rewritten path. -
To try and remedy the situation, you can create a
.envfile with the content:SCRIPT_NAME=/demo2-serviceThis will automatically be used by the docker-compose configuration so just restart the service (
make clean && make start). SettingSCRIPT_NAMEto a non-empty string will affect how the application is initialized.app = FastAPI( title="FastAPI Mount Demo", description="A prototype of mounting the main FastAPI app under " "SCRIPT_NAME.", openapi_prefix=settings.SCRIPT_NAME, )When you now visit the docs at
http://localhost/demo2-service/docsit works as expected!
This is a working strategy but it is rather tedious. We had to rewrite the URL
in the reverse proxy and modify our application's source code (we still made it
configurable) to manually set the openapi_prefix. There should be a better
way.
Solution
Please take a look at the root-path branch on GitHub and the version of the README there for a proper solution implementation.
Copyright
-
Copyright © 2019, Moritz E. Beber. All rights reserved.
-
Free software licensed under the Apache Software License 2.0.
-
This README and other documentation are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
