-
Notifications
You must be signed in to change notification settings - Fork 21
FastAPI integration docs #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| FastAPI | ||
| ======= | ||
|
|
||
| This documents the various FastAPI specific functionality but doesn't cover | ||
| internals of the extension. | ||
|
|
||
| Extension | ||
| --------- | ||
|
|
||
| .. automodule:: dockerflow.fastapi | ||
| :members: router |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,325 @@ | ||
| FastAPI | ||
| ======= | ||
|
|
||
| The package ``dockerflow.fastapi`` package implements various tools to support | ||
| `FastAPI`_ based projects that want to follow the Dockerflow specs: | ||
|
|
||
| - A Python logging formatter following the `mozlog`_ format. | ||
|
|
||
| - A FastAPI extension implements: | ||
|
|
||
| - Emitting of `request.summary`_ log records based on request specific data. | ||
|
|
||
| - Views for health monitoring: | ||
|
|
||
| - ``/__version__`` - Serves a ``version.json`` file | ||
|
|
||
| - ``/__heartbeat__`` - Runs the configured Dockerflow checks | ||
|
|
||
| - ``/__lbheartbeat__`` - Retuns a HTTP 200 response | ||
|
|
||
| - Hooks to add custom Dockerflow checks. | ||
|
|
||
| .. _`FastAPI`: https://fastapi.tiangolo.com | ||
| .. _`mozlog`: https://github.com/mozilla-services/Dockerflow/blob/main/docs/mozlog.md | ||
| .. _`request.summary`: https://github.com/mozilla-services/Dockerflow/blob/main/docs/mozlog.md#application-request-summary-type-requestsummary | ||
|
|
||
| .. seealso:: | ||
|
|
||
| For more information see the :doc:`API documentation <api/fastapi>` for | ||
| the ``dockerflow.fastapi`` module. | ||
|
|
||
| Setup | ||
| ----- | ||
|
|
||
| To install ``python-dockerflow``'s FastAPI support please follow these steps: | ||
|
|
||
| #. In your code where your FastAPI application lives set up the dockerflow FastAPI | ||
| extension:: | ||
|
|
||
| from fastapi import FastAPI | ||
| from dockerflow.fastapi import router | ||
| from dockerflow.fastapi.middleware import MozlogRequestSummaryLogger | ||
|
|
||
| app = FastAPI() | ||
| app.include_router(router) | ||
| app.add_middleware(MozlogRequestSummaryLogger) | ||
|
|
||
| #. Make sure the app root path is set correctly as this will be used | ||
| to locate the ``version.json`` file that is generated by | ||
| your CI or another process during deployment. | ||
|
|
||
| .. seealso:: :ref:`fastapi-versions` for more information | ||
|
|
||
| #. Configure logging to use the ``JsonLogFormatter`` logging formatter for the | ||
| ``request.summary`` logger (you may have to extend your existing logging | ||
| configuration), see :ref:`fastapi-logging` for more information. | ||
|
|
||
| .. _fastapi-config: | ||
|
|
||
| Configuration | ||
| ------------- | ||
|
|
||
| .. epigraph:: | ||
|
|
||
| Accept its configuration through environment variables. | ||
|
|
||
| There are several options to handle configuration values through | ||
| environment variables when configuring FastAPI. | ||
|
|
||
| ``pydantic-settings`` | ||
| ~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| The simplest is to use `pydantic-settings`_ that will load settings from | ||
| environment variables or secrets files, and turn them into model instance. | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from pydantic_settings import BaseSettings | ||
|
|
||
| class Settings(BaseSettings): | ||
| port: int = 8000 | ||
|
|
||
| settings = Settings() | ||
|
|
||
| .. _pydantic-settings: https://docs.pydantic.dev/latest/concepts/pydantic_settings/ | ||
|
|
||
| .. _fastapi-serving: | ||
|
|
||
| ``PORT`` | ||
| -------- | ||
|
|
||
| .. epigraph:: | ||
|
|
||
| Listen on environment variable ``$PORT`` for HTTP requests. | ||
|
|
||
| Depending on which ASGI server you are using to run your Python application | ||
| there are different ways to accept the :envvar:`PORT` as the port to launch | ||
| your application with. | ||
|
|
||
| It's recommended to use port ``8000`` by default. | ||
|
|
||
| Uvicorn | ||
| ~~~~~~~ | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| import uvicorn | ||
|
|
||
| from myapp import Settings | ||
|
|
||
| settings = Settings() | ||
|
|
||
| if __name__ == "__main__": | ||
| server = uvicorn.Server( | ||
| uvicorn.Config( | ||
| "myapp:app", | ||
| host=settings.host, | ||
| port=settings.port, | ||
| reload=settings.app_reload, | ||
| log_config=None, | ||
| ) | ||
| ) | ||
| server.run() | ||
|
|
||
| .. _fastapi-versions: | ||
|
|
||
| Versions | ||
| -------- | ||
|
|
||
| .. epigraph:: | ||
|
|
||
| Must have a JSON version object at /app/version.json. | ||
|
|
||
| Dockerflow requires writing a `version object`_ to the file | ||
| ``/app/version.json`` as seen from the docker container to be served under | ||
leplatrem marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| the URL path ``/__version__``. | ||
|
|
||
| .. note:: | ||
|
|
||
| The default ``/app`` location can be customized using the ``APP_DIR`` | ||
| environment variable. | ||
|
|
||
| To facilitate this python-dockerflow comes with a FastAPI view to read the | ||
| file under path the parent directory of the app root. See the | ||
| :class:`FastAPI API docs <~fastapi.FastAPI>` for more information about the | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently, we have the same behaviour on Flask docs https://python-dockerflow.readthedocs.io/en/main/flask.html#versions |
||
| app root path. | ||
|
|
||
| .. _version object: https://github.com/mozilla-services/Dockerflow/blob/main/docs/version_object.md | ||
|
|
||
| .. _fastapi-health: | ||
|
|
||
| Health monitoring | ||
| ----------------- | ||
|
|
||
| Health monitoring happens via three different views following the Dockerflow_ | ||
| spec: | ||
|
|
||
| .. http:get:: /__version__ | ||
|
|
||
| The view that serves the :ref:`version information <fastapi-versions>`. | ||
|
|
||
| **Example request**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| GET /__version__ HTTP/1.1 | ||
| Host: example.com | ||
|
|
||
| **Example response**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| HTTP/1.1 200 OK | ||
| Vary: Accept-Encoding | ||
| Content-Type: application/json | ||
|
|
||
| { | ||
| "commit": "52ce614fbf99540a1bf6228e36be6cef63b4d73b", | ||
| "version": "2017.11.0", | ||
| "source": "https://github.com/mozilla/telemetry-analysis-service", | ||
| "build": "https://circleci.com/gh/mozilla/telemetry-analysis-service/2223" | ||
| } | ||
|
|
||
| :statuscode 200: no error | ||
| :statuscode 404: a version.json wasn't found | ||
|
|
||
| .. http:get:: /__heartbeat__ | ||
|
|
||
| The heartbeat view will go through the list of registered Dockerflow | ||
| checks, run each check and add their results to a JSON response. | ||
|
|
||
| The view will return HTTP responses with either an status code of 200 if | ||
| all checks ran successfully or 500 if there was one or more warnings or | ||
| errors returned by the checks. | ||
|
|
||
| Here's an example of a check that handles various levels of exceptions | ||
| from an external storage system with different check message:: | ||
|
|
||
| from dockerflow import checks | ||
|
|
||
| @checks.register | ||
| def storage_reachable(): | ||
| result = [] | ||
| try: | ||
| acme.storage.ping() | ||
| except SlowConnectionException as exc: | ||
| result.append(checks.Warning(exc.msg, id='acme.health.0002')) | ||
| except StorageException as exc: | ||
| result.append(checks.Error(exc.msg, id='acme.health.0001')) | ||
| return result | ||
|
|
||
| **Example request**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| GET /__heartbeat__ HTTP/1.1 | ||
| Host: example.com | ||
|
|
||
| **Example response**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| HTTP/1.1 500 Internal Server Error | ||
| Vary: Accept-Encoding | ||
| Content-Type: application/json | ||
|
|
||
| { | ||
| "status": "warning", | ||
| "checks": { | ||
| "check_debug": "ok", | ||
| "check_sts_preload": "warning" | ||
| }, | ||
| "details": { | ||
| "check_sts_preload": { | ||
| "status": "warning", | ||
| "level": 30, | ||
| "messages": { | ||
| "security.W021": "You have not set the SECURE_HSTS_PRELOAD setting to True. Without this, your site cannot be submitted to the browser preload list." | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| :statuscode 200: no error | ||
| :statuscode 500: there was an error | ||
|
|
||
| .. http:get:: /__lbheartbeat__ | ||
|
|
||
| The view that simply returns a successful HTTP response so that a load | ||
| balancer in front of the application can check that the web application | ||
| has started up. | ||
|
|
||
| **Example request**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| GET /__lbheartbeat__ HTTP/1.1 | ||
| Host: example.com | ||
|
|
||
| **Example response**: | ||
|
|
||
| .. sourcecode:: http | ||
|
|
||
| HTTP/1.1 200 OK | ||
| Vary: Accept-Encoding | ||
| Content-Type: application/json | ||
|
|
||
| :statuscode 200: no error | ||
|
|
||
| .. _Dockerflow: https://github.com/mozilla-services/Dockerflow | ||
|
|
||
| .. _fastapi-logging: | ||
|
|
||
| Logging | ||
| ------- | ||
|
|
||
| Dockerflow provides a :class:`~dockerflow.logging.JsonLogFormatter` Python | ||
| logging formatter class. | ||
|
|
||
| To use it, put something like this **BEFORE** your FastAPI app is initialized | ||
| for at least the ``request.summary`` logger: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from logging.conf import dictConfig | ||
|
|
||
| dictConfig({ | ||
| 'version': 1, | ||
| 'formatters': { | ||
| 'json': { | ||
| '()': 'dockerflow.logging.JsonLogFormatter', | ||
| 'logger_name': 'myproject' | ||
| } | ||
| }, | ||
| 'handlers': { | ||
| 'console': { | ||
| 'level': 'DEBUG', | ||
| 'class': 'logging.StreamHandler', | ||
| 'formatter': 'json' | ||
| }, | ||
| }, | ||
| 'loggers': { | ||
| 'request.summary': { | ||
| 'handlers': ['console'], | ||
| 'level': 'DEBUG', | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| .. _fastapi-static: | ||
|
|
||
| Static content | ||
| -------------- | ||
|
|
||
| We recommend using default `FastAPI features <https://fastapi.tiangolo.com/reference/staticfiles/>`_ for static files: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from fastapi.staticfiles import StaticFiles | ||
|
|
||
| SRC_DIR = Path(__file__).parent | ||
|
|
||
| app = FastAPI() | ||
|
|
||
| app.mount("/static", StaticFiles(directory=SRC_DIR / "static"), name="static") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| -r ../tests/requirements/default.txt | ||
| -r ../tests/requirements/docs.txt | ||
| -r ../tests/requirements/django.txt | ||
| -r ../tests/requirements/fastapi.txt | ||
| -r ../tests/requirements/flask.txt | ||
| -r ../tests/requirements/sanic.txt |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does

epigraphsuggest that this should have more formatting that just an indentation?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is like a note... I'd say that it just has some indentation