From a42c69049647f4fb731afc86c6eeb959248217e4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 5 Nov 2020 21:50:37 +0100 Subject: [PATCH] =?utf8?q?=F0=9F=93=9D=20Add=20deployment=20to=20Deta,=20t?= =?utf8?q?he=20first=20gold=20sponsor=20=F0=9F=8E=89=20(#2303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * 📝 Add docs for sponsors * 📝 Add docs for deploying on Deta * 🍱 Add Deta docs screenshots * ♻️ Refactor and separate deployment docs * 📝 Update internal docs links to Deployment * 📝 Update links in Deta tutorial * 🍱 Update sponsors images * 🔧 Use sponsors data from YAML * 📝 Update sponsors in languages docs * ✨ Update docs generation scripts * ✅ Update README.md testing * 📝 Update main README * 🔧 Update fastapi-people action handling individual sponsors * ✏️ Fix typos in Deta tutorial --- .github/actions/people/app/main.py | 6 +- README.md | 10 + docs/en/data/sponsors.yml | 8 + docs/en/docs/alternatives.md | 2 +- docs/en/docs/async.md | 2 +- docs/en/docs/deployment.md | 396 ------------------- docs/en/docs/deployment/deta.md | 240 +++++++++++ docs/en/docs/deployment/docker.md | 179 +++++++++ docs/en/docs/deployment/https.md | 48 +++ docs/en/docs/deployment/index.md | 7 + docs/en/docs/deployment/manually.md | 69 ++++ docs/en/docs/deployment/versions.md | 87 ++++ docs/en/docs/fastapi-people.md | 24 +- docs/en/docs/img/deployment/deta/image01.png | Bin 0 -> 39996 bytes docs/en/docs/img/deployment/deta/image02.png | Bin 0 -> 48297 bytes docs/en/docs/img/sponsors/deta.svg | 99 +++++ docs/en/docs/img/sponsors/testdriven.svg | 235 +++++++++++ docs/en/docs/index.md | 14 + docs/en/mkdocs.yml | 8 +- docs/es/docs/async.md | 2 +- docs/es/docs/index.md | 14 + docs/fr/docs/index.md | 14 + docs/it/docs/index.md | 14 + docs/ja/docs/alternatives.md | 2 +- docs/ja/docs/index.md | 14 + docs/ko/docs/index.md | 14 + docs/pt/docs/alternatives.md | 2 +- docs/pt/docs/index.md | 14 + docs/ru/docs/index.md | 14 + docs/tr/docs/index.md | 14 + docs/uk/docs/index.md | 14 + docs/zh/docs/index.md | 14 + scripts/docs.py | 69 +++- scripts/test.sh | 2 +- 34 files changed, 1236 insertions(+), 415 deletions(-) create mode 100644 docs/en/data/sponsors.yml delete mode 100644 docs/en/docs/deployment.md create mode 100644 docs/en/docs/deployment/deta.md create mode 100644 docs/en/docs/deployment/docker.md create mode 100644 docs/en/docs/deployment/https.md create mode 100644 docs/en/docs/deployment/index.md create mode 100644 docs/en/docs/deployment/manually.md create mode 100644 docs/en/docs/deployment/versions.md create mode 100644 docs/en/docs/img/deployment/deta/image01.png create mode 100644 docs/en/docs/img/deployment/deta/image02.png create mode 100644 docs/en/docs/img/sponsors/deta.svg create mode 100644 docs/en/docs/img/sponsors/testdriven.svg diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py index a4d3af1fd8..2847ccae4e 100644 --- a/.github/actions/people/app/main.py +++ b/.github/actions/people/app/main.py @@ -375,7 +375,7 @@ def get_contributors(settings: Settings): return contributors, commentors, reviewers, authors -def get_sponsors(settings: Settings): +def get_individual_sponsors(settings: Settings, max_individual_sponsor: int = 5): nodes: List[SponsorshipAsMaintainerNode] = [] edges = get_graphql_sponsor_edges(settings=settings) @@ -387,6 +387,8 @@ def get_sponsors(settings: Settings): entities: Dict[str, SponsorEntity] = {} for node in nodes: + if node.tier.monthlyPriceInDollars > max_individual_sponsor: + continue entities[node.sponsorEntity.login] = node.sponsorEntity return entities @@ -473,7 +475,7 @@ if __name__ == "__main__": skip_users=skip_users, ) - sponsors_by_login = get_sponsors(settings=settings) + sponsors_by_login = get_individual_sponsors(settings=settings) sponsors = [] for login, sponsor in sponsors_by_login.items(): sponsors.append( diff --git a/README.md b/README.md index d0b73f9fc2..67ddcd87b2 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + + + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml new file mode 100644 index 0000000000..931e62813c --- /dev/null +++ b/docs/en/data/sponsors.yml @@ -0,0 +1,8 @@ +gold: + - url: https://www.deta.sh/?ref=fastapi + title: The launchpad for all your (team's) ideas + img: /img/sponsors/deta.svg +silver: + - url: https://testdriven.io/ + title: Learn to build high-quality web apps with best practices + img: /img/sponsors/testdriven.svg diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md index 3d9e3a55af..cec53a4e20 100644 --- a/docs/en/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -410,7 +410,7 @@ It is the recommended server for Starlette and **FastAPI**. You can combine it with Gunicorn, to have an asynchronous multi-process server. - Check more details in the [Deployment](deployment.md){.internal-link target=_blank} section. + Check more details in the [Deployment](deployment/index.md){.internal-link target=_blank} section. ## Benchmarks and speed diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index ac21b3eed2..7c3dcfdea0 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -261,7 +261,7 @@ But you can also exploit the benefits of parallelism and multiprocessing (having That, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others). -To see how to achieve this parallelism in production see the section about [Deployment](deployment.md){.internal-link target=_blank}. +To see how to achieve this parallelism in production see the section about [Deployment](deployment/index.md){.internal-link target=_blank}. ## `async` and `await` diff --git a/docs/en/docs/deployment.md b/docs/en/docs/deployment.md deleted file mode 100644 index 5e62d1e8d5..0000000000 --- a/docs/en/docs/deployment.md +++ /dev/null @@ -1,396 +0,0 @@ -# Deployment - -Deploying a **FastAPI** application is relatively easy. - -There are several ways to do it depending on your specific use case and the tools that you use. - -You will see more about some of the ways to do it in the next sections. - -## FastAPI versions - -**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly. - -New features are added frequently, bugs are fixed regularly, and the code is still continuously improving. - -That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the Semantic Versioning conventions. - -You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code. - -### Pin your `fastapi` version - -The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application. - -For example, let's say you are using version `0.45.0` in your app. - -If you use a `requirements.txt` file you could specify the version with: - -```txt -fastapi==0.45.0 -``` - -that would mean that you would use exactly the version `0.45.0`. - -Or you could also pin it with: - -```txt -fastapi>=0.45.0,<0.46.0 -``` - -that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted. - -If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages. - -### Available versions - -You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](release-notes.md){.internal-link target=_blank}. - -### About versions - -Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes. - -FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes. - -!!! tip - The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`. - -So, you should be able to pin to a version like: - -```txt -fastapi>=0.45.0,<0.46.0 -``` - -Breaking changes and new features are added in "MINOR" versions. - -!!! tip - The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`. - -### Upgrading the FastAPI versions - -You should add tests for your app. - -With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](tutorial/testing.md){.internal-link target=_blank} - -After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests. - -If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version. - -### About Starlette - -You shouldn't pin the version of `starlette`. - -Different versions of **FastAPI** will use a specific newer version of Starlette. - -So, you can just let **FastAPI** use the correct Starlette version. - -### About Pydantic - -Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI. - -You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`. - -For example: - -```txt -pydantic>=1.2.0,<2.0.0 -``` - -## Docker - -In this section you'll see instructions and links to guides to know how to: - -* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**. -* (Optionally) understand what you, as a developer, need to know about HTTPS. -* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**. -* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**. - -You can use **Docker** for deployment. It has several advantages like security, replicability, development simplicity, etc. - -If you are using Docker, you can use the official Docker image: - -### tiangolo/uvicorn-gunicorn-fastapi - -This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices. - -But you can still change and update all the configurations with environment variables or configuration files. - -!!! tip - To see all the configurations and options, go to the Docker image page: tiangolo/uvicorn-gunicorn-fastapi. - -### Create a `Dockerfile` - -* Go to your project directory. -* Create a `Dockerfile` with: - -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 - -COPY ./app /app -``` - -#### Bigger Applications - -If you followed the section about creating [Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like: - -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 - -COPY ./app /app/app -``` - -#### Raspberry Pi and other architectures - -If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone. - -In this case, your `Dockerfile` could look like: - -```Dockerfile -FROM python:3.7 - -RUN pip install fastapi uvicorn - -EXPOSE 80 - -COPY ./app /app - -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] -``` - -### Create the **FastAPI** Code - -* Create an `app` directory and enter in it. -* Create a `main.py` file with: - -```Python -from typing import Optional - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): - return {"item_id": item_id, "q": q} -``` - -* You should now have a directory structure like: - -``` -. -├── app -│ └── main.py -└── Dockerfile -``` - -### Build the Docker image - -* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory). -* Build your FastAPI image: - -
- -```console -$ docker build -t myimage . - ----> 100% -``` - -
- -### Start the Docker container - -* Run a container based on your image: - -
- -```console -$ docker run -d --name mycontainer -p 80:80 myimage -``` - -
- -Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores). - -### Check it - -You should be able to check it in your Docker container's URL, for example: http://192.168.99.100/items/5?q=somequery or http://127.0.0.1/items/5?q=somequery (or equivalent, using your Docker host). - -You will see something like: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -### Interactive API docs - -Now you can go to http://192.168.99.100/docs or http://127.0.0.1/docs (or equivalent, using your Docker host). - -You will see the automatic interactive API documentation (provided by Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternative API docs - -And you can also go to http://192.168.99.100/redoc or http://127.0.0.1/redoc (or equivalent, using your Docker host). - -You will see the alternative automatic documentation (provided by ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## HTTPS - -### About HTTPS - -It is easy to assume that HTTPS is something that is just "enabled" or not. - -But it is way more complex than that. - -!!! tip - If you are in a hurry or don't care, continue with the next section for step by step instructions to set everything up. - -To learn the basics of HTTPS, from a consumer perspective, check https://howhttps.works/. - -Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS: - -* For HTTPS, the server needs to have "certificates" generated by a third party. - * Those certificates are actually acquired from the third-party, not "generated". -* Certificates have a lifetime. - * They expire. - * And then they need to be renewed, acquired again from the third party. -* The encryption of the connection happens at the TCP level. - * That's one layer below HTTP. - * So, the certificate and encryption handling is done before HTTP. -* TCP doesn't know about "domains". Only about IP addresses. - * The information about the specific domain requested goes in the HTTP data. -* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with. -* By default, that would mean that you can only have one HTTPS certificate per IP address. - * No matter how big your server is or how small each application you have on it might be. - * There is a solution to this, however. -* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called SNI. - * This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications. - * For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server. -* After obtaining a secure connection, the communication protocol is still HTTP. - * The contents are encrypted, even though they are being sent with the HTTP protocol. - -It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a TLS Termination Proxy. - -### Let's Encrypt - -Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties. - -The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive. - -But then Let's Encrypt was created. - -It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan. - -The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates. - -The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever. - -### Traefik - -Traefik is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features). - -It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal. - -It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration. - ---- - -With this information and tools, continue with the next section to combine everything. - -## Docker Swarm mode cluster with Traefik and HTTPS - -You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal). - -By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers. - -To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide: - -### Docker Swarm Mode and Traefik for an HTTPS cluster - -### Deploy a FastAPI application - -The easiest way to set everything up, would be using the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}. - -It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above. - -You can generate a project in about 2 min. - -The generated project has instructions to deploy it, doing it takes another 2 min. - -## Alternatively, deploy **FastAPI** without Docker - -You can deploy **FastAPI** directly without Docker too. - -You just need to install an ASGI compatible server like: - -=== "Uvicorn" - - * Uvicorn, a lightning-fast ASGI server, built on uvloop and httptools. - -
- - ```console - $ pip install uvicorn - - ---> 100% - ``` - -
- -=== "Hypercorn" - - * Hypercorn, an ASGI server also compatible with HTTP/2. - -
- - ```console - $ pip install hypercorn - - ---> 100% - ``` - -
- - ...or any other ASGI server. - -And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: - -=== "Uvicorn" - -
- - ```console - $ uvicorn main:app --host 0.0.0.0 --port 80 - - INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) - ``` - -
- -=== "Hypercorn" - -
- - ```console - $ hypercorn main:app --bind 0.0.0.0:80 - - Running on 0.0.0.0:8080 over http (CTRL + C to quit) - ``` - -
- -You might want to set up some tooling to make sure it is restarted automatically if it stops. - -You might also want to install Gunicorn and use it as a manager for Uvicorn, or use Hypercorn with multiple workers. - -Making sure to fine-tune the number of workers, etc. - -But if you are doing all that, you might just use the Docker image that does it automatically. diff --git a/docs/en/docs/deployment/deta.md b/docs/en/docs/deployment/deta.md new file mode 100644 index 0000000000..ae7a00d3de --- /dev/null +++ b/docs/en/docs/deployment/deta.md @@ -0,0 +1,240 @@ +# Deploy on Deta + +In this section you will learn see how to easily deploy a **FastAPI** application on Deta using the free plan. 🎁 + +It will take you about **10 minutes**. + +!!! info + Deta is a **FastAPI** sponsor. 🎉 + +## A basic **FastAPI** app + +* Create a directory for your app, for example `./fastapideta/` and enter in it. + +### FastAPI code + +* Create a `main.py` file with: + +```Python +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int): + return {"item_id": item_id} +``` + +### Requirements + +Now, in the same directory create a file `requirements.txt` with: + +```text +fastapi +``` + +!!! tip + You don't need to install Uvicorn to deploy on Deta, although you would probably want to install it locally to test your app. + +### Directory structure + +You will now have one directory `./fastapideta/` with two files: + +``` +. +└── main.py +└── requirements.txt +``` + +## Create a free Deta account + +Now create a free account on Deta, you just need an email and password. + +You don't even need a credit card. + +## Install the CLI + +Once you have your account, install the Deta CLI: + +=== "Linux, macOS" + +
+ + ```console + $ curl -fsSL https://get.deta.dev/cli.sh | sh + ``` + +
+ +=== "Windows PowerShell" + +
+ + ```console + $ iwr https://get.deta.dev/cli.ps1 -useb | iex + ``` + +
+ +After installing it, open a new terminal so that the installed CLI is detected. + +In a new terminal, confirm that it was correctly installed with: + +
+ +```console +$ deta --help + +Deta command line interface for managing deta micros. +Complete documentation available at https://docs.deta.sh + +Usage: + deta [flags] + deta [command] + +Available Commands: + auth Change auth settings for a deta micro + +... +``` + +
+ +!!! tip + If you have problems installing the CLI, check the official Deta docs. + +## Login with the CLI + +Now login to Deta from the CLI with: + +
+ +```console +$ deta login + +Please, log in from the web page. Waiting.. +Logged in successfully. +``` + +
+ +This will open a web browser and authenticate automatically. + +## Deploy with Deta + +Next, deploy your application with the Deta CLI: + +
+ +```console +$ deta new + +Successfully created a new micro + +// Notice the "endpoint" 🔍 + +{ + "name": "fastapideta", + "runtime": "python3.7", + "endpoint": "https://qltnci.deta.dev", + "visor": "enabled", + "http_auth": "enabled" +} + +Adding dependencies... + + +---> 100% + + +Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 +``` + +
+ +You will see a JSON message similar to: + +```JSON hl_lines="4" +{ + "name": "fastapideta", + "runtime": "python3.7", + "endpoint": "https://qltnci.deta.dev", + "visor": "enabled", + "http_auth": "enabled" +} +``` + +!!! tip + Your deployment will have a different `"endpoint"` URL. + +## Check it + +Now open your browser in your `endpoint` URL. In the example above it was `https://qltnci.deta.dev`, but yours will be different. + +You will see the JSON response from your FastAPI app: + +```JSON +{ + "Hello": "World" +} +``` + +And now go to the `/docs` for your API, in the example above it would be `https://qltnci.deta.dev/docs`. + +It will show your docs like: + + + +## Enable public access + +By default, Deta will handle authentication using cookies for your account. + +But once you are ready, you can make it public with: + +
+ +```console +$ deta auth disable + +Successfully disabled http auth +``` + +
+ +Now you can share that URL with anyone and they will be able to access your API. 🚀 + +## HTTPS + +Congrats! You deployed your FastAPI app to Deta! 🎉 🍰 + +Also notice that Deta correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your clients will have a secure encrypted connection. ✅ 🔒 + +## Check the Visor + +From your docs UI (they will be in a URL like `https://qltnci.deta.dev/docs`) send a request to your *path operation* `/items/{item_id}`. + +For example with ID `5`. + +Now go to https://web.deta.sh. + +You will see there's a section to the left called "Micros" with each of your apps. + +You will see a tab with "Details", and also a tab "Visor", go to the tab "Visor". + +In there you can inspect the recent requests sent to your app. + +You can also edit them and re-play them. + + + +## Learn more + +At some point you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base, it also has a generous **free tier**. + +You can also read more in the Deta Docs. diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md new file mode 100644 index 0000000000..e32a2969de --- /dev/null +++ b/docs/en/docs/deployment/docker.md @@ -0,0 +1,179 @@ +# Deploy with Docker + +In this section you'll see instructions and links to guides to know how to: + +* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**. +* (Optionally) understand what you, as a developer, need to know about HTTPS. +* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**. +* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**. + +You can use **Docker** for deployment. It has several advantages like security, replicability, development simplicity, etc. + +If you are using Docker, you can use the official Docker image: + +## tiangolo/uvicorn-gunicorn-fastapi + +This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices. + +But you can still change and update all the configurations with environment variables or configuration files. + +!!! tip + To see all the configurations and options, go to the Docker image page: tiangolo/uvicorn-gunicorn-fastapi. + +## Create a `Dockerfile` + +* Go to your project directory. +* Create a `Dockerfile` with: + +```Dockerfile +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 + +COPY ./app /app +``` + +### Bigger Applications + +If you followed the section about creating [Bigger Applications with Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like: + +```Dockerfile +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 + +COPY ./app /app/app +``` + +### Raspberry Pi and other architectures + +If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone. + +In this case, your `Dockerfile` could look like: + +```Dockerfile +FROM python:3.7 + +RUN pip install fastapi uvicorn + +EXPOSE 80 + +COPY ./app /app + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +``` + +## Create the **FastAPI** Code + +* Create an `app` directory and enter in it. +* Create a `main.py` file with: + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +* You should now have a directory structure like: + +``` +. +├── app +│ └── main.py +└── Dockerfile +``` + +## Build the Docker image + +* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory). +* Build your FastAPI image: + +
+ +```console +$ docker build -t myimage . + +---> 100% +``` + +
+ +## Start the Docker container + +* Run a container based on your image: + +
+ +```console +$ docker run -d --name mycontainer -p 80:80 myimage +``` + +
+ +Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores). + +## Check it + +You should be able to check it in your Docker container's URL, for example: http://192.168.99.100/items/5?q=somequery or http://127.0.0.1/items/5?q=somequery (or equivalent, using your Docker host). + +You will see something like: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +## Interactive API docs + +Now you can go to http://192.168.99.100/docs or http://127.0.0.1/docs (or equivalent, using your Docker host). + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +## Alternative API docs + +And you can also go to http://192.168.99.100/redoc or http://127.0.0.1/redoc (or equivalent, using your Docker host). + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Traefik + +Traefik is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features). + +It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal. + +It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration. + +--- + +With this information and tools, continue with the next section to combine everything. + +## Docker Swarm mode cluster with Traefik and HTTPS + +You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal). + +By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers. + +To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide: + +### Docker Swarm Mode and Traefik for an HTTPS cluster + +### Deploy a FastAPI application + +The easiest way to set everything up, would be using the [**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}. + +It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above. + +You can generate a project in about 2 min. + +The generated project has instructions to deploy it, doing it takes another 2 min. diff --git a/docs/en/docs/deployment/https.md b/docs/en/docs/deployment/https.md new file mode 100644 index 0000000000..c735f1f4a1 --- /dev/null +++ b/docs/en/docs/deployment/https.md @@ -0,0 +1,48 @@ +# About HTTPS + +It is easy to assume that HTTPS is something that is just "enabled" or not. + +But it is way more complex than that. + +!!! tip + If you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques. + +To learn the basics of HTTPS, from a consumer perspective, check https://howhttps.works/. + +Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS: + +* For HTTPS, the server needs to have "certificates" generated by a third party. + * Those certificates are actually acquired from the third-party, not "generated". +* Certificates have a lifetime. + * They expire. + * And then they need to be renewed, acquired again from the third party. +* The encryption of the connection happens at the TCP level. + * That's one layer below HTTP. + * So, the certificate and encryption handling is done before HTTP. +* TCP doesn't know about "domains". Only about IP addresses. + * The information about the specific domain requested goes in the HTTP data. +* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with. +* By default, that would mean that you can only have one HTTPS certificate per IP address. + * No matter how big your server is or how small each application you have on it might be. + * There is a solution to this, however. +* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called SNI. + * This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications. + * For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server. +* After obtaining a secure connection, the communication protocol is still HTTP. + * The contents are encrypted, even though they are being sent with the HTTP protocol. + +It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a TLS Termination Proxy. + +## Let's Encrypt + +Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties. + +The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive. + +But then Let's Encrypt was created. + +It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan. + +The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates. + +The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever. diff --git a/docs/en/docs/deployment/index.md b/docs/en/docs/deployment/index.md new file mode 100644 index 0000000000..d898cfefc1 --- /dev/null +++ b/docs/en/docs/deployment/index.md @@ -0,0 +1,7 @@ +# Deployment - Intro + +Deploying a **FastAPI** application is relatively easy. + +There are several ways to do it depending on your specific use case and the tools that you use. + +You will see more details to have in mind and some of the techniques to do it in the next sections. diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md new file mode 100644 index 0000000000..4051241653 --- /dev/null +++ b/docs/en/docs/deployment/manually.md @@ -0,0 +1,69 @@ +# Deploy manually + +You can deploy **FastAPI** manually as well. + +You just need to install an ASGI compatible server like: + +=== "Uvicorn" + + * Uvicorn, a lightning-fast ASGI server, built on uvloop and httptools. + +
+ + ```console + $ pip install uvicorn + + ---> 100% + ``` + +
+ +=== "Hypercorn" + + * Hypercorn, an ASGI server also compatible with HTTP/2. + +
+ + ```console + $ pip install hypercorn + + ---> 100% + ``` + +
+ + ...or any other ASGI server. + +And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: + +=== "Uvicorn" + +
+ + ```console + $ uvicorn main:app --host 0.0.0.0 --port 80 + + INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) + ``` + +
+ +=== "Hypercorn" + +
+ + ```console + $ hypercorn main:app --bind 0.0.0.0:80 + + Running on 0.0.0.0:8080 over http (CTRL + C to quit) + ``` + +
+ +You might want to set up some tooling to make sure it is restarted automatically if it stops. + +You might also want to install Gunicorn and use it as a manager for Uvicorn, or use Hypercorn with multiple workers. + +Making sure to fine-tune the number of workers, etc. + +But if you are doing all that, you might just use the Docker image that does it automatically. diff --git a/docs/en/docs/deployment/versions.md b/docs/en/docs/deployment/versions.md new file mode 100644 index 0000000000..4be9385ddf --- /dev/null +++ b/docs/en/docs/deployment/versions.md @@ -0,0 +1,87 @@ +# About FastAPI versions + +**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly. + +New features are added frequently, bugs are fixed regularly, and the code is still continuously improving. + +That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the Semantic Versioning conventions. + +You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code. + +## Pin your `fastapi` version + +The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application. + +For example, let's say you are using version `0.45.0` in your app. + +If you use a `requirements.txt` file you could specify the version with: + +```txt +fastapi==0.45.0 +``` + +that would mean that you would use exactly the version `0.45.0`. + +Or you could also pin it with: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted. + +If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages. + +## Available versions + +You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](../release-notes.md){.internal-link target=_blank}. + +## About versions + +Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes. + +FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes. + +!!! tip + The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`. + +So, you should be able to pin to a version like: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +Breaking changes and new features are added in "MINOR" versions. + +!!! tip + The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`. + +## Upgrading the FastAPI versions + +You should add tests for your app. + +With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](../tutorial/testing.md){.internal-link target=_blank} + +After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests. + +If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version. + +## About Starlette + +You shouldn't pin the version of `starlette`. + +Different versions of **FastAPI** will use a specific newer version of Starlette. + +So, you can just let **FastAPI** use the correct Starlette version. + +## About Pydantic + +Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI. + +You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`. + +For example: + +```txt +pydantic>=1.2.0,<2.0.0 +``` diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index 80b225efd0..42148c1f55 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -112,7 +112,25 @@ The **Top Reviewers** 🕵️ have reviewed the most Pull Requests from others, These are the **Sponsors**. 😎 -They are supporting my work with **FastAPI** (and others) through GitHub Sponsors. +They are supporting my work with **FastAPI** (and others), mainly through GitHub Sponsors. + +### Gold Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + +### Silver Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + +### Individual Sponsors {% if people %}
@@ -126,10 +144,12 @@ They are supporting my work with **FastAPI** (and others) through source code here. +Here I'm also highlighting contributions from sponsors. + I also reserve the right to update the algorithm, sections, thresholds, etc (just in case 🤷). diff --git a/docs/en/docs/img/deployment/deta/image01.png b/docs/en/docs/img/deployment/deta/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..f2e058b58037657c26e3e107e00d886a5efd840b GIT binary patch literal 39996 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%0Do+UgxdAY)QJ@Ve!N&c>cqoMtuy- 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 literal 0 Hc-jL100001 diff --git a/docs/en/docs/img/deployment/deta/image02.png b/docs/en/docs/img/deployment/deta/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..897ec41fb11972f3aaeee85d872e74c859a81663 GIT binary patch literal 48297 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 z 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 z zva*sh)}A9wEpbvR`W1{UJv+7xnOQ=TOusC@eX93Q;6Fjc+ACPm)!6q4k||@u&VQEW z)>!a>P90F_EX2Ct2Gjt2It(I3K0_NOVo)}gUJwtziAjyU+h>?Rz?uA~h1xIu|7cWF z_IcW;?J)s7diI1rixQjN1(~>xTRQQ6TNYAGRYtX}%Q3!JSJclaIn$`E$^v0Es2e>@ z!~uD)Y=8iOIHt2iZDVYTDRnAA)1V+&Jsxa%lkN&)&i+J@_#Qj>^*sz=xKqeZm|Xk) zTyu_f4*9fMxM95D^}%yMi$w64kxOWgMIj>oK3mn9K~g%Xem=k8Q43BSQ{E_{Bg5gS z-|f?uG`xo#T%cWYErlLc29G#`@-`Bx=?S&Ae}k;wMB#YTvoL|Rt|J)5?wf4Yx!!;D z$!Mz5m7zU&ZKOl*c86vUr8g55_7BMUc1L|I>-;0xMNPBUot4?s`|kCBCEu7pgi>`P z<;BAsZ@IIibwxF+nyRLP2~hv33pvSNqC7n^b_xy+-Q>ozO3X*&uM2u%h=_}fZ%I@wU5VF5}l^o#?#BUzZw*~!OS9ElKzI^J;g$gb$E=IL_A{_w5lka=W^cz|n xV0tBTPMd?3W}8hLg{P8~k+?5* + + + + + image/svg+xml + + + + + + + + + + + + + + + Deploy your FastAPI app for free + + + + + + + + diff --git a/docs/en/docs/img/sponsors/testdriven.svg b/docs/en/docs/img/sponsors/testdriven.svg new file mode 100644 index 0000000000..9ed2dc72e2 --- /dev/null +++ b/docs/en/docs/img/sponsors/testdriven.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Learn Test-Driven Development with FastAPI + + diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index d0b73f9fc2..cef2d8e051 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -43,6 +43,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 6fa7dc6640..abd0d54bbc 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -123,7 +123,13 @@ nav: - advanced/openapi-callbacks.md - advanced/wsgi.md - async.md -- deployment.md +- Deployment: + - deployment/index.md + - deployment/versions.md + - deployment/https.md + - deployment/deta.md + - deployment/docker.md + - deployment/manually.md - project-generation.md - alternatives.md - history-design-future.md diff --git a/docs/es/docs/async.md b/docs/es/docs/async.md index c1d714b287..6246a35272 100644 --- a/docs/es/docs/async.md +++ b/docs/es/docs/async.md @@ -261,7 +261,7 @@ Pero también puedes aprovechar los beneficios del paralelismo y el multiprocesa Eso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena combinación para las API y aplicaciones web de Data Science / Machine Learning (entre muchas otras). -Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Despliegue](deployment.md){.internal-link target=_blank}. +Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Despliegue](deployment/index.md){.internal-link target=_blank}. ## `async` y `await` diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index 30e5b1d92a..77053bdbd9 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -42,6 +42,20 @@ Sus características principales son: * Esta estimación está basada en pruebas con un equipo de desarrollo interno contruyendo aplicaciones listas para producción. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Otros sponsors + ## Opiniones "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 5fb52cc3cb..7013e33c1f 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md index 687cc7c2bf..16ba91418f 100644 --- a/docs/it/docs/index.md +++ b/docs/it/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/ja/docs/alternatives.md b/docs/ja/docs/alternatives.md index 57bf461187..27e3c8846d 100644 --- a/docs/ja/docs/alternatives.md +++ b/docs/ja/docs/alternatives.md @@ -408,7 +408,7 @@ Starletteや**FastAPI**のサーバーとして推奨されています。 Gunicornと組み合わせることで、非同期でマルチプロセスなサーバーを持つことがきます。 - 詳細は[デプロイ](deployment.md){.internal-link target=_blank}の項目で確認してください。 + 詳細は[デプロイ](deployment/index.md){.internal-link target=_blank}の項目で確認してください。 ## ベンチマーク と スピード diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md index 9fdce0ef2c..72745e1ce4 100644 --- a/docs/ja/docs/index.md +++ b/docs/ja/docs/index.md @@ -43,6 +43,20 @@ FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以 \* 本番アプリケーションを構築している開発チームのテストによる見積もり。 +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## 評価 "_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな**Windows**製品と**Office**製品に統合されつつあります。_" diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index 8db98885d3..3f03a337f8 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/pt/docs/alternatives.md b/docs/pt/docs/alternatives.md index 384eb08020..1269fe66d8 100644 --- a/docs/pt/docs/alternatives.md +++ b/docs/pt/docs/alternatives.md @@ -406,7 +406,7 @@ Ele é o servidor recomendado para Starlette e **FastAPI**. Você pode combinar ele com o Gunicorn, para ter um servidor multi-processos assíncrono. - Verifique mais detalhes na seção [Deployment](deployment.md){.internal-link target=_blank}. + Verifique mais detalhes na seção [Deployment](deployment/index.md){.internal-link target=_blank}. ## Performance e velocidade diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index ed87d6897a..906b524444 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -42,6 +42,20 @@ Os recursos chave são: * estimativas baseadas em testes realizados com equipe interna de desenvolvimento, construindo aplicações em produção. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opiniões "*[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços _Machine Learning_ na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**.*" diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 03abddc1d1..086eb209c5 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 8db98885d3..3f03a337f8 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index d236da22c1..671b3cf104 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -47,6 +47,20 @@ The key features are: * estimation based on tests on an internal development team, building production applications. +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## Opinions "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 93d9d98c49..52a45eb0c1 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -43,6 +43,20 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框 * 根据对某个构建线上应用的内部开发团队所进行的测试估算得出。 +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + ## 评价 「_[...] 最近我一直在使用 **FastAPI**。[...] 实际上我正在计划将其用于我所在的**微软**团队的所有**机器学习服务**。其中一些服务正被集成进核心 **Windows** 产品和一些 **Office** 产品。_」 diff --git a/scripts/docs.py b/scripts/docs.py index 284f344f68..e11bacb646 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -1,4 +1,5 @@ import os +import re import shutil from http.server import HTTPServer, SimpleHTTPRequestHandler from multiprocessing import Pool @@ -11,6 +12,7 @@ import mkdocs.config import mkdocs.utils import typer import yaml +from jinja2 import Template app = typer.Typer() @@ -194,6 +196,62 @@ def build_lang( typer.secho(f"Successfully built docs for: {lang}", color=typer.colors.GREEN) +index_sponsors_template = """ +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} +""" + + +def generate_readme_content(): + en_index = en_docs_path / "docs" / "index.md" + content = en_index.read_text("utf-8") + match_start = re.search(r"", content) + match_end = re.search(r"", content) + sponsors_data_path = en_docs_path / "data" / "sponsors.yml" + sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding="utf-8")) + if not (match_start and match_end): + raise RuntimeError("Couldn't auto-generate sponsors section") + pre_end = match_start.end() + post_start = match_end.start() + template = Template(index_sponsors_template) + message = template.render(sponsors=sponsors) + pre_content = content[:pre_end] + post_content = content[post_start:] + new_content = pre_content + message + post_content + return new_content + + +@app.command() +def generate_readme(): + """ + Generate README.md content from main index.md + """ + typer.echo("Generating README") + readme_path = Path("README.md") + new_content = generate_readme_content() + readme_path.write_text(new_content, encoding="utf-8") + + +@app.command() +def verify_readme(): + """ + Verify README.md content from main index.md + """ + typer.echo("Verifying README") + readme_path = Path("README.md") + generated_content = generate_readme_content() + readme_content = readme_path.read_text("utf-8") + if generated_content != readme_content: + typer.secho( + "README.md outdated from the latest index.md", color=typer.colors.RED + ) + raise typer.Abort() + typer.echo("Valid README ✅") + + @app.command() def build_all(): """ @@ -202,24 +260,19 @@ def build_all(): """ site_path = Path("site").absolute() update_languages(lang=None) - en_build_path: Path = docs_path / "en" current_dir = os.getcwd() - os.chdir(en_build_path) - typer.echo(f"Building docs for: en") + os.chdir(en_docs_path) + typer.echo("Building docs for: en") mkdocs.commands.build.build(mkdocs.config.load_config(site_dir=str(site_path))) os.chdir(current_dir) - langs = [] for lang in get_lang_paths(): - if lang == en_build_path or not lang.is_dir(): + if lang == en_docs_path or not lang.is_dir(): continue langs.append(lang.name) cpu_count = os.cpu_count() or 1 with Pool(cpu_count * 2) as p: p.map(build_lang, langs) - typer.echo("Copying en index.md to README.md") - en_index = en_build_path / "docs" / "index.md" - shutil.copyfile(en_index, "README.md") def update_single_lang(lang: str): diff --git a/scripts/test.sh b/scripts/test.sh index e43f179ce1..b593133d82 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -5,6 +5,6 @@ set -x bash ./scripts/lint.sh # Check README.md is up to date -diff --brief docs/en/docs/index.md README.md +python ./scripts/docs.py verify-readme export PYTHONPATH=./docs_src pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing --cov-report=xml tests ${@} -- 2.47.3