From efdafa43613f084d198e51f6858e8610beddb5ed Mon Sep 17 00:00:00 2001 From: Neizvestnyj Date: Mon, 29 Sep 2025 05:57:38 +0300 Subject: [PATCH 01/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20`tutorial/securit?= =?UTF-8?q?y/oauth2-jwt/`=20to=20use=20`pwdlib`=20with=20Argon2=20instead?= =?UTF-8?q?=20of=20`passlib`=20(#13917)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/en/docs/how-to/conditional-openapi.md | 2 +- docs/en/docs/tutorial/security/oauth2-jwt.md | 24 ++++++++++---------- docs_src/security/tutorial004.py | 10 ++++---- docs_src/security/tutorial004_an.py | 10 ++++---- docs_src/security/tutorial004_an_py310.py | 10 ++++---- docs_src/security/tutorial004_an_py39.py | 10 ++++---- docs_src/security/tutorial004_py310.py | 10 ++++---- docs_src/security/tutorial005.py | 12 +++++----- docs_src/security/tutorial005_an.py | 12 +++++----- docs_src/security/tutorial005_an_py310.py | 12 +++++----- docs_src/security/tutorial005_an_py39.py | 12 +++++----- docs_src/security/tutorial005_py310.py | 12 +++++----- docs_src/security/tutorial005_py39.py | 12 +++++----- pyproject.toml | 2 -- requirements-tests.txt | 2 +- 15 files changed, 75 insertions(+), 77 deletions(-) diff --git a/docs/en/docs/how-to/conditional-openapi.md b/docs/en/docs/how-to/conditional-openapi.md index 833123e6a..e5893e584 100644 --- a/docs/en/docs/how-to/conditional-openapi.md +++ b/docs/en/docs/how-to/conditional-openapi.md @@ -17,7 +17,7 @@ If you want to secure your API, there are several better things you can do, for * Make sure you have well defined Pydantic models for your request bodies and responses. * Configure any required permissions and roles using dependencies. * Never store plaintext passwords, only password hashes. -* Implement and use well-known cryptographic tools, like Passlib and JWT tokens, etc. +* Implement and use well-known cryptographic tools, like pwdlib and JWT tokens, etc. * Add more granular permission controls with OAuth2 scopes where needed. * ...etc. diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index e9ae0db68..95baf871c 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -64,20 +64,20 @@ If your database is stolen, the thief won't have your users' plaintext passwords So, the thief won't be able to try to use that password in another system (as many users use the same password everywhere, this would be dangerous). -## Install `passlib` { #install-passlib } +## Install `pwdlib` { #install-pwdlib } -PassLib is a great Python package to handle password hashes. +pwdlib is a great Python package to handle password hashes. It supports many secure hashing algorithms and utilities to work with them. -The recommended algorithm is "Bcrypt". +The recommended algorithm is "Argon2". -Make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install PassLib with Bcrypt: +Make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install pwdlib with Argon2:
```console -$ pip install "passlib[bcrypt]" +$ pip install "pwdlib[argon2]" ---> 100% ``` @@ -86,7 +86,7 @@ $ pip install "passlib[bcrypt]" /// tip -With `passlib`, you could even configure it to be able to read passwords created by **Django**, a **Flask** security plug-in or many others. +With `pwdlib`, you could even configure it to be able to read passwords created by **Django**, a **Flask** security plug-in or many others. So, you would be able to, for example, share the same data from a Django application in a database with a FastAPI application. Or gradually migrate a Django application using the same database. @@ -96,15 +96,15 @@ And your users would be able to login from your Django app or from your **FastAP ## Hash and verify the passwords { #hash-and-verify-the-passwords } -Import the tools we need from `passlib`. +Import the tools we need from `pwdlib`. -Create a PassLib "context". This is what will be used to hash and verify passwords. +Create a PasswordHash instance with recommended settings - it will be used for hashing and verifying passwords. /// tip -The PassLib context also has functionality to use different hashing algorithms, including deprecated old ones only to allow verifying them, etc. +pwdlib also supports the bcrypt hashing algorithm but does not include legacy algorithms - for working with outdated hashes, it is recommended to use the passlib library. -For example, you could use it to read and verify passwords generated by another system (like Django) but hash any new passwords with a different algorithm like Bcrypt. +For example, you could use it to read and verify passwords generated by another system (like Django) but hash any new passwords with a different algorithm like Argon2 or Bcrypt. And be compatible with all of them at the same time. @@ -120,7 +120,7 @@ And another one to authenticate and return a user. /// note -If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`. +If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. /// @@ -264,7 +264,7 @@ Many packages that simplify it a lot have to make many compromises with the data It gives you all the flexibility to choose the ones that fit your project the best. -And you can use directly many well maintained and widely used packages like `passlib` and `PyJWT`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages. +And you can use directly many well maintained and widely used packages like `pwdlib` and `PyJWT`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages. But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security. diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py index 222589618..130dc699a 100644 --- a/docs_src/security/tutorial004.py +++ b/docs_src/security/tutorial004.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py index e2221cd39..018234e30 100644 --- a/docs_src/security/tutorial004_an.py +++ b/docs_src/security/tutorial004_an.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel from typing_extensions import Annotated @@ -21,7 +21,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } @@ -47,7 +47,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -55,11 +55,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index a3f74fc0e..18ea96bc5 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py index b33d677ed..d3fd29e5a 100644 --- a/docs_src/security/tutorial004_an_py39.py +++ b/docs_src/security/tutorial004_an_py39.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py index d46ce26bf..cd1dcff46 100644 --- a/docs_src/security/tutorial004_py310.py +++ b/docs_src/security/tutorial004_py310.py @@ -4,7 +4,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -19,7 +19,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } @@ -45,7 +45,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -53,11 +53,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py index 447dacb37..fdd73bcd8 100644 --- a/docs_src/security/tutorial005.py +++ b/docs_src/security/tutorial005.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py index d2c4fe9b8..e1d7b4f62 100644 --- a/docs_src/security/tutorial005_an.py +++ b/docs_src/security/tutorial005_an.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError from typing_extensions import Annotated @@ -25,14 +25,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -59,7 +59,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -70,11 +70,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py index e3527370d..df55951c0 100644 --- a/docs_src/security/tutorial005_an_py310.py +++ b/docs_src/security/tutorial005_an_py310.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py index 3dc3140c3..983c1c22c 100644 --- a/docs_src/security/tutorial005_an_py39.py +++ b/docs_src/security/tutorial005_an_py39.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py index 3fc15212b..d08e2c59f 100644 --- a/docs_src/security/tutorial005_py310.py +++ b/docs_src/security/tutorial005_py310.py @@ -8,7 +8,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -23,14 +23,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -57,7 +57,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -68,11 +68,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py index f9aed0a42..5bde47ef4 100644 --- a/docs_src/security/tutorial005_py39.py +++ b/docs_src/security/tutorial005_py39.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/pyproject.toml b/pyproject.toml index fbfdea79a..41ef1eb76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -172,8 +172,6 @@ junit_family = "xunit2" filterwarnings = [ "error", 'ignore:starlette.middleware.wsgi is deprecated and will be removed in a future release\..*:DeprecationWarning:starlette', - # For passlib - "ignore:'crypt' is deprecated and slated for removal in Python 3.13:DeprecationWarning", # see https://trio.readthedocs.io/en/stable/history.html#trio-0-22-0-2022-09-28 "ignore:You seem to already have a custom.*:RuntimeWarning:trio", # TODO: remove after upgrading SQLAlchemy to a version that includes the following changes diff --git a/requirements-tests.txt b/requirements-tests.txt index e87a42162..53ec28d2e 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -9,7 +9,7 @@ flask >=1.1.2,<4.0.0 anyio[trio] >=3.2.1,<5.0.0 PyJWT==2.9.0 pyyaml >=5.3.1,<7.0.0 -passlib[bcrypt] >=1.7.2,<2.0.0 +pwdlib[argon2] >=0.2.1 inline-snapshot>=0.21.1 # types types-ujson ==5.10.0.20240515 From 861b22c40897a03d2d7e5926923d962121ed5e2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 02:58:20 +0000 Subject: [PATCH 02/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fe1fac8cf..3eeb976d7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Docs +* 📝 Update `tutorial/security/oauth2-jwt/` to use `pwdlib` with Argon2 instead of `passlib`. PR [#13917](https://github.com/fastapi/fastapi/pull/13917) by [@Neizvestnyj](https://github.com/Neizvestnyj). * ✏️ Fix typos in OAuth2 password request forms. PR [#14112](https://github.com/fastapi/fastapi/pull/14112) by [@alv2017](https://github.com/alv2017). * 📝 Update contributing guidelines for installing requirements. PR [#14095](https://github.com/fastapi/fastapi/pull/14095) by [@alejsdev](https://github.com/alejsdev). From e329d78f866a12893699f786f1209a666e1688e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 29 Sep 2025 12:29:38 +0900 Subject: [PATCH 03/38] =?UTF-8?q?=F0=9F=90=9B=20Fix=20support=20for=20`Str?= =?UTF-8?q?eamingResponse`s=20with=20dependencies=20with=20`yield`=20or=20?= =?UTF-8?q?`UploadFile`s,=20close=20after=20the=20response=20is=20done=20(?= =?UTF-8?q?#14099)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../en/docs/advanced/advanced-dependencies.md | 88 +++++ .../dependencies/dependencies-with-yield.md | 53 +-- docs_src/dependencies/tutorial013_an_py310.py | 38 ++ docs_src/dependencies/tutorial014_an_py310.py | 39 ++ fastapi/applications.py | 53 ++- fastapi/middleware/asyncexitstack.py | 18 + fastapi/routing.py | 333 +++++++++++------- tests/test_dependency_after_yield_raise.py | 69 ++++ .../test_dependency_after_yield_streaming.py | 130 +++++++ .../test_dependency_after_yield_websockets.py | 79 +++++ tests/test_dependency_contextmanager.py | 11 +- ..._dependency_yield_except_httpexception.py} | 0 tests/test_route_scope.py | 2 +- .../test_dependencies/test_tutorial008c.py | 2 +- 14 files changed, 731 insertions(+), 184 deletions(-) create mode 100644 docs_src/dependencies/tutorial013_an_py310.py create mode 100644 docs_src/dependencies/tutorial014_an_py310.py create mode 100644 fastapi/middleware/asyncexitstack.py create mode 100644 tests/test_dependency_after_yield_raise.py create mode 100644 tests/test_dependency_after_yield_streaming.py create mode 100644 tests/test_dependency_after_yield_websockets.py rename tests/{test_dependency_normal_exceptions.py => test_dependency_yield_except_httpexception.py} (100%) diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index c71c11404..e0404b389 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -63,3 +63,91 @@ In the chapters about security, there are utility functions that are implemented If you understood all this, you already know how those utility tools for security work underneath. /// + +## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks } + +/// warning + +You most probably don't need these technical details. + +These details are useful mainly if you had a FastAPI application older than 0.118.0 and you are facing issues with dependencies with `yield`. + +/// + +Dependencies with `yield` have evolved over time to account for the different use cases and to fix some issues, here's a summary of what has changed. + +### Dependencies with `yield` and `StreamingResponse`, Technical Details { #dependencies-with-yield-and-streamingresponse-technical-details } + +Before FastAPI 0.118.0, if you used a dependency with `yield`, it would run the exit code after the *path operation function* returned but right before sending the response. + +The intention was to avoid holding resources for longer than necessary, waiting for the response to travel through the network. + +This change also meant that if you returned a `StreamingResponse`, the exit code of the dependency with `yield` would have been already run. + +For example, if you had a database session in a dependency with `yield`, the `StreamingResponse` would not be able to use that session while streaming data because the session would have already been closed in the exit code after `yield`. + +This behavior was reverted in 0.118.0, to make the exit code after `yield` be executed after the response is sent. + +/// info + +As you will see below, this is very similar to the behavior before version 0.106.0, but with several improvements and bug fixes for corner cases. + +/// + +#### Use Cases with Early Exit Code { #use-cases-with-early-exit-code } + +There are some use cases with specific conditions that could benefit from the old behavior of running the exit code of dependencies with `yield` before sending the response. + +For example, imagine you have code that uses a database session in a dependency with `yield` only to verify a user, but the database session is never used again in the *path operation function*, only in the dependency, **and** the response takes a long time to be sent, like a `StreamingResponse` that sends data slowly, but for some reason doesn't use the database. + +In this case, the database session would be held until the response is finished being sent, but if you don't use it, then it wouldn't be necessary to hold it. + +Here's how it could look like: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py *} + +The exit code, the automatic closing of the `Session` in: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *} + +...would be run after the the response finishes sending the slow data: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *} + +But as `generate_stream()` doesn't use the database session, it is not really necessary to keep the session open while sending the response. + +If you have this specific use case using SQLModel (or SQLAlchemy), you could explicitly close the session after you don't need it anymore: + +{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *} + +That way the session would release the database connection, so other requests could use it. + +If you have a different use case that needs to exit early from a dependency with `yield`, please create a GitHub Discussion Question with your specific use case and why you would benefit from having early closing for dependencies with `yield`. + +If there are compelling use cases for early closing in dependencies with `yield`, I would consider adding a new way to opt in to early closing. + +### Dependencies with `yield` and `except`, Technical Details { #dependencies-with-yield-and-except-technical-details } + +Before FastAPI 0.110.0, if you used a dependency with `yield`, and then you captured an exception with `except` in that dependency, and you didn't raise the exception again, the exception would be automatically raised/forwarded to any exception handlers or the internal server error handler. + +This was changed in version 0.110.0 to fix unhandled memory consumption from forwarded exceptions without a handler (internal server errors), and to make it consistent with the behavior of regular Python code. + +### Background Tasks and Dependencies with `yield`, Technical Details { #background-tasks-and-dependencies-with-yield-technical-details } + +Before FastAPI 0.106.0, raising exceptions after `yield` was not possible, the exit code in dependencies with `yield` was executed *after* the response was sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} would have already run. + +This was designed this way mainly to allow using the same objects "yielded" by dependencies inside of background tasks, because the exit code would be executed after the background tasks were finished. + +This was changed in FastAPI 0.106.0 with the intention to not hold resources while waiting for the response to travel through the network. + +/// tip + +Additionally, a background task is normally an independent set of logic that should be handled separately, with its own resources (e.g. its own database connection). + +So, this way you will probably have cleaner code. + +/// + +If you used to rely on this behavior, now you should create the resources for background tasks inside the background task itself, and use internally only data that doesn't depend on the resources of dependencies with `yield`. + +For example, instead of using the same database session, you would create a new database session inside of the background task, and you would obtain the objects from the database using this new session. And then instead of passing the object from the database as a parameter to the background task function, you would pass the ID of that object and then obtain the object again inside the background task function. diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 2e2a6a8e3..adc1afa8d 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -35,7 +35,7 @@ The yielded value is what is injected into *path operations* and other dependenc {* ../../docs_src/dependencies/tutorial007.py hl[4] *} -The code following the `yield` statement is executed after creating the response but before sending it: +The code following the `yield` statement is executed after the response: {* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} @@ -51,7 +51,7 @@ You can use `async` or regular functions. If you use a `try` block in a dependency with `yield`, you'll receive any exception that was thrown when using the dependency. -For example, if some code at some point in the middle, in another dependency or in a *path operation*, made a database transaction "rollback" or create any other error, you will receive the exception in your dependency. +For example, if some code at some point in the middle, in another dependency or in a *path operation*, made a database transaction "rollback" or created any other exception, you would receive the exception in your dependency. So, you can look for that specific exception inside the dependency with `except SomeException`. @@ -95,9 +95,11 @@ This works thanks to Python's ASGIApp: + # Duplicate/override from Starlette to add AsyncExitStackMiddleware + # inside of ExceptionMiddleware, inside of custom user middlewares + debug = self.debug + error_handler = None + exception_handlers: dict[Any, ExceptionHandler] = {} + + for key, value in self.exception_handlers.items(): + if key in (500, Exception): + error_handler = value + else: + exception_handlers[key] = value + + middleware = ( + [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)] + + self.user_middleware + + [ + Middleware( + ExceptionMiddleware, handlers=exception_handlers, debug=debug + ), + # Add FastAPI-specific AsyncExitStackMiddleware for closing files. + # Before this was also used for closing dependencies with yield but + # those now have their own AsyncExitStack, to properly support + # streaming responses while keeping compatibility with the previous + # versions (as of writing 0.117.1) that allowed doing + # except HTTPException inside a dependency with yield. + # This needs to happen after user middlewares because those create a + # new contextvars context copy by using a new AnyIO task group. + # This AsyncExitStack preserves the context for contextvars, not + # strictly necessary for closing files but it was one of the original + # intentions. + # If the AsyncExitStack lived outside of the custom middlewares and + # contextvars were set, for example in a dependency with 'yield' + # in that internal contextvars context, the values would not be + # available in the outer context of the AsyncExitStack. + # By placing the middleware and the AsyncExitStack here, inside all + # user middlewares, the same context is used. + # This is currently not needed, only for closing files, but used to be + # important when dependencies with yield were closed here. + Middleware(AsyncExitStackMiddleware), + ] + ) + + app = self.router + for cls, args, kwargs in reversed(middleware): + app = cls(app, *args, **kwargs) + return app + def openapi(self) -> Dict[str, Any]: """ Generate the OpenAPI schema of the application. This is called by FastAPI diff --git a/fastapi/middleware/asyncexitstack.py b/fastapi/middleware/asyncexitstack.py new file mode 100644 index 000000000..4ce3f5a62 --- /dev/null +++ b/fastapi/middleware/asyncexitstack.py @@ -0,0 +1,18 @@ +from contextlib import AsyncExitStack + +from starlette.types import ASGIApp, Receive, Scope, Send + + +# Used mainly to close files after the request is done, dependencies are closed +# in their own AsyncExitStack +class AsyncExitStackMiddleware: + def __init__( + self, app: ASGIApp, context_name: str = "fastapi_middleware_astack" + ) -> None: + self.app = app + self.context_name = context_name + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + async with AsyncExitStack() as stack: + scope[self.context_name] = stack + await self.app(scope, receive, send) diff --git a/fastapi/routing.py b/fastapi/routing.py index f620ced5f..65f739d95 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -1,5 +1,6 @@ import dataclasses import email.message +import functools import inspect import json import sys @@ -8,6 +9,7 @@ from enum import Enum, IntEnum from typing import ( Any, AsyncIterator, + Awaitable, Callable, Collection, Coroutine, @@ -59,6 +61,8 @@ from fastapi.utils import ( ) from pydantic import BaseModel from starlette import routing +from starlette._exception_handler import wrap_app_handling_exceptions +from starlette._utils import is_async_callable from starlette.concurrency import run_in_threadpool from starlette.exceptions import HTTPException from starlette.requests import Request @@ -68,11 +72,9 @@ from starlette.routing import ( Match, compile_path, get_name, - request_response, - websocket_session, ) from starlette.routing import Mount as Mount # noqa -from starlette.types import AppType, ASGIApp, Lifespan, Scope +from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send from starlette.websockets import WebSocket from typing_extensions import Annotated, Doc, deprecated @@ -82,6 +84,73 @@ else: # pragma: no cover from asyncio import iscoroutinefunction +# Copy of starlette.routing.request_response modified to include the +# dependencies' AsyncExitStack +def request_response( + func: Callable[[Request], Union[Awaitable[Response], Response]], +) -> ASGIApp: + """ + Takes a function or coroutine `func(request) -> response`, + and returns an ASGI application. + """ + f: Callable[[Request], Awaitable[Response]] = ( + func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore + ) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + request = Request(scope, receive, send) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + # Starts customization + response_awaited = False + async with AsyncExitStack() as stack: + scope["fastapi_inner_astack"] = stack + # Same as in Starlette + response = await f(request) + await response(scope, receive, send) + # Continues customization + response_awaited = True + if not response_awaited: + raise FastAPIError( + "Response not awaited. There's a high chance that the " + "application code is raising an exception and a dependency with yield " + "has a block with a bare except, or a block with except Exception, " + "and is not raising the exception again. Read more about it in the " + "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except" + ) + + # Same as in Starlette + await wrap_app_handling_exceptions(app, request)(scope, receive, send) + + return app + + +# Copy of starlette.routing.websocket_session modified to include the +# dependencies' AsyncExitStack +def websocket_session( + func: Callable[[WebSocket], Awaitable[None]], +) -> ASGIApp: + """ + Takes a coroutine `func(session)`, and returns an ASGI application. + """ + # assert asyncio.iscoroutinefunction(func), "WebSocket endpoints must be async" + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + session = WebSocket(scope, receive=receive, send=send) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + # Starts customization + async with AsyncExitStack() as stack: + scope["fastapi_inner_astack"] = stack + # Same as in Starlette + await func(session) + + # Same as in Starlette + await wrap_app_handling_exceptions(app, session)(scope, receive, send) + + return app + + def _prepare_response_content( res: Any, *, @@ -246,119 +315,120 @@ def get_request_handler( async def app(request: Request) -> Response: response: Union[Response, None] = None - async with AsyncExitStack() as file_stack: - try: - body: Any = None - if body_field: - if is_body_form: - body = await request.form() - file_stack.push_async_callback(body.close) - else: - body_bytes = await request.body() - if body_bytes: - json_body: Any = Undefined - content_type_value = request.headers.get("content-type") - if not content_type_value: - json_body = await request.json() - else: - message = email.message.Message() - message["content-type"] = content_type_value - if message.get_content_maintype() == "application": - subtype = message.get_content_subtype() - if subtype == "json" or subtype.endswith("+json"): - json_body = await request.json() - if json_body != Undefined: - body = json_body - else: - body = body_bytes - except json.JSONDecodeError as e: - validation_error = RequestValidationError( - [ - { - "type": "json_invalid", - "loc": ("body", e.pos), - "msg": "JSON decode error", - "input": {}, - "ctx": {"error": e.msg}, - } - ], - body=e.doc, - ) - raise validation_error from e - except HTTPException: - # If a middleware raises an HTTPException, it should be raised again - raise - except Exception as e: - http_error = HTTPException( - status_code=400, detail="There was an error parsing the body" - ) - raise http_error from e - errors: List[Any] = [] - async with AsyncExitStack() as async_exit_stack: - solved_result = await solve_dependencies( - request=request, - dependant=dependant, - body=body, - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - errors = solved_result.errors - if not errors: - raw_response = await run_endpoint_function( - dependant=dependant, - values=solved_result.values, - is_coroutine=is_coroutine, - ) - if isinstance(raw_response, Response): - if raw_response.background is None: - raw_response.background = solved_result.background_tasks - response = raw_response - else: - response_args: Dict[str, Any] = { - "background": solved_result.background_tasks - } - # If status_code was set, use it, otherwise use the default from the - # response class, in the case of redirect it's 307 - current_status_code = ( - status_code - if status_code - else solved_result.response.status_code - ) - if current_status_code is not None: - response_args["status_code"] = current_status_code - if solved_result.response.status_code: - response_args["status_code"] = ( - solved_result.response.status_code - ) - content = await serialize_response( - field=response_field, - response_content=raw_response, - include=response_model_include, - exclude=response_model_exclude, - by_alias=response_model_by_alias, - exclude_unset=response_model_exclude_unset, - exclude_defaults=response_model_exclude_defaults, - exclude_none=response_model_exclude_none, - is_coroutine=is_coroutine, - ) - response = actual_response_class(content, **response_args) - if not is_body_allowed_for_status_code(response.status_code): - response.body = b"" - response.headers.raw.extend(solved_result.response.headers.raw) - if errors: - validation_error = RequestValidationError( - _normalize_errors(errors), body=body - ) - raise validation_error - if response is None: - raise FastAPIError( - "No response object was returned. There's a high chance that the " - "application code is raising an exception and a dependency with yield " - "has a block with a bare except, or a block with except Exception, " - "and is not raising the exception again. Read more about it in the " - "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except" + file_stack = request.scope.get("fastapi_middleware_astack") + assert isinstance(file_stack, AsyncExitStack), ( + "fastapi_middleware_astack not found in request scope" + ) + + # Read body and auto-close files + try: + body: Any = None + if body_field: + if is_body_form: + body = await request.form() + file_stack.push_async_callback(body.close) + else: + body_bytes = await request.body() + if body_bytes: + json_body: Any = Undefined + content_type_value = request.headers.get("content-type") + if not content_type_value: + json_body = await request.json() + else: + message = email.message.Message() + message["content-type"] = content_type_value + if message.get_content_maintype() == "application": + subtype = message.get_content_subtype() + if subtype == "json" or subtype.endswith("+json"): + json_body = await request.json() + if json_body != Undefined: + body = json_body + else: + body = body_bytes + except json.JSONDecodeError as e: + validation_error = RequestValidationError( + [ + { + "type": "json_invalid", + "loc": ("body", e.pos), + "msg": "JSON decode error", + "input": {}, + "ctx": {"error": e.msg}, + } + ], + body=e.doc, ) + raise validation_error from e + except HTTPException: + # If a middleware raises an HTTPException, it should be raised again + raise + except Exception as e: + http_error = HTTPException( + status_code=400, detail="There was an error parsing the body" + ) + raise http_error from e + + # Solve dependencies and run path operation function, auto-closing dependencies + errors: List[Any] = [] + async_exit_stack = request.scope.get("fastapi_inner_astack") + assert isinstance(async_exit_stack, AsyncExitStack), ( + "fastapi_inner_astack not found in request scope" + ) + solved_result = await solve_dependencies( + request=request, + dependant=dependant, + body=body, + dependency_overrides_provider=dependency_overrides_provider, + async_exit_stack=async_exit_stack, + embed_body_fields=embed_body_fields, + ) + errors = solved_result.errors + if not errors: + raw_response = await run_endpoint_function( + dependant=dependant, + values=solved_result.values, + is_coroutine=is_coroutine, + ) + if isinstance(raw_response, Response): + if raw_response.background is None: + raw_response.background = solved_result.background_tasks + response = raw_response + else: + response_args: Dict[str, Any] = { + "background": solved_result.background_tasks + } + # If status_code was set, use it, otherwise use the default from the + # response class, in the case of redirect it's 307 + current_status_code = ( + status_code if status_code else solved_result.response.status_code + ) + if current_status_code is not None: + response_args["status_code"] = current_status_code + if solved_result.response.status_code: + response_args["status_code"] = solved_result.response.status_code + content = await serialize_response( + field=response_field, + response_content=raw_response, + include=response_model_include, + exclude=response_model_exclude, + by_alias=response_model_by_alias, + exclude_unset=response_model_exclude_unset, + exclude_defaults=response_model_exclude_defaults, + exclude_none=response_model_exclude_none, + is_coroutine=is_coroutine, + ) + response = actual_response_class(content, **response_args) + if not is_body_allowed_for_status_code(response.status_code): + response.body = b"" + response.headers.raw.extend(solved_result.response.headers.raw) + if errors: + validation_error = RequestValidationError( + _normalize_errors(errors), body=body + ) + raise validation_error + + # Return response + assert response return response return app @@ -370,24 +440,23 @@ def get_websocket_app( embed_body_fields: bool = False, ) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]: async def app(websocket: WebSocket) -> None: - async with AsyncExitStack() as async_exit_stack: - # TODO: remove this scope later, after a few releases - # This scope fastapi_astack is no longer used by FastAPI, kept for - # compatibility, just in case - websocket.scope["fastapi_astack"] = async_exit_stack - solved_result = await solve_dependencies( - request=websocket, - dependant=dependant, - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, + async_exit_stack = websocket.scope.get("fastapi_inner_astack") + assert isinstance(async_exit_stack, AsyncExitStack), ( + "fastapi_inner_astack not found in request scope" + ) + solved_result = await solve_dependencies( + request=websocket, + dependant=dependant, + dependency_overrides_provider=dependency_overrides_provider, + async_exit_stack=async_exit_stack, + embed_body_fields=embed_body_fields, + ) + if solved_result.errors: + raise WebSocketRequestValidationError( + _normalize_errors(solved_result.errors) ) - if solved_result.errors: - raise WebSocketRequestValidationError( - _normalize_errors(solved_result.errors) - ) - assert dependant.call is not None, "dependant.call must be a function" - await dependant.call(**solved_result.values) + assert dependant.call is not None, "dependant.call must be a function" + await dependant.call(**solved_result.values) return app diff --git a/tests/test_dependency_after_yield_raise.py b/tests/test_dependency_after_yield_raise.py new file mode 100644 index 000000000..b560dc36f --- /dev/null +++ b/tests/test_dependency_after_yield_raise.py @@ -0,0 +1,69 @@ +from typing import Any + +import pytest +from fastapi import Depends, FastAPI, HTTPException +from fastapi.testclient import TestClient +from typing_extensions import Annotated + + +class CustomError(Exception): + pass + + +def catching_dep() -> Any: + try: + yield "s" + except CustomError as err: + raise HTTPException(status_code=418, detail="Session error") from err + + +def broken_dep() -> Any: + yield "s" + raise ValueError("Broken after yield") + + +app = FastAPI() + + +@app.get("/catching") +def catching(d: Annotated[str, Depends(catching_dep)]) -> Any: + raise CustomError("Simulated error during streaming") + + +@app.get("/broken") +def broken(d: Annotated[str, Depends(broken_dep)]) -> Any: + return {"message": "all good?"} + + +client = TestClient(app) + + +def test_catching(): + response = client.get("/catching") + assert response.status_code == 418 + assert response.json() == {"detail": "Session error"} + + +def test_broken_raise(): + with pytest.raises(ValueError, match="Broken after yield"): + client.get("/broken") + + +def test_broken_no_raise(): + """ + When a dependency with yield raises after the yield (not in an except), the + response is already "successfully" sent back to the client, but there's still + an error in the server afterwards, an exception is raised and captured or shown + in the server logs. + """ + with TestClient(app, raise_server_exceptions=False) as client: + response = client.get("/broken") + assert response.status_code == 200 + assert response.json() == {"message": "all good?"} + + +def test_broken_return_finishes(): + client = TestClient(app, raise_server_exceptions=False) + response = client.get("/broken") + assert response.status_code == 200 + assert response.json() == {"message": "all good?"} diff --git a/tests/test_dependency_after_yield_streaming.py b/tests/test_dependency_after_yield_streaming.py new file mode 100644 index 000000000..7e1c8822b --- /dev/null +++ b/tests/test_dependency_after_yield_streaming.py @@ -0,0 +1,130 @@ +from contextlib import contextmanager +from typing import Any, Generator + +import pytest +from fastapi import Depends, FastAPI +from fastapi.responses import StreamingResponse +from fastapi.testclient import TestClient +from typing_extensions import Annotated + + +class Session: + def __init__(self) -> None: + self.data = ["foo", "bar", "baz"] + self.open = True + + def __iter__(self) -> Generator[str, None, None]: + for item in self.data: + if self.open: + yield item + else: + raise ValueError("Session closed") + + +@contextmanager +def acquire_session() -> Generator[Session, None, None]: + session = Session() + try: + yield session + finally: + session.open = False + + +def dep_session() -> Any: + with acquire_session() as s: + yield s + + +def broken_dep_session() -> Any: + with acquire_session() as s: + s.open = False + yield s + + +SessionDep = Annotated[Session, Depends(dep_session)] +BrokenSessionDep = Annotated[Session, Depends(broken_dep_session)] + +app = FastAPI() + + +@app.get("/data") +def get_data(session: SessionDep) -> Any: + data = list(session) + return data + + +@app.get("/stream-simple") +def get_stream_simple(session: SessionDep) -> Any: + def iter_data(): + yield from ["x", "y", "z"] + + return StreamingResponse(iter_data()) + + +@app.get("/stream-session") +def get_stream_session(session: SessionDep) -> Any: + def iter_data(): + yield from session + + return StreamingResponse(iter_data()) + + +@app.get("/broken-session-data") +def get_broken_session_data(session: BrokenSessionDep) -> Any: + return list(session) + + +@app.get("/broken-session-stream") +def get_broken_session_stream(session: BrokenSessionDep) -> Any: + def iter_data(): + yield from session + + return StreamingResponse(iter_data()) + + +client = TestClient(app) + + +def test_regular_no_stream(): + response = client.get("/data") + assert response.json() == ["foo", "bar", "baz"] + + +def test_stream_simple(): + response = client.get("/stream-simple") + assert response.text == "xyz" + + +def test_stream_session(): + response = client.get("/stream-session") + assert response.text == "foobarbaz" + + +def test_broken_session_data(): + with pytest.raises(ValueError, match="Session closed"): + client.get("/broken-session-data") + + +def test_broken_session_data_no_raise(): + client = TestClient(app, raise_server_exceptions=False) + response = client.get("/broken-session-data") + assert response.status_code == 500 + assert response.text == "Internal Server Error" + + +def test_broken_session_stream_raise(): + # Can raise ValueError on Pydantic v2 and ExceptionGroup on Pydantic v1 + with pytest.raises((ValueError, Exception)): + client.get("/broken-session-stream") + + +def test_broken_session_stream_no_raise(): + """ + When a dependency with yield raises after the streaming response already started + the 200 status code is already sent, but there's still an error in the server + afterwards, an exception is raised and captured or shown in the server logs. + """ + with TestClient(app, raise_server_exceptions=False) as client: + response = client.get("/broken-session-stream") + assert response.status_code == 200 + assert response.text == "" diff --git a/tests/test_dependency_after_yield_websockets.py b/tests/test_dependency_after_yield_websockets.py new file mode 100644 index 000000000..7c323c338 --- /dev/null +++ b/tests/test_dependency_after_yield_websockets.py @@ -0,0 +1,79 @@ +from contextlib import contextmanager +from typing import Any, Generator + +import pytest +from fastapi import Depends, FastAPI, WebSocket +from fastapi.testclient import TestClient +from typing_extensions import Annotated + + +class Session: + def __init__(self) -> None: + self.data = ["foo", "bar", "baz"] + self.open = True + + def __iter__(self) -> Generator[str, None, None]: + for item in self.data: + if self.open: + yield item + else: + raise ValueError("Session closed") + + +@contextmanager +def acquire_session() -> Generator[Session, None, None]: + session = Session() + try: + yield session + finally: + session.open = False + + +def dep_session() -> Any: + with acquire_session() as s: + yield s + + +def broken_dep_session() -> Any: + with acquire_session() as s: + s.open = False + yield s + + +SessionDep = Annotated[Session, Depends(dep_session)] +BrokenSessionDep = Annotated[Session, Depends(broken_dep_session)] + +app = FastAPI() + + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket, session: SessionDep): + await websocket.accept() + for item in session: + await websocket.send_text(f"{item}") + + +@app.websocket("/ws-broken") +async def websocket_endpoint_broken(websocket: WebSocket, session: BrokenSessionDep): + await websocket.accept() + for item in session: + await websocket.send_text(f"{item}") # pragma no cover + + +client = TestClient(app) + + +def test_websocket_dependency_after_yield(): + with client.websocket_connect("/ws") as websocket: + data = websocket.receive_text() + assert data == "foo" + data = websocket.receive_text() + assert data == "bar" + data = websocket.receive_text() + assert data == "baz" + + +def test_websocket_dependency_after_yield_broken(): + with pytest.raises(ValueError, match="Session closed"): + with client.websocket_connect("/ws-broken"): + pass # pragma no cover diff --git a/tests/test_dependency_contextmanager.py b/tests/test_dependency_contextmanager.py index 039c423b9..02c10458c 100644 --- a/tests/test_dependency_contextmanager.py +++ b/tests/test_dependency_contextmanager.py @@ -286,12 +286,12 @@ def test_background_tasks(): assert data["context_a"] == "started a" assert data["bg"] == "not set" middleware_state = json.loads(response.headers["x-state"]) - assert middleware_state["context_b"] == "finished b with a: started a" - assert middleware_state["context_a"] == "finished a" + assert middleware_state["context_b"] == "started b" + assert middleware_state["context_a"] == "started a" assert middleware_state["bg"] == "not set" assert state["context_b"] == "finished b with a: started a" assert state["context_a"] == "finished a" - assert state["bg"] == "bg set - b: finished b with a: started a - a: finished a" + assert state["bg"] == "bg set - b: started b - a: started a" def test_sync_raise_raises(): @@ -397,7 +397,4 @@ def test_sync_background_tasks(): assert data["sync_bg"] == "not set" assert state["context_b"] == "finished b with a: started a" assert state["context_a"] == "finished a" - assert ( - state["sync_bg"] - == "sync_bg set - b: finished b with a: started a - a: finished a" - ) + assert state["sync_bg"] == "sync_bg set - b: started b - a: started a" diff --git a/tests/test_dependency_normal_exceptions.py b/tests/test_dependency_yield_except_httpexception.py similarity index 100% rename from tests/test_dependency_normal_exceptions.py rename to tests/test_dependency_yield_except_httpexception.py diff --git a/tests/test_route_scope.py b/tests/test_route_scope.py index 2021c828f..792ea66c3 100644 --- a/tests/test_route_scope.py +++ b/tests/test_route_scope.py @@ -47,4 +47,4 @@ def test_websocket(): def test_websocket_invalid_path_doesnt_match(): with pytest.raises(WebSocketDisconnect): with client.websocket_connect("/itemsx/portal-gun"): - pass + pass # pragma: no cover diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c.py b/tests/test_tutorial/test_dependencies/test_tutorial008c.py index 11e96bf46..369b0a221 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008c.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008c.py @@ -40,7 +40,7 @@ def test_fastapi_error(mod: ModuleType): client = TestClient(mod.app) with pytest.raises(FastAPIError) as exc_info: client.get("/items/portal-gun") - assert "No response object was returned" in exc_info.value.args[0] + assert "raising an exception and a dependency with yield" in exc_info.value.args[0] def test_internal_server_error(mod: ModuleType): From bfa54b406d298155edbdfe8fdd173479857d5ad6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 03:31:17 +0000 Subject: [PATCH 04/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3eeb976d7..5ba550dbb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Fixes + +* 🐛 Fix support for `StreamingResponse`s with dependencies with `yield` or `UploadFile`s, close after the response is done. PR [#14099](https://github.com/fastapi/fastapi/pull/14099) by [@tiangolo](https://github.com/tiangolo). + ### Docs * 📝 Update `tutorial/security/oauth2-jwt/` to use `pwdlib` with Argon2 instead of `passlib`. PR [#13917](https://github.com/fastapi/fastapi/pull/13917) by [@Neizvestnyj](https://github.com/Neizvestnyj). From 1d5168a4a1293fbc44799fbab615a120c6fdb85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 29 Sep 2025 05:33:39 +0200 Subject: [PATCH 05/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5ba550dbb..684100693 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -11,6 +11,16 @@ hide: * 🐛 Fix support for `StreamingResponse`s with dependencies with `yield` or `UploadFile`s, close after the response is done. PR [#14099](https://github.com/fastapi/fastapi/pull/14099) by [@tiangolo](https://github.com/tiangolo). +Before FastAPI 0.118.0, if you used a dependency with `yield`, it would run the exit code after the *path operation function* returned but right before sending the response. + +This change also meant that if you returned a `StreamingResponse`, the exit code of the dependency with `yield` would have been already run. + +For example, if you had a database session in a dependency with `yield`, the `StreamingResponse` would not be able to use that session while streaming data because the session would have already been closed in the exit code after `yield`. + +This behavior was reverted in 0.118.0, to make the exit code after `yield` be executed after the response is sent. + +You can read more about it in the docs for [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](https://fastapi.tiangolo.com/advanced/advanced-dependencies#dependencies-with-yield-httpexception-except-and-background-tasks). Including what you could do if you wanted to close a database session earlier, before returning the response to the client. + ### Docs * 📝 Update `tutorial/security/oauth2-jwt/` to use `pwdlib` with Argon2 instead of `passlib`. PR [#13917](https://github.com/fastapi/fastapi/pull/13917) by [@Neizvestnyj](https://github.com/Neizvestnyj). From 333f1ba737be6507fc707278f6b69cf1f81efdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 29 Sep 2025 05:34:21 +0200 Subject: [PATCH 06/38] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.118.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 684100693..29112649c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,8 @@ hide: ## Latest Changes +## 0.118.0 + ### Fixes * 🐛 Fix support for `StreamingResponse`s with dependencies with `yield` or `UploadFile`s, close after the response is done. PR [#14099](https://github.com/fastapi/fastapi/pull/14099) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 986fd200c..03a5aaad5 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.117.1" +__version__ = "0.118.0" from starlette import status as status From 06367347e6da987db8e6806792d04b8aad8662e0 Mon Sep 17 00:00:00 2001 From: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Date: Tue, 30 Sep 2025 06:06:57 +0200 Subject: [PATCH 07/38] =?UTF-8?q?=F0=9F=94=A8=20Modify=20`mkdocs=5Fhooks.p?= =?UTF-8?q?y`=20to=20add=20`title`=20to=20page's=20metadata=20(remove=20pe?= =?UTF-8?q?rmalinks=20in=20social=20cards)=20(#14125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 1 + scripts/mkdocs_hooks.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 7de1590b1..a5761361d 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -40,6 +40,7 @@ jobs: - mkdocs.no-insiders.yml - .github/workflows/build-docs.yml - .github/workflows/deploy-docs.yml + - scripts/mkdocs_hooks.py langs: needs: - changes diff --git a/scripts/mkdocs_hooks.py b/scripts/mkdocs_hooks.py index e4a49165c..b9e4ff59e 100644 --- a/scripts/mkdocs_hooks.py +++ b/scripts/mkdocs_hooks.py @@ -132,6 +132,15 @@ def on_pre_page(page: Page, *, config: MkDocsConfig, files: Files) -> Page: def on_page_markdown( markdown: str, *, page: Page, config: MkDocsConfig, files: Files ) -> str: + # Set matadata["social"]["cards_layout_options"]["title"] to clean title (without + # permalink) + title = page.title + clean_title = title.split("{ #")[0] + if clean_title: + page.meta.setdefault("social", {}) + page.meta["social"].setdefault("cards_layout_options", {}) + page.meta["social"]["cards_layout_options"]["title"] = clean_title + if isinstance(page.file, EnFile): for excluded_section in non_translated_sections: if page.file.src_path.startswith(excluded_section): From 36a3830ba29818c601e08c9e48871d0b6dffcde9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 Sep 2025 04:07:18 +0000 Subject: [PATCH 08/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 29112649c..6597640e1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Internal + +* 🔨 Modify `mkdocs_hooks.py` to add `title` to page's metadata (remove permalinks in social cards). PR [#14125](https://github.com/fastapi/fastapi/pull/14125) by [@YuriiMotov](https://github.com/YuriiMotov). + ## 0.118.0 ### Fixes From 2f6fb122589fbdb9d581de9586c0ab3c4ab4b94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 30 Sep 2025 14:56:53 +0900 Subject: [PATCH 09/38] =?UTF-8?q?=F0=9F=91=B7=20Update=20docs=20previews?= =?UTF-8?q?=20comment,=20single=20comment,=20add=20failure=20status=20(#14?= =?UTF-8?q?129)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/deploy-docs.yml | 11 ++++++- scripts/deploy_docs_status.py | 54 ++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index ffa07b94d..2c432da8c 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -44,6 +44,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} RUN_ID: ${{ github.run_id }} + STATE: "pending" - name: Clean site run: | rm -rf ./site @@ -67,6 +68,14 @@ jobs: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} command: pages deploy ./site --project-name=${{ env.PROJECT_NAME }} --branch=${{ env.BRANCH }} + - name: Deploy Docs Status Error + if: failure() + run: python ./scripts/deploy_docs_status.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + RUN_ID: ${{ github.run_id }} + STATE: "error" - name: Comment Deploy run: python ./scripts/deploy_docs_status.py env: @@ -74,4 +83,4 @@ jobs: DEPLOY_URL: ${{ steps.deploy.outputs.deployment-url }} COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} RUN_ID: ${{ github.run_id }} - IS_DONE: "true" + STATE: "success" diff --git a/scripts/deploy_docs_status.py b/scripts/deploy_docs_status.py index c652cdb6e..e620b15ba 100644 --- a/scripts/deploy_docs_status.py +++ b/scripts/deploy_docs_status.py @@ -1,7 +1,8 @@ import logging import re +from typing import Literal -from github import Github +from github import Auth, Github from pydantic import BaseModel, SecretStr from pydantic_settings import BaseSettings @@ -12,7 +13,7 @@ class Settings(BaseSettings): deploy_url: str | None = None commit_sha: str run_id: int - is_done: bool = False + state: Literal["pending", "success", "error"] = "pending" class LinkData(BaseModel): @@ -26,7 +27,7 @@ def main() -> None: settings = Settings() logging.info(f"Using config: {settings.model_dump_json()}") - g = Github(settings.github_token.get_secret_value()) + g = Github(auth=Auth.Token(settings.github_token.get_secret_value())) repo = g.get_repo(settings.github_repository) use_pr = next( (pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None @@ -37,16 +38,7 @@ def main() -> None: commits = list(use_pr.get_commits()) current_commit = [c for c in commits if c.sha == settings.commit_sha][0] run_url = f"https://github.com/{settings.github_repository}/actions/runs/{settings.run_id}" - if settings.is_done and not settings.deploy_url: - current_commit.create_status( - state="success", - description="No Docs Changes", - context="deploy-docs", - target_url=run_url, - ) - logging.info("No docs changes found") - return - if not settings.deploy_url: + if settings.state == "pending": current_commit.create_status( state="pending", description="Deploying Docs", @@ -55,6 +47,26 @@ def main() -> None: ) logging.info("No deploy URL available yet") return + if settings.state == "error": + current_commit.create_status( + state="error", + description="Error Deploying Docs", + context="deploy-docs", + target_url=run_url, + ) + logging.info("Error deploying docs") + return + assert settings.state == "success" + if not settings.deploy_url: + current_commit.create_status( + state="success", + description="No Docs Changes", + context="deploy-docs", + target_url=run_url, + ) + logging.info("No docs changes found") + return + assert settings.deploy_url current_commit.create_status( state="success", description="Docs Deployed", @@ -104,7 +116,9 @@ def main() -> None: current_lang_links.sort(key=lambda x: x.preview_link) links.extend(current_lang_links) - message = f"📝 Docs preview for commit {settings.commit_sha} at: {deploy_url}" + header = "## 📝 Docs preview" + message = header + message += f"\n\nLast commit {settings.commit_sha} at: {deploy_url}" if links: message += "\n\n### Modified Pages\n\n" @@ -116,7 +130,17 @@ def main() -> None: message += "\n" print(message) - use_pr.as_issue().create_comment(message) + issue = use_pr.as_issue() + comments = list(issue.get_comments()) + for comment in comments: + if ( + comment.body.startswith(header) + and comment.user.login == "github-actions[bot]" + ): + comment.edit(message) + break + else: + issue.create_comment(message) logging.info("Finished") From 3481aad827987b0bfabe55143af71091b2d5d2f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 Sep 2025 05:57:45 +0000 Subject: [PATCH 10/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6597640e1..95ee46fad 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Internal +* 👷 Update docs previews comment, single comment, add failure status. PR [#14129](https://github.com/fastapi/fastapi/pull/14129) by [@tiangolo](https://github.com/tiangolo). * 🔨 Modify `mkdocs_hooks.py` to add `title` to page's metadata (remove permalinks in social cards). PR [#14125](https://github.com/fastapi/fastapi/pull/14125) by [@YuriiMotov](https://github.com/YuriiMotov). ## 0.118.0 From e7fc394e15d2d5ca2149d5cfe21c0fcbbd12e6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 30 Sep 2025 15:25:57 +0900 Subject: [PATCH 11/38] =?UTF-8?q?=F0=9F=8C=90=20Remove=20configuration=20f?= =?UTF-8?q?iles=20for=20inactive=20translations=20(#14130)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/docs/index.md | 467 -------------------- docs/az/docs/learn/index.md | 5 - docs/az/mkdocs.yml | 1 - docs/bn/docs/about/index.md | 3 - docs/bn/docs/environment-variables.md | 298 ------------- docs/bn/docs/index.md | 466 -------------------- docs/bn/docs/learn/index.md | 5 - docs/bn/docs/python-types.md | 586 ------------------------- docs/bn/mkdocs.yml | 1 - docs/en/mkdocs.yml | 20 - docs/he/docs/index.md | 469 -------------------- docs/he/mkdocs.yml | 1 - docs/hu/docs/index.md | 467 -------------------- docs/hu/mkdocs.yml | 1 - docs/id/docs/index.md | 495 ---------------------- docs/id/docs/tutorial/first-steps.md | 332 --------------- docs/id/docs/tutorial/index.md | 83 ---- docs/id/docs/tutorial/path-params.md | 257 ----------- docs/id/docs/tutorial/static-files.md | 40 -- docs/id/mkdocs.yml | 1 - docs/it/docs/index.md | 463 -------------------- docs/it/mkdocs.yml | 1 - docs/nl/docs/environment-variables.md | 298 ------------- docs/nl/docs/features.md | 201 --------- docs/nl/docs/index.md | 494 ---------------------- docs/nl/docs/python-types.md | 587 -------------------------- docs/nl/mkdocs.yml | 1 - docs/pl/docs/features.md | 201 --------- docs/pl/docs/help-fastapi.md | 269 ------------ docs/pl/docs/index.md | 467 -------------------- docs/pl/docs/tutorial/first-steps.md | 335 --------------- docs/pl/docs/tutorial/index.md | 83 ---- docs/pl/mkdocs.yml | 1 - docs/ur/docs/benchmarks.md | 51 --- docs/ur/mkdocs.yml | 1 - docs/yo/docs/index.md | 474 --------------------- docs/yo/mkdocs.yml | 1 - 37 files changed, 7926 deletions(-) delete mode 100644 docs/az/docs/index.md delete mode 100644 docs/az/docs/learn/index.md delete mode 100644 docs/az/mkdocs.yml delete mode 100644 docs/bn/docs/about/index.md delete mode 100644 docs/bn/docs/environment-variables.md delete mode 100644 docs/bn/docs/index.md delete mode 100644 docs/bn/docs/learn/index.md delete mode 100644 docs/bn/docs/python-types.md delete mode 100644 docs/bn/mkdocs.yml delete mode 100644 docs/he/docs/index.md delete mode 100644 docs/he/mkdocs.yml delete mode 100644 docs/hu/docs/index.md delete mode 100644 docs/hu/mkdocs.yml delete mode 100644 docs/id/docs/index.md delete mode 100644 docs/id/docs/tutorial/first-steps.md delete mode 100644 docs/id/docs/tutorial/index.md delete mode 100644 docs/id/docs/tutorial/path-params.md delete mode 100644 docs/id/docs/tutorial/static-files.md delete mode 100644 docs/id/mkdocs.yml delete mode 100644 docs/it/docs/index.md delete mode 100644 docs/it/mkdocs.yml delete mode 100644 docs/nl/docs/environment-variables.md delete mode 100644 docs/nl/docs/features.md delete mode 100644 docs/nl/docs/index.md delete mode 100644 docs/nl/docs/python-types.md delete mode 100644 docs/nl/mkdocs.yml delete mode 100644 docs/pl/docs/features.md delete mode 100644 docs/pl/docs/help-fastapi.md delete mode 100644 docs/pl/docs/index.md delete mode 100644 docs/pl/docs/tutorial/first-steps.md delete mode 100644 docs/pl/docs/tutorial/index.md delete mode 100644 docs/pl/mkdocs.yml delete mode 100644 docs/ur/docs/benchmarks.md delete mode 100644 docs/ur/mkdocs.yml delete mode 100644 docs/yo/docs/index.md delete mode 100644 docs/yo/mkdocs.yml diff --git a/docs/az/docs/index.md b/docs/az/docs/index.md deleted file mode 100644 index 4e14d7060..000000000 --- a/docs/az/docs/index.md +++ /dev/null @@ -1,467 +0,0 @@ -

- FastAPI -

-

- FastAPI framework, yüksək məshuldarlı, öyrənməsi asan, çevik kodlama, istifadəyə hazırdır -

-

- - Test - - - Əhatə - - - Paket versiyası - - - Dəstəklənən Python versiyaları - -

- ---- - -**Sənədlər**: https://fastapi.tiangolo.com - -**Qaynaq Kodu**: https://github.com/fastapi/fastapi - ---- - -FastAPI Python ilə API yaratmaq üçün standart Python tip məsləhətlərinə əsaslanan, müasir, sürətli (yüksək performanslı) framework-dür. - -Əsas xüsusiyyətləri bunlardır: - -* **Sürətli**: Çox yüksək performans, **NodeJS** və **Go** səviyyəsində (Starlette və Pydantic-ə təşəkkürlər). [Ən sürətli Python frameworklərindən biridir](#performans). -* **Çevik kodlama**: Funksiyanallıqları inkişaf etdirmək sürətini təxminən 200%-dən 300%-ə qədər artırın. * -* **Daha az xəta**: İnsan (developer) tərəfindən törədilən səhvlərin təxminən 40% -ni azaldın. * -* **İntuitiv**: Əla redaktor dəstəyi. Hər yerdə otomatik tamamlama. Xətaları müəyyənləşdirməyə daha az vaxt sərf edəcəksiniz. -* **Asan**: İstifadəsi və öyrənilməsi asan olması üçün nəzərdə tutulmuşdur. Sənədləri oxumaq üçün daha az vaxt ayıracaqsınız. -* **Qısa**: Kod təkrarlanmasını minimuma endirin. Hər bir parametr tərifində birdən çox xüsusiyyət ilə və daha az səhvlə qarşılaşacaqsınız. -* **Güclü**: Avtomatik və interaktiv sənədlərlə birlikdə istifadəyə hazır kod əldə edə bilərsiniz. -* **Standartlara əsaslanan**: API-lar üçün açıq standartlara əsaslanır (və tam uyğun gəlir): OpenAPI (əvvəlki adı ilə Swagger) və JSON Schema. - -* Bu fikirlər daxili development komandasının hazırladıqları məhsulların sınaqlarına əsaslanır. - -## Sponsorlar - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%}` -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Digər sponsorlar - -## Rəylər - -"_[...] Son günlərdə **FastAPI**-ı çox istifadə edirəm. [...] Əslində onu komandamın bütün **Microsoftda ML sevislərində** istifadə etməyi planlayıram. Onların bəziləri **windows**-un əsas məhsuluna və bəzi **Office** məhsullarına inteqrasiya olunurlar._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_**FastAPI** kitabxanasını **Proqnozlar** əldə etmək üçün sorğulana bilən **REST** serverini yaratmaqda istifadə etdik._" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** **böhran idarəçiliyi** orkestrləşmə framework-nün açıq qaynaqlı buraxılışını elan etməkdən məmnundur: **Dispatch**! [**FastAPI** ilə quruldu]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_**FastAPI** üçün həyəcanlıyam. Çox əyləncəlidir!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Düzünü desəm, sizin qurduğunuz şey həqiqətən möhkəm və peşəkar görünür. Bir çox cəhətdən **Hug**-un olmasını istədiyim kimdir - kiminsə belə bir şey qurduğunu görmək həqiqətən ruhlandırıcıdır._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_Əgər REST API-lər yaratmaq üçün **müasir framework** öyrənmək istəyirsinizsə, **FastAPI**-a baxın [...] Sürətli, istifadəsi və öyrənməsi asandır. [...]_" - -"_**API** xidmətlərimizi **FastAPI**-a köçürdük [...] Sizin də bəyənəcəyinizi düşünürük._" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -"_Python ilə istifadəyə hazır API qurmaq istəyən hər kəsə **FastAPI**-ı tövsiyə edirəm. **Möhtəşəm şəkildə dizayn edilmiş**, **istifadəsi asan** və **yüksək dərəcədə genişlənə bilən**-dir, API əsaslı inkişaf strategiyamızın **əsas komponentinə** çevrilib və Virtual TAC Engineer kimi bir çox avtomatlaşdırma və servisləri idarə edir._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, CLI-ların FastAPI-ı - - - -Əgər siz veb API əvəzinə terminalda istifadə ediləcək CLI proqramı qurursunuzsa, **Typer**-a baxa bilərsiniz. - -**Typer** FastAPI-ın kiçik qardaşıdır. Və o, CLI-lərin **FastAPI**-ı olmaq üçün nəzərdə tutulub. ⌨️ 🚀 - -## Tələblər - -FastAPI nəhənglərin çiyinlərində dayanır: - -* Web tərəfi üçün Starlette. -* Data tərəfi üçün Pydantic. - -## Quraşdırma - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -Tətbiqimizi əlçatan etmək üçün bizə Uvicorn və ya Hypercorn kimi ASGI server lazımdır. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## Nümunə - -### Kodu yaradaq - -* `main.py` adlı fayl yaradaq və ona aşağıdakı kodu yerləşdirək: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Və ya async def... - -Əgər kodunuzda `async` və ya `await` vardırsa `async def` istifadə edə bilərik: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Qeyd**: - -Əgər bu mövzu haqqında məlumatınız yoxdursa `async` və `await` sənədindəki _"Tələsirsən?"_ bölməsinə baxa bilərsiniz. - -
- -### Kodu işə salaq - -Serveri aşağıdakı əmr ilə işə salaq: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-uvicorn main:app --reload əmri haqqında... - -`uvicorn main:app` əmri aşağıdakılara instinad edir: - -* `main`: `main.py` faylı (yəni Python "modulu"). -* `app`: `main.py` faylında `app = FastAPI()` sətrində yaratdığımız `FastAPI` obyektidir. -* `--reload`: kod dəyişikliyindən sonra avtomatik olaraq serveri yenidən işə salır. Bu parametrdən yalnız development mərhələsində istifadə etməliyik. - -
- -### İndi yoxlayaq - -Bu linki brauzerimizdə açaq http://127.0.0.1:8000/items/5?q=somequery. - -Aşağıdakı kimi bir JSON cavabı görəcəksiniz: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Siz artıq bir API yaratmısınız, hansı ki: - -* `/` və `/items/{item_id}` _yollarında_ HTTP sorğularını qəbul edir. -* Hər iki _yolda_ `GET` əməliyyatlarını (həmçinin HTTP _metodları_ kimi bilinir) aparır. -* `/items/{item_id}` _yolu_ `item_id` adlı `int` qiyməti almalı olan _yol parametrinə_ sahibdir. -* `/items/{item_id}` _yolunun_ `q` adlı yol parametri var və bu parametr istəyə bağlı olsa da, `str` qiymətini almalıdır. - -### İnteraktiv API Sənədləri - -İndi http://127.0.0.1:8000/docs ünvanına daxil olun. - -Avtomatik interaktiv API sənədlərini görəcəksiniz (Swagger UI tərəfindən təmin edilir): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternativ API sənədləri - -İndi isə http://127.0.0.1:8000/redoc ünvanına daxil olun. - -ReDoc tərəfindən təqdim edilən avtomatik sənədləri görəcəksiniz: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Nümunəni Yeniləyək - -İndi gəlin `main.py` faylını `PUT` sorğusu ilə birlikdə gövdə qəbul edəcək şəkildə dəyişdirək. - -Pydantic sayəsində standart Python tiplərindən istifadə edərək gövdəni müəyyən edək. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` -Server avtomatik olaraq yenidən işə salınmalı idi (çünki biz yuxarıda `uvicorn` əmri ilə `--reload` parametrindən istifadə etmişik). - -### İnteraktiv API sənədlərindəki dəyişikliyə baxaq - -Yenidən http://127.0.0.1:8000/docs ünvanına daxil olun. - -* İnteraktiv API sənədləri yeni gövdə də daxil olmaq ilə avtomatik olaraq yenilənəcək: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* "Try it out" düyməsini klikləyin, bu, parametrləri doldurmağa və API ilə birbaşa əlaqə saxlamağa imkan verir: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Sonra "Execute" düyməsini klikləyin, istifadəçi interfeysi API ilə əlaqə quracaq, parametrləri göndərəcək, nəticələri əldə edəcək və onları ekranda göstərəcək: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Alternativ API Sənədlərindəki Dəyişikliyə Baxaq - -İndi isə yenidən http://127.0.0.1:8000/redoc ünvanına daxil olun. - -* Alternativ sənədlər həm də yeni sorğu parametri və gövdəsini əks etdirəcək: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Xülasə - -Ümumiləşdirsək, parametrlər, gövdə və s. Biz məlumat növlərini **bir dəfə** funksiya parametrləri kimi təyin edirik. - -Bunu standart müasir Python tipləri ilə edirsiniz. - -Yeni sintaksis, müəyyən bir kitabxananın metodlarını və ya siniflərini və s. öyrənmək məcburiyyətində deyilsiniz. - -Sadəcə standart **Python**. - -Məsələn, `int` üçün: - -```Python -item_id: int -``` - -və ya daha mürəkkəb `Item` modeli üçün: - -```Python -item: Item -``` - -...və yalnız parametr tipini təyin etməklə bunları əldə edirsiniz: - -* Redaktor dəstəyi ilə: - * Avtomatik tamamlama. - * Tip yoxlanması. -* Məlumatların Təsdiqlənməsi: - * Məlumat etibarsız olduqda avtomatik olaraq aydın xətalar göstərir. - * Hətta çox dərin JSON obyektlərində belə doğrulama aparır. -* Daxil olan məlumatları çevirmək üçün aşağıdakı məlumat növlərindən istifadə edilir: - * JSON. - * Yol parametrləri. - * Sorğu parametrləri. - * Çərəzlər. - * Başlıqlaq. - * Formalar. - * Fayllar. -* Daxil olan məlumatları çevirmək üçün aşağıdakı məlumat növlərindən istifadə edilir (JSON olaraq): - * Python tiplərinin (`str`, `int`, `float`, `bool`, `list`, və s) çevrilməsi. - * `datetime` obyektləri. - * `UUID` obyektləri. - * Verilənlər bazası modelləri. - * və daha çoxu... -* 2 alternativ istifadəçi interfeysi daxil olmaqla avtomatik interaktiv API sənədlərini təmin edir: - * Swagger UI. - * ReDoc. - ---- - -Gəlin əvvəlki nümunəyə qayıdaq və **FastAPI**-nin nələr edəcəyinə nəzər salaq: - -* `GET` və `PUT` sorğuları üçün `item_id`-nin yolda olub-olmadığını yoxlayacaq. -* `item_id`-nin `GET` və `PUT` sorğuları üçün növünün `int` olduğunu yoxlayacaq. - * Əgər `int` deyilsə, səbəbini göstərən bir xəta mesajı göstərəcəkdir. -* məcburi olmayan `q` parametrinin `GET` (`http://127.0.0.1:8000/items/foo?q=somequery` burdakı kimi) sorğusu içərisində olub olmadığını yoxlayacaq. - * `q` parametrini `= None` ilə yaratdığımız üçün, məcburi olmayan parametr olacaq. - * Əgər `None` olmasaydı, bu məcburi parametr olardı (`PUT` metodunun gövdəsində olduğu kimi). -* `PUT` sorğusu üçün, `/items/{item_id}` gövdəsini JSON olaraq oxuyacaq: - * `name` adında məcburi bir parametr olub olmadığını və əgər varsa, tipinin `str` olub olmadığını yoxlayacaq. - * `price` adında məcburi bir parametr olub olmadığını və əgər varsa, tipinin `float` olub olmadığını yoxlayacaq. - * `is_offer` adında məcburi olmayan bir parametr olub olmadığını və əgər varsa, tipinin `float` olub olmadığını yoxlayacaq. - * Bütün bunlar ən dərin JSON obyektlərində belə işləyəcək. -* Məlumatların JSON-a və JSON-un Python obyektinə çevrilməsi avtomatik həyata keçiriləcək. -* Hər şeyi OpenAPI ilə uyğun olacaq şəkildə avtomatik olaraq sənədləşdirəcək və onları aşağıdakı kimi istifadə edə biləcək: - * İnteraktiv sənədləşmə sistemləri. - * Bir çox proqramlaşdırma dilləri üçün avtomatlaşdırılmış müştəri kodu yaratma sistemləri. -* 2 interaktiv sənədləşmə veb interfeysini birbaşa təmin edəcək. - ---- - -Yeni başlamışıq, amma siz artıq işin məntiqini başa düşmüsünüz. - -İndi aşağıdakı sətri dəyişdirməyə çalışın: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...bundan: - -```Python - ... "item_name": item.name ... -``` - -...buna: - -```Python - ... "item_price": item.price ... -``` - -...və redaktorun məlumat tiplərini bildiyini və avtomatik tamaladığını görəcəksiniz: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Daha çox funksiyaya malik daha dolğun nümunə üçün Öyrədici - İstifadəçi Təlimatı səhifəsinə baxa bilərsiniz. - -**Spoiler xəbərdarlığı**: Öyrədici - istifadəçi təlimatına bunlar daxildir: - -* **Parametrlərin**, **başlıqlar**, çərəzlər, **forma sahələri** və **fayllar** olaraq müəyyən edilməsi. -* `maximum_length` və ya `regex` kimi **doğrulama məhdudiyyətlərinin** necə təyin ediləcəyi. -* Çox güclü və istifadəsi asan **Dependency Injection** sistemi. -* Təhlükəsizlik və autentifikasiya, **JWT tokenləri** ilə **OAuth2** dəstəyi və **HTTP Basic** autentifikasiyası. -* **çox dərin JSON modellərini** müəyyən etmək üçün daha irəli səviyyə (lakin eyni dərəcədə asan) üsullar (Pydantic sayəsində). -* Strawberry və digər kitabxanalar ilə **GraphQL** inteqrasiyası. -* Digər əlavə xüsusiyyətlər (Starlette sayəsində): - * **WebSockets** - * HTTPX və `pytest` sayəsində çox asan testlər - * **CORS** - * **Cookie Sessions** - * ...və daha çoxu. - -## Performans - -Müstəqil TechEmpower meyarları göstərir ki, Uvicorn üzərində işləyən **FastAPI** proqramları ən sürətli Python kitabxanalarından biridir, yalnız Starlette və Uvicorn-un özündən yavaşdır, ki FastAPI bunların üzərinə qurulmuş bir framework-dür. (*) - -Ətraflı məlumat üçün bu bölməyə nəzər salın Müqayisələr. - -## Məcburi Olmayan Tələblər - -Pydantic tərəfindən istifadə olunanlar: - -* email-validator - e-poçtun yoxlanılması üçün. -* pydantic-settings - parametrlərin idarə edilməsi üçün. -* pydantic-extra-types - Pydantic ilə istifadə edilə bilən əlavə tiplər üçün. - -Starlette tərəfindən istifadə olunanlar: - -* httpx - Əgər `TestClient` strukturundan istifadə edəcəksinizsə, tələb olunur. -* jinja2 - Standart şablon konfiqurasiyasından istifadə etmək istəyirsinizsə, tələb olunur. -* python-multipart - `request.form()` ilə forma "çevirmə" dəstəyindən istifadə etmək istəyirsinizsə, tələb olunur. -* itsdangerous - `SessionMiddleware` dəstəyi üçün tələb olunur. -* pyyaml - `SchemaGenerator` dəstəyi üçün tələb olunur (Çox güman ki, FastAPI istifadə edərkən buna ehtiyacınız olmayacaq). -* ujson - `UJSONResponse` istifadə etmək istəyirsinizsə, tələb olunur. - -Həm FastAPI, həm də Starlette tərəfindən istifadə olunur: - -* uvicorn - Yaratdığımız proqramı servis edəcək veb server kimi fəaliyyət göstərir. -* orjson - `ORJSONResponse` istifadə edəcəksinizsə tələb olunur. - -Bütün bunları `pip install fastapi[all]` ilə quraşdıra bilərsiniz. - -## Lisenziya - -Bu layihə MIT lisenziyasının şərtlərinə əsasən lisenziyalaşdırılıb. diff --git a/docs/az/docs/learn/index.md b/docs/az/docs/learn/index.md deleted file mode 100644 index cc32108bf..000000000 --- a/docs/az/docs/learn/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Öyrən - -Burada **FastAPI** öyrənmək üçün giriş bölmələri və dərsliklər yer alır. - -Siz bunu kitab, kurs, FastAPI öyrənmək üçün rəsmi və tövsiyə olunan üsul hesab edə bilərsiniz. 😎 diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/az/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/bn/docs/about/index.md b/docs/bn/docs/about/index.md deleted file mode 100644 index b6d611ae9..000000000 --- a/docs/bn/docs/about/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# সম্পর্কে - -**FastAPI** সম্পর্কে বিস্তারিত — এর ডিজাইন, অনুপ্রেরণা ও আরও অনেক কিছু। 🤓 diff --git a/docs/bn/docs/environment-variables.md b/docs/bn/docs/environment-variables.md deleted file mode 100644 index 9122ca5bf..000000000 --- a/docs/bn/docs/environment-variables.md +++ /dev/null @@ -1,298 +0,0 @@ -# এনভায়রনমেন্ট ভেরিয়েবলস - -/// tip - -আপনি যদি "এনভায়রনমেন্ট ভেরিয়েবলস" কী এবং সেগুলো কীভাবে ব্যবহার করতে হয় সেটা জানেন, তাহলে এই অংশটি স্কিপ করে যেতে পারেন। - -/// - -এনভায়রনমেন্ট ভেরিয়েবল (সংক্ষেপে "**env var**" নামেও পরিচিত) হলো এমন একটি ভেরিয়েবল যা পাইথন কোডের **বাইরে**, **অপারেটিং সিস্টেমে** থাকে এবং আপনার পাইথন কোড (বা অন্যান্য প্রোগ্রাম) দ্বারা যাকে রিড করা যায়। - -এনভায়রনমেন্ট ভেরিয়েবলস অ্যাপ্লিকেশনের **সেটিংস** পরিচালনা করতে, পাইথনের **ইনস্টলেশন** প্রক্রিয়ার অংশ হিসেবে, ইত্যাদি কাজে উপযোগী হতে পারে। - -## Env Vars তৈরী এবং ব্যবহার - -আপনি **শেল (টার্মিনাল)**-এ, পাইথনের প্রয়োজন ছাড়াই, এনভায়রনমেন্ট ভেরিয়েবলস **তৈরি** এবং ব্যবহার করতে পারবেনঃ - -//// tab | লিনাক্স, ম্যাকওএস, উইন্ডোজ Bash - -
- -```console -// আপনি চাইলে MY_NAME নামে একটি env var তৈরি করতে পারেন -$ export MY_NAME="Wade Wilson" - -// তারপরে এটিকে চাইলে অন্যান্য প্রোগ্রামে ব্যবহার করতে পারেন -$ echo "Hello $MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -//// tab | উইন্ডোজ পাওয়ারশেল - -
- -```console -// MY_NAME নামে env var তৈরি -$ $Env:MY_NAME = "Wade Wilson" - -// অন্যান্য প্রোগ্রামে এটিকে ব্যবহার -$ echo "Hello $Env:MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -## পাইথনে env vars রিড করা - -আপনি চাইলে পাইথনের **বাইরে**, টার্মিনালে (বা অন্য কোনো উপায়ে) এনভায়রনমেন্ট ভেরিয়েবলস তৈরি করতে পারেন, এবং পরে সেগুলো **পাইথনে রিড** (অ্যাক্সেস করতে) পারেন। - -উদাহরণস্বরূপ, আপনার `main.py` নামে একটি ফাইল থাকতে পারেঃ - -```Python hl_lines="3" -import os - -name = os.getenv("MY_NAME", "World") -print(f"Hello {name} from Python") -``` - -/// tip - -`os.getenv()` এর দ্বিতীয় আর্গুমেন্টটি হলো এর ডিফল্ট ভ্যালু যা রিটার্ন করা হবে। - -যদি এটি দেওয়া না হয়, ডিফল্টভাবে `None` ব্যবহৃত হবে, এখানে আমরা ডিফল্ট ভ্যালু হিসেবে `"World"` ব্যবহার করেছি। - -/// - -তারপরে পাইথন প্রোগ্রামটিকে নিম্নোক্তভাবে কল করা যাবেঃ - -//// tab | লিনাক্স, ম্যাকওএস, উইন্ডোজ Bash - -
- -```console -// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি -$ python main.py - -// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি - -Hello World from Python - -// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই -$ export MY_NAME="Wade Wilson" - -// এবং তারপর আবার প্রোগ্রাটিকে কল করি -$ python main.py - -// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে - -Hello Wade Wilson from Python -``` - -
- -//// - -//// tab | উইন্ডোজ পাওয়ারশেল - -
- -```console -// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি -$ python main.py - -// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি - -Hello World from Python - -// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই -$ $Env:MY_NAME = "Wade Wilson" - -// এবং তারপর আবার প্রোগ্রাটিকে কল করি -$ python main.py - -// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে - -Hello Wade Wilson from Python -``` - -
- -//// - -যেহেতু এনভায়রনমেন্ট ভেরিয়েবলস কোডের বাইরে সেট করা যায়, কিন্তু পরবর্তীতে কোড দ্বারা রিড করা যায়, এবং বাকি ফাইলগুলোর সাথে রাখতে (`git` এ কমিট) হয় না, তাই কনফিগারেশনস বা **সেটিংস** এর জন্য এগুলো সাধারণত ব্যবহৃত হয়ে থাকে। - -আপনি একটি এনভায়রনমেন্ট ভেরিয়েবল শুধুমাত্র একটি **নির্দিষ্ট প্রোগ্রাম ইনভোকেশনের** জন্যও তৈরি করতে পারেন, যা শুধুমাত্র সেই প্রোগ্রামের জন্যই এভেইলেবল থাকবে এবং শুধুমাত্র তার চলাকালীন সময় পর্যন্তই সক্রিয় থাকবে। - -এটি করতে, প্রোগ্রামটি রান করার ঠিক আগেই, একই লাইনে এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন: - -
- -```console -// প্রোগ্রামটি কল করার সময় একই লাইনে MY_NAME এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন -$ MY_NAME="Wade Wilson" python main.py - -// এখন এটি এনভায়রনমেন্ট ভ্যরিয়েবলটিকে রিড করতে পারবে - -Hello Wade Wilson from Python - -// পরবর্তীতে এনভায়রনমেন্ট ভেরিয়েবলটিকে আর ব্যবহার করা যাচ্ছে না -$ python main.py - -Hello World from Python -``` - -
- -/// tip - -এটি নিয়ে আরো বিস্তারিত পড়তে পারেন এখানে The Twelve-Factor App: Config। - -/// - -## টাইপস এবং ভ্যালিডেশন - -এই এনভায়রনমেন্ট ভেরিয়েবলগুলো শুধুমাত্র **টেক্সট স্ট্রিংস** হ্যান্ডেল করতে পারে, যেহেতু এগুলো পাইথনের বাইরে অবস্থিত এবং অন্যান্য প্রোগ্রাম এবং সিস্টেমের বাকি অংশের (এমনকি বিভিন্ন অপারেটিং সিস্টেম যেমন লিনাক্স, উইন্ডোজ, ম্যাকওএস) সাথে সামঞ্জস্যপূর্ণ হতে হয়। - -এর অর্থ হচ্ছে পাইথনে এনভায়রনমেন্ট ভেরিয়েবল থেকে রিড করা **যেকোনো ভ্যালু** একটি `str` হবে, এবং অন্য কোনো টাইপে কনভার্সন বা যেকোনো ভেলিডেশন কোডে আলাদাভাবে করতে হবে। - -এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে **এপ্লিকেশন সেটিংস** হ্যান্ডেল করা নিয়ে আরো বিস্তারিত জানা যাবে [Advanced User Guide - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank}. - -## `PATH` এনভায়রনমেন্ট ভেরিয়েবল - -**`PATH`** নামে একটি **বিশেষ** এনভায়রনমেন্ট ভেরিয়েবল রয়েছে, যেটি প্রোগ্রাম রান করার জন্য অপারেটিং সিস্টেমস (লিনাক্স, ম্যাকওএস, উইন্ডোজ) দ্বারা ব্যবহৃত হয়। - -`PATH` ভেরিয়েবল এর ভ্যালু হচ্ছে একটি বিশাল স্ট্রিং যা ডিরেক্টরিকে কোলন `:` দিয়ে আলাদা করার মাধ্যমে লিনাক্সে ও ম্যাকওএস এ, এবং সেমিকোলন `;` এর মাধ্যমে উইন্ডোজ এ তৈরি করা থাকে। - -উদাহরণস্বরূপ, `PATH` ভেরিয়েবল নিচের মতো দেখতে হতে পারেঃ - -//// tab | লিনাক্স, ম্যাকওএস - -```plaintext -/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin -``` - -তারমানে হলো সিস্টেম প্রোগ্রামগুলোকে নিচের ডিরেক্টরিগুলোতে খুঁজবেঃ - -* `/usr/local/bin` -* `/usr/bin` -* `/bin` -* `/usr/sbin` -* `/sbin` - -//// - -//// tab | উইন্ডোজ - -```plaintext -C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32 -``` - -তারমানে হলো সিস্টেম প্রোগ্রামগুলোকে নিচের ডিরেক্টরিগুলোতে খুঁজবেঃ - -* `C:\Program Files\Python312\Scripts` -* `C:\Program Files\Python312` -* `C:\Windows\System32` - -//// - -যখন আপনি টার্মিনালে কোনো **কমান্ড** লিখবেন, অপারেটিং সিস্টেম **প্রত্যেকটি ডিরেক্টরিতে** প্রোগ্রামটি **খুঁজবে** যেগুলো `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ লিস্ট করা আছে। - -উদাহরণস্বরূপ, যখন আপনি টার্মিনালে `python` টাইপ করবেন, অপারেটিং সিস্টেম এই লিস্ট এর **প্রথম ডিরেক্টরিতে** `python` নামের একটি প্রোগ্রাম খুঁজবে। - -যদি এটি খুঁজে পায়, তাহলে এটি প্রোগ্রামটিকে ব্যবহার করবে। অন্যথায় এটি **অন্যান্য ডিরেক্টরিগুলোতে** এটিকে খুঁজতে থাকবে। - -### পাইথন ইনস্টল এবং `PATH` আপডেট - -যখন আপনি পাইথন ইনস্টল করেন, আপনি `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান কিনা সেটা জিজ্ঞেস করা হতে পারে। - -//// tab | লিনাক্স, ম্যাকওএস - -ধরা যাক আপনি পাইথন ইনস্টল করলেন এবং এটি `/opt/custompython/bin` ডিরেক্টরিতে ইনস্টল হচ্ছে। - -যদি আপনি "Yes" সিলেক্ট করে `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান, তাহলে ইনস্টলার `/opt/custompython/bin` কে `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ এড করে দিবে। - -এটা দেখতে এমনটা হতে পারেঃ - -```plaintext -/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin -``` - -এইভাবে, আপনি যখন টার্মিনালে `python` টাইপ করেন, সিস্টেম পাইথন প্রোগ্রামটিকে `/opt/custompython/bin` (সর্বশেষ ডিরেক্টরি) তে খুঁজে পাবে এবং এটাকে ব্যবহার করবে। - -//// - -//// tab | উইন্ডোজ - -ধরা যাক আপনি পাইথন ইনস্টল করলেন এবং এটি `C:\opt\custompython\bin` ডিরেক্টরিতে ইনস্টল হচ্ছে। - -যদি আপনি "Yes" সিলেক্ট করে `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান, তাহলে ইনস্টলার `C:\opt\custompython\bin` কে `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ এড করে দিবে। - -```plaintext -C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin -``` - -এইভাবে, আপনি যখন টার্মিনালে `python` টাইপ করেন, সিস্টেম পাইথন প্রোগ্রামটিকে `C:\opt\custompython\bin` (সর্বশেষ ডিরেক্টরি) তে খুঁজে পাবে এবং এটাকে ব্যবহার করবে। - -//// - -তাই, আপনি যদি টাইপ করেনঃ - -
- -```console -$ python -``` - -
- -//// tab | লিনাক্স, ম্যাকওএস - -সিস্টেম `python` প্রোগ্রামকে `/opt/custompython/bin` এ **খুঁজে পাবে** এবং এটাকে রান করবে। - -এটা মোটামুটিভাবে নিচের মতো করে লেখার সমান হবেঃ - -
- -```console -$ /opt/custompython/bin/python -``` - -
- -//// - -//// tab | উইন্ডোজ - -সিস্টেম `python` প্রোগ্রামকে `C:\opt\custompython\bin\python` এ **খুঁজে পাবে** এবং এটাকে রান করবে। - -এটা মোটামুটিভাবে নিচের মতো করে লেখার সমান হবেঃ - -
- -```console -$ C:\opt\custompython\bin\python -``` - -
- -//// - -এই তথ্যগুলো [ভার্চুয়াল এনভায়রনমেন্টস](virtual-environments.md){.internal-link target=_blank} শেখার ক্ষেত্রে সহায়ক হবে। - -## উপসংহার - -এর মাধ্যমে আপনি **এনভায়রনমেন্ট ভেরিয়েবলস** কি এবং এটিকে পাইথনে কিভাবে ব্যবহার করতে হয় তার সম্পর্কে বেসিক ধারনা পেলেন। - -চাইলে এই সম্পর্কে আরো বিস্তারিত পড়তে পারেন Wikipedia for Environment Variable এ। - -অনেক ক্ষেত্রে, দেখা মাত্রই এনভায়রনমেন্ট ভেরিয়েবল কীভাবে প্রয়োজন হবে তা স্পষ্ট হয় না। কিন্তু ডেভেলপমেন্টের সময় আপনি নানা রকম পরিস্থিতিতে এগুলোর সম্মুখীন হবেন, তাই এগুলো সম্পর্কে জেনে রাখা ভালো। - -উদাহরণস্বরূপ, আপনার এই ইনফরমেশনটি পরবর্তী, [ভার্চুয়াল এনভায়রনমেন্টস](virtual-environments.md) অংশে দরকার হবে। diff --git a/docs/bn/docs/index.md b/docs/bn/docs/index.md deleted file mode 100644 index 84acc0798..000000000 --- a/docs/bn/docs/index.md +++ /dev/null @@ -1,466 +0,0 @@ -

- FastAPI -

-

- FastAPI উচ্চক্ষমতা সম্পন্ন, সহজে শেখার এবং দ্রুত কোড করে প্রোডাকশনের জন্য ফ্রামওয়ার্ক। -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**নির্দেশিকা নথি**: https://fastapi.tiangolo.com - -**সোর্স কোড**: https://github.com/fastapi/fastapi - ---- - -FastAPI একটি আধুনিক, দ্রুত ( বেশি ক্ষমতা ) সম্পন্ন, Python 3.6+ দিয়ে API তৈরির জন্য স্ট্যান্ডার্ড পাইথন টাইপ ইঙ্গিত ভিত্তিক ওয়েব ফ্রেমওয়ার্ক। - -এর মূল বৈশিষ্ট্য গুলো হলঃ - -- **গতি**: এটি **NodeJS** এবং **Go** এর মত কার্যক্ষমতা সম্পন্ন (Starlette এবং Pydantic এর সাহায্যে)। [পাইথন এর দ্রুততম ফ্রেমওয়ার্ক গুলোর মধ্যে এটি একটি](#_11)। -- **দ্রুত কোড করা**:বৈশিষ্ট্য তৈরির গতি ২০০% থেকে ৩০০% বৃদ্ধি করে৷ \* -- **স্বল্প bugs**: মানুব (ডেভেলপার) সৃষ্ট ত্রুটির প্রায় ৪০% হ্রাস করে। \* -- **স্বজ্ঞাত**: দুর্দান্ত এডিটর সাহায্য Completion নামেও পরিচিত। দ্রুত ডিবাগ করা যায়। - -- **সহজ**: এটি এমন ভাবে সজানো হয়েছে যেন নির্দেশিকা নথি পড়ে সহজে শেখা এবং ব্যবহার করা যায়। -- **সংক্ষিপ্ত**: কোড পুনরাবৃত্তি কমানোর পাশাপাশি, bug কমায় এবং প্রতিটি প্যারামিটার ঘোষণা থেকে একাধিক ফিচার পাওয়া যায় । -- **জোরালো**: স্বয়ংক্রিয় ভাবে তৈরি ক্রিয়াশীল নির্দেশনা নথি (documentation) সহ উৎপাদন উপযোগি (Production-ready) কোড পাওয়া যায়। -- **মান-ভিত্তিক**: এর ভিত্তি OpenAPI (যা পুর্বে Swagger নামে পরিচিত ছিল) এবং JSON Schema এর আদর্শের মানের ওপর - -\* উৎপাদনমুখি এপ্লিকেশন বানানোর এক দল ডেভেলপার এর মতামত ভিত্তিক ফলাফল। - -## স্পনসর গণ - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -অন্যান্য স্পনসর গণ - -## মতামত সমূহ - -"_আমি আজকাল **FastAPI** ব্যবহার করছি। [...] আমরা ভাবছি মাইক্রোসফ্টে **ML সার্ভিস** এ সকল দলের জন্য এটি ব্যবহার করব। যার মধ্যে কিছু পণ্য **Windows** এ সংযোযন হয় এবং কিছু **Office** এর সাথে সংযোযন হচ্ছে।_" - -
কবির খান - মাইক্রোসফ্টে (ref)
- ---- - -"_আমরা **FastAPI** লাইব্রেরি গ্রহণ করেছি একটি **REST** সার্ভার তৈরি করতে, যা **ভবিষ্যদ্বাণী** পাওয়ার জন্য কুয়েরি করা যেতে পারে। [লুডউইগের জন্য]_" - -
পিয়েরো মোলিনো, ইয়ারোস্লাভ দুদিন, এবং সাই সুমন্থ মিরিয়ালা - উবার (ref)
- ---- - -"_**Netflix** আমাদের **ক্রাইসিস ম্যানেজমেন্ট** অর্কেস্ট্রেশন ফ্রেমওয়ার্ক: **ডিসপ্যাচ** এর ওপেন সোর্স রিলিজ ঘোষণা করতে পেরে আনন্দিত! [যাকিনা **FastAPI** দিয়ে নির্মিত]_" - -
কেভিন গ্লিসন, মার্ক ভিলানোভা, ফরেস্ট মনসেন - নেটফ্লিক্স (ref)
- ---- - -"_আমি **FastAPI** নিয়ে চাঁদের সমান উৎসাহিত। এটি খুবই মজার!_" - -
ব্রায়ান ওকেন - পাইথন বাইটস পডকাস্ট হোস্ট (ref)
- ---- - -"\_সত্যিই, আপনি যা তৈরি করেছেন তা খুব মজবুত এবং পরিপূর্ন৷ অনেক উপায়ে, আমি যা **Hug** এ করতে চেয়েছিলাম - তা কাউকে তৈরি করতে দেখে আমি সত্যিই অনুপ্রানিত৷\_" - -
টিমোথি ক্রসলে - Hug স্রষ্টা (ref)
- ---- - -"আপনি যদি REST API তৈরির জন্য একটি **আধুনিক ফ্রেমওয়ার্ক** শিখতে চান, তাহলে **FastAPI** দেখুন [...] এটি দ্রুত, ব্যবহার করা সহজ এবং শিখতেও সহজ [...]\_" - -"_আমরা আমাদের **APIs** [...] এর জন্য **FastAPI**- তে এসেছি [...] আমি মনে করি আপনিও এটি পছন্দ করবেন [...]_" - -
ইনেস মন্টানি - ম্যাথিউ হোনিবাল - Explosion AI প্রতিষ্ঠাতা - spaCy স্রষ্টা (ref) - (ref)
- ---- - -## **Typer**, CLI এর জন্য FastAPI - - - -আপনি যদি CLI অ্যাপ বানাতে চান, যা কিনা ওয়েব API এর পরিবর্তে টার্মিনালে ব্যবহার হবে, তাহলে দেখুন**Typer**. - -**টাইপার** হল FastAPI এর ছোট ভাইয়ের মত। এবং এটির উদ্দেশ্য ছিল **CLIs এর FastAPI** হওয়া। ⌨️ 🚀 - -## প্রয়োজনীয়তা গুলো - -Python 3.7+ - -FastAPI কিছু দানবেদের কাঁধে দাঁড়িয়ে আছে: - -- Starlette ওয়েব অংশের জন্য. -- Pydantic ডেটা অংশগুলির জন্য. - -## ইনস্টলেশন প্রক্রিয়া - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -আপনার একটি ASGI সার্ভারেরও প্রয়োজন হবে, প্রোডাকশনের জন্য Uvicorn অথবা Hypercorn. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## উদাহরণ - -### তৈরি - -- `main.py` নামে একটি ফাইল তৈরি করুন: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-অথবা ব্যবহার করুন async def... - -যদি আপনার কোড `async` / `await`, ব্যবহার করে তাহলে `async def` ব্যবহার করুন: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**টীকা**: - -আপনি যদি না জানেন, _"তাড়াহুড়ো?"_ বিভাগটি দেখুন `async` এবং `await` নথির মধ্যে দেখুন . - -
- -### এটি চালান - -সার্ভার চালু করুন: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-নির্দেশনা সম্পর্কে uvicorn main:app --reload... - -`uvicorn main:app` নির্দেশনাটি দ্বারা বোঝায়: - -- `main`: ফাইল `main.py` (পাইথন "মডিউল")। -- `app`: `app = FastAPI()` লাইন দিয়ে `main.py` এর ভিতরে তৈরি করা অবজেক্ট। -- `--reload`: কোড পরিবর্তনের পরে সার্ভার পুনরায় চালু করুন। এটি শুধুমাত্র ডেভেলপমেন্ট এর সময় ব্যবহার করুন। - -
- -### এটা চেক করুন - -আপনার ব্রাউজার খুলুন http://127.0.0.1:8000/items/5?q=somequery এ। - -আপনি JSON রেসপন্স দেখতে পাবেন: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -আপনি ইতিমধ্যে একটি API তৈরি করেছেন যা: - -- `/` এবং `/items/{item_id}` _paths_ এ HTTP অনুরোধ গ্রহণ করে। -- উভয় *path*ই `GET` অপারেশন নেয় ( যা HTTP _methods_ নামেও পরিচিত)। -- _path_ `/items/{item_id}`-এ একটি _path প্যারামিটার_ `item_id` আছে যা কিনা `int` হতে হবে। -- _path_ `/items/{item_id}`-এর একটি ঐচ্ছিক `str` _query প্যারামিটার_ `q` আছে। - -### ক্রিয়াশীল API নির্দেশিকা নথি - -এখন যান http://127.0.0.1:8000/docs. - -আপনি স্বয়ংক্রিয় ভাবে প্রস্তুত ক্রিয়াশীল API নির্দেশিকা নথি দেখতে পাবেন (Swagger UI প্রদত্ত): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### বিকল্প API নির্দেশিকা নথি - -এবং এখন http://127.0.0.1:8000/redoc এ যান. - -আপনি স্বয়ংক্রিয় ভাবে প্রস্তুত বিকল্প নির্দেশিকা নথি দেখতে পাবেন (ReDoc প্রদত্ত): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## উদাহরণস্বরূপ আপগ্রেড - -এখন `main.py` ফাইলটি পরিবর্তন করুন যেন এটি `PUT` রিকুয়েস্ট থেকে বডি পেতে পারে। - -Python স্ট্যান্ডার্ড লাইব্রেরি, Pydantic এর সাহায্যে বডি ঘোষণা করুন। - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -সার্ভারটি স্বয়ংক্রিয়ভাবে পুনরায় লোড হওয়া উচিত (কারণ আপনি উপরের `uvicorn` কমান্ডে `--reload` যোগ করেছেন)। - -### ক্রিয়াশীল API নির্দেশিকা নথি উন্নীতকরণ - -এখন http://127.0.0.1:8000/docs এডড্রেসে যান. - -- ক্রিয়াশীল API নির্দেশিকা নথিটি স্বয়ংক্রিয়ভাবে উন্নীত হযে যাবে, নতুন বডি সহ: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -- "Try it out" বাটনে চাপুন, এটি আপনাকে পেরামিটারগুলো পূরণ করতে এবং API এর সাথে সরাসরি ক্রিয়া-কলাপ করতে দিবে: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -- তারপরে "Execute" বাটনে চাপুন, ব্যবহারকারীর ইন্টারফেস আপনার API এর সাথে যোগাযোগ করবে, পেরামিটার পাঠাবে, ফলাফলগুলি পাবে এবং সেগুলি পর্রদায় দেখাবে: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### বিকল্প API নির্দেশিকা নথি আপগ্রেড - -এবং এখন http://127.0.0.1:8000/redoc এ যান। - -- বিকল্প নির্দেশিকা নথিতেও নতুন কুয়েরি প্যারামিটার এবং বডি প্রতিফলিত হবে: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### সংক্ষিপ্তকরণ - -সংক্ষেপে, আপনি **শুধু একবার** প্যারামিটারের ধরন, বডি ইত্যাদি ফাংশন প্যারামিটার হিসেবে ঘোষণা করেন। - -আপনি সেটি আধুনিক পাইথনের সাথে করেন। - -আপনাকে নতুন করে নির্দিষ্ট কোন লাইব্রেরির বাক্য গঠন, ফাংশন বা ক্লাস কিছুই শিখতে হচ্ছে না। - -শুধুই আধুনিক **Python 3.6+** - -উদাহরণস্বরূপ, `int` এর জন্য: - -```Python -item_id: int -``` - -অথবা আরও জটিল `Item` মডেলের জন্য: - -```Python -item: Item -``` - -...এবং সেই একই ঘোষণার সাথে আপনি পাবেন: - -- এডিটর সাহায্য, যেমন - - সমাপ্তি। - - ধরণ যাচাই -- তথ্য যাচাইকরণ: - - ডেটা অবৈধ হলে স্বয়ংক্রিয় এবং পরিষ্কার ত্রুটির নির্দেশনা। - - এমনকি গভীরভাবে নেস্ট করা JSON অবজেক্টের জন্য বৈধতা। -- প্রেরিত তথ্য রূপান্তর: যা নেটওয়ার্ক থেকে পাইথনের তথ্য এবং ধরনে আসে, এবং সেখান থেকে পড়া: - - - JSON। - - পাথ প্যারামিটার। - - কুয়েরি প্যারামিটার। - - কুকিজ - - হেডার - - ফর্ম - - ফাইল - -- আউটপুট ডেটার রূপান্তর: পাইথন ডেটা এবং টাইপ থেকে নেটওয়ার্ক ডেটাতে রূপান্তর করা (JSON হিসাবে): - -পাইথন টাইপে রূপান্তর করুন (`str`, `int`, `float`, `bool`, `list`, ইত্যাদি)। - - `datetime` অবজেক্ট। - - `UUID` objeঅবজেক্টcts। - - ডাটাবেস মডেল। - - ...এবং আরো অনেক। -- স্বয়ংক্রিয় ক্রিয়াশীল API নির্দেশিকা নথি, 2টি বিকল্প ব্যবহারকারীর ইন্টারফেস সহ: - - সোয়াগার ইউ আই (Swagger UI)। - - রিডক (ReDoc)। - ---- - -পূর্ববর্তী কোড উদাহরণে ফিরে আসা যাক, **FastAPI** যা করবে: - -- `GET` এবং `PUT` অনুরোধের জন্য পথে `item_id` আছে কিনা তা যাচাই করবে। -- `GET` এবং `PUT` অনুরোধের জন্য `item_id` টাইপ `int` এর হতে হবে তা যাচাই করবে। - - যদি না হয় তবে ক্লায়েন্ট একটি উপযুক্ত, পরিষ্কার ত্রুটি দেখতে পাবেন। -- `GET` অনুরোধের জন্য একটি ঐচ্ছিক ক্যুয়েরি প্যারামিটার নামক `q` (যেমন `http://127.0.0.1:8000/items/foo?q=somequery`) আছে কি তা চেক করবে। - - যেহেতু `q` প্যারামিটারটি `= None` দিয়ে ঘোষণা করা হয়েছে, তাই এটি ঐচ্ছিক। - - `None` ছাড়া এটি প্রয়োজনীয় হতো (যেমন `PUT` এর ক্ষেত্রে হয়েছে)। -- `/items/{item_id}` এর জন্য `PUT` অনুরোধের বডি JSON হিসাবে পড়ুন: - - লক্ষ করুন, `name` একটি প্রয়োজনীয় অ্যাট্রিবিউট হিসাবে বিবেচনা করেছে এবং এটি `str` হতে হবে। - - লক্ষ করুন এখানে, `price` অ্যাট্রিবিউটটি আবশ্যক এবং এটি `float` হতে হবে। - - লক্ষ করুন `is_offer` একটি ঐচ্ছিক অ্যাট্রিবিউট এবং এটি `bool` হতে হবে যদি উপস্থিত থাকে। - - এই সবটি গভীরভাবে অবস্থানরত JSON অবজেক্টগুলিতেও কাজ করবে। -- স্বয়ংক্রিয়ভাবে JSON হতে এবং JSON থেকে কনভার্ট করুন। -- OpenAPI দিয়ে সবকিছু ডকুমেন্ট করুন, যা ব্যবহার করা যেতে পারে: - - ক্রিয়াশীল নির্দেশিকা নথি। - - অনেক ভাষার জন্য স্বয়ংক্রিয় ক্লায়েন্ট কোড তৈরির ব্যবস্থা। -- সরাসরি 2টি ক্রিয়াশীল নির্দেশিকা নথি ওয়েব পৃষ্ঠ প্রদান করা হয়েছে। - ---- - -আমরা এতক্ষন শুধু এর পৃষ্ঠ তৈরি করেছি, কিন্তু আপনি ইতমধ্যেই এটি কিভাবে কাজ করে তার ধারণাও পেয়ে গিয়েছেন। - -নিম্নোক্ত লাইন গুলো পরিবর্তন করার চেষ্টা করুন: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...পুর্বে: - -```Python - ... "item_name": item.name ... -``` - -...পরবর্তীতে: - -```Python - ... "item_price": item.price ... -``` - -...এবং দেখুন কিভাবে আপনার এডিটর উপাদানগুলোকে সয়ংক্রিয়ভাবে-সম্পন্ন করবে এবং তাদের ধরন জানতে পারবে: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -আরও বৈশিষ্ট্য সম্পন্ন উদাহরণের জন্য, দেখুন টিউটোরিয়াল - ব্যবহারকারীর গাইড. - -**স্পয়লার সতর্কতা**: টিউটোরিয়াল - ব্যবহারকারীর গাইড নিম্নোক্ত বিষয়গুলি অন্তর্ভুক্ত করে: - -- **হেডার**, **কুকিজ**, **ফর্ম ফিল্ড** এবং **ফাইলগুলি** এমন অন্যান্য জায়গা থেকে প্যারামিটার ঘোষণা করা। -- `maximum_length` বা `regex` এর মতো **যাচাইকরণ বাধামুক্তি** সেট করা হয় কিভাবে, তা নিয়ে আলোচনা করা হবে। -- একটি খুব শক্তিশালী এবং ব্যবহার করা সহজ ডিপেন্ডেন্সি ইনজেকশন পদ্ধতি -- **OAuth2** এবং **JWT টোকেন** এবং **HTTP Basic** auth সহ নিরাপত্তা এবং অনুমোদনপ্রাপ্তি সম্পর্কিত বিষয়সমূহের উপর। -- **গভীরভাবে অবস্থানরত JSON মডেল** ঘোষণা করার জন্য আরও উন্নত (কিন্তু সমান সহজ) কৌশল (Pydantic কে ধন্যবাদ)। -- আরো অতিরিক্ত বৈশিষ্ট্য (স্টারলেটকে ধন্যবাদ) হিসাবে: - - **WebSockets** - - **GraphQL** - - HTTPX এবং `pytest` ভিত্তিক অত্যন্ত সহজ পরীক্ষা - - **CORS** - - **Cookie Sessions** - - ...এবং আরো। - -## কর্মক্ষমতা - -স্বাধীন TechEmpower Benchmarks দেখায় যে **FastAPI** অ্যাপ্লিকেশনগুলি Uvicorn-এর অধীনে চলমান দ্রুততমপাইথন ফ্রেমওয়ার্কগুলির মধ্যে একটি, শুধুমাত্র Starlette এবং Uvicorn-এর পর (FastAPI দ্বারা অভ্যন্তরীণভাবে ব্যবহৃত)। (\*) - -এটি সম্পর্কে আরও বুঝতে, দেখুন Benchmarks. - -## ঐচ্ছিক নির্ভরশীলতা - -Pydantic দ্বারা ব্যবহৃত: - -- email-validator - ইমেল যাচাইকরণের জন্য। - -স্টারলেট দ্বারা ব্যবহৃত: - -- httpx - আপনি যদি `TestClient` ব্যবহার করতে চান তাহলে আবশ্যক। -- jinja2 - আপনি যদি প্রদত্ত টেমপ্লেট রূপরেখা ব্যবহার করতে চান তাহলে প্রয়োজন। -- python-multipart - আপনি যদি ফর্ম সহায়তা করতে চান তাহলে প্রয়োজন "parsing", `request.form()` সহ। -- itsdangerous - `SessionMiddleware` সহায়তার জন্য প্রয়োজন। -- pyyaml - স্টারলেটের SchemaGenerator সাপোর্ট এর জন্য প্রয়োজন (আপনার সম্ভাবত FastAPI প্রয়োজন নেই)। -- graphene - `GraphQLApp` সহায়তার জন্য প্রয়োজন। - -FastAPI / Starlette দ্বারা ব্যবহৃত: - -- uvicorn - সার্ভারের জন্য যা আপনার অ্যাপ্লিকেশন লোড করে এবং পরিবেশন করে। -- orjson - আপনি `ORJSONResponse` ব্যবহার করতে চাইলে প্রয়োজন। -- ujson - আপনি `UJSONResponse` ব্যবহার করতে চাইলে প্রয়োজন। - -আপনি এই সব ইনস্টল করতে পারেন `pip install fastapi[all]` দিয়ে. - -## লাইসেন্স - -এই প্রজেক্ট MIT লাইসেন্স নীতিমালার অধীনে শর্তায়িত। diff --git a/docs/bn/docs/learn/index.md b/docs/bn/docs/learn/index.md deleted file mode 100644 index 4e4c62038..000000000 --- a/docs/bn/docs/learn/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# শিখুন - -এখানে **FastAPI** শিখার জন্য প্রাথমিক বিভাগগুলি এবং টিউটোরিয়ালগুলি রয়েছে। - -আপনি এটিকে একটি **বই**, একটি **কোর্স**, এবং FastAPI শিখার **অফিসিয়াল** এবং প্রস্তাবিত উপায় বিবেচনা করতে পারেন। 😎 diff --git a/docs/bn/docs/python-types.md b/docs/bn/docs/python-types.md deleted file mode 100644 index d98c2ec87..000000000 --- a/docs/bn/docs/python-types.md +++ /dev/null @@ -1,586 +0,0 @@ -# পাইথন এর টাইপ্স পরিচিতি - -Python-এ ঐচ্ছিক "টাইপ হিন্ট" (যা "টাইপ অ্যানোটেশন" নামেও পরিচিত) এর জন্য সাপোর্ট রয়েছে। - -এই **"টাইপ হিন্ট"** বা অ্যানোটেশনগুলি এক ধরণের বিশেষ সিনট্যাক্স যা একটি ভেরিয়েবলের টাইপ ঘোষণা করতে দেয়। - -ভেরিয়েবলগুলির জন্য টাইপ ঘোষণা করলে, এডিটর এবং টুলগুলি আপনাকে আরও ভালো সাপোর্ট দিতে পারে। - -এটি পাইথন টাইপ হিন্ট সম্পর্কে একটি দ্রুত **টিউটোরিয়াল / রিফ্রেশার** মাত্র। এটি **FastAPI** এর সাথে ব্যবহার করার জন্য শুধুমাত্র ন্যূনতম প্রয়োজনীয়তা কভার করে... যা আসলে খুব একটা বেশি না। - -**FastAPI** এই টাইপ হিন্টগুলির উপর ভিত্তি করে নির্মিত, যা এটিকে অনেক সুবিধা এবং লাভ প্রদান করে। - -তবে, আপনি যদি কখনো **FastAPI** ব্যবহার নাও করেন, তবুও এগুলি সম্পর্কে একটু শেখা আপনার উপকারে আসবে। - -/// note - -যদি আপনি একজন Python বিশেষজ্ঞ হন, এবং টাইপ হিন্ট সম্পর্কে সবকিছু জানেন, তাহলে পরবর্তী অধ্যায়ে চলে যান। - -/// - -## প্রেরণা - -চলুন একটি সাধারণ উদাহরণ দিয়ে শুরু করি: - -{* ../../docs_src/python_types/tutorial001.py *} - - -এই প্রোগ্রামটি কল করলে আউটপুট হয়: - -``` -John Doe -``` - -ফাংশনটি নিম্নলিখিত কাজ করে: - -* `first_name` এবং `last_name` নেয়। -* প্রতিটির প্রথম অক্ষরকে `title()` ব্যবহার করে বড় হাতের অক্ষরে রূপান্তর করে। -* তাদেরকে মাঝখানে একটি স্পেস দিয়ে concatenate করে। - -{* ../../docs_src/python_types/tutorial001.py hl[2] *} - - -### এটি সম্পাদনা করুন - -এটি একটি খুব সাধারণ প্রোগ্রাম। - -কিন্তু এখন কল্পনা করুন যে আপনি এটি শুরু থেকে লিখছিলেন। - -এক পর্যায়ে আপনি ফাংশনের সংজ্ঞা শুরু করেছিলেন, আপনার প্যারামিটারগুলি প্রস্তুত ছিল... - -কিন্তু তারপর আপনাকে "সেই method কল করতে হবে যা প্রথম অক্ষরকে বড় হাতের অক্ষরে রূপান্তর করে"। - -এটা কি `upper` ছিল? নাকি `uppercase`? `first_uppercase`? `capitalize`? - -তারপর, আপনি পুরোনো প্রোগ্রামারের বন্ধু, এডিটর অটোকমপ্লিশনের সাহায্যে নেওয়ার চেষ্টা করেন। - -আপনি ফাংশনের প্রথম প্যারামিটার `first_name` টাইপ করেন, তারপর একটি ডট (`.`) টাইপ করেন এবং `Ctrl+Space` চাপেন অটোকমপ্লিশন ট্রিগার করার জন্য। - -কিন্তু, দুর্ভাগ্যবশত, আপনি কিছুই উপযোগী পান না: - - - -### টাইপ যোগ করুন - -আসুন আগের সংস্করণ থেকে একটি লাইন পরিবর্তন করি। - -আমরা ঠিক এই অংশটি পরিবর্তন করব অর্থাৎ ফাংশনের প্যারামিটারগুলি, এইগুলি: - -```Python - first_name, last_name -``` - -থেকে এইগুলি: - -```Python - first_name: str, last_name: str -``` - -ব্যাস। - -এগুলিই "টাইপ হিন্ট": - -{* ../../docs_src/python_types/tutorial002.py hl[1] *} - - -এটি ডিফল্ট ভ্যালু ঘোষণা করার মত নয় যেমন: - -```Python - first_name="john", last_name="doe" -``` - -এটি একটি ভিন্ন জিনিস। - -আমরা সমান (`=`) নয়, কোলন (`:`) ব্যবহার করছি। - -এবং টাইপ হিন্ট যোগ করা সাধারণত তেমন কিছু পরিবর্তন করে না যা টাইপ হিন্ট ছাড়াই ঘটত। - -কিন্তু এখন, কল্পনা করুন আপনি আবার সেই ফাংশন তৈরির মাঝখানে আছেন, কিন্তু টাইপ হিন্ট সহ। - -একই পর্যায়ে, আপনি অটোকমপ্লিট ট্রিগার করতে `Ctrl+Space` চাপেন এবং আপনি দেখতে পান: - - - -এর সাথে, আপনি অপশনগুলি দেখে, স্ক্রল করতে পারেন, যতক্ষণ না আপনি এমন একটি অপশন খুঁজে পান যা কিছু মনে পরিয়ে দেয়: - - - -## আরও প্রেরণা - -এই ফাংশনটি দেখুন, এটিতে ইতিমধ্যে টাইপ হিন্ট রয়েছে: - -{* ../../docs_src/python_types/tutorial003.py hl[1] *} - - -এডিটর ভেরিয়েবলগুলির টাইপ জানার কারণে, আপনি শুধুমাত্র অটোকমপ্লিশনই পান না, আপনি এরর চেকও পান: - - - -এখন আপনি জানেন যে আপনাকে এটি ঠিক করতে হবে, `age`-কে একটি স্ট্রিং হিসেবে রূপান্তর করতে `str(age)` ব্যবহার করতে হবে: - -{* ../../docs_src/python_types/tutorial004.py hl[2] *} - - -## টাইপ ঘোষণা - -আপনি এতক্ষন টাইপ হিন্ট ঘোষণা করার মূল স্থানটি দেখে ফেলেছেন-- ফাংশন প্যারামিটার হিসেবে। - -সাধারণত এটি **FastAPI** এর ক্ষেত্রেও একই। - -### সিম্পল টাইপ - -আপনি `str` ছাড়াও সমস্ত স্ট্যান্ডার্ড পাইথন টাইপ ঘোষণা করতে পারেন। - -উদাহরণস্বরূপ, আপনি এগুলো ব্যবহার করতে পারেন: - -* `int` -* `float` -* `bool` -* `bytes` - -{* ../../docs_src/python_types/tutorial005.py hl[1] *} - - -### টাইপ প্যারামিটার সহ জেনেরিক টাইপ - -কিছু ডাটা স্ট্রাকচার অন্যান্য মান ধারণ করতে পারে, যেমন `dict`, `list`, `set` এবং `tuple`। এবং অভ্যন্তরীণ মানগুলোরও নিজেদের টাইপ থাকতে পারে। - -এই ধরনের টাইপগুলিকে বলা হয় "**জেনেরিক**" টাইপ এবং এগুলিকে তাদের অভ্যন্তরীণ টাইপগুলি সহ ঘোষণা করা সম্ভব। - -এই টাইপগুলি এবং অভ্যন্তরীণ টাইপগুলি ঘোষণা করতে, আপনি Python মডিউল `typing` ব্যবহার করতে পারেন। এটি বিশেষভাবে এই টাইপ হিন্টগুলি সমর্থন করার জন্য রয়েছে। - -#### Python এর নতুন সংস্করণ - -`typing` ব্যবহার করা সিনট্যাক্সটি Python 3.6 থেকে সর্বশেষ সংস্করণগুলি পর্যন্ত, অর্থাৎ Python 3.9, Python 3.10 ইত্যাদি সহ সকল সংস্করণের সাথে **সামঞ্জস্যপূর্ণ**। - -Python যত এগিয়ে যাচ্ছে, **নতুন সংস্করণগুলি** এই টাইপ অ্যানোটেশনগুলির জন্য তত উন্নত সাপোর্ট নিয়ে আসছে এবং অনেক ক্ষেত্রে আপনাকে টাইপ অ্যানোটেশন ঘোষণা করতে `typing` মডিউল ইম্পোর্ট এবং ব্যবহার করার প্রয়োজন হবে না। - -যদি আপনি আপনার প্রজেক্টের জন্য Python-এর আরও সাম্প্রতিক সংস্করণ নির্বাচন করতে পারেন, তাহলে আপনি সেই অতিরিক্ত সরলতা থেকে সুবিধা নিতে পারবেন। - -ডক্সে রয়েছে Python-এর প্রতিটি সংস্করণের সাথে সামঞ্জস্যপূর্ণ উদাহরণগুলি (যখন পার্থক্য আছে)। - -উদাহরণস্বরূপ, "**Python 3.6+**" মানে এটি Python 3.6 বা তার উপরে সামঞ্জস্যপূর্ণ (যার মধ্যে 3.7, 3.8, 3.9, 3.10, ইত্যাদি অন্তর্ভুক্ত)। এবং "**Python 3.9+**" মানে এটি Python 3.9 বা তার উপরে সামঞ্জস্যপূর্ণ (যার মধ্যে 3.10, ইত্যাদি অন্তর্ভুক্ত)। - -যদি আপনি Python-এর **সর্বশেষ সংস্করণগুলি ব্যবহার করতে পারেন**, তাহলে সর্বশেষ সংস্করণের জন্য উদাহরণগুলি ব্যবহার করুন, সেগুলি আপনাকে **সর্বোত্তম এবং সহজতম সিনট্যাক্স** প্রদান করবে, যেমন, "**Python 3.10+**"। - -#### লিস্ট - -উদাহরণস্বরূপ, একটি ভেরিয়েবলকে `str`-এর একটি `list` হিসেবে সংজ্ঞায়িত করা যাক। - -//// tab | Python 3.9+ - -ভেরিয়েবলটি ঘোষণা করুন, একই কোলন (`:`) সিনট্যাক্স ব্যবহার করে। - -টাইপ হিসেবে, `list` ব্যবহার করুন। - -যেহেতু লিস্ট এমন একটি টাইপ যা অভ্যন্তরীণ টাইপগুলি ধারণ করে, আপনি তাদের স্কোয়ার ব্রাকেটের ভিতরে ব্যবহার করুন: - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -`typing` থেকে `List` (বড় হাতের `L` দিয়ে) ইমপোর্ট করুন: - -``` Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -ভেরিয়েবলটি ঘোষণা করুন, একই কোলন (`:`) সিনট্যাক্স ব্যবহার করে। - -টাইপ হিসেবে, `typing` থেকে আপনার ইম্পোর্ট করা `List` ব্যবহার করুন। - -যেহেতু লিস্ট এমন একটি টাইপ যা অভ্যন্তরীণ টাইপগুলি ধারণ করে, আপনি তাদের স্কোয়ার ব্রাকেটের ভিতরে করুন: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// - -/// info - -স্কোয়ার ব্রাকেট এর ভিতরে ব্যবহৃত এইসব অভন্তরীন টাইপগুলোকে "ইন্টারনাল টাইপ" বলে। - -এই উদাহরণে, এটি হচ্ছে `List`(অথবা পাইথন ৩.৯ বা তার উপরের সংস্করণের ক্ষেত্রে `list`) এ পাস করা টাইপ প্যারামিটার। - -/// - -এর অর্থ হচ্ছে: "ভেরিয়েবল `items` একটি `list`, এবং এই লিস্টের প্রতিটি আইটেম একটি `str`।" - -/// tip - -যদি আপনি Python 3.9 বা তার উপরে ব্যবহার করেন, আপনার `typing` থেকে `List` আমদানি করতে হবে না, আপনি সাধারণ `list` ওই টাইপের পরিবর্তে ব্যবহার করতে পারেন। - -/// - -এর মাধ্যমে, আপনার এডিটর লিস্ট থেকে আইটেম প্রসেস করার সময় সাপোর্ট প্রদান করতে পারবে: - - - -টাইপগুলি ছাড়া, এটি করা প্রায় অসম্ভব। - -লক্ষ্য করুন যে ভেরিয়েবল `item` হল `items` লিস্টের একটি এলিমেন্ট। - -তবুও, এডিটর জানে যে এটি একটি `str`, এবং তার জন্য সাপোর্ট প্রদান করে। - -#### টাপল এবং সেট - -আপনি `tuple` এবং `set` ঘোষণা করার জন্য একই প্রক্রিয়া অনুসরণ করবেন: - -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// - -এর মানে হল: - -* ভেরিয়েবল `items_t` হল একটি `tuple` যা ৩টি আইটেম ধারণ করে, একটি `int`, অন্য একটি `int`, এবং একটি `str`। -* ভেরিয়েবল `items_s` হল একটি `set`, এবং এর প্রতিটি আইটেম হল `bytes` টাইপের। - -#### ডিক্ট - -একটি `dict` সংজ্ঞায়িত করতে, আপনি ২টি টাইপ প্যারামিটার কমা দ্বারা পৃথক করে দেবেন। - -প্রথম টাইপ প্যারামিটারটি হল `dict`-এর কীগুলির জন্য। - -দ্বিতীয় টাইপ প্যারামিটারটি হল `dict`-এর মানগুলির জন্য: - -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// - -এর মানে হল: - -* ভেরিয়েবল `prices` হল একটি `dict`: - * এই `dict`-এর কীগুলি হল `str` টাইপের (ধরা যাক, প্রতিটি আইটেমের নাম)। - * এই `dict`-এর মানগুলি হল `float` টাইপের (ধরা যাক, প্রতিটি আইটেমের দাম)। - -#### ইউনিয়ন - -আপনি একটি ভেরিয়েবলকে এমনভাবে ঘোষণা করতে পারেন যেন তা **একাধিক টাইপের** হয়, উদাহরণস্বরূপ, একটি `int` অথবা `str`। - -Python 3.6 এবং তার উপরের সংস্করণগুলিতে (Python 3.10 অন্তর্ভুক্ত) আপনি `typing` থেকে `Union` টাইপ ব্যবহার করতে পারেন এবং স্কোয়ার ব্র্যাকেটের মধ্যে গ্রহণযোগ্য টাইপগুলি রাখতে পারেন। - -Python 3.10-এ একটি **নতুন সিনট্যাক্স** আছে যেখানে আপনি সম্ভাব্য টাইপগুলিকে একটি ভার্টিকাল বার (`|`) দ্বারা পৃথক করতে পারেন। - -//// tab | Python 3.10+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008b_py310.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} -``` - -//// - -উভয় ক্ষেত্রেই এর মানে হল যে `item` হতে পারে একটি `int` অথবা `str`। - -#### সম্ভবত `None` - -আপনি এমনভাবে ঘোষণা করতে পারেন যে একটি মান হতে পারে এক টাইপের, যেমন `str`, আবার এটি `None`-ও হতে পারে। - -Python 3.6 এবং তার উপরের সংস্করণগুলিতে (Python 3.10 অনতর্ভুক্ত) আপনি `typing` মডিউল থেকে `Optional` ইমপোর্ট করে এটি ঘোষণা এবং ব্যবহার করতে পারেন। - -```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} -``` - -`Optional[str]` ব্যবহার করা মানে হল শুধু `str` নয়, এটি হতে পারে `None`-ও, যা আপনার এডিটরকে সেই ত্রুটিগুলি শনাক্ত করতে সাহায্য করবে যেখানে আপনি ধরে নিচ্ছেন যে একটি মান সবসময় `str` হবে, অথচ এটি `None`-ও হতে পারেও। - -`Optional[Something]` মূলত `Union[Something, None]`-এর একটি শর্টকাট, এবং তারা সমতুল্য। - -এর মানে হল, Python 3.10-এ, আপনি টাইপগুলির ইউনিয়ন ঘোষণা করতে `Something | None` ব্যবহার করতে পারেন: - -//// tab | Python 3.10+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial009_py310.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} -``` - -//// - -//// tab | Python 3.8+ বিকল্প - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} -``` - -//// - -#### `Union` বা `Optional` ব্যবহার - -যদি আপনি Python 3.10-এর নীচের সংস্করণ ব্যবহার করেন, তবে এখানে আমার খুবই **ব্যক্তিগত** দৃষ্টিভঙ্গি থেকে একটি টিপস: - -* 🚨 `Optional[SomeType]` ব্যবহার এড়িয়ে চলুন। -* এর পরিবর্তে ✨ **`Union[SomeType, None]` ব্যবহার করুন** ✨। - -উভয়ই সমতুল্য এবং মূলে একই, কিন্তু আমি `Union`-এর পক্ষে সুপারিশ করব কারণ "**অপশনাল**" শব্দটি মনে হতে পারে যে মানটি ঐচ্ছিক,অথচ এটি আসলে মানে "এটি হতে পারে `None`", এমনকি যদি এটি ঐচ্ছিক না হয়েও আবশ্যিক হয়। - -আমি মনে করি `Union[SomeType, None]` এর অর্থ আরও স্পষ্টভাবে প্রকাশ করে। - -এটি কেবল শব্দ এবং নামের ব্যাপার। কিন্তু সেই শব্দগুলি আপনি এবং আপনার সহকর্মীরা কোড সম্পর্কে কীভাবে চিন্তা করেন তা প্রভাবিত করতে পারে। - -একটি উদাহরণ হিসেবে, এই ফাংশনটি নিন: - -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} - - -`name` প্যারামিটারটি `Optional[str]` হিসেবে সংজ্ঞায়িত হয়েছে, কিন্তু এটি **অপশনাল নয়**, আপনি প্যারামিটার ছাড়া ফাংশনটি কল করতে পারবেন না: - -```Python -say_hi() # ওহ না, এটি একটি ত্রুটি নিক্ষেপ করবে! 😱 -``` - -`name` প্যারামিটারটি **এখনও আবশ্যিক** (নন-অপশনাল) কারণ এটির কোনো ডিফল্ট মান নেই। তবুও, `name` এর মান হিসেবে `None` গ্রহণযোগ্য: - -```Python -say_hi(name=None) # এটি কাজ করে, None বৈধ 🎉 -``` - -সুখবর হল, একবার আপনি Python 3.10 ব্যবহার করা শুরু করলে, আপনাকে এগুলোর ব্যাপারে আর চিন্তা করতে হবে না, যেহুতু আপনি | ব্যবহার করেই ইউনিয়ন ঘোষণা করতে পারবেন: - -{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} - - -এবং তারপর আপনাকে নামগুলি যেমন `Optional` এবং `Union` নিয়ে আর চিন্তা করতে হবে না। 😎 - -#### জেনেরিক টাইপস - -স্কোয়ার ব্র্যাকেটে টাইপ প্যারামিটার নেওয়া এই টাইপগুলিকে **জেনেরিক টাইপ** বা **জেনেরিকস** বলা হয়, যেমন: - -//// tab | Python 3.10+ - -আপনি সেই একই বিল্টইন টাইপ জেনেরিক্স হিসেবে ব্যবহার করতে পারবেন(ভিতরে টাইপ সহ স্কয়ারে ব্রাকেট দিয়ে): - -* `list` -* `tuple` -* `set` -* `dict` - -এবং Python 3.8 এর মতোই, `typing` মডিউল থেকে: - -* `Union` -* `Optional` (Python 3.8 এর মতোই) -* ...এবং অন্যান্য। - -Python 3.10-এ, `Union` এবং `Optional` জেনেরিকস ব্যবহার করার বিকল্প হিসেবে, আপনি টাইপগুলির ইউনিয়ন ঘোষণা করতে ভার্টিকাল বার (`|`) ব্যবহার করতে পারেন, যা ওদের থেকে অনেক ভালো এবং সহজ। - -//// - -//// tab | Python 3.9+ - -আপনি সেই একই বিল্টইন টাইপ জেনেরিক্স হিসেবে ব্যবহার করতে পারবেন(ভিতরে টাইপ সহ স্কয়ারে ব্রাকেট দিয়ে): - -* `list` -* `tuple` -* `set` -* `dict` - -এবং Python 3.8 এর মতোই, `typing` মডিউল থেকে: - -* `Union` -* `Optional` -* ...এবং অন্যান্য। - -//// - -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...এবং অন্যান্য। - -//// - -### ক্লাস হিসেবে টাইপস - -আপনি একটি ভেরিয়েবলের টাইপ হিসেবে একটি ক্লাস ঘোষণা করতে পারেন। - -ধরুন আপনার কাছে `Person` নামে একটি ক্লাস আছে, যার একটি নাম আছে: - -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} - - -তারপর আপনি একটি ভেরিয়েবলকে `Person` টাইপের হিসেবে ঘোষণা করতে পারেন: - -{* ../../docs_src/python_types/tutorial010.py hl[6] *} - - -এবং তারপর, আবার, আপনি এডিটর সাপোর্ট পেয়ে যাবেন: - - - -লক্ষ্য করুন যে এর মানে হল "`one_person` হল ক্লাস `Person`-এর একটি **ইন্সট্যান্স**।" - -এর মানে এটি নয় যে "`one_person` হল **ক্লাস** যাকে বলা হয় `Person`।" - -## Pydantic মডেল - -[Pydantic](https://docs.pydantic.dev/) হল একটি Python লাইব্রেরি যা ডাটা ভ্যালিডেশন সম্পাদন করে। - -আপনি ডাটার "আকার" এট্রিবিউট সহ ক্লাস হিসেবে ঘোষণা করেন। - -এবং প্রতিটি এট্রিবিউট এর একটি টাইপ থাকে। - -তারপর আপনি যদি কিছু মান দিয়ে সেই ক্লাসের একটি ইন্সট্যান্স তৈরি করেন-- এটি মানগুলিকে ভ্যালিডেট করবে, প্রয়োজন অনুযায়ী তাদেরকে উপযুক্ত টাইপে রূপান্তর করবে এবং আপনাকে সমস্ত ডাটা সহ একটি অবজেক্ট প্রদান করবে। - -এবং আপনি সেই ফলাফল অবজেক্টের সাথে এডিটর সাপোর্ট পাবেন। - -অফিসিয়াল Pydantic ডক্স থেকে একটি উদাহরণ: - -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// - -/// info - -[Pydantic সম্পর্কে আরও জানতে, এর ডকুমেন্টেশন দেখুন](https://docs.pydantic.dev/)। - -/// - -**FastAPI** মূলত Pydantic-এর উপর নির্মিত। - -আপনি এই সমস্ত কিছুর অনেক বাস্তবসম্মত উদাহরণ পাবেন [টিউটোরিয়াল - ইউজার গাইডে](https://fastapi.tiangolo.com/tutorial/)। - -/// tip - -যখন আপনি `Optional` বা `Union[Something, None]` ব্যবহার করেন এবং কোনো ডিফল্ট মান না থাকে, Pydantic-এর একটি বিশেষ আচরণ রয়েছে, আপনি Pydantic ডকুমেন্টেশনে [Required Optional fields](https://docs.pydantic.dev/latest/concepts/models/#required-optional-fields) সম্পর্কে আরও পড়তে পারেন। - -/// - -## মেটাডাটা অ্যানোটেশন সহ টাইপ হিন্টস - -Python-এ এমন একটি ফিচার আছে যা `Annotated` ব্যবহার করে এই টাইপ হিন্টগুলিতে **অতিরিক্ত মেটাডাটা** রাখতে দেয়। - -//// tab | Python 3.9+ - -Python 3.9-এ, `Annotated` স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত, তাই আপনি এটি `typing` থেকে ইমপোর্ট করতে পারেন। - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -Python 3.9-এর নীচের সংস্করণগুলিতে, আপনি `Annotated`-কে `typing_extensions` থেকে ইমপোর্ট করেন। - -এটি **FastAPI** এর সাথে ইতিমদ্ধে ইনস্টল হয়ে থাকবে। - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// - -Python নিজে এই `Annotated` দিয়ে কিছুই করে না। এবং এডিটর এবং অন্যান্য টুলগুলির জন্য, টাইপটি এখনও `str`। - -কিন্তু আপনি এই `Annotated` এর মধ্যকার জায়গাটির মধ্যে **FastAPI**-এ কীভাবে আপনার অ্যাপ্লিকেশন আচরণ করুক তা সম্পর্কে অতিরিক্ত মেটাডাটা প্রদান করার জন্য ব্যবহার করতে পারেন। - -মনে রাখার গুরুত্বপূর্ণ বিষয় হল যে **প্রথম *টাইপ প্যারামিটার*** আপনি `Annotated`-এ পাস করেন সেটি হল **আসল টাইপ**। বাকি শুধুমাত্র অন্যান্য টুলগুলির জন্য মেটাডাটা। - -এখন আপনার কেবল জানা প্রয়োজন যে `Annotated` বিদ্যমান, এবং এটি স্ট্যান্ডার্ড Python। 😎 - -পরবর্তীতে আপনি দেখবেন এটি কতটা **শক্তিশালী** হতে পারে। - -/// tip - -এটি **স্ট্যান্ডার্ড Python** হওয়ার মানে হল আপনি আপনার এডিটরে, আপনি যে টুলগুলি কোড বিশ্লেষণ এবং রিফ্যাক্টর করার জন্য ব্যবহার করেন তাতে **সেরা সম্ভাব্য ডেভেলপার এক্সপেরিয়েন্স** পাবেন। ✨ - -এবং এছাড়াও আপনার কোড অন্যান্য অনেক Python টুল এবং লাইব্রেরিগুলির সাথে খুব সামঞ্জস্যপূর্ণ হবে। 🚀 - -/// - -## **FastAPI**-এ টাইপ হিন্টস - -**FastAPI** এই টাইপ হিন্টগুলি ব্যবহার করে বেশ কিছু জিনিস করে। - -**FastAPI**-এ আপনি টাইপ হিন্টগুলি সহ প্যারামিটার ঘোষণা করেন এবং আপনি পান: - -* **এডিটর সাপোর্ট**। -* **টাইপচেক**। - -...এবং **FastAPI** একই ঘোষণাগুলি ব্যবহার করে: - -* **রিকুইরেমেন্টস সংজ্ঞায়িত করে**: রিকোয়েস্ট পাথ প্যারামিটার, কুয়েরি প্যারামিটার, হেডার, বডি, ডিপেন্ডেন্সিস, ইত্যাদি থেকে। -* **ডেটা রূপান্তর করে**: রিকোয়েস্ট থেকে প্রয়োজনীয় টাইপে ডেটা। -* **ডেটা যাচাই করে**: প্রতিটি রিকোয়েস্ট থেকে আসা ডেটা: - * যখন ডেটা অবৈধ হয় তখন **স্বয়ংক্রিয় ত্রুটি** গ্রাহকের কাছে ফেরত পাঠানো। -* **API ডকুমেন্টেশন তৈরি করে**: OpenAPI ব্যবহার করে: - * যা স্বয়ংক্রিয় ইন্টার‌্যাক্টিভ ডকুমেন্টেশন ইউজার ইন্টারফেস দ্বারা ব্যবহৃত হয়। - -এই সব কিছু আপনার কাছে অস্পষ্ট মনে হতে পারে। চিন্তা করবেন না। আপনি [টিউটোরিয়াল - ইউজার গাইড](https://fastapi.tiangolo.com/tutorial/) এ এই সব কিছু প্র্যাকটিসে দেখতে পাবেন। - -গুরুত্বপূর্ণ বিষয় হল, আপনি যদি স্ট্যান্ডার্ড Python টাইপগুলি ব্যবহার করেন, তবে আরও বেশি ক্লাস, ডেকোরেটর ইত্যাদি যোগ না করেই একই স্থানে **FastAPI** আপনার অনেক কাজ করে দিবে। - -/// info - -যদি আপনি টিউটোরিয়ালের সমস্ত বিষয় পড়ে ফেলে থাকেন এবং টাইপ সম্পর্কে আরও জানতে চান, তবে একটি ভালো রিসোর্স হল [mypy এর "cheat sheet"](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html)। এই "cheat sheet" এ আপনি Python টাইপ হিন্ট সম্পর্কে বেসিক থেকে উন্নত লেভেলের ধারণা পেতে পারেন, যা আপনার কোডে টাইপ সেফটি এবং স্পষ্টতা বাড়াতে সাহায্য করবে। - -/// diff --git a/docs/bn/mkdocs.yml b/docs/bn/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/bn/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 27b229590..e85f31102 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -303,10 +303,6 @@ extra: alternate: - link: / name: en - English - - link: /az/ - name: az - azərbaycan dili - - link: /bn/ - name: bn - বাংলা - link: /de/ name: de - Deutsch - link: /es/ @@ -315,22 +311,10 @@ extra: name: fa - فارسی - link: /fr/ name: fr - français - - link: /he/ - name: he - עברית - - link: /hu/ - name: hu - magyar - - link: /id/ - name: id - Bahasa Indonesia - - link: /it/ - name: it - italiano - link: /ja/ name: ja - 日本語 - link: /ko/ name: ko - 한국어 - - link: /nl/ - name: nl - Nederlands - - link: /pl/ - name: pl - Polski - link: /pt/ name: pt - português - link: /ru/ @@ -339,12 +323,8 @@ extra: name: tr - Türkçe - link: /uk/ name: uk - українська мова - - link: /ur/ - name: ur - اردو - link: /vi/ name: vi - Tiếng Việt - - link: /yo/ - name: yo - Yorùbá - link: /zh/ name: zh - 简体中文 - link: /zh-hant/ diff --git a/docs/he/docs/index.md b/docs/he/docs/index.md deleted file mode 100644 index 14ea82f5e..000000000 --- a/docs/he/docs/index.md +++ /dev/null @@ -1,469 +0,0 @@ -# FastAPI - - - -

- FastAPI -

-

- תשתית FastAPI, ביצועים גבוהים, קלה ללמידה, מהירה לתכנות, מוכנה לסביבת ייצור -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**תיעוד**: https://fastapi.tiangolo.com - -**קוד**: https://github.com/fastapi/fastapi - ---- - -FastAPI היא תשתית רשת מודרנית ומהירה (ביצועים גבוהים) לבניית ממשקי תכנות יישומים (API) עם פייתון 3.6+ בהתבסס על רמזי טיפוסים סטנדרטיים. - -תכונות המפתח הן: - -- **מהירה**: ביצועים גבוהים מאוד, בקנה אחד עם NodeJS ו - Go (תודות ל - Starlette ו - Pydantic). [אחת מתשתיות הפייתון המהירות ביותר](#_14). - -- **מהירה לתכנות**: הגבירו את מהירות פיתוח התכונות החדשות בכ - %200 עד %300. \* -- **פחות שגיאות**: מנעו כ - %40 משגיאות אנוש (מפתחים). \* -- **אינטואיטיבית**: תמיכת עורך מעולה. השלמה בכל מקום. פחות זמן ניפוי שגיאות. -- **קלה**: מתוכננת להיות קלה לשימוש וללמידה. פחות זמן קריאת תיעוד. -- **קצרה**: מזערו שכפול קוד. מספר תכונות מכל הכרזת פרמטר. פחות שגיאות. -- **חסונה**: קבלו קוד מוכן לסביבת ייצור. עם תיעוד אינטרקטיבי אוטומטי. -- **מבוססת סטנדרטים**: מבוססת על (ותואמת לחלוטין ל -) הסטדנרטים הפתוחים לממשקי תכנות יישומים: OpenAPI (ידועים לשעבר כ - Swagger) ו - JSON Schema. - -\* הערכה מבוססת על בדיקות של צוות פיתוח פנימי שבונה אפליקציות בסביבת ייצור. - -## נותני חסות - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -נותני חסות אחרים - -## דעות - -"_[...] 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._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" - -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -## **Typer**, ה - FastAPI של ממשקי שורת פקודה (CLI). - - - -אם אתם בונים אפליקציית CLI לשימוש במסוף במקום ממשק רשת, העיפו מבט על **Typer**. - -**Typer** היא אחותה הקטנה של FastAPI. ומטרתה היא להיות ה - **FastAPI של ממשקי שורת פקודה**. ⌨️ 🚀 - -## תלויות - -פייתון 3.6+ - -FastAPI עומדת על כתפי ענקיות: - -- Starlette לחלקי הרשת. -- Pydantic לחלקי המידע. - -## התקנה - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -תצטרכו גם שרת ASGI כגון Uvicorn או Hypercorn. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## דוגמא - -### צרו אותה - -- צרו קובץ בשם `main.py` עם: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-או השתמשו ב - async def... - -אם הקוד שלכם משתמש ב - `async` / `await`, השתמשו ב - `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**שימו לב**: - -אם אינכם יודעים, בדקו את פרק "ממהרים?" על `async` ו - `await` בתיעוד. - -
- -### הריצו אותה - -התחילו את השרת עם: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-על הפקודה uvicorn main:app --reload... - -הפקודה `uvicorn main:app` מתייחסת ל: - -- `main`: הקובץ `main.py` (מודול פייתון). -- `app`: האובייקט שנוצר בתוך `main.py` עם השורה app = FastAPI(). -- --reload: גרמו לשרת להתאתחל לאחר שינויים בקוד. עשו זאת רק בסביבת פיתוח. - -
- -### בדקו אותה - -פתחו את הדפדפן שלכם בכתובת http://127.0.0.1:8000/items/5?q=somequery. - -אתם תראו תגובת JSON: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -כבר יצרתם API ש: - -- מקבל בקשות HTTP בנתיבים `/` ו - /items/{item_id}. -- שני ה _נתיבים_ מקבלים _בקשות_ `GET` (ידועות גם כ*מתודות* HTTP). -- ה _נתיב_ /items/{item_id} כולל \*פרמטר נתיב\_ `item_id` שאמור להיות `int`. -- ה _נתיב_ /items/{item_id} \*פרמטר שאילתא\_ אופציונלי `q`. - -### תיעוד API אינטרקטיבי - -כעת פנו לכתובת http://127.0.0.1:8000/docs. - -אתם תראו את התיעוד האוטומטי (מסופק על ידי Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### תיעוד אלטרנטיבי - -כעת פנו לכתובת http://127.0.0.1:8000/redoc. - -אתם תראו תיעוד אלטרנטיבי (מסופק על ידי ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## שדרוג לדוגמא - -כעת ערכו את הקובץ `main.py` כך שיוכל לקבל גוף מבקשת `PUT`. - -הגדירו את הגוף בעזרת רמזי טיפוסים סטנדרטיים, הודות ל - `Pydantic`. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -השרת אמול להתאתחל אוטומטית (מאחר והוספתם --reload לפקודת `uvicorn` שלמעלה). - -### שדרוג התיעוד האינטרקטיבי - -כעת פנו לכתובת http://127.0.0.1:8000/docs. - -- התיעוד האוטומטי יתעדכן, כולל הגוף החדש: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -- לחצו על הכפתור "Try it out", הוא יאפשר לכם למלא את הפרמטרים ולעבוד ישירות מול ה - API. - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -- אחר כך לחצו על הכפתור "Execute", האתר יתקשר עם ה - API שלכם, ישלח את הפרמטרים, ישיג את התוצאות ואז יראה אותן על המסך: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### שדרוג התיעוד האלטרנטיבי - -כעת פנו לכתובת http://127.0.0.1:8000/redoc. - -- התיעוד האלטרנטיבי גם יראה את פרמטר השאילתא והגוף החדשים. - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### סיכום - -לסיכום, אתם מכריזים ** פעם אחת** על טיפוסי הפרמטרים, גוף וכו' כפרמטרים לפונקציה. - -אתם עושים את זה עם טיפוסי פייתון מודרניים. - -אתם לא צריכים ללמוד תחביר חדש, מתודות או מחלקות של ספרייה ספיציפית, וכו' - -רק **פייתון 3.6+** סטנדרטי. - -לדוגמא, ל - `int`: - -```Python -item_id: int -``` - -או למודל `Item` מורכב יותר: - -```Python -item: Item -``` - -...ועם הכרזת הטיפוס האחת הזו אתם מקבלים: - -- תמיכת עורך, כולל: - - השלמות. - - בדיקת טיפוסים. -- אימות מידע: - - שגיאות ברורות ואטומטיות כאשר מוכנס מידע לא חוקי . - - אימות אפילו לאובייקטי JSON מקוננים. -- המרה של מידע קלט: המרה של מידע שמגיע מהרשת למידע וטיפוסים של פייתון. קורא מ: - - JSON. - - פרמטרי נתיב. - - פרמטרי שאילתא. - - עוגיות. - - כותרות. - - טפסים. - - קבצים. -- המרה של מידע פלט: המרה של מידע וטיפוסים מפייתון למידע רשת (כ - JSON): - - המירו טיפוסי פייתון (`str`, `int`, `float`, `bool`, `list`, etc). - - עצמי `datetime`. - - עצמי `UUID`. - - מודלי בסיסי נתונים. - - ...ורבים אחרים. -- תיעוד API אוטומטי ואינטרקטיבית כולל שתי אלטרנטיבות לממשק המשתמש: - - Swagger UI. - - ReDoc. - ---- - -בחזרה לדוגמאת הקוד הקודמת, **FastAPI** ידאג: - -- לאמת שיש `item_id` בנתיב בבקשות `GET` ו - `PUT`. -- לאמת שה - `item_id` הוא מטיפוס `int` בבקשות `GET` ו - `PUT`. - - אם הוא לא, הלקוח יראה שגיאה ברורה ושימושית. -- לבדוק האם קיים פרמטר שאילתא בשם `q` (קרי `http://127.0.0.1:8000/items/foo?q=somequery`) לבקשות `GET`. - - מאחר והפרמטר `q` מוגדר עם = None, הוא אופציונלי. - - לולא ה - `None` הוא היה חובה (כמו הגוף במקרה של `PUT`). -- לבקשות `PUT` לנתיב /items/{item_id}, לקרוא את גוף הבקשה כ - JSON: - - לאמת שהוא כולל את מאפיין החובה `name` שאמור להיות מטיפוס `str`. - - לאמת שהוא כולל את מאפיין החובה `price` שחייב להיות מטיפוס `float`. - - לבדוק האם הוא כולל את מאפיין הרשות `is_offer` שאמור להיות מטיפוס `bool`, אם הוא נמצא. - - כל זה יעבוד גם לאובייקט JSON מקונן. -- להמיר מ - JSON ול- JSON אוטומטית. -- לתעד הכל באמצעות OpenAPI, תיעוד שבו יוכלו להשתמש: - - מערכות תיעוד אינטרקטיביות. - - מערכות ייצור קוד אוטומטיות, להרבה שפות. -- לספק ישירות שתי מערכות תיעוד רשתיות. - ---- - -רק גרדנו את קצה הקרחון, אבל כבר יש לכם רעיון של איך הכל עובד. - -נסו לשנות את השורה: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...מ: - -```Python - ... "item_name": item.name ... -``` - -...ל: - -```Python - ... "item_price": item.price ... -``` - -...וראו איך העורך שלכם משלים את המאפיינים ויודע את הטיפוסים שלהם: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -לדוגמא יותר שלמה שכוללת עוד תכונות, ראו את המדריך - למשתמש. - -**התראת ספוילרים**: המדריך - למשתמש כולל: - -- הכרזה על **פרמטרים** ממקורות אחרים ושונים כגון: **כותרות**, **עוגיות**, **טפסים** ו - **קבצים**. -- איך לקבוע **מגבלות אימות** בעזרת `maximum_length` או `regex`. -- דרך חזקה וקלה להשתמש ב**הזרקת תלויות**. -- אבטחה והתאמתות, כולל תמיכה ב - **OAuth2** עם **JWT** והתאמתות **HTTP Basic**. -- טכניקות מתקדמות (אבל קלות באותה מידה) להכרזת אובייקטי JSON מקוננים (תודות ל - Pydantic). -- אינטרקציה עם **GraphQL** דרך Strawberry וספריות אחרות. -- תכונות נוספות רבות (תודות ל - Starlette) כגון: - - **WebSockets** - - בדיקות קלות במיוחד מבוססות על `requests` ו - `pytest` - - **CORS** - - **Cookie Sessions** - - ...ועוד. - -## ביצועים - -בדיקות עצמאיות של TechEmpower הראו שאפליקציות **FastAPI** שרצות תחת Uvicorn הן מתשתיות הפייתון המהירות ביותר, רק מתחת ל - Starlette ו - Uvicorn עצמן (ש - FastAPI מבוססת עליהן). (\*) - -כדי להבין עוד על הנושא, ראו את הפרק Benchmarks. - -## תלויות אופציונליות - -בשימוש Pydantic: - -- email-validator - לאימות כתובות אימייל. - -בשימוש Starlette: - -- httpx - דרוש אם ברצונכם להשתמש ב - `TestClient`. -- jinja2 - דרוש אם ברצונכם להשתמש בברירת המחדל של תצורת הטמפלייטים. -- python-multipart - דרוש אם ברצונכם לתמוך ב "פרסור" טפסים, באצמעות request.form(). -- itsdangerous - דרוש אם ברצונכם להשתמש ב - `SessionMiddleware`. -- pyyaml - דרוש אם ברצונכם להשתמש ב - `SchemaGenerator` של Starlette (כנראה שאתם לא צריכים את זה עם FastAPI). - -בשימוש FastAPI / Starlette: - -- uvicorn - לשרת שטוען ומגיש את האפליקציה שלכם. -- orjson - דרוש אם ברצונכם להשתמש ב - `ORJSONResponse`. -- ujson - דרוש אם ברצונכם להשתמש ב - `UJSONResponse`. - -תוכלו להתקין את כל אלו באמצעות pip install "fastapi[all]". - -## רשיון - -הפרויקט הזה הוא תחת התנאים של רשיון MIT. diff --git a/docs/he/mkdocs.yml b/docs/he/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/he/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/hu/docs/index.md b/docs/hu/docs/index.md deleted file mode 100644 index f60b6b349..000000000 --- a/docs/hu/docs/index.md +++ /dev/null @@ -1,467 +0,0 @@ -

- FastAPI -

-

- FastAPI keretrendszer, nagy teljesítmény, könnyen tanulható, gyorsan kódolható, productionre kész -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Dokumentáció**: https://fastapi.tiangolo.com - -**Forrás kód**: https://github.com/fastapi/fastapi - ---- -A FastAPI egy modern, gyors (nagy teljesítményű), webes keretrendszer API-ok építéséhez Python -al, a Python szabványos típusjelöléseire építve. - - -Kulcs funkciók: - -* **Gyors**: Nagyon nagy teljesítmény, a **NodeJS**-el és a **Go**-val egyenrangú (a Starlettenek és a Pydantic-nek köszönhetően). [Az egyik leggyorsabb Python keretrendszer](#performance). -* **Gyorsan kódolható**: A funkciók fejlesztési sebességét 200-300 százalékkal megnöveli. * -* **Kevesebb hiba**: Körülbelül 40%-al csökkenti az emberi (fejlesztői) hibák számát. * -* **Intuitív**: Kiváló szerkesztő támogatás. Kiegészítés mindenhol. Kevesebb hibakereséssel töltött idő. -* **Egyszerű**: Egyszerű tanulásra és használatra tervezve. Kevesebb dokumentáció olvasással töltött idő. -* **Rövid**: Kód duplikáció minimalizálása. Több funkció minden paraméter deklarálásával. Kevesebb hiba. -* **Robosztus**: Production ready kód. Automatikus interaktív dokumentáció val. -* **Szabvány alapú**: Az API-ok nyílt szabványaira alapuló (és azokkal teljesen kompatibilis): OpenAPI (korábban Swagger néven ismert) és a JSON Schema. - -* Egy production alkalmazásokat építő belső fejlesztői csapat tesztjein alapuló becslés. - -## Szponzorok - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -További szponzorok - -## Vélemények - -"_[...] 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._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" - -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, a CLI-ok FastAPI-ja - - - -Ha egy olyan CLI alkalmazást fejlesztesz amit a parancssorban kell használni webes API helyett, tekintsd meg: **Typer**. - -**Typer** a FastAPI kistestvére. A **CLI-k FastAPI-ja**. ⌨️ 🚀 - -## Követelmények - -A FastAPI óriások vállán áll: - -* Starlette a webes részekhez. -* Pydantic az adat részekhez. - -## Telepítés - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -A production-höz egy ASGI szerverre is szükség lesz, mint például az Uvicorn vagy a Hypercorn. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## Példa - -### Hozd létre - -* Hozz létre a `main.py` fájlt a következő tartalommal: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Vagy használd az async def-et... - -Ha a kódod `async` / `await`-et, használ `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Megjegyzés**: - -Ha nem tudod, tekintsd meg a _"Sietsz?"_ szekciót `async` és `await`-ről dokumentációba. - -
- -### Futtasd le - -Indítsd el a szervert a következő paranccsal: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-A parancsról uvicorn main:app --reload... - -A `uvicorn main:app` parancs a következőre utal: - -* `main`: fájl `main.py` (a Python "modul"). -* `app`: a `main.py`-ban a `app = FastAPI()` sorral létrehozott objektum. -* `--reload`: kód változtatás esetén újra indítja a szervert. Csak fejlesztés közben használandó. - -
- -### Ellenőrizd - -Nyisd meg a böngésződ a következő címen: http://127.0.0.1:8000/items/5?q=somequery. - -A következő JSON választ fogod látni: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Máris létrehoztál egy API-t ami: - -* HTTP kéréseket fogad a `/` és `/items/{item_id}` _útvonalakon_. -* Mindkét _útvonal_ a `GET` műveletet használja (másik elnevezés: HTTP _metódus_). -* A `/items/{item_id}` _útvonalnak_ van egy _path paramétere_, az `item_id`, aminek `int` típusúnak kell lennie. -* A `/items/{item_id}` _útvonalnak_ még van egy opcionális, `str` típusú _query paramétere_ is, a `q`. - -### Interaktív API dokumentáció - -Most nyisd meg a http://127.0.0.1:8000/docs címet. - -Az automatikus interaktív API dokumentációt fogod látni (amit a Swagger UI-al hozunk létre): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternatív API dokumentáció - -És most menj el a http://127.0.0.1:8000/redoc címre. - -Az alternatív automatikus dokumentációt fogod látni. (lásd ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Példa frissítése - -Módosítsuk a `main.py` fájlt, hogy `PUT` kérések esetén tudjon body-t fogadni. - -Deklaráld a body-t standard Python típusokkal, a Pydantic-nak köszönhetően. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -A szerver automatikusan újraindul (mert hozzáadtuk a --reload paramétert a fenti `uvicorn` parancshoz). - -### Interaktív API dokumentáció frissítése - -Most menj el a http://127.0.0.1:8000/docs címre. - -* Az interaktív API dokumentáció automatikusan frissült így már benne van az új body. - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Kattints rá a "Try it out" gombra, ennek segítségével kitöltheted a paramétereket és közvetlen használhatod az API-t: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Ezután kattints az "Execute" gompra, a felhasználói felület kommunikálni fog az API-oddal. Elküldi a paramétereket és a visszakapott választ megmutatja a képernyődön. - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Alternatív API dokumentáció frissítés - -Most menj el a http://127.0.0.1:8000/redoc címre. - -* Az alternatív dokumentáció szintúgy tükrözni fogja az új kérési paraméter és body-t. - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Összefoglalás - -Összegzésül, deklarálod **egyszer** a paraméterek, body, stb típusát funkciós paraméterekként. - -Ezt standard modern Python típusokkal csinálod. - -Nem kell új szintaxist, vagy specifikus könyvtár mert metódósait, stb. megtanulnod. - -Csak standard **Python**. - -Például egy `int`-nek: - -```Python -item_id: int -``` - -Egy komplexebb `Item` modellnek: - -```Python -item: Item -``` - -... És csupán egy deklarációval megkapod a: - -* Szerkesztő támogatást, beleértve: - * Szövegkiegészítés. - * Típus ellenőrzés. -* Adatok validációja: - * Automatikus és érthető hibák amikor az adatok hibásak. - * Validáció mélyen ágyazott objektumok esetén is. -* Bemeneti adatok átváltása : a hálózatról érkező Python adatokká és típusokká. Adatok olvasása következő forrásokból: - * JSON. - * Cím paraméterek. - * Query paraméterek. - * Cookie-k. - * Header-ök. - * Formok. - * Fájlok. -* Kimeneti adatok átváltása: Python adatok is típusokról hálózati adatokká: - * válts át Python típusokat (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` csak objektumokat. - * `UUID` objektumokat. - * Adatbázis modelleket. - * ...És sok mást. -* Automatikus interaktív dokumentáció, beleértve két alternatív dokumentációt is: - * Swagger UI. - * ReDoc. - ---- - -Visszatérve az előző kód példához. A **FastAPI**: - -* Validálja hogy van egy `item_id` mező a `GET` és `PUT` kérésekben. -* Validálja hogy az `item_id` `int` típusú a `GET` és `PUT` kérésekben. - * Ha nem akkor látni fogunk egy tiszta hibát ezzel kapcsolatban. -* ellenőrzi hogyha van egy opcionális query paraméter `q` névvel (azaz `http://127.0.0.1:8000/items/foo?q=somequery`) `GET` kérések esetén. - * Mivel a `q` paraméter `= None`-al van deklarálva, ezért opcionális. - * `None` nélkül ez a mező kötelező lenne (mint például a body `PUT` kérések esetén). -* a `/items/{item_id}` címre érkező `PUT` kérések esetén, a JSON-t a következőképpen olvassa be: - * Ellenőrzi hogy létezik a kötelező `name` nevű attribútum és `string`. - * Ellenőrzi hogy létezik a kötelező `price` nevű attribútum és `float`. - * Ellenőrzi hogy létezik a `is_offer` nevű opcionális paraméter, ami ha létezik akkor `bool` - * Ez ágyazott JSON objektumokkal is működik -* JSONről való automatikus konvertálás. -* dokumentáljuk mindent OpenAPI-al amit használható: - * Interaktív dokumentációs rendszerekkel. - * Automatikus kliens kód generáló a rendszerekkel, több nyelven. -* Hozzá tartozik kettő interaktív dokumentációs web felület. - ---- - -Eddig csak a felszínt kapargattuk, de a lényeg hogy most már könnyebben érthető hogyan működik. - -Próbáld kicserélni a következő sorban: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...ezt: - -```Python - ... "item_name": item.name ... -``` - -...erre: - -```Python - ... "item_price": item.price ... -``` - -... És figyeld meg hogy a szerkesztő automatikusan tudni fogja a típusokat és kiegészíti azokat: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Teljesebb példákért és funkciókért tekintsd meg a Tutorial - User Guide -t. - -**Spoiler veszély**: a Tutorial - User Guidehoz tartozik: - -* **Paraméterek** deklarációja különböző helyekről: **header-ök**, **cookie-k**, **form mezők** és **fájlok**. -* Hogyan állíts be **validációs feltételeket** mint a `maximum_length` vagy a `regex`. -* Nagyon hatékony és erős **Függőség Injekció** rendszerek. -* Biztonság és autentikáció beleértve, **OAuth2**, **JWT tokens** és **HTTP Basic** támogatást. -* Több haladó (de ugyanannyira könnyű) technika **mélyen ágyazott JSON modellek deklarációjára** (Pydantic-nek köszönhetően). -* **GraphQL** integráció Strawberry-vel és más könyvtárakkal. -* több extra funkció (Starlette-nek köszönhetően) pl.: - * **WebSockets** - * rendkívül könnyű tesztek HTTPX és `pytest` alapokra építve - * **CORS** - * **Cookie Sessions** - * ...és több. - -## Teljesítmény - -A független TechEmpower benchmarkok szerint az Uvicorn alatt futó **FastAPI** alkalmazások az egyik leggyorsabb Python keretrendszerek közé tartoznak, éppen lemaradva a Starlette és az Uvicorn (melyeket a FastAPI belsőleg használ) mögött.(*) - -Ezeknek a további megértéséhez: Benchmarks. - -## Opcionális követelmények - -Pydantic által használt: - -* email-validator - e-mail validációkra. -* pydantic-settings - Beállítások követésére. -* pydantic-extra-types - Extra típusok Pydantic-hoz. - -Starlette által használt: - -* httpx - Követelmény ha a `TestClient`-et akarod használni. -* jinja2 - Követelmény ha az alap template konfigurációt akarod használni. -* python-multipart - Követelmény ha "parsing"-ot akarsz támogatni, `request.form()`-al. -* itsdangerous - Követelmény `SessionMiddleware` támogatáshoz. -* pyyaml - Követelmény a Starlette `SchemaGenerator`-ának támogatásához (valószínűleg erre nincs szükség FastAPI használása esetén). - -FastAPI / Starlette által használt - -* uvicorn - Szerverekhez amíg betöltik és szolgáltatják az applikációdat. -* orjson - Követelmény ha `ORJSONResponse`-t akarsz használni. -* ujson - Követelmény ha `UJSONResponse`-t akarsz használni. - -Ezeket mind telepítheted a `pip install "fastapi[all]"` paranccsal. - -## Licensz -Ez a projekt az MIT license, licensz alatt fut diff --git a/docs/hu/mkdocs.yml b/docs/hu/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/hu/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md deleted file mode 100644 index b29d42dfd..000000000 --- a/docs/id/docs/index.md +++ /dev/null @@ -1,495 +0,0 @@ -# FastAPI - - - -

- FastAPI -

-

- FastAPI, framework performa tinggi, mudah dipelajari, cepat untuk coding, siap untuk pengembangan -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Dokumentasi**: https://fastapi.tiangolo.com - -**Kode Sumber**: https://github.com/fastapi/fastapi - ---- - -FastAPI adalah *framework* *web* moderen, cepat (performa-tinggi) untuk membangun API dengan Python berdasarkan tipe petunjuk Python. - -Fitur utama FastAPI: - -* **Cepat**: Performa sangat tinggi, setara **NodeJS** dan **Go** (berkat Starlette dan Pydantic). [Salah satu *framework* Python tercepat yang ada](#performa). -* **Cepat untuk coding**: Meningkatkan kecepatan pengembangan fitur dari 200% sampai 300%. * -* **Sedikit bug**: Mengurangi hingga 40% kesalahan dari manusia (pemrogram). * -* **Intuitif**: Dukungan editor hebat. Penyelesaian di mana pun. Lebih sedikit *debugging*. -* **Mudah**: Dibuat mudah digunakan dan dipelajari. Sedikit waktu membaca dokumentasi. -* **Ringkas**: Mengurasi duplikasi kode. Beragam fitur dari setiap deklarasi parameter. Lebih sedikit *bug*. -* **Handal**: Dapatkan kode siap-digunakan. Dengan dokumentasi otomatis interaktif. -* **Standar-resmi**: Berdasarkan (kompatibel dengan ) standar umum untuk API: OpenAPI (sebelumnya disebut Swagger) dan JSON Schema. - -* estimasi berdasarkan pengujian tim internal pengembangan applikasi siap pakai. - -## Sponsor - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Sponsor lainnya - -## Opini - -"_[...] Saya banyak menggunakan **FastAPI** sekarang ini. [...] Saya berencana menggunakannya di semua tim servis ML Microsoft. Beberapa dari mereka sudah mengintegrasikan dengan produk inti *Windows** dan sebagian produk **Office**._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_Kami adopsi library **FastAPI** untuk membuat server **REST** yang melakukan kueri untuk menghasilkan **prediksi**. [untuk Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** dengan bangga mengumumkan rilis open-source orkestrasi framework **manajemen krisis** : **Dispatch**! [dibuat dengan **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_Saya sangat senang dengan **FastAPI**. Sangat menyenangkan!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Jujur, apa yang anda buat sangat solid dan berkualitas. Ini adalah yang saya inginkan di **Hug** - sangat menginspirasi melihat seseorang membuat ini._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_Jika anda ingin mempelajari **framework moderen** untuk membangun REST API, coba **FastAPI** [...] cepat, mudah digunakan dan dipelajari [...]_" - -"_Kami sudah pindah ke **FastAPI** untuk **API** kami [...] Saya pikir kamu juga akan suka [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- -"_Jika anda ingin membuat API Python siap pakai, saya merekomendasikan **FastAPI**. FastAPI **didesain indah**, **mudah digunakan** dan **sangat scalable**, FastAPI adalah **komponen kunci** di strategi pengembangan API pertama kami dan mengatur banyak otomatisasi dan service seperti TAC Engineer kami._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, CLI FastAPI - - - -Jika anda mengembangkan app CLI yang digunakan di terminal bukan sebagai API web, kunjungi **Typer**. - -**Typer** adalah saudara kecil FastAPI. Dan ditujukan sebagai **CLI FastAPI**. ⌨️ 🚀 - -## Prayarat - -FastAPI berdiri di pundak raksasa: - -* Starlette untuk bagian web. -* Pydantic untuk bagian data. - -## Instalasi - -Buat dan aktifkan virtual environment kemudian *install* FastAPI: - -
- -```console -$ pip install "fastapi[standard]" - ----> 100% -``` - -
- -**Catatan**: Pastikan anda menulis `"fastapi[standard]"` dengan tanda petik untuk memastikan bisa digunakan di semua *terminal*. - -## Contoh - -### Buat app - -* Buat file `main.py` dengan: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Atau gunakan async def... - -Jika kode anda menggunakan `async` / `await`, gunakan `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Catatan**: - -Jika anda tidak paham, kunjungi _"Panduan cepat"_ bagian `async` dan `await` di dokumentasi. - -
- -### Jalankan - -Jalankan *server* dengan: - -
- -```console -$ fastapi dev main.py - - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - │ fastapi run │ - │ │ - ╰─────────────────────────────────────────────────────╯ - -INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [2248755] using WatchFiles -INFO: Started server process [2248757] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-Mengenai perintah fastapi dev main.py... - -Perintah `fastapi dev` membaca file `main.py`, memeriksa app **FastAPI** di dalamnya, dan menjalan server dengan Uvicorn. - -Secara otomatis, `fastapi dev` akan mengaktifkan *auto-reload* untuk pengembangan lokal. - -Informasi lebih lanjut kunjungi Dokumen FastAPI CLI. - -
- -### Periksa - -Buka *browser* di http://127.0.0.1:8000/items/5?q=somequery. - -Anda akan melihat respon JSON berikut: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Anda telah membuat API: - -* Menerima permintaan HTTP di _path_ `/` dan `/items/{item_id}`. -* Kedua _paths_ menerima operasi `GET` (juga disebut _metode_ HTTP). -* _path_ `/items/{item_id}` memiliki _parameter path_ `item_id` yang harus berjenis `int`. -* _path_ `/items/{item_id}` memiliki _query parameter_ `q` berjenis `str`. - -### Dokumentasi API interaktif - -Sekarang kunjungi http://127.0.0.1:8000/docs. - -Anda akan melihat dokumentasi API interaktif otomatis (dibuat oleh Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Dokumentasi API alternatif - -Kemudian kunjungi http://127.0.0.1:8000/redoc. - -Anda akan melihat dokumentasi alternatif otomatis (dibuat oleh ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Contoh upgrade - -Sekarang ubah `main.py` untuk menerima struktur permintaan `PUT`. - -Deklarasikan struktur menggunakan tipe standar Python, berkat Pydantic. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -Server `fastapi dev` akan otomatis memuat kembali. - -### Upgrade dokumentasi API interaktif - -Kunjungi http://127.0.0.1:8000/docs. - -* Dokumentasi API interaktif akan otomatis diperbarui, termasuk kode yang baru: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Klik tombol "Try it out", anda dapat mengisi parameter dan langsung berinteraksi dengan API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Kemudian klik tombol "Execute", tampilan pengguna akan berkomunikasi dengan API, mengirim parameter, mendapatkan dan menampilkan hasil ke layar: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Upgrade dokumentasi API alternatif - -Kunjungi http://127.0.0.1:8000/redoc. - -* Dokumentasi alternatif akan menampilkan parameter *query* dan struktur *request*: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Ringkasan - -Singkatnya, anda mendeklarasikan **sekali** jenis parameter, struktur, dll. sebagai parameter fungsi. - -Anda melakukannya dengan tipe standar moderen Python. - -Anda tidak perlu belajar sintaksis, metode, *classs* baru dari *library* tertentu, dll. - -Cukup **Python** standar. - -Sebagai contoh untuk `int`: - -```Python -item_id: int -``` - -atau untuk model lebih rumit `Item`: - -```Python -item: Item -``` - -...dengan sekali deklarasi anda mendapatkan: - -* Dukungan editor, termasuk: - * Pelengkapan kode. - * Pengecekan tipe. -* Validasi data: - * Kesalahan otomatis dan jelas ketika data tidak sesuai. - * Validasi hingga untuk object JSON bercabang mendalam. -* Konversi input data: berasal dari jaringan ke data dan tipe Python. Membaca dari: - * JSON. - * Parameter path. - * Parameter query. - * Cookie. - * Header. - * Form. - * File. -* Konversi output data: konversi data Python ke tipe jaringan data (seperti JSON): - * Konversi tipe Python (`str`, `int`, `float`, `bool`, `list`, dll). - * Objek `datetime`. - * Objek `UUID`. - * Model database. - * ...dan banyak lagi. -* Dokumentasi interaktif otomatis, termasuk 2 alternatif tampilan pengguna: - * Swagger UI. - * ReDoc. - ---- - -Kembali ke kode contoh sebelumnya, **FastAPI** akan: - -* Validasi apakah terdapat `item_id` di *path* untuk permintaan `GET` dan `PUT` requests. -* Validasi apakah `item_id` berjenit `int` untuk permintaan `GET` dan `PUT`. - * Jika tidak, klien akan melihat pesan kesalahan jelas. -* Periksa jika ada parameter *query* opsional bernama `q` (seperti `http://127.0.0.1:8000/items/foo?q=somequery`) untuk permintaan `GET`. - * Karena parameter `q` dideklarasikan dengan `= None`, maka bersifat opsional. - * Tanpa `None` maka akan menjadi wajib ada (seperti struktur di kondisi dengan `PUT`). -* Untuk permintaan `PUT` `/items/{item_id}`, membaca struktur sebagai JSON: - * Memeriksa terdapat atribut wajib `name` harus berjenis `str`. - * Memeriksa terdapat atribut wajib`price` harus berjenis `float`. - * Memeriksa atribut opsional `is_offer`, harus berjenis `bool`, jika ada. - * Semua ini juga sama untuk objek json yang bersarang mendalam. -* Konversi dari dan ke JSON secara otomatis. -* Dokumentasi segalanya dengan OpenAPI, dengan menggunakan: - * Sistem dokumentasi interaktif. - * Sistem otomatis penghasil kode, untuk banyak bahasa. -* Menyediakan 2 tampilan dokumentasi web interaktif dengan langsung. - ---- - -Kita baru menyentuh permukaannya saja, tetapi anda sudah mulai paham gambaran besar cara kerjanya. - -Coba ubah baris: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...dari: - -```Python - ... "item_name": item.name ... -``` - -...menjadi: - -```Python - ... "item_price": item.price ... -``` - -...anda akan melihat kode editor secara otomatis melengkapi atributnya dan tahu tipe nya: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Untuk contoh lengkap termasuk fitur lainnya, kunjungi Tutorial - Panduan Pengguna. - -**Peringatan spoiler**: tutorial - panduan pengguna termasuk: - -* Deklarasi **parameter** dari tempat berbeda seperti: **header**, **cookie**, **form field** and **file**. -* Bagaimana mengatur **batasan validasi** seperti `maximum_length`atau `regex`. -* Sistem **Dependency Injection** yang hebat dan mudah digunakan. -* Keamanan dan autentikasi, termasuk dukungan ke **OAuth2** dengan **JWT token** dan autentikasi **HTTP Basic**. -* Teknik lebih aju (tetapi mudah dipakai untuk deklarasi **model JSON bersarang ke dalam** (berkat Pydantic). -* Integrasi **GraphQL** dengan Strawberry dan library lainnya. -* Fitur lainnya (berkat Starlette) seperti: - * **WebSocket** - * Test yang sangat mudah berdasarkan HTTPX dan `pytest` - * **CORS** - * **Cookie Session** - * ...dan lainnya. - -## Performa - -Tolok ukur Independent TechEmpower mendapati aplikasi **FastAPI** berjalan menggunakan Uvicorn sebagai salah satu framework Python tercepat yang ada, hanya di bawah Starlette dan Uvicorn itu sendiri (digunakan di internal FastAPI). (*) - -Penjelasan lebih lanjut, lihat bagian Tolok ukur. - -## Dependensi - -FastAPI bergantung pada Pydantic dan Starlette. - -### Dependensi `standar` - -Ketika anda meng-*install* FastAPI dengan `pip install "fastapi[standard]"`, maka FastAPI akan menggunakan sekumpulan dependensi opsional `standar`: - -Digunakan oleh Pydantic: - -* email-validator - untuk validasi email. - -Digunakan oleh Starlette: - -* httpx - Dibutuhkan jika anda menggunakan `TestClient`. -* jinja2 - Dibutuhkan jika anda menggunakan konfigurasi template bawaan. -* python-multipart - Dibutuhkan jika anda menggunakan form dukungan "parsing", dengan `request.form()`. - -Digunakan oleh FastAPI / Starlette: - -* uvicorn - untuk server yang memuat dan melayani aplikasi anda. Termasuk `uvicorn[standard]`, yang memasukan sejumlah dependensi (misal `uvloop`) untuk needed melayani dengan performa tinggi. -* `fastapi-cli` - untuk menyediakan perintah `fastapi`. - -### Tanpda dependensi `standard` - -Jika anda tidak ingin menambahkan dependensi opsional `standard`, anda dapat menggunakan `pip install fastapi` daripada `pip install "fastapi[standard]"`. - -### Dependensi Opsional Tambahan - -Ada beberapa dependensi opsional yang bisa anda install. - -Dependensi opsional tambahan Pydantic: - -* pydantic-settings - untuk manajemen setting. -* pydantic-extra-types - untuk tipe tambahan yang digunakan dengan Pydantic. - -Dependensi tambahan opsional FastAPI: - -* orjson - Diperlukan jika anda akan menggunakan`ORJSONResponse`. -* ujson - Diperlukan jika anda akan menggunakan `UJSONResponse`. - -## Lisensi - -Project terlisensi dengan lisensi MIT. diff --git a/docs/id/docs/tutorial/first-steps.md b/docs/id/docs/tutorial/first-steps.md deleted file mode 100644 index 9b461507d..000000000 --- a/docs/id/docs/tutorial/first-steps.md +++ /dev/null @@ -1,332 +0,0 @@ -# Langkah Pertama - -File FastAPI yang paling sederhana bisa seperti berikut: - -{* ../../docs_src/first_steps/tutorial001.py *} - -Salin file tersebut ke `main.py`. - -Jalankan di server: - -
- -```console -$ fastapi dev main.py -INFO Using path main.py -INFO Resolved absolute path /home/user/code/awesomeapp/main.py -INFO Searching for package file structure from directories with __init__.py files -INFO Importing from /home/user/code/awesomeapp - - ╭─ Python module file ─╮ - │ │ - │ 🐍 main.py │ - │ │ - ╰──────────────────────╯ - -INFO Importing module main -INFO Found importable FastAPI app - - ╭─ Importable FastAPI app ─╮ - │ │ - │ from main import app │ - │ │ - ╰──────────────────────────╯ - -INFO Using import string main:app - - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - fastapi run - │ │ - ╰─────────────────────────────────────────────────────╯ - -INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [2265862] using WatchFiles -INFO: Started server process [2265873] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -Di output, terdapat sebaris pesan: - -```hl_lines="4" -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -Baris tersebut menunjukan URL dimana app aktif di komputer anda. - - -### Mencoba aplikasi - -Buka browser di http://127.0.0.1:8000. - -Anda akan melihat response JSON sebagai berikut: - -```JSON -{"message": "Hello World"} -``` - -### Dokumen API interaktif - -Sekarang kunjungi http://127.0.0.1:8000/docs. - -Anda akan melihat dokumentasi API interaktif otomatis (dibuat oleh Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Dokumen API alternatif - -Dan sekarang, kunjungi http://127.0.0.1:8000/redoc. - -Anda akan melihat dokumentasi alternatif otomatis (dibuat oleh ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -### OpenAPI - -**FastAPI** membuat sebuah "schema" dimana semua API anda menggunakan standar **OpenAPI** untuk mendefinisikan API. - -#### "Schema" - -"schema" adalah suatu definisi atau deskripsi dari sesuatu. Bukan kode yang mengimplementasi definisi tersebut. Ini hanyalah sebuah deskripsi abstrak. - -#### "schema" API - -Dalam hal ini, OpenAPI adalah spesifikasi yang menunjukan bagaimana untuk mendefinisikan sebuah skema di API anda. - -Definisi skema ini termasuk jalur API anda, parameter yang bisa diterima, dll. - -#### "schema" Data - -Istilah "schema" bisa juga merujuk ke struktur data, seperti konten JSON. - -Dalam kondisi ini, ini berarti attribut JSON dan tipe data yang dimiliki, dll. - -#### Schema OpenAPI and JSON - -"schema" OpenAPI mendefinisikan skema API dari API yang anda buat. Skema tersebut termasuk definisi (atau "schema") dari data yang dikirim atau diterima oleh API dari **JSON Schema**, skema data standar JSON. - -#### Lihat `openapi.json` - -Jika anda penasaran bagaimana skema OpenAPI polos seperti apa, FastAPI secara otomatis membuat JSON (schema) dengan deksripsi API anda. - -anda bisa melihatnya di: http://127.0.0.1:8000/openapi.json. - -Anda akan melihat JSON yang dimulai seperti: - -```JSON -{ - "openapi": "3.1.0", - "info": { - "title": "FastAPI", - "version": "0.1.0" - }, - "paths": { - "/items/": { - "get": { - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - - - -... -``` - -#### Kegunaan OpenAPI - -Skema OpenAPI adalah tulang punggung dua sistem dokumentasi API interaktif yang ada di FastAPI. - -Ada banyak alternatif sistem dokumentasi lainnya yang semuanya berdasarkan OpenAPI. Anda bisa menambahkannya ke aplikasi **FastAPI** anda. - -Anda juga bisa menggunakan OpenAPI untuk membuat kode secara otomatis, untuk klien yang menggunakan API anda. Sebagai contoh, frontend, aplikasi mobile atau IoT. - -## Ringkasan, secara bertahap - -### Langkah 1: impor `FastAPI` - -{* ../../docs_src/first_steps/tutorial001.py hl[1] *} - -`FastAPI` adalah class Python yang menyediakan semua fungsionalitas API anda. - -/// note | Detail Teknis - -`FastAPI` adalah class turunan langsung dari `Starlette`. - -Anda bisa menggunakan semua fungsionalitas Starlette dengan `FastAPI` juga. - -/// - -### Langkah 2: buat "instance" dari `FastAPI` - -{* ../../docs_src/first_steps/tutorial001.py hl[3] *} - -Di sini variabel `app` akan menjadi sebuah "instance" dari class `FastAPI`. - -Ini akan menjadi gerbang utama untuk membuat semua API anda. - -### Langkah 3: Buat *operasi path* - -#### Path - -"Path" atau jalur di sini merujuk ke bagian URL terakhir dimulai dari `/` pertama. - -Sehingga, URL seperti: - -``` -https://example.com/items/foo -``` - -...path-nya adalah: - -``` -/items/foo -``` - -/// info - -"path" juga biasa disebut "endpoint" atau "route". - -/// - -ketika membuat API, "path" adalah jalan utama untuk memisahkan "concern" dan "resources". - -#### Operasi - -"Operasi" di sini merujuk ke salah satu dari metode HTTP berikut. - -Salah satu dari: - -* `POST` -* `GET` -* `PUT` -* `DELETE` - -...dan operasi lainnya yang unik: - -* `OPTIONS` -* `HEAD` -* `PATCH` -* `TRACE` - -Dalam protokol HTTP, anda bisa berkomunikasi ke setiap path menggunakan satu (atau lebih) metode di atas. - ---- - -Ketika membuat API, anda umumnya menggunakan metode HTTP tertentu untuk proses tertentu. - -Umumnya menggunakan: - -* `POST`: untuk membuat data. -* `GET`: untuk membaca data. -* `PUT`: untuk memperbarui data. -* `DELETE`: untuk menghapus data. - -Sehingga, di OpanAPI, setiap metode HTTP ini disebut sebuah "operasi". - -Kita akan menyebut mereka juga "**operasi**". - -#### Mendefinisikan *dekorator operasi path* - -{* ../../docs_src/first_steps/tutorial001.py hl[6] *} - -`@app.get("/")` memberitahu **FastAPI** bahwa fungsi di bawahnya mengurusi request yang menuju ke: - -* path `/` -* menggunakan operasi get - -/// info | `@decorator` Info - -Sintaksis `@sesuatu` di Python disebut "dekorator". - -Dekorator ditempatkan di atas fungsi. Seperti sebuah topi cantik (Saya pikir istilah ini berasal dari situ). - -"dekorator" memanggil dan bekerja dengan fungsi yang ada di bawahnya - -Pada kondisi ini, dekorator ini memberi tahu **FastAPI** bahwa fungsi di bawah nya berhubungan dengan **path** `/` dengan **operasi** `get`. - -Sehingga disebut **dekorator operasi path**. - -/// - -Operasi lainnya yang bisa digunakan: - -* `@app.post()` -* `@app.put()` -* `@app.delete()` - -Dan operasi unik lainnya: - -* `@app.options()` -* `@app.head()` -* `@app.patch()` -* `@app.trace()` - -/// tip | Tips - -Jika anda bisa menggunakan operasi apa saja (metode HTTP). - -**FastAPI** tidak mengharuskan anda menggunakan operasi tertentu. - -Informasi di sini hanyalah sebagai panduan, bukan keharusan. - -Sebagai contoh, ketika menggunakan GraphQL, semua operasi umumnya hanya menggunakan `POST`. - -/// - -### Langkah 4: mendefinisikan **fungsi operasi path** - -Ini "**fungsi operasi path**" kita: - -* **path**: adalah `/`. -* **operasi**: adalah `get`. -* **fungsi**: adalah fungsi yang ada di bawah dekorator (di bawah `@app.get("/")`). - -{* ../../docs_src/first_steps/tutorial001.py hl[7] *} - -Ini adalah fungsi Python. - -Fungsi ini dipanggil **FastAPI** setiap kali menerima request ke URL "`/`" dengan operasi `GET`. - -Di kondisi ini, ini adalah sebuah fungsi `async`. - ---- - -Anda bisa mendefinisikan fungsi ini sebagai fungsi normal daripada `async def`: - -{* ../../docs_src/first_steps/tutorial003.py hl[7] *} - -/// note | Catatan - -Jika anda tidak tahu perbedaannya, kunjungi [Async: *"Panduan cepat"*](../async.md#in-a-hurry){.internal-link target=_blank}. - -/// - -### Langkah 5: hasilkan konten - -{* ../../docs_src/first_steps/tutorial001.py hl[8] *} - -Anda bisa menghasilkan `dict`, `list`, nilai singular seperti `str`, `int`, dll. - -Anda juga bisa menghasilkan model Pydantic (anda akan belajar mengenai ini nanti). - -Ada banyak objek dan model yang secara otomatis dikonversi ke JSON (termasuk ORM, dll). Anda bisa menggunakan yang anda suka, kemungkinan sudah didukung. - -## Ringkasan - -* Impor `FastAPI`. -* Buat sebuah instance `app`. -* Tulis **dekorator operasi path** menggunakan dekorator seperti `@app.get("/")`. -* Definisikan **fungsi operasi path**; sebagai contoh, `def root(): ...`. -* Jalankan server development dengan perintah `fastapi dev`. diff --git a/docs/id/docs/tutorial/index.md b/docs/id/docs/tutorial/index.md deleted file mode 100644 index c01ec9a89..000000000 --- a/docs/id/docs/tutorial/index.md +++ /dev/null @@ -1,83 +0,0 @@ -# Tutorial - Pedoman Pengguna - Pengenalan - -Tutorial ini menunjukan cara menggunakan ***FastAPI*** dengan semua fitur-fiturnya, tahap demi tahap. - -Setiap bagian dibangun secara bertahap dari bagian sebelumnya, tetapi terstruktur untuk memisahkan banyak topik, sehingga kamu bisa secara langsung menuju ke topik spesifik untuk menyelesaikan kebutuhan API tertentu. - -Ini juga dibangun untuk digunakan sebagai referensi yang akan datang. - -Sehingga kamu dapat kembali lagi dan mencari apa yang kamu butuhkan dengan tepat. - -## Jalankan kode - -Semua blok-blok kode dapat disalin dan digunakan langsung (Mereka semua sebenarnya adalah file python yang sudah teruji). - -Untuk menjalankan setiap contoh, salin kode ke file `main.py`, dan jalankan `uvicorn` dengan: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -**SANGAT disarankan** agar kamu menulis atau menyalin kode, mengubahnya dan menjalankannya secara lokal. - -Dengan menggunakannya di dalam editor, benar-benar memperlihatkan manfaat dari FastAPI, melihat bagaimana sedikitnya kode yang harus kamu tulis, semua pengecekan tipe, pelengkapan otomatis, dll. - ---- - -## Install FastAPI - -Langkah pertama adalah dengan meng-install FastAPI. - -Untuk tutorial, kamu mungkin hendak meng-installnya dengan semua pilihan fitur dan dependensinya: - -
- -```console -$ pip install "fastapi[all]" - ----> 100% -``` - -
- -...yang juga termasuk `uvicorn`, yang dapat kamu gunakan sebagai server yang menjalankan kodemu. - -/// note | Catatan - -Kamu juga dapat meng-installnya bagian demi bagian. - -Hal ini mungkin yang akan kamu lakukan ketika kamu hendak menyebarkan (men-deploy) aplikasimu ke tahap produksi: - -``` -pip install fastapi -``` - -Juga install `uvicorn` untuk menjalankan server" - -``` -pip install "uvicorn[standard]" -``` - -Dan demikian juga untuk pilihan dependensi yang hendak kamu gunakan. - -/// - -## Pedoman Pengguna Lanjutan - -Tersedia juga **Pedoman Pengguna Lanjutan** yang dapat kamu baca nanti setelah **Tutorial - Pedoman Pengguna** ini. - -**Pedoman Pengguna Lanjutan**, dibangun atas hal ini, menggunakan konsep yang sama, dan mengajarkan kepadamu beberapa fitur tambahan. - -Tetapi kamu harus membaca terlebih dahulu **Tutorial - Pedoman Pengguna** (apa yang sedang kamu baca sekarang). - -Hal ini dirancang supaya kamu dapat membangun aplikasi lengkap dengan hanya **Tutorial - Pedoman Pengguna**, dan kemudian mengembangkannya ke banyak cara yang berbeda, tergantung dari kebutuhanmu, menggunakan beberapa ide-ide tambahan dari **Pedoman Pengguna Lanjutan**. diff --git a/docs/id/docs/tutorial/path-params.md b/docs/id/docs/tutorial/path-params.md deleted file mode 100644 index 5ac6c8cd6..000000000 --- a/docs/id/docs/tutorial/path-params.md +++ /dev/null @@ -1,257 +0,0 @@ -# Parameter Path - -"parameter" atau "variabel" path didefinisikan dengan sintaksis Python format string: - -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} - -Nilai parameter path `item_id` akan dikirim ke fungsi sebagai argument `item_id`: - -Jika anda menjalankan contoh berikut dan kunjungi http://127.0.0.1:8000/items/foo, anda akan melihat respon: - -```JSON -{"item_id":"foo"} -``` - -## Parameter path dengan tipe data - -Tipe data parameter path bisa didefinisikan di dalam fungsi, menggunakan anotasi tipe data standar Python: - -{* ../../docs_src/path_params/tutorial002.py hl[7] *} - -Dalam hal ini `item_id` didefinisikan sebagai `int`. - -/// check | Periksa - -Penyunting kode anda bisa membantu periksa di dalam fungsi seperti pemeriksaan kesalahan, kelengkapan kode, dll. - -/// - -## Konversi data - -Jika contoh berikut dijalankan dan diakses browser melalui http://127.0.0.1:8000/items/3, anda akan melihat respon: - -```JSON -{"item_id":3} -``` - -/// check | Periksa - -Perhatikan nilai fungsi yang diterima (dan dihasilkan) adalah `3`, sebagai `int` di Python, dan bukan string `"3"`. - -Sehingga dengan deklarasi tipe data **FastAPI** memberikan request otomatis "parsing". - -/// - -## Validasi Data - -Tetapi jika di browser anda akses http://127.0.0.1:8000/items/foo, anda akan melihat pesan kesalahan HTTP: - -```JSON -{ - "detail": [ - { - "type": "int_parsing", - "loc": [ - "path", - "item_id" - ], - "msg": "Input should be a valid integer, unable to parse string as an integer", - "input": "foo" - } - ] -} -``` - -Karena parameter path `item_id` bernilai `"foo"` yang bukan tipe data `int`. - -Kesalahan yang sama akan muncul jika menggunakan `float` daripada `int`, seperti di: http://127.0.0.1:8000/items/4.2 - -/// check | Periksa - -Dengan deklarasi tipe data Python, **FastAPI** melakukan validasi data. - -Perhatikan kesalahan tersebut juga menjelaskan validasi apa yang tidak sesuai. - -Validasi ini sangat membantu ketika mengembangkan dan men-*debug* kode yang berhubungan dengan API anda. - -/// - -## Dokumentasi - -Ketika anda membuka browser di http://127.0.0.1:8000/docs, anda melihat dokumentasi API interaktif otomatis berikut: - - - -/// check | Periksa - -Dengan deklarasi tipe data Python yang sama, **FastAPI** membuat dokumentasi interaktif otomatis (terintegrasi Swagger UI). - -Perhatikan parameter path dideklarasikan sebagai integer. - -/// - -## Keuntungan basis-standar, dokumentasi alternatif - -Karena skema yang dibuat berasal dari standar OpenAPI, maka banyak alat lain yang kompatibel. - -Sehingga **FastAPI** menyediakan dokumentasi alternatif (menggunakan ReDoc), yang bisa diakses di http://127.0.0.1:8000/redoc: - - - -Cara yang sama untuk menggunakan tools kompatibel lainnya. Termasuk alat membuat kode otomatis untuk banyak bahasa. - -## Pydantic - -Semua validasi data dikerjakan di belakang layar oleh Pydantic, sehingga anda mendapatkan banyak kemudahan. Anda juga tahu proses ini akan ditangani dengan baik. - -Anda bisa mendeklarasikan tipe data dengan `str`, `float`, `bool` dan banyak tipe data kompleks lainnya. - -Beberapa tipe di atas akan dibahas pada bab berikutnya tutorial ini. - -## Urutan berpengaruh - -Ketika membuat *operasi path*, anda bisa menghadapi kondisi dimana *path* nya sudah tetap. - -Seperti `/users/me`, untuk mendapatkan data user yang sedang aktif. - -Kemudian anda bisa memiliki path `/users/{user_id}` untuk mendapatkan data user tertentu melalui user ID. - -karena *operasi path* dievaluasi melalui urutan, anda harus memastikan path untuk `/users/me` dideklarasikan sebelum `/user/{user_id}`: - -{* ../../docs_src/path_params/tutorial003.py hl[6,11] *} - -Sebaliknya, path `/users/{user_id}` juga akan sesuai dengan `/users/me`, "menganggap" menerima parameter `user_id` dengan nilai `"me"`. - -Serupa, anda juga tidak bisa mendefinisikan operasi path: - -{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *} - -Path pertama akan selalu digunakan karena path sesuai dengan yang pertama. - -## Nilai terdefinisi - -Jika ada *operasi path* yang menerima *parameter path*, tetapi anda ingin nilai valid *parameter path* sudah terdefinisi, anda bisa menggunakan standar Python `Enum`. - -### Membuat class `Enum` - -Import `Enum` dan buat *sub-class* warisan dari `str` dan `Enum`. - -Dengan warisan dari `str` dokumen API mengetahui nilai nya harus berjenis `string` supaya bisa digunakan dengan benar. - -Kemudian buat atribut *class* dengan nilai tetap *string* yang benar: - -{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *} - -/// info - -Enumerasi (atau enum) tersedia di Python sejak versi 3.4. - -/// - -/// tip | Tips - -"AlxexNet", "ResNet", dan "LeNet" adalah nama model *Machine Learning*. - -/// - -### Mendeklarasikan *parameter path* - -Kemudian buat *parameter path* dengan tipe anotasi menggunakan *class* enum dari (`ModelName`) - -{* ../../docs_src/path_params/tutorial005.py hl[16] *} - -### Periksa dokumentasi - -Karena nilai yang tersedia untuk *parameter path* telah terdefinisi, dokumen interatik bisa memunculkan: - - - -### Bekerja dengan *enumarasi* Python - -Nilai *parameter path* akan menjadi *anggota enumerasi*. - -#### Membandingkan *anggota enumerasi* - -Anda bisa membandingkan parameter *path* dengan *anggota enumerasi* di enum `ModelName` yang anda buat: - -{* ../../docs_src/path_params/tutorial005.py hl[17] *} - -#### Mendapatkan *nilai enumerasi* - -Anda bisa mendapatkan nilai (`str` dalam kasus ini) menggunakan `model_name.value`, atau secara umum `anggota_enum_anda.value`: - -{* ../../docs_src/path_params/tutorial005.py hl[20] *} - -/// tip | Tips - -Anda bisa mengakses nilai `"lenet"` dnegan `ModelName.lenet.value`. - -/// - -#### Menghasilkan *anggota enumerasi* - -Anda bisa menghasilkan *anggota enumerasi* dari *operasi path* bahkan di body JSON bersarang (contoh `dict`). - -They will be converted to their corresponding values (strings in this case) before returning them to the client: - -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} - -Klien akan mendapatkan respon JSON seperti berikut: - -```JSON -{ - "model_name": "alexnet", - "message": "Deep Learning FTW!" -} -``` - -## Parameter path berisi path - -Misalkan terdapat *operasi path* dengan path `/files/{file_path}`. - -Tetapi anda memerlukan `file_path` itu berisi *path*, seperti like `home/johndoe/myfile.txt`. - -Sehingga URL untuk file tersebut akan seperti: `/files/home/johndoe/myfile.txt`. - -### Dukungan OpenAPI - -OpenAPI tidak bisa mendeklarasikan *parameter path* berisi *path* di dalamnya, karena menyebabkan kondisi yang sulit di*test* dan didefinisikan. - -Tetapi, di **FastAPI** anda tetap bisa melakukannya dengan menggunakan *tools* internal dari Starlette. - -Dan dokumentasi tetap berfungsi walaupun tidak menambahkan keterangan bahwa parameter harus berisi *path*. - -### Konverter path - -Melalui Starlette anda bisa mendeklarasikan *parameter path* berisi *path* dengan URL seperti: - -``` -/files/{file_path:path} -``` - -Dikondisi ini nama parameter adalah `file_path` dan bagian terakhir `:path` menginformasikan parameter harus sesuai dengan setiap *path*. - -Sehingga anda bisa menggunakan: - -{* ../../docs_src/path_params/tutorial004.py hl[6] *} - -/// tip | Tips - -Anda mungkin perlu parameter berisi `/home/johndoe/myfile.txt` di awali garis belakang (`/`). - -Di kondisi ini, URL nya menjadi: `/files//home/johndoe/myfile.txt`, dengan dua garis belakang (`//`) di antara `files` dan `home`. - -/// - -## Ringkasan - -Di **FastAPI** dengan menggunakan deklarasi tipe Python standar, pendek, intuitif, anda mendapatkan: - -* Dukungan editor: pemeriksaan kesalahan, autocompletion, dll. -* "Parsing" data. -* Validasi data. -* Annotasi API dan dokumentasi otomatis. - -Semua itu anda hanya perlu mendeklarasikan sekali saja. - -Ini adalah salah satu keunggulan **FastAPI** dibandingkan dengan *framework* lainnya (selain dari performa Python *native*c) diff --git a/docs/id/docs/tutorial/static-files.md b/docs/id/docs/tutorial/static-files.md deleted file mode 100644 index b55f31394..000000000 --- a/docs/id/docs/tutorial/static-files.md +++ /dev/null @@ -1,40 +0,0 @@ -# Berkas Statis - -Anda dapat menyajikan berkas statis secara otomatis dari sebuah direktori menggunakan `StaticFiles`. - -## Penggunaan `StaticFiles` - -* Mengimpor `StaticFiles`. -* "Mount" representatif `StaticFiles()` di jalur spesifik. - -{* ../../docs_src/static_files/tutorial001.py hl[2,6] *} - -/// note | Detail Teknis - -Anda dapat pula menggunakan `from starlette.staticfiles import StaticFiles`. - -**FastAPI** menyediakan `starlette.staticfiles` sama seperti `fastapi.staticfiles` sebagai kemudahan pada Anda, yaitu para pengembang. Tetapi ini asli berasal langsung dari Starlette. - -/// - -### Apa itu "Mounting" - -"Mounting" dimaksud menambah aplikasi "independen" secara lengkap di jalur spesifik, kemudian menangani seluruh sub-jalur. - -Hal ini berbeda dari menggunakan `APIRouter` karena aplikasi yang dimount benar-benar independen. OpenAPI dan dokumentasi dari aplikasi utama Anda tak akan menyertakan apa pun dari aplikasi yang dimount, dst. - -Anda dapat mempelajari mengenai ini dalam [Panduan Pengguna Lanjutan](../advanced/index.md){.internal-link target=_blank}. - -## Detail - -Terhadap `"/static"` pertama mengacu pada sub-jalur yang akan menjadi tempat "sub-aplikasi" ini akan "dimount". Maka, jalur apa pun yang dimulai dengan `"/static"` akan ditangani oleh sub-jalur tersebut. - -Terhadap `directory="static"` mengacu pada nama direktori yang berisi berkas statis Anda. - -Terhadap `name="static"` ialah nama yang dapat digunakan secara internal oleh **FastAPI**. - -Seluruh parameter ini dapat berbeda dari sekadar "`static`", sesuaikan parameter dengan keperluan dan detail spesifik akan aplikasi Anda. - -## Info lanjutan - -Sebagai detail dan opsi tambahan lihat dokumentasi Starlette perihal Berkas Statis. diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/id/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md deleted file mode 100644 index 7214df8a8..000000000 --- a/docs/it/docs/index.md +++ /dev/null @@ -1,463 +0,0 @@ -

- FastAPI -

-

- FastAPI framework, alte prestazioni, facile da imparare, rapido da implementare, pronto per il rilascio in produzione -

- -

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Documentazione**: https://fastapi.tiangolo.com - -**Codice Sorgente**: https://github.com/fastapi/fastapi - ---- - -FastAPI è un web framework moderno e veloce (a prestazioni elevate) che serve a creare API con Python 3.6+ basato sulle annotazioni di tipo di Python. - -Le sue caratteristiche principali sono: - -* **Velocità**: Prestazioni molto elevate, alla pari di **NodeJS** e **Go** (grazie a Starlette e Pydantic). [Uno dei framework Python più veloci in circolazione](#performance). -* **Veloce da programmare**: Velocizza il lavoro consentendo il rilascio di nuove funzionalità tra il 200% e il 300% più rapidamente. * -* **Meno bug**: Riduce di circa il 40% gli errori che commettono gli sviluppatori durante la scrittura del codice. * -* **Intuitivo**: Grande supporto per gli editor di testo con autocompletamento in ogni dove. In questo modo si può dedicare meno tempo al debugging. -* **Facile**: Progettato per essere facile da usare e imparare. Si riduce il tempo da dedicare alla lettura della documentazione. -* **Sintentico**: Minimizza la duplicazione di codice. Molteplici funzionalità, ognuna con la propria dichiarazione dei parametri. Meno errori. -* **Robusto**: Crea codice pronto per la produzione con documentazione automatica interattiva. -* **Basato sugli standard**: Basato su (e completamente compatibile con) gli open standard per le API: OpenAPI (precedentemente Swagger) e JSON Schema. - -* Stima basata sull'esito di test eseguiti su codice sorgente di applicazioni rilasciate in produzione da un team interno di sviluppatori. - -## Sponsor - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Altri sponsor - -## Recensioni - -"_[...] 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._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
Piero Molino, Yaroslav Dudin, e Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" - -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -## **Typer**, la FastAPI delle CLI - - - -Se stai sviluppando un'app CLI da usare nel terminale invece che una web API, ti consigliamo **Typer**. - -**Typer** è il fratello minore di FastAPI. Ed è stato ideato per essere la **FastAPI delle CLI**. ⌨️ 🚀 - -## Requisiti - -Python 3.6+ - -FastAPI è basata su importanti librerie: - -* Starlette per le parti web. -* Pydantic per le parti dei dati. - -## Installazione - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -Per il rilascio in produzione, sarà necessario un server ASGI come Uvicorn oppure Hypercorn. - -
- -```console -$ pip install uvicorn[standard] - ----> 100% -``` - -
- -## Esempio - -### Crea un file - -* Crea un file `main.py` con: - -```Python -from fastapi import FastAPI -from typing import Optional - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: str = Optional[None]): - return {"item_id": item_id, "q": q} -``` - -
-Oppure usa async def... - -Se il tuo codice usa `async` / `await`, allora usa `async def`: - -```Python hl_lines="7 12" -from fastapi import FastAPI -from typing import Optional - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): - return {"item_id": item_id, "q": q} -``` - -**Nota**: - -e vuoi approfondire, consulta la sezione _"In a hurry?"_ su `async` e `await` nella documentazione. - -
- -### Esegui il server - -Puoi far partire il server così: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-Informazioni sul comando uvicorn main:app --reload... - -Vediamo il comando `uvicorn main:app` in dettaglio: - -* `main`: il file `main.py` (il "modulo" Python). -* `app`: l'oggetto creato dentro `main.py` con la riga di codice `app = FastAPI()`. -* `--reload`: ricarica il server se vengono rilevati cambiamenti del codice. Usalo solo durante la fase di sviluppo. - -
- -### Testa l'API - -Apri il browser all'indirizzo http://127.0.0.1:8000/items/5?q=somequery. - -Vedrai la seguente risposta JSON: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Hai appena creato un'API che: - -* Riceve richieste HTTP sui _paths_ `/` and `/items/{item_id}`. -* Entrambi i _paths_ accettano`GET` operations (conosciuti anche come HTTP _methods_). -* Il _path_ `/items/{item_id}` ha un _path parameter_ `item_id` che deve essere un `int`. -* Il _path_ `/items/{item_id}` ha una `str` _query parameter_ `q`. - -### Documentazione interattiva dell'API - -Adesso vai all'indirizzo http://127.0.0.1:8000/docs. - -Vedrai la documentazione interattiva dell'API (offerta da Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Documentazione interattiva alternativa - -Adesso accedi all'url http://127.0.0.1:8000/redoc. - -Vedrai la documentazione interattiva dell'API (offerta da ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Esempio più avanzato - -Adesso modifica il file `main.py` per ricevere un _body_ da una richiesta `PUT`. - -Dichiara il _body_ usando le annotazioni di tipo standard di Python, grazie a Pydantic. - -```Python hl_lines="2 7-10 23-25" -from fastapi import FastAPI -from pydantic import BaseModel -from typing import Optional - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: bool = Optional[None] - - -@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} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -Il server dovrebbe ricaricarsi in automatico (perché hai specificato `--reload` al comando `uvicorn` lanciato precedentemente). - -### Aggiornamento della documentazione interattiva - -Adesso vai su http://127.0.0.1:8000/docs. - -* La documentazione interattiva dell'API verrà automaticamente aggiornata, includendo il nuovo _body_: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Fai click sul pulsante "Try it out", che ti permette di inserire i parametri per interagire direttamente con l'API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Successivamente, premi sul pulsante "Execute". L'interfaccia utente comunicherà con la tua API, invierà i parametri, riceverà i risultati della richiesta, e li mostrerà sullo schermo: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Aggiornamento della documentazione alternativa - -Ora vai su http://127.0.0.1:8000/redoc. - -* Anche la documentazione alternativa dell'API mostrerà il nuovo parametro della query e il _body_: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Riepilogo - -Ricapitolando, è sufficiente dichiarare **una sola volta** i tipi dei parametri, del body, ecc. come parametri di funzioni. - -Questo con le annotazioni per i tipi standard di Python. - -Non c'è bisogno di imparare una nuova sintassi, metodi o classi specifici a una libreria, ecc. - -È normalissimo **Python 3.6+**. - -Per esempio, per un `int`: - -```Python -item_id: int -``` - -o per un modello `Item` più complesso: - -```Python -item: Item -``` - -...e con quella singola dichiarazione hai in cambio: - -* Supporto per gli editor di testo, incluso: - * Autocompletamento. - * Controllo sulle annotazioni di tipo. -* Validazione dei dati: - * Errori chiari e automatici quando i dati sono invalidi. - * Validazione anche per gli oggetti JSON più complessi. -* Conversione dei dati di input: da risorse esterne a dati e tipi di Python. È possibile leggere da: - * JSON. - * Path parameters. - * Query parameters. - * Cookies. - * Headers. - * Form. - * File. -* Conversione dei dati di output: converte dati e tipi di Python a dati per la rete (come JSON): - * Converte i tipi di Python (`str`, `int`, `float`, `bool`, `list`, ecc). - * Oggetti `datetime`. - * Oggetti `UUID`. - * Modelli del database. - * ...e molto di più. -* Generazione di una documentazione dell'API interattiva, con scelta dell'interfaccia grafica: - * Swagger UI. - * ReDoc. - ---- - -Tornando al precedente esempio, **FastAPI**: - -* Validerà che esiste un `item_id` nel percorso delle richieste `GET` e `PUT`. -* Validerà che `item_id` sia di tipo `int` per le richieste `GET` e `PUT`. - * Se non lo è, il client vedrà un errore chiaro e utile. -* Controllerà se ci sia un parametro opzionale chiamato `q` (per esempio `http://127.0.0.1:8000/items/foo?q=somequery`) per le richieste `GET`. - * Siccome il parametro `q` è dichiarato con `= None`, è opzionale. - * Senza il `None` sarebbe stato obbligatorio (come per il body della richiesta `PUT`). -* Per le richieste `PUT` su `/items/{item_id}`, leggerà il body come JSON, questo comprende: - * verifica che la richiesta abbia un attributo obbligatorio `name` e che sia di tipo `str`. - * verifica che la richiesta abbia un attributo obbligatorio `price` e che sia di tipo `float`. - * verifica che la richiesta abbia un attributo opzionale `is_offer` e che sia di tipo `bool`, se presente. - * Tutto questo funzionerebbe anche con oggetti JSON più complessi. -* Convertirà *da* e *a* JSON automaticamente. -* Documenterà tutto con OpenAPI, che può essere usato per: - * Sistemi di documentazione interattivi. - * Sistemi di generazione di codice dal lato client, per molti linguaggi. -* Fornirà 2 interfacce di documentazione dell'API interattive. - ---- - -Questa è solo la punta dell'iceberg, ma dovresti avere già un'idea di come il tutto funzioni. - -Prova a cambiare questa riga di codice: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...da: - -```Python - ... "item_name": item.name ... -``` - -...a: - -```Python - ... "item_price": item.price ... -``` - -...e osserva come il tuo editor di testo autocompleterà gli attributi e sarà in grado di riconoscere i loro tipi: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Per un esempio più completo che mostra più funzionalità del framework, consulta Tutorial - Guida Utente. - -**Spoiler alert**: il tutorial - Guida Utente include: - -* Dichiarazione di **parameters** da altri posti diversi come: **headers**, **cookies**, **form fields** e **files**. -* Come stabilire **vincoli di validazione** come `maximum_length` o `regex`. -* Un sistema di **Dependency Injection** facile da usare e molto potente. -e potente. -* Sicurezza e autenticazione, incluso il supporto per **OAuth2** con **token JWT** e autenticazione **HTTP Basic**. -* Tecniche più avanzate (ma ugualmente semplici) per dichiarare **modelli JSON altamente nidificati** (grazie a Pydantic). -* E altre funzionalità (grazie a Starlette) come: - * **WebSockets** - * **GraphQL** - * test molto facili basati su `requests` e `pytest` - * **CORS** - * **Cookie Sessions** - * ...e altro ancora. - -## Prestazioni - -Benchmark indipendenti di TechEmpower mostrano che **FastAPI** basato su Uvicorn è uno dei framework Python più veloci in circolazione, solamente dietro a Starlette e Uvicorn (usate internamente da FastAPI). (*) - -Per approfondire, consulta la sezione Benchmarks. - -## Dipendenze opzionali - -Usate da Pydantic: - -* email-validator - per la validazione di email. - -Usate da Starlette: - -* requests - Richiesto se vuoi usare il `TestClient`. -* aiofiles - Richiesto se vuoi usare `FileResponse` o `StaticFiles`. -* jinja2 - Richiesto se vuoi usare la configurazione template di default. -* python-multipart - Richiesto se vuoi supportare il "parsing" con `request.form()`. -* itsdangerous - Richiesto per usare `SessionMiddleware`. -* pyyaml - Richiesto per il supporto dello `SchemaGenerator` di Starlette (probabilmente non ti serve con FastAPI). -* graphene - Richiesto per il supporto di `GraphQLApp`. - -Usate da FastAPI / Starlette: - -* uvicorn - per il server che carica e serve la tua applicazione. -* orjson - ichiesto se vuoi usare `ORJSONResponse`. -* ujson - Richiesto se vuoi usare `UJSONResponse`. - -Puoi installarle tutte con `pip install fastapi[all]`. - -## Licenza - -Questo progetto è concesso in licenza in base ai termini della licenza MIT. diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/it/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/nl/docs/environment-variables.md b/docs/nl/docs/environment-variables.md deleted file mode 100644 index f6b3d285b..000000000 --- a/docs/nl/docs/environment-variables.md +++ /dev/null @@ -1,298 +0,0 @@ -# Omgevingsvariabelen - -/// tip - -Als je al weet wat "omgevingsvariabelen" zijn en hoe je ze kunt gebruiken, kun je deze stap gerust overslaan. - -/// - -Een omgevingsvariabele (ook bekend als "**env var**") is een variabele die **buiten** de Python-code leeft, in het **besturingssysteem** en die door je Python-code (of door andere programma's) kan worden gelezen. - -Omgevingsvariabelen kunnen nuttig zijn voor het bijhouden van applicatie **instellingen**, als onderdeel van de **installatie** van Python, enz. - -## Omgevingsvariabelen maken en gebruiken - -Je kunt omgevingsvariabelen **maken** en gebruiken in de **shell (terminal)**, zonder dat je Python nodig hebt: - -//// tab | Linux, macOS, Windows Bash - -
- -```console -// Je zou een omgevingsvariabele MY_NAME kunnen maken met -$ export MY_NAME="Wade Wilson" - -// Dan zou je deze met andere programma's kunnen gebruiken, zoals -$ echo "Hello $MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -//// tab | Windows PowerShell - -
- -```console -// Maak een omgevingsvariabel MY_NAME -$ $Env:MY_NAME = "Wade Wilson" - -// Gebruik het met andere programma's, zoals -$ echo "Hello $Env:MY_NAME" - -Hello Wade Wilson -``` - -
- -//// - -## Omgevingsvariabelen uitlezen in Python - -Je kunt omgevingsvariabelen **buiten** Python aanmaken, in de terminal (of met een andere methode) en ze vervolgens **in Python uitlezen**. - -Je kunt bijvoorbeeld een bestand `main.py` hebben met: - -```Python hl_lines="3" -import os - -name = os.getenv("MY_NAME", "World") -print(f"Hello {name} from Python") -``` - -/// tip - -Het tweede argument van `os.getenv()` is de standaardwaarde die wordt geretourneerd. - -Als je dit niet meegeeft, is de standaardwaarde `None`. In dit geval gebruiken we standaard `"World"`. - -/// - -Dan zou je dat Python-programma kunnen aanroepen: - -//// tab | Linux, macOS, Windows Bash - -
- -```console -// Hier stellen we de omgevingsvariabelen nog niet in -$ python main.py - -// Omdat we de omgevingsvariabelen niet hebben ingesteld, krijgen we de standaardwaarde - -Hello World from Python - -// Maar als we eerst een omgevingsvariabele aanmaken -$ export MY_NAME="Wade Wilson" - -// en het programma dan opnieuw aanroepen -$ python main.py - -// kan het de omgevingsvariabele nu wel uitlezen - -Hello Wade Wilson from Python -``` - -
- -//// - -//// tab | Windows PowerShell - -
- -```console -// Hier stellen we de omgevingsvariabelen nog niet in -$ python main.py - -// Omdat we de omgevingsvariabelen niet hebben ingesteld, krijgen we de standaardwaarde - -Hello World from Python - -// Maar als we eerst een omgevingsvariabele aanmaken -$ $Env:MY_NAME = "Wade Wilson" - -// en het programma dan opnieuw aanroepen -$ python main.py - -// kan het de omgevingsvariabele nu wel uitlezen - -Hello Wade Wilson from Python -``` - -
- -//// - -Omdat omgevingsvariabelen buiten de code kunnen worden ingesteld, maar wel door de code kunnen worden gelezen en niet hoeven te worden opgeslagen (gecommit naar `git`) met de rest van de bestanden, worden ze vaak gebruikt voor configuraties of **instellingen**. - -Je kunt ook een omgevingsvariabele maken die alleen voor een **specifieke programma-aanroep** beschikbaar is, die alleen voor dat programma beschikbaar is en alleen voor de duur van dat programma. - -Om dat te doen, maak je het vlak voor het programma zelf aan, op dezelfde regel: - -
- -```console -// Maak een omgevingsvariabele MY_NAME in de regel voor deze programma-aanroep -$ MY_NAME="Wade Wilson" python main.py - -// Nu kan het de omgevingsvariabele lezen - -Hello Wade Wilson from Python - -// De omgevingsvariabelen bestaan daarna niet meer -$ python main.py - -Hello World from Python -``` - -
- -/// tip - -Je kunt er meer over lezen op The Twelve-Factor App: Config. - -/// - -## Types en Validatie - -Deze omgevingsvariabelen kunnen alleen **tekstuele gegevens** verwerken, omdat ze extern zijn aan Python, compatibel moeten zijn met andere programma's en de rest van het systeem (zelfs met verschillende besturingssystemen, zoals Linux, Windows en macOS). - -Dat betekent dat **elke waarde** die in Python uit een omgevingsvariabele wordt gelezen **een `str` zal zijn** en dat elke conversie naar een ander type of elke validatie in de code moet worden uitgevoerd. - -Meer informatie over het gebruik van omgevingsvariabelen voor het verwerken van **applicatie instellingen** vind je in de [Geavanceerde gebruikershandleiding - Instellingen en Omgevingsvariabelen](./advanced/settings.md){.internal-link target=_blank}. - -## `PATH` Omgevingsvariabele - -Er is een **speciale** omgevingsvariabele met de naam **`PATH`**, die door de besturingssystemen (Linux, macOS, Windows) wordt gebruikt om programma's te vinden die uitgevoerd kunnen worden. - -De waarde van de variabele `PATH` is een lange string die bestaat uit mappen die gescheiden worden door een dubbele punt `:` op Linux en macOS en door een puntkomma `;` op Windows. - -De omgevingsvariabele `PATH` zou er bijvoorbeeld zo uit kunnen zien: - -//// tab | Linux, macOS - -```plaintext -/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin -``` - -Dit betekent dat het systeem naar programma's zoekt in de mappen: - -* `/usr/local/bin` -* `/usr/bin` -* `/bin` -* `/usr/sbin` -* `/sbin` - -//// - -//// tab | Windows - -```plaintext -C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32 -``` - -Dit betekent dat het systeem naar programma's zoekt in de mappen: - -* `C:\Program Files\Python312\Scripts` -* `C:\Program Files\Python312` -* `C:\Windows\System32` - -//// - -Wanneer je een **opdracht** in de terminal typt, **zoekt** het besturingssysteem naar het programma in **elk van de mappen** die vermeld staan in de omgevingsvariabele `PATH`. - -Wanneer je bijvoorbeeld `python` in de terminal typt, zoekt het besturingssysteem naar een programma met de naam `python` in de **eerste map** in die lijst. - -Zodra het gevonden wordt, zal het dat programma **gebruiken**. Anders blijft het in de **andere mappen** zoeken. - -### Python installeren en `PATH` bijwerken - -Wanneer je Python installeert, word je mogelijk gevraagd of je de omgevingsvariabele `PATH` wilt bijwerken. - -//// tab | Linux, macOS - -Stel dat je Python installeert en het komt terecht in de map `/opt/custompython/bin`. - -Als je kiest om de `PATH` omgevingsvariabele bij te werken, zal het installatieprogramma `/opt/custompython/bin` toevoegen aan de `PATH` omgevingsvariabele. - -Dit zou er zo uit kunnen zien: - -```plaintext -/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin -``` - -Op deze manier zal het systeem, wanneer je `python` in de terminal typt, het Python-programma in `/opt/custompython/bin` (de laatste map) vinden en dat gebruiken. - -//// - -//// tab | Windows - -Stel dat je Python installeert en het komt terecht in de map `C:\opt\custompython\bin`. - -Als je kiest om de `PATH` omgevingsvariabele bij te werken, zal het installatieprogramma `C:\opt\custompython\bin` toevoegen aan de `PATH` omgevingsvariabele. - -```plaintext -C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin -``` - -Op deze manier zal het systeem, wanneer je `python` in de terminal typt, het Python-programma in `C:\opt\custompython\bin` (de laatste map) vinden en dat gebruiken. - -//// - -Dus als je typt: - -
- -```console -$ python -``` - -
- -//// tab | Linux, macOS - -Zal het systeem het `python`-programma in `/opt/custompython/bin` **vinden** en uitvoeren. - -Het zou ongeveer hetzelfde zijn als het typen van: - -
- -```console -$ /opt/custompython/bin/python -``` - -
- -//// - -//// tab | Windows - -Zal het systeem het `python`-programma in `C:\opt\custompython\bin\python` **vinden** en uitvoeren. - -Het zou ongeveer hetzelfde zijn als het typen van: - -
- -```console -$ C:\opt\custompython\bin\python -``` - -
- -//// - -Deze informatie is handig wanneer je meer wilt weten over [virtuele omgevingen](virtual-environments.md){.internal-link target=_blank}. - -## Conclusion - -Hiermee heb je basiskennis van wat **omgevingsvariabelen** zijn en hoe je ze in Python kunt gebruiken. - -Je kunt er ook meer over lezen op de Wikipedia over omgevingsvariabelen. - -In veel gevallen is het niet direct duidelijk hoe omgevingsvariabelen nuttig zijn en hoe je ze moet toepassen. Maar ze blijven in veel verschillende scenario's opduiken als je aan het ontwikkelen bent, dus het is goed om er meer over te weten. - -Je hebt deze informatie bijvoorbeeld nodig in de volgende sectie, over [Virtuele Omgevingen](virtual-environments.md). diff --git a/docs/nl/docs/features.md b/docs/nl/docs/features.md deleted file mode 100644 index 848b155ec..000000000 --- a/docs/nl/docs/features.md +++ /dev/null @@ -1,201 +0,0 @@ -# Functionaliteit - -## FastAPI functionaliteit - -**FastAPI** biedt je het volgende: - -### Gebaseerd op open standaarden - -* OpenAPI voor het maken van API's, inclusief declaraties van padbewerkingen, parameters, request bodies, beveiliging, enz. -* Automatische datamodel documentatie met JSON Schema (aangezien OpenAPI zelf is gebaseerd op JSON Schema). -* Ontworpen op basis van deze standaarden, na zorgvuldig onderzoek. In plaats van achteraf deze laag er bovenop te bouwen. -* Dit maakt het ook mogelijk om automatisch **clientcode te genereren** in verschillende programmeertalen. - -### Automatische documentatie - -Interactieve API-documentatie en verkenning van webgebruikersinterfaces. Aangezien dit framework is gebaseerd op OpenAPI, zijn er meerdere documentatie opties mogelijk, waarvan er standaard 2 zijn inbegrepen. - -* Swagger UI, met interactieve interface, maakt het mogelijk je API rechtstreeks vanuit de browser aan te roepen en te testen. - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Alternatieve API-documentatie met ReDoc. - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Gewoon Moderne Python - -Het is allemaal gebaseerd op standaard **Python type** declaraties (dankzij Pydantic). Je hoeft dus geen nieuwe syntax te leren. Het is gewoon standaard moderne Python. - -Als je een opfriscursus van 2 minuten nodig hebt over het gebruik van Python types (zelfs als je FastAPI niet gebruikt), bekijk dan deze korte tutorial: [Python Types](python-types.md){.internal-link target=_blank}. - -Je schrijft gewoon standaard Python met types: - -```Python -from datetime import date - -from pydantic import BaseModel - -# Declareer een variabele als een str -# en krijg editorondersteuning in de functie -def main(user_id: str): - return user_id - - -# Een Pydantic model -class User(BaseModel): - id: int - name: str - joined: date -``` - -Vervolgens kan je het op deze manier gebruiken: - -```Python -my_user: User = User(id=3, name="John Doe", joined="2018-07-19") - -second_user_data = { - "id": 4, - "name": "Mary", - "joined": "2018-11-30", -} - -my_second_user: User = User(**second_user_data) -``` - -/// info - -`**second_user_data` betekent: - -Geef de sleutels (keys) en waarden (values) van de `second_user_data` dict direct door als sleutel-waarden argumenten, gelijk aan: `User(id=4, name=“Mary”, joined=“2018-11-30”)` - -/// - -### Editor-ondersteuning - -Het gehele framework is ontworpen om eenvoudig en intuïtief te zijn in gebruik. Alle beslissingen zijn getest op meerdere code-editors nog voordat het daadwerkelijke ontwikkelen begon, om zo de beste ontwikkelervaring te garanderen. - -Uit enquêtes onder Python ontwikkelaars blijkt maar al te duidelijk dat "(automatische) code aanvulling" een van de meest gebruikte functionaliteiten is. - -Het hele **FastAPI** framework is daarop gebaseerd. Automatische code aanvulling werkt overal. - -Je hoeft zelden terug te vallen op de documentatie. - -Zo kan je editor je helpen: - -* in Visual Studio Code: - -![editor ondersteuning](https://fastapi.tiangolo.com/img/vscode-completion.png) - -* in PyCharm: - -![editor ondersteuning](https://fastapi.tiangolo.com/img/pycharm-completion.png) - -Je krijgt autocomletion die je voorheen misschien zelfs voor onmogelijk had gehouden. Zoals bijvoorbeeld de `price` key in een JSON body (die genest had kunnen zijn) die afkomstig is van een request. - -Je hoeft niet langer de verkeerde keys in te typen, op en neer te gaan tussen de documentatie, of heen en weer te scrollen om te checken of je `username` of toch `user_name` had gebruikt. - -### Kort - -Dit framework heeft voor alles verstandige **standaardinstellingen**, met overal optionele configuraties. Alle parameters kunnen worden verfijnd zodat het past bij wat je nodig hebt, om zo de API te kunnen definiëren die jij nodig hebt. - -Maar standaard werkt alles **“gewoon”**. - -### Validatie - -* Validatie voor de meeste (of misschien wel alle?) Python **datatypes**, inclusief: - * JSON objecten (`dict`). - * JSON array (`list`) die itemtypes definiëren. - * String (`str`) velden, die min en max lengtes hebben. - * Getallen (`int`, `float`) met min en max waarden, enz. - -* Validatie voor meer exotische typen, zoals: - * URL. - * E-mail. - * UUID. - * ...en anderen. - -Alle validatie wordt uitgevoerd door het beproefde en robuuste **Pydantic**. - -### Beveiliging en authenticatie - -Beveiliging en authenticatie is geïntegreerd. Zonder compromissen te doen naar databases of datamodellen. - -Alle beveiligingsschema's gedefinieerd in OpenAPI, inclusief: - -* HTTP Basic. -* **OAuth2** (ook met **JWT tokens**). Bekijk de tutorial over [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. -* API keys in: - * Headers. - * Query parameters. - * Cookies, enz. - -Plus alle beveiligingsfuncties van Starlette (inclusief **sessiecookies**). - -Gebouwd als een herbruikbare tool met componenten die makkelijk te integreren zijn in en met je systemen, datastores, relationele en NoSQL databases, enz. - -### Dependency Injection - -FastAPI bevat een uiterst eenvoudig, maar uiterst krachtig Dependency Injection systeem. - -* Zelfs dependencies kunnen dependencies hebben, waardoor een hiërarchie of **“graph” van dependencies** ontstaat. -* Allemaal **automatisch afgehandeld** door het framework. -* Alle dependencies kunnen data nodig hebben van request, de vereiste **padoperaties veranderen** en automatische documentatie verstrekken. -* **Automatische validatie** zelfs voor *padoperatie* parameters gedefinieerd in dependencies. -* Ondersteuning voor complexe gebruikersauthenticatiesystemen, **databaseverbindingen**, enz. -* **Geen compromisen** met databases, gebruikersinterfaces, enz. Maar eenvoudige integratie met ze allemaal. - -### Ongelimiteerde "plug-ins" - -Of anders gezegd, je hebt ze niet nodig, importeer en gebruik de code die je nodig hebt. - -Elke integratie is ontworpen om eenvoudig te gebruiken (met afhankelijkheden), zodat je een “plug-in" kunt maken in 2 regels code, met dezelfde structuur en syntax die wordt gebruikt voor je *padbewerkingen*. - -### Getest - -* 100% van de code is getest. -* 100% type geannoteerde codebase. -* Wordt gebruikt in productietoepassingen. - -## Starlette functies - -**FastAPI** is volledig verenigbaar met (en gebaseerd op) Starlette. - -`FastAPI` is eigenlijk een subklasse van `Starlette`. Dus als je Starlette al kent of gebruikt, zal de meeste functionaliteit op dezelfde manier werken. - -Met **FastAPI** krijg je alle functies van **Starlette** (FastAPI is gewoon Starlette op steroïden): - -* Zeer indrukwekkende prestaties. Het is een van de snelste Python frameworks, vergelijkbaar met **NodeJS** en **Go**. -* **WebSocket** ondersteuning. -* Taken in de achtergrond tijdens het proces. -* Opstart- en afsluit events. -* Test client gebouwd op HTTPX. -* **CORS**, GZip, Statische bestanden, Streaming reacties. -* **Sessie en Cookie** ondersteuning. -* 100% van de code is getest. -* 100% type geannoteerde codebase. - -## Pydantic functionaliteit - -**FastAPI** is volledig verenigbaar met (en gebaseerd op) Pydantic. Dus alle extra Pydantic code die je nog hebt werkt ook. - -Inclusief externe pakketten die ook gebaseerd zijn op Pydantic, zoals ORMs, ODMs voor databases. - -Dit betekent ook dat je in veel gevallen het object dat je van een request krijgt **direct naar je database** kunt sturen, omdat alles automatisch wordt gevalideerd. - -Hetzelfde geldt ook andersom, in veel gevallen kun je dus het object dat je krijgt van de database **direct doorgeven aan de client**. - -Met **FastAPI** krijg je alle functionaliteit van **Pydantic** (omdat FastAPI is gebaseerd op Pydantic voor alle dataverwerking): - -* **Geen brainfucks**: - * Je hoeft geen nieuwe microtaal voor schemadefinities te leren. - * Als je bekend bent Python types, weet je hoe je Pydantic moet gebruiken. -* Werkt goed samen met je **IDE/linter/hersenen**: - * Doordat pydantic's datastructuren enkel instanties zijn van klassen, die je definieert, werkt automatische aanvulling, linting, mypy en je intuïtie allemaal goed met je gevalideerde data. -* Valideer **complexe structuren**: - * Gebruik van hiërarchische Pydantic modellen, Python `typing`'s `List` en `Dict`, enz. - * Met validators kunnen complexe dataschema's duidelijk en eenvoudig worden gedefinieerd, gecontroleerd en gedocumenteerd als JSON Schema. - * Je kunt diep **geneste JSON** objecten laten valideren en annoteren. -* **Uitbreidbaar**: - * Met Pydantic kunnen op maat gemaakte datatypen worden gedefinieerd of je kunt validatie uitbreiden met methoden op een model dat is ingericht met de decorator validator. -* 100% van de code is getest. diff --git a/docs/nl/docs/index.md b/docs/nl/docs/index.md deleted file mode 100644 index 8d4ad92c7..000000000 --- a/docs/nl/docs/index.md +++ /dev/null @@ -1,494 +0,0 @@ -# FastAPI - - - -

- FastAPI -

-

- FastAPI framework, zeer goede prestaties, eenvoudig te leren, snel te programmeren, klaar voor productie -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Documentatie**: https://fastapi.tiangolo.com - -**Broncode**: https://github.com/tiangolo/fastapi - ---- - -FastAPI is een modern, snel (zeer goede prestaties), web framework voor het bouwen van API's in Python, gebruikmakend van standaard Python type-hints. - -De belangrijkste kenmerken zijn: - -* **Snel**: Zeer goede prestaties, vergelijkbaar met **NodeJS** en **Go** (dankzij Starlette en Pydantic). [Een van de snelste beschikbare Python frameworks](#prestaties). -* **Snel te programmeren**: Verhoog de snelheid om functionaliteit te ontwikkelen met ongeveer 200% tot 300%. * -* **Minder bugs**: Verminder ongeveer 40% van de door mensen (ontwikkelaars) veroorzaakte fouten. * -* **Intuïtief**: Buitengewoon goede ondersteuning voor editors. Overal automische code aanvulling. Minder tijd kwijt aan debuggen. -* **Eenvoudig**: Ontworpen om gemakkelijk te gebruiken en te leren. Minder tijd nodig om documentatie te lezen. -* **Kort**: Minimaliseer codeduplicatie. Elke parameterdeclaratie ondersteunt meerdere functionaliteiten. Minder bugs. -* **Robust**: Code gereed voor productie. Met automatische interactieve documentatie. -* **Standards-based**: Gebaseerd op (en volledig verenigbaar met) open standaarden voor API's: OpenAPI (voorheen bekend als Swagger) en JSON Schema. - -* schatting op basis van testen met een intern ontwikkelteam en bouwen van productieapplicaties. - -## Sponsors - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Overige sponsoren - -## Meningen - -"_[...] Ik gebruik **FastAPI** heel vaak tegenwoordig. [...] Ik ben van plan om het te gebruiken voor alle **ML-services van mijn team bij Microsoft**. Sommige van deze worden geïntegreerd in het kernproduct van **Windows** en sommige **Office**-producten._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We hebben de **FastAPI** library gebruikt om een **REST** server te maken die bevraagd kan worden om **voorspellingen** te maken. [voor Ludwig]_" - -
Piero Molino, Yaroslav Dudin en Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is verheugd om een open-source release aan te kondigen van ons **crisismanagement**-orkestratieframework: **Dispatch**! [gebouwd met **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_Ik ben super enthousiast over **FastAPI**. Het is zo leuk!_" - -
Brian Okken - Python Bytes podcast presentator (ref)
- ---- - -"_Wat je hebt gebouwd ziet er echt super solide en gepolijst uit. In veel opzichten is het wat ik wilde dat **Hug** kon zijn - het is echt inspirerend om iemand dit te zien bouwen._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"Wie geïnteresseerd is in een **modern framework** voor het bouwen van REST API's, bekijkt best eens **FastAPI** [...] Het is snel, gebruiksvriendelijk en gemakkelijk te leren [...]_" - -"_We zijn overgestapt naar **FastAPI** voor onze **API's** [...] Het gaat jou vast ook bevallen [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI oprichters - spaCy ontwikkelaars (ref) - (ref)
- ---- - -"_Wie een Python API wil bouwen voor productie, kan ik ten stelligste **FastAPI** aanraden. Het is **prachtig ontworpen**, **eenvoudig te gebruiken** en **gemakkelijk schaalbaar**, het is een **cruciale component** geworden in onze strategie om API's centraal te zetten, en het vereenvoudigt automatisering en diensten zoals onze Virtual TAC Engineer._" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, de FastAPI van CLIs - - - -Als je een CLI-app bouwt die in de terminal moet worden gebruikt in plaats van een web-API, gebruik dan **Typer**. - -**Typer** is het kleine broertje van FastAPI. En het is bedoeld als de **FastAPI van CLI's**. ️ - -## Vereisten - -FastAPI staat op de schouders van reuzen: - -* Starlette voor de webonderdelen. -* Pydantic voor de datadelen. - -## Installatie - -
- -```console -$ pip install "fastapi[standard]" - ----> 100% -``` - -
- -**Opmerking**: Zet `"fastapi[standard]"` tussen aanhalingstekens om ervoor te zorgen dat het werkt in alle terminals. - -## Voorbeeld - -### Creëer het - -* Maak het bestand `main.py` aan met daarin: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Of maak gebruik van async def... - -Als je code gebruik maakt van `async` / `await`, gebruik dan `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Opmerking**: - -Als je het niet weet, kijk dan in het gedeelte _"Heb je haast?"_ over `async` en `await` in de documentatie. - -
- -### Voer het uit - -Run de server met: - -
- -```console -$ fastapi dev main.py - - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - │ fastapi run │ - │ │ - ╰─────────────────────────────────────────────────────╯ - -INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [2248755] using WatchFiles -INFO: Started server process [2248757] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-Over het commando fastapi dev main.py... - -Het commando `fastapi dev` leest het `main.py` bestand, detecteert de **FastAPI** app, en start een server met Uvicorn. - -Standaard zal dit commando `fastapi dev` starten met "auto-reload" geactiveerd voor ontwikkeling op het lokale systeem. - -Je kan hier meer over lezen in de FastAPI CLI documentatie. - -
- -### Controleer het - -Open je browser op http://127.0.0.1:8000/items/5?q=somequery. - -Je zult een JSON response zien: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Je hebt een API gemaakt die: - -* HTTP verzoeken kan ontvangen op de _paden_ `/` en `/items/{item_id}`. -* Beide _paden_ hebben `GET` operaties (ook bekend als HTTP _methoden_). -* Het _pad_ `/items/{item_id}` heeft een _pad parameter_ `item_id` dat een `int` moet zijn. -* Het _pad_ `/items/{item_id}` heeft een optionele `str` _query parameter_ `q`. - -### Interactieve API documentatie - -Ga naar http://127.0.0.1:8000/docs. - -Je ziet de automatische interactieve API documentatie (verstrekt door Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternatieve API documentatie - -Ga vervolgens naar http://127.0.0.1:8000/redoc. - -Je ziet de automatische interactieve API documentatie (verstrekt door ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Voorbeeld upgrade - -Pas nu het bestand `main.py` aan om de body van een `PUT` request te ontvangen. - -Dankzij Pydantic kunnen we de body declareren met standaard Python types. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -De `fastapi dev` server zou automatisch moeten herladen. - -### Interactieve API documentatie upgrade - -Ga nu naar http://127.0.0.1:8000/docs. - -* De interactieve API-documentatie wordt automatisch bijgewerkt, inclusief de nieuwe body: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Klik op de knop "Try it out", hiermee kan je de parameters invullen en direct met de API interacteren: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Klik vervolgens op de knop "Execute", de gebruikersinterface zal communiceren met jouw API, de parameters verzenden, de resultaten ophalen en deze op het scherm tonen: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Alternatieve API documentatie upgrade - -Ga vervolgens naar http://127.0.0.1:8000/redoc. - -* De alternatieve documentatie zal ook de nieuwe queryparameter en body weergeven: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Samenvatting - -Samengevat declareer je **eenmalig** de types van parameters, body, etc. als functieparameters. - -Dat doe je met standaard moderne Python types. - -Je hoeft geen nieuwe syntax te leren, de methods of klassen van een specifieke bibliotheek, etc. - -Gewoon standaard **Python**. - -Bijvoorbeeld, voor een `int`: - -```Python -item_id: int -``` - -of voor een complexer `Item` model: - -```Python -item: Item -``` - -...en met die ene verklaring krijg je: - -* Editor ondersteuning, inclusief: - * Code aanvulling. - * Type validatie. -* Validatie van data: - * Automatische en duidelijke foutboodschappen wanneer de data ongeldig is. - * Validatie zelfs voor diep geneste JSON objecten. -* Conversie van invoergegevens: afkomstig van het netwerk naar Python-data en -types. Zoals: - * JSON. - * Pad parameters. - * Query parameters. - * Cookies. - * Headers. - * Formulieren. - * Bestanden. -* Conversie van uitvoergegevens: converstie van Python-data en -types naar netwerkgegevens (zoals JSON): - * Converteer Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objecten. - * `UUID` objecten. - * Database modellen. - * ...en nog veel meer. -* Automatische interactieve API-documentatie, inclusief 2 alternatieve gebruikersinterfaces: - * Swagger UI. - * ReDoc. - ---- - -Terugkomend op het vorige code voorbeeld, **FastAPI** zal: - -* Valideren dat er een `item_id` bestaat in het pad voor `GET` en `PUT` verzoeken. -* Valideren dat het `item_id` van het type `int` is voor `GET` en `PUT` verzoeken. - * Wanneer dat niet het geval is, krijgt de cliënt een nuttige, duidelijke foutmelding. -* Controleren of er een optionele query parameter is met de naam `q` (zoals in `http://127.0.0.1:8000/items/foo?q=somequery`) voor `GET` verzoeken. - * Aangezien de `q` parameter werd gedeclareerd met `= None`, is deze optioneel. - * Zonder de `None` declaratie zou deze verplicht zijn (net als bij de body in het geval met `PUT`). -* Voor `PUT` verzoeken naar `/items/{item_id}`, lees de body als JSON: - * Controleer of het een verplicht attribuut `naam` heeft en dat dat een `str` is. - * Controleer of het een verplicht attribuut `price` heeft en dat dat een`float` is. - * Controleer of het een optioneel attribuut `is_offer` heeft, dat een `bool` is wanneer het aanwezig is. - * Dit alles werkt ook voor diep geneste JSON objecten. -* Converteer automatisch van en naar JSON. -* Documenteer alles met OpenAPI, dat gebruikt kan worden door: - * Interactieve documentatiesystemen. - * Automatische client code generatie systemen, voor vele talen. -* Biedt 2 interactieve documentatie-webinterfaces aan. - ---- - -Dit was nog maar een snel overzicht, maar je zou nu toch al een idee moeten hebben over hoe het allemaal werkt. - -Probeer deze regel te veranderen: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...van: - -```Python - ... "item_name": item.name ... -``` - -...naar: - -```Python - ... "item_price": item.price ... -``` - -...en zie hoe je editor de attributen automatisch invult en hun types herkent: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Voor een vollediger voorbeeld met meer mogelijkheden, zie de Tutorial - Gebruikershandleiding. - -**Spoiler alert**: de tutorial - gebruikershandleiding bevat: - -* Declaratie van **parameters** op andere plaatsen zoals: **headers**, **cookies**, **formuliervelden** en **bestanden**. -* Hoe stel je **validatie restricties** in zoals `maximum_length` of een `regex`. -* Een zeer krachtig en eenvoudig te gebruiken **Dependency Injection** systeem. -* Beveiliging en authenticatie, inclusief ondersteuning voor **OAuth2** met **JWT-tokens** en **HTTP Basic** auth. -* Meer geavanceerde (maar even eenvoudige) technieken voor het declareren van **diep geneste JSON modellen** (dankzij Pydantic). -* **GraphQL** integratie met Strawberry en andere packages. -* Veel extra functies (dankzij Starlette) zoals: - * **WebSockets** - * uiterst gemakkelijke tests gebaseerd op HTTPX en `pytest` - * **CORS** - * **Cookie Sessions** - * ...en meer. - -## Prestaties - -Onafhankelijke TechEmpower benchmarks tonen **FastAPI** applicaties draaiend onder Uvicorn aan als een van de snelste Python frameworks beschikbaar, alleen onder Starlette en Uvicorn zelf (intern gebruikt door FastAPI). (*) - -Zie de sectie Benchmarks om hier meer over te lezen. - -## Afhankelijkheden - -FastAPI maakt gebruik van Pydantic en Starlette. - -### `standard` Afhankelijkheden - -Wanneer je FastAPI installeert met `pip install "fastapi[standard]"`, worden de volgende `standard` optionele afhankelijkheden geïnstalleerd: - -Gebruikt door Pydantic: - -* email_validator - voor email validatie. - -Gebruikt door Starlette: - -* httpx - Vereist indien je de `TestClient` wil gebruiken. -* jinja2 - Vereist als je de standaard templateconfiguratie wil gebruiken. -* python-multipart - Vereist indien je "parsen" van formulieren wil ondersteunen met `requests.form()`. - -Gebruikt door FastAPI / Starlette: - -* uvicorn - voor de server die jouw applicatie laadt en bedient. -* `fastapi-cli` - om het `fastapi` commando te voorzien. - -### Zonder `standard` Afhankelijkheden - -Indien je de optionele `standard` afhankelijkheden niet wenst te installeren, kan je installeren met `pip install fastapi` in plaats van `pip install "fastapi[standard]"`. - -### Bijkomende Optionele Afhankelijkheden - -Er zijn nog een aantal bijkomende afhankelijkheden die je eventueel kan installeren. - -Bijkomende optionele afhankelijkheden voor Pydantic: - -* pydantic-settings - voor het beheren van settings. -* pydantic-extra-types - voor extra data types die gebruikt kunnen worden met Pydantic. - -Bijkomende optionele afhankelijkheden voor FastAPI: - -* orjson - Vereist indien je `ORJSONResponse` wil gebruiken. -* ujson - Vereist indien je `UJSONResponse` wil gebruiken. - -## Licentie - -Dit project is gelicenseerd onder de voorwaarden van de MIT licentie. diff --git a/docs/nl/docs/python-types.md b/docs/nl/docs/python-types.md deleted file mode 100644 index fb8b1e5fd..000000000 --- a/docs/nl/docs/python-types.md +++ /dev/null @@ -1,587 +0,0 @@ -# Introductie tot Python Types - -Python biedt ondersteuning voor optionele "type hints" (ook wel "type annotaties" genoemd). - -Deze **"type hints"** of annotaties zijn een speciale syntax waarmee het type van een variabele kan worden gedeclareerd. - -Door types voor je variabelen te declareren, kunnen editors en hulpmiddelen je beter ondersteunen. - -Dit is slechts een **korte tutorial/opfrisser** over Python type hints. Het behandelt enkel het minimum dat nodig is om ze te gebruiken met **FastAPI**... en dat is relatief weinig. - -**FastAPI** is helemaal gebaseerd op deze type hints, ze geven veel voordelen. - -Maar zelfs als je **FastAPI** nooit gebruikt, heb je er baat bij om er iets over te leren. - -/// note - -Als je een Python expert bent en alles al weet over type hints, sla dan dit hoofdstuk over. - -/// - -## Motivatie - -Laten we beginnen met een eenvoudig voorbeeld: - -{* ../../docs_src/python_types/tutorial001.py *} - - -Het aanroepen van dit programma leidt tot het volgende resultaat: - -``` -John Doe -``` - -De functie voert het volgende uit: - -* Neem een `first_name` en een `last_name` -* Converteer de eerste letter van elk naar een hoofdletter met `title()`. -`` -* Voeg samen met een spatie in het midden. - -{* ../../docs_src/python_types/tutorial001.py hl[2] *} - - -### Bewerk het - -Dit is een heel eenvoudig programma. - -Maar stel je nu voor dat je het vanaf nul zou moeten maken. - -Op een gegeven moment zou je aan de definitie van de functie zijn begonnen, je had de parameters klaar... - -Maar dan moet je “die methode die de eerste letter naar hoofdletters converteert” aanroepen. - -Was het `upper`? Was het `uppercase`? `first_uppercase`? `capitalize`? - -Dan roep je de hulp in van je oude programmeursvriend, (automatische) code aanvulling in je editor. - -Je typt de eerste parameter van de functie, `first_name`, dan een punt (`.`) en drukt dan op `Ctrl+Spatie` om de aanvulling te activeren. - -Maar helaas krijg je niets bruikbaars: - - - -### Types toevoegen - -Laten we een enkele regel uit de vorige versie aanpassen. - -We zullen precies dit fragment, de parameters van de functie, wijzigen van: - -```Python - first_name, last_name -``` - -naar: - -```Python - first_name: str, last_name: str -``` - -Dat is alles. - -Dat zijn de "type hints": - -{* ../../docs_src/python_types/tutorial002.py hl[1] *} - - -Dit is niet hetzelfde als het declareren van standaardwaarden zoals bij: - -```Python - first_name="john", last_name="doe" -``` - -Het is iets anders. - -We gebruiken dubbele punten (`:`), geen gelijkheidstekens (`=`). - -Het toevoegen van type hints verandert normaal gesproken niet wat er gebeurt in je programma t.o.v. wat er zonder type hints zou gebeuren. - -Maar stel je voor dat je weer bezig bent met het maken van een functie, maar deze keer met type hints. - -Op hetzelfde moment probeer je de automatische aanvulling te activeren met `Ctrl+Spatie` en je ziet: - - - -Nu kun je de opties bekijken en er doorheen scrollen totdat je de optie vindt die “een belletje doet rinkelen”: - - - -### Meer motivatie - -Bekijk deze functie, deze heeft al type hints: - -{* ../../docs_src/python_types/tutorial003.py hl[1] *} - - -Omdat de editor de types van de variabelen kent, krijgt u niet alleen aanvulling, maar ook controles op fouten: - - - -Nu weet je hoe je het moet oplossen, converteer `age` naar een string met `str(age)`: - -{* ../../docs_src/python_types/tutorial004.py hl[2] *} - - -## Types declareren - -Je hebt net de belangrijkste plek om type hints te declareren gezien. Namelijk als functieparameters. - -Dit is ook de belangrijkste plek waar je ze gebruikt met **FastAPI**. - -### Eenvoudige types - -Je kunt alle standaard Python types declareren, niet alleen `str`. - -Je kunt bijvoorbeeld het volgende gebruiken: - -* `int` -* `float` -* `bool` -* `bytes` - -{* ../../docs_src/python_types/tutorial005.py hl[1] *} - - -### Generieke types met typeparameters - -Er zijn enkele datastructuren die andere waarden kunnen bevatten, zoals `dict`, `list`, `set` en `tuple` en waar ook de interne waarden hun eigen type kunnen hebben. - -Deze types die interne types hebben worden “**generieke**” types genoemd. Het is mogelijk om ze te declareren, zelfs met hun interne types. - -Om deze types en de interne types te declareren, kun je de standaard Python module `typing` gebruiken. Deze module is speciaal gemaakt om deze type hints te ondersteunen. - -#### Nieuwere versies van Python - -De syntax met `typing` is **verenigbaar** met alle versies, van Python 3.6 tot aan de nieuwste, inclusief Python 3.9, Python 3.10, enz. - -Naarmate Python zich ontwikkelt, worden **nieuwere versies**, met verbeterde ondersteuning voor deze type annotaties, beschikbaar. In veel gevallen hoef je niet eens de `typing` module te importeren en te gebruiken om de type annotaties te declareren. - -Als je een recentere versie van Python kunt kiezen voor je project, kun je profiteren van die extra eenvoud. - -In alle documentatie staan voorbeelden die compatibel zijn met elke versie van Python (als er een verschil is). - -Bijvoorbeeld “**Python 3.6+**” betekent dat het compatibel is met Python 3.6 of hoger (inclusief 3.7, 3.8, 3.9, 3.10, etc). En “**Python 3.9+**” betekent dat het compatibel is met Python 3.9 of hoger (inclusief 3.10, etc). - -Als je de **laatste versies van Python** kunt gebruiken, gebruik dan de voorbeelden voor de laatste versie, die hebben de **beste en eenvoudigste syntax**, bijvoorbeeld “**Python 3.10+**”. - -#### List - -Laten we bijvoorbeeld een variabele definiëren als een `list` van `str`. - -//// tab | Python 3.9+ - -Declareer de variabele met dezelfde dubbele punt (`:`) syntax. - -Als type, vul `list` in. - -Doordat de list een type is dat enkele interne types bevat, zet je ze tussen vierkante haakjes: - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -Van `typing`, importeer `List` (met een hoofdletter `L`): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Declareer de variabele met dezelfde dubbele punt (`:`) syntax. - -Zet als type de `List` die je hebt geïmporteerd uit `typing`. - -Doordat de list een type is dat enkele interne types bevat, zet je ze tussen vierkante haakjes: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// - -/// info - -De interne types tussen vierkante haakjes worden “typeparameters” genoemd. - -In dit geval is `str` de typeparameter die wordt doorgegeven aan `List` (of `list` in Python 3.9 en hoger). - -/// - -Dat betekent: “de variabele `items` is een `list`, en elk van de items in deze list is een `str`”. - -/// tip - -Als je Python 3.9 of hoger gebruikt, hoef je `List` niet te importeren uit `typing`, je kunt in plaats daarvan hetzelfde reguliere `list` type gebruiken. - -/// - -Door dat te doen, kan je editor ondersteuning bieden, zelfs tijdens het verwerken van items uit de list: - - - -Zonder types is dat bijna onmogelijk om te bereiken. - -Merk op dat de variabele `item` een van de elementen is in de lijst `items`. - -Toch weet de editor dat het een `str` is, en biedt daar vervolgens ondersteuning voor aan. - -#### Tuple en Set - -Je kunt hetzelfde doen om `tuple`s en `set`s te declareren: - -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// - -Dit betekent: - -* De variabele `items_t` is een `tuple` met 3 items, een `int`, nog een `int`, en een `str`. -* De variabele `items_s` is een `set`, en elk van de items is van het type `bytes`. - -#### Dict - -Om een `dict` te definiëren, geef je 2 typeparameters door, gescheiden door komma's. - -De eerste typeparameter is voor de sleutels (keys) van de `dict`. - -De tweede typeparameter is voor de waarden (values) van het `dict`: - -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// - -Dit betekent: - -* De variabele `prices` is een `dict`: - * De sleutels van dit `dict` zijn van het type `str` (bijvoorbeeld de naam van elk item). - * De waarden van dit `dict` zijn van het type `float` (bijvoorbeeld de prijs van elk item). - -#### Union - -Je kunt een variable declareren die van **verschillende types** kan zijn, bijvoorbeeld een `int` of een `str`. - -In Python 3.6 en hoger (inclusief Python 3.10) kun je het `Union`-type van `typing` gebruiken en de mogelijke types die je wilt accepteren, tussen de vierkante haakjes zetten. - -In Python 3.10 is er ook een **nieuwe syntax** waarin je de mogelijke types kunt scheiden door een verticale balk (`|`). - -//// tab | Python 3.10+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008b_py310.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} -``` - -//// - -In beide gevallen betekent dit dat `item` een `int` of een `str` kan zijn. - -#### Mogelijk `None` - -Je kunt declareren dat een waarde een type kan hebben, zoals `str`, maar dat het ook `None` kan zijn. - -In Python 3.6 en hoger (inclusief Python 3.10) kun je het declareren door `Optional` te importeren en te gebruiken vanuit de `typing`-module. - -```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} -``` - -Door `Optional[str]` te gebruiken in plaats van alleen `str`, kan de editor je helpen fouten te detecteren waarbij je ervan uit zou kunnen gaan dat een waarde altijd een `str` is, terwijl het in werkelijkheid ook `None` zou kunnen zijn. - -`Optional[EenType]` is eigenlijk een snelkoppeling voor `Union[EenType, None]`, ze zijn equivalent. - -Dit betekent ook dat je in Python 3.10 `EenType | None` kunt gebruiken: - -//// tab | Python 3.10+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial009_py310.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} -``` - -//// - -//// tab | Python 3.8+ alternative - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} -``` - -//// - -#### Gebruik van `Union` of `Optional` - -Als je een Python versie lager dan 3.10 gebruikt, is dit een tip vanuit mijn **subjectieve** standpunt: - -* 🚨 Vermijd het gebruik van `Optional[EenType]`. -* Gebruik in plaats daarvan **`Union[EenType, None]`** ✨. - -Beide zijn gelijkwaardig en onderliggend zijn ze hetzelfde, maar ik zou `Union` aanraden in plaats van `Optional` omdat het woord “**optional**” lijkt te impliceren dat de waarde optioneel is, en het eigenlijk betekent “het kan `None` zijn”, zelfs als het niet optioneel is en nog steeds vereist is. - -Ik denk dat `Union[SomeType, None]` explicieter is over wat het betekent. - -Het gaat alleen om de woorden en naamgeving. Maar die naamgeving kan invloed hebben op hoe jij en je teamgenoten over de code denken. - -Laten we als voorbeeld deze functie nemen: - -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} - - -De parameter `name` is gedefinieerd als `Optional[str]`, maar is **niet optioneel**, je kunt de functie niet aanroepen zonder de parameter: - -```Python -say_hi() # Oh, nee, dit geeft een foutmelding! 😱 -``` - -De `name` parameter is **nog steeds vereist** (niet *optioneel*) omdat het geen standaardwaarde heeft. Toch accepteert `name` `None` als waarde: - -```Python -say_hi(name=None) # Dit werkt, None is geldig 🎉 -``` - -Het goede nieuws is dat als je eenmaal Python 3.10 gebruikt, je je daar geen zorgen meer over hoeft te maken, omdat je dan gewoon `|` kunt gebruiken om unions van types te definiëren: - -{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} - - -Dan hoef je je geen zorgen te maken over namen als `Optional` en `Union`. 😎 - -#### Generieke typen - -De types die typeparameters in vierkante haakjes gebruiken, worden **Generieke types** of **Generics** genoemd, bijvoorbeeld: - -//// tab | Python 3.10+ - -Je kunt dezelfde ingebouwde types gebruiken als generics (met vierkante haakjes en types erin): - -* `list` -* `tuple` -* `set` -* `dict` - -Hetzelfde als bij Python 3.8, uit de `typing`-module: - -* `Union` -* `Optional` (hetzelfde als bij Python 3.8) -* ...en anderen. - -In Python 3.10 kun je , als alternatief voor de generieke `Union` en `Optional`, de verticale lijn (`|`) gebruiken om unions van typen te voorzien, dat is veel beter en eenvoudiger. - -//// - -//// tab | Python 3.9+ - -Je kunt dezelfde ingebouwde types gebruiken als generieke types (met vierkante haakjes en types erin): - -* `list` -* `tuple` -* `set` -* `dict` - -En hetzelfde als met Python 3.8, vanuit de `typing`-module: - -* `Union` -* `Optional` -* ...en anderen. - -//// - -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...en anderen. - -//// - -### Klassen als types - -Je kunt een klasse ook declareren als het type van een variabele. - -Stel dat je een klasse `Person` hebt, met een naam: - -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} - - -Vervolgens kun je een variabele van het type `Persoon` declareren: - -{* ../../docs_src/python_types/tutorial010.py hl[6] *} - - -Dan krijg je ook nog eens volledige editorondersteuning: - - - -Merk op dat dit betekent dat "`one_person` een **instantie** is van de klasse `Person`". - -Dit betekent niet dat `one_person` de **klasse** is met de naam `Person`. - -## Pydantic modellen - -Pydantic is een Python-pakket voor het uitvoeren van datavalidatie. - -Je declareert de "vorm" van de data als klassen met attributen. - -Elk attribuut heeft een type. - -Vervolgens maak je een instantie van die klasse met een aantal waarden en het valideert de waarden, converteert ze naar het juiste type (als dat het geval is) en geeft je een object met alle data terug. - -Daarnaast krijg je volledige editorondersteuning met dat resulterende object. - -Een voorbeeld uit de officiële Pydantic-documentatie: - -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// - -/// info - -Om meer te leren over Pydantic, bekijk de documentatie. - -/// - -**FastAPI** is volledig gebaseerd op Pydantic. - -Je zult veel meer van dit alles in de praktijk zien in de [Tutorial - Gebruikershandleiding](tutorial/index.md){.internal-link target=_blank}. - -/// tip - -Pydantic heeft een speciaal gedrag wanneer je `Optional` of `Union[EenType, None]` gebruikt zonder een standaardwaarde, je kunt er meer over lezen in de Pydantic-documentatie over Verplichte optionele velden. - -/// - -## Type Hints met Metadata Annotaties - -Python heeft ook een functie waarmee je **extra metadata** in deze type hints kunt toevoegen met behulp van `Annotated`. - -//// tab | Python 3.9+ - -In Python 3.9 is `Annotated` onderdeel van de standaardpakket, dus je kunt het importeren vanuit `typing`. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -In versies lager dan Python 3.9 importeer je `Annotated` vanuit `typing_extensions`. - -Het wordt al geïnstalleerd met **FastAPI**. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// - -Python zelf doet niets met deze `Annotated` en voor editors en andere hulpmiddelen is het type nog steeds een `str`. - -Maar je kunt deze ruimte in `Annotated` gebruiken om **FastAPI** te voorzien van extra metadata over hoe je wilt dat je applicatie zich gedraagt. - -Het belangrijkste om te onthouden is dat **de eerste *typeparameter*** die je doorgeeft aan `Annotated` het **werkelijke type** is. De rest is gewoon metadata voor andere hulpmiddelen. - -Voor nu hoef je alleen te weten dat `Annotated` bestaat en dat het standaard Python is. 😎 - -Later zul je zien hoe **krachtig** het kan zijn. - -/// tip - -Het feit dat dit **standaard Python** is, betekent dat je nog steeds de **best mogelijke ontwikkelaarservaring** krijgt in je editor, met de hulpmiddelen die je gebruikt om je code te analyseren en te refactoren, enz. ✨ - -Daarnaast betekent het ook dat je code zeer verenigbaar zal zijn met veel andere Python-hulpmiddelen en -pakketten. 🚀 - -/// - -## Type hints in **FastAPI** - -**FastAPI** maakt gebruik van type hints om verschillende dingen te doen. - -Met **FastAPI** declareer je parameters met type hints en krijg je: - -* **Editor ondersteuning**. -* **Type checks**. - -...en **FastAPI** gebruikt dezelfde declaraties om: - -* **Vereisten te definïeren **: van request pad parameters, query parameters, headers, bodies, dependencies, enz. -* **Data te converteren**: van de request naar het vereiste type. -* **Data te valideren**: afkomstig van elke request: - * **Automatische foutmeldingen** te genereren die naar de client worden geretourneerd wanneer de data ongeldig is. -* De API met OpenAPI te **documenteren**: - * die vervolgens wordt gebruikt door de automatische interactieve documentatie gebruikersinterfaces. - -Dit klinkt misschien allemaal abstract. Maak je geen zorgen. Je ziet dit allemaal in actie in de [Tutorial - Gebruikershandleiding](tutorial/index.md){.internal-link target=_blank}. - -Het belangrijkste is dat door standaard Python types te gebruiken, op één plek (in plaats van meer klassen, decorators, enz. toe te voegen), **FastAPI** een groot deel van het werk voor je doet. - -/// info - -Als je de hele tutorial al hebt doorgenomen en terug bent gekomen om meer te weten te komen over types, is een goede bron het "cheat sheet" van `mypy`. - -/// diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/nl/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/pl/docs/features.md b/docs/pl/docs/features.md deleted file mode 100644 index 80d3bdece..000000000 --- a/docs/pl/docs/features.md +++ /dev/null @@ -1,201 +0,0 @@ -# Cechy - -## Cechy FastAPI - -**FastAPI** zapewnia Ci następujące korzyści: - -### Oparcie o standardy open - -* OpenAPI do tworzenia API, w tym deklaracji ścieżek operacji, parametrów, ciał zapytań, bezpieczeństwa, itp. -* Automatyczna dokumentacja modelu danych za pomocą JSON Schema (ponieważ OpenAPI bazuje na JSON Schema). -* Zaprojektowane z myślą o zgodności z powyższymi standardami zamiast dodawania ich obsługi po fakcie. -* Możliwość automatycznego **generowania kodu klienta** w wielu językach. - -### Automatyczna dokumentacja - -Interaktywna dokumentacja i webowe interfejsy do eksploracji API. Z racji tego, że framework bazuje na OpenAPI, istnieje wiele opcji, z czego 2 są domyślnie dołączone. - -* Swagger UI, z interaktywnym interfejsem - odpytuj i testuj swoje API bezpośrednio z przeglądarki. - -![Swagger UI interakcja](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Alternatywna dokumentacja API z ReDoc. - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Nowoczesny Python - -Wszystko opiera się na standardowych deklaracjach typu **Python 3.8** (dzięki Pydantic). Brak nowej składni do uczenia. Po prostu standardowy, współczesny Python. - -Jeśli potrzebujesz szybkiego przypomnienia jak używać deklaracji typów w Pythonie (nawet jeśli nie używasz FastAPI), sprawdź krótki samouczek: [Python Types](python-types.md){.internal-link target=_blank}. - -Wystarczy, że napiszesz standardowe deklaracje typów Pythona: - -```Python -from datetime import date - -from pydantic import BaseModel - -# Zadeklaruj parametr jako str -# i uzyskaj wsparcie edytora wewnątrz funkcji -def main(user_id: str): - return user_id - - -# Model Pydantic -class User(BaseModel): - id: int - name: str - joined: date -``` - -A one będą mogły zostać później użyte w następujący sposób: - -```Python -my_user: User = User(id=3, name="John Doe", joined="2018-07-19") - -second_user_data = { - "id": 4, - "name": "Mary", - "joined": "2018-11-30", -} - -my_second_user: User = User(**second_user_data) -``` - -/// info - -`**second_user_data` oznacza: - -Przekaż klucze i wartości słownika `second_user_data` bezpośrednio jako argumenty klucz-wartość, co jest równoznaczne z: `User(id=4, name="Mary", joined="2018-11-30")` - -/// - -### Wsparcie edytora - -Cały framework został zaprojektowany tak, aby był łatwy i intuicyjny w użyciu. Wszystkie pomysły zostały przetestowane na wielu edytorach jeszcze przed rozpoczęciem procesu tworzenia, aby zapewnić najlepsze wrażenia programistyczne. - -Ostatnia ankieta Python developer survey jasno wskazuje, że najczęściej używaną funkcjonalnością jest autouzupełnianie w edytorze. - -Cała struktura frameworku **FastAPI** jest na tym oparta. Autouzupełnianie działa wszędzie. - -Rzadko będziesz musiał wracać do dokumentacji. - -Oto, jak twój edytor może Ci pomóc: - -* Visual Studio Code: - -![wsparcie edytora](https://fastapi.tiangolo.com/img/vscode-completion.png) - -* PyCharm: - -![wsparcie edytora](https://fastapi.tiangolo.com/img/pycharm-completion.png) - -Otrzymasz uzupełnienie nawet w miejscach, w których normalnie uzupełnienia nie ma. Na przykład klucz "price" w treści JSON (który mógł być zagnieżdżony), który pochodzi z zapytania. - -Koniec z wpisywaniem błędnych nazw kluczy, przechodzeniem tam i z powrotem w dokumentacji lub przewijaniem w górę i w dół, aby sprawdzić, czy w końcu użyłeś nazwy `username` czy `user_name`. - -### Zwięzłość - -Wszystko posiada sensowne **domyślne wartości**. Wszędzie znajdziesz opcjonalne konfiguracje. Wszystkie parametry możesz dostroić, aby zrobić to co potrzebujesz do zdefiniowania API. - -Ale domyślnie wszystko **"po prostu działa"**. - -### Walidacja - -* Walidacja większości (lub wszystkich?) **typów danych** Pythona, w tym: - * Obiektów JSON (`dict`). - * Tablic JSON (`list`) ze zdefiniowanym typem elementów. - * Pól tekstowych (`str`) z określeniem minimalnej i maksymalnej długości. - * Liczb (`int`, `float`) z wartościami minimalnymi, maksymalnymi, itp. - -* Walidacja bardziej egzotycznych typów danych, takich jak: - * URL. - * Email. - * UUID. - * ...i inne. - -Cała walidacja jest obsługiwana przez ugruntowaną i solidną bibliotekę **Pydantic**. - -### Bezpieczeństwo i uwierzytelnianie - -Bezpieczeństwo i uwierzytelnianie jest zintegrowane. Bez żadnych kompromisów z bazami czy modelami danych. - -Wszystkie schematy bezpieczeństwa zdefiniowane w OpenAPI, w tym: - -* Podstawowy protokół HTTP. -* **OAuth2** (również z **tokenami JWT**). Sprawdź samouczek [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. -* Klucze API w: - * Nagłówkach. - * Parametrach zapytań. - * Ciasteczkach, itp. - -Plus wszystkie funkcje bezpieczeństwa Starlette (włączając w to **ciasteczka sesyjne**). - -Wszystko zbudowane jako narzędzia i komponenty wielokrotnego użytku, które można łatwo zintegrować z systemami, magazynami oraz bazami danych - relacyjnymi, NoSQL, itp. - -### Wstrzykiwanie Zależności - -FastAPI zawiera niezwykle łatwy w użyciu, ale niezwykle potężny system Wstrzykiwania Zależności. - -* Nawet zależności mogą mieć zależności, tworząc hierarchię lub **"graf" zależności**. -* Wszystko jest **obsługiwane automatycznie** przez framework. -* Wszystkie zależności mogą wymagać danych w żądaniach oraz rozszerzać ograniczenia i automatyczną dokumentację **operacji na ścieżce**. -* **Automatyczna walidacja** parametrów *operacji na ścieżce* zdefiniowanych w zależnościach. -* Obsługa złożonych systemów uwierzytelniania użytkowników, **połączeń z bazami danych**, itp. -* Bazy danych, front end, itp. **bez kompromisów**, ale wciąż łatwe do integracji. - -### Nieograniczone "wtyczki" - -Lub ujmując to inaczej - brak potrzeby wtyczek. Importuj i używaj kod, który potrzebujesz. - -Każda integracja została zaprojektowana tak, aby była tak prosta w użyciu (z zależnościami), że możesz utworzyć "wtyczkę" dla swojej aplikacji w 2 liniach kodu, używając tej samej struktury i składni, które są używane w *operacjach na ścieżce*. - -### Testy - -* 100% pokrycia kodu testami. -* 100% adnotacji typów. -* Używany w aplikacjach produkcyjnych. - -## Cechy Starlette - -**FastAPI** jest w pełni kompatybilny z (oraz bazuje na) Starlette. Tak więc każdy dodatkowy kod Starlette, który posiadasz, również będzie działał. - -`FastAPI` jest w rzeczywistości podklasą `Starlette`, więc jeśli już znasz lub używasz Starlette, większość funkcji będzie działać w ten sam sposób. - -Dzięki **FastAPI** otrzymujesz wszystkie funkcje **Starlette** (ponieważ FastAPI to po prostu Starlette na sterydach): - -* Bardzo imponująca wydajność. Jest to jeden z najszybszych dostępnych frameworków Pythona, na równi z **NodeJS** i **Go**. -* Wsparcie dla **WebSocket**. -* Zadania w tle. -* Eventy startup i shutdown. -* Klient testowy zbudowany na bazie biblioteki `requests`. -* **CORS**, GZip, pliki statyczne, streamy. -* Obsługa **sesji i ciasteczek**. -* 100% pokrycie testami. -* 100% adnotacji typów. - -## Cechy Pydantic - -**FastAPI** jest w pełni kompatybilny z (oraz bazuje na) Pydantic. Tak więc każdy dodatkowy kod Pydantic, który posiadasz, również będzie działał. - -Wliczając w to zewnętrzne biblioteki, również oparte o Pydantic, takie jak ORM, ODM dla baz danych. - -Oznacza to, że w wielu przypadkach możesz przekazać ten sam obiekt, który otrzymasz z żądania **bezpośrednio do bazy danych**, ponieważ wszystko jest walidowane automatycznie. - -Działa to również w drugą stronę, w wielu przypadkach możesz po prostu przekazać obiekt otrzymany z bazy danych **bezpośrednio do klienta**. - -Dzięki **FastAPI** otrzymujesz wszystkie funkcje **Pydantic** (ponieważ FastAPI bazuje na Pydantic do obsługi wszystkich danych): - -* **Bez prania mózgu**: - * Brak nowego mikrojęzyka do definiowania schematu, którego trzeba się nauczyć. - * Jeśli znasz adnotacje typów Pythona to wiesz jak używać Pydantic. -* Dobrze współpracuje z Twoim **IDE/linterem/mózgiem**: - * Ponieważ struktury danych Pydantic to po prostu instancje klas, które definiujesz; autouzupełnianie, linting, mypy i twoja intuicja powinny działać poprawnie z Twoimi zwalidowanymi danymi. -* Walidacja **złożonych struktur**: - * Wykorzystanie hierarchicznych modeli Pydantic, Pythonowego modułu `typing` zawierającego `List`, `Dict`, itp. - * Walidatory umożliwiają jasne i łatwe definiowanie, sprawdzanie złożonych struktur danych oraz dokumentowanie ich jako JSON Schema. - * Możesz mieć głęboko **zagnieżdżone obiekty JSON** i wszystkie je poddać walidacji i adnotować. -* **Rozszerzalność**: - * Pydantic umożliwia zdefiniowanie niestandardowych typów danych lub rozszerzenie walidacji o metody na modelu, na których użyty jest dekorator walidatora. -* 100% pokrycie testami. diff --git a/docs/pl/docs/help-fastapi.md b/docs/pl/docs/help-fastapi.md deleted file mode 100644 index 05e491d55..000000000 --- a/docs/pl/docs/help-fastapi.md +++ /dev/null @@ -1,269 +0,0 @@ -# Pomóż FastAPI - Uzyskaj pomoc - -Czy podoba Ci się **FastAPI**? - -Czy chciałbyś pomóc FastAPI, jego użytkownikom i autorowi? - -Może napotkałeś na trudności z **FastAPI** i potrzebujesz pomocy? - -Istnieje kilka bardzo łatwych sposobów, aby pomóc (czasami wystarczy jedno lub dwa kliknięcia). - -Istnieje również kilka sposobów uzyskania pomocy. - -## Zapisz się do newslettera - -Możesz zapisać się do rzadkiego [newslettera o **FastAPI i jego przyjaciołach**](newsletter.md){.internal-link target=_blank}, aby być na bieżąco z: - -* Aktualnościami o FastAPI i przyjaciołach 🚀 -* Przewodnikami 📝 -* Funkcjami ✨ -* Przełomowymi zmianami 🚨 -* Poradami i sztuczkami ✅ - -## Śledź FastAPI na X (Twitter) - -Śledź @fastapi na **X (Twitter)** aby być na bieżąco z najnowszymi wiadomościami o **FastAPI**. 🐦 - -## Dodaj gwiazdkę **FastAPI** na GitHubie - -Możesz "dodać gwiazdkę" FastAPI na GitHubie (klikając przycisk gwiazdki w prawym górnym rogu): https://github.com/fastapi/fastapi. ⭐️ - -Dodając gwiazdkę, inni użytkownicy będą mogli łatwiej znaleźć projekt i zobaczyć, że był już przydatny dla innych. - -## Obserwuj repozytorium GitHub w poszukiwaniu nowych wydań - -Możesz "obserwować" FastAPI na GitHubie (klikając przycisk "obserwuj" w prawym górnym rogu): https://github.com/fastapi/fastapi. 👀 - -Wybierz opcję "Tylko wydania". - -Dzięki temu będziesz otrzymywać powiadomienia (na swój adres e-mail) za każdym razem, gdy pojawi się nowe wydanie (nowa wersja) **FastAPI** z poprawkami błędów i nowymi funkcjami. - -## Skontaktuj się z autorem - -Możesz skontaktować się ze mną (Sebastián Ramírez / `tiangolo`), autorem. - -Możesz: - -* Śledzić mnie na **GitHubie**. - * Zobacz inne projekty open source, które stworzyłem, a mogą być dla Ciebie pomocne. - * Śledź mnie, aby dostać powiadomienie, gdy utworzę nowy projekt open source. -* Śledzić mnie na **X (Twitter)** lub na Mastodonie. - * Napisz mi, w jaki sposób korzystasz z FastAPI (uwielbiam o tym czytać). - * Dowiedz się, gdy ogłoszę coś nowego lub wypuszczę nowe narzędzia. - * Możesz także śledzić @fastapi na X (Twitter) (to oddzielne konto). -* Nawiąż ze mną kontakt na **Linkedinie**. - * Dowiedz się, gdy ogłoszę coś nowego lub wypuszczę nowe narzędzia (chociaż częściej korzystam z Twittera 🤷‍♂). -* Czytaj moje posty (lub śledź mnie) na **Dev.to** lub na **Medium**. - * Czytaj o innych pomysłach, artykułach i dowiedz się o narzędziach, które stworzyłem. - * Śledź mnie, by wiedzieć gdy opublikuję coś nowego. - -## Napisz tweeta o **FastAPI** - -Napisz tweeta o **FastAPI** i powiedz czemu Ci się podoba. 🎉 - -Uwielbiam czytać w jaki sposób **FastAPI** jest używane, co Ci się w nim podobało, w jakim projekcie/firmie go używasz itp. - -## Głosuj na FastAPI - -* Głosuj na **FastAPI** w Slant. -* Głosuj na **FastAPI** w AlternativeTo. -* Powiedz, że używasz **FastAPI** na StackShare. - -## Pomagaj innym, odpowiadając na ich pytania na GitHubie - -Możesz spróbować pomóc innym, odpowiadając w: - -* Dyskusjach na GitHubie -* Problemach na GitHubie - -W wielu przypadkach możesz już znać odpowiedź na te pytania. 🤓 - -Jeśli pomożesz wielu ludziom, możesz zostać oficjalnym [Ekspertem FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 - -Pamiętaj tylko o najważniejszym: bądź życzliwy. Ludzie przychodzą sfrustrowani i w wielu przypadkach nie zadają pytań w najlepszy sposób, ale mimo to postaraj się być dla nich jak najbardziej życzliwy. 🤗 - -Chciałbym, by społeczność **FastAPI** była życzliwa i przyjazna. Nie akceptuj prześladowania ani braku szacunku wobec innych. Dbajmy o siebie nawzajem. - ---- - -Oto, jak pomóc innym z pytaniami (w dyskusjach lub problemach): - -### Zrozum pytanie - -* Upewnij się, czy rozumiesz **cel** i przypadek użycia osoby pytającej. - -* Następnie sprawdź, czy pytanie (większość to pytania) jest **jasne**. - -* W wielu przypadkach zadane pytanie dotyczy rozwiązania wymyślonego przez użytkownika, ale może istnieć **lepsze** rozwiązanie. Jeśli dokładnie zrozumiesz problem i przypadek użycia, być może będziesz mógł zaproponować lepsze **alternatywne rozwiązanie**. - -* Jeśli nie rozumiesz pytania, poproś o więcej **szczegółów**. - -### Odtwórz problem - -W większości przypadków problem wynika z **autorskiego kodu** osoby pytającej. - -Często pytający umieszczają tylko fragment kodu, niewystarczający do **odtworzenia problemu**. - -* Możesz poprosić ich o dostarczenie minimalnego, odtwarzalnego przykładu, który możesz **skopiować i wkleić** i uruchomić lokalnie, aby zobaczyć ten sam błąd lub zachowanie, które widzą, lub lepiej zrozumieć ich przypadki użycia. - -* Jeśli jesteś wyjątkowo pomocny, możesz spróbować **stworzyć taki przykład** samodzielnie, opierając się tylko na opisie problemu. Miej na uwadze, że może to zająć dużo czasu i lepiej może być najpierw poprosić ich o wyjaśnienie problemu. - -### Proponuj rozwiązania - -* Po zrozumieniu pytania możesz podać im możliwą **odpowiedź**. - -* W wielu przypadkach lepiej zrozumieć ich **podstawowy problem lub przypadek użycia**, ponieważ może istnieć lepszy sposób rozwiązania niż to, co próbują zrobić. - -### Poproś o zamknięcie - -Jeśli odpowiedzą, jest duża szansa, że rozwiązałeś ich problem, gratulacje, **jesteś bohaterem**! 🦸 - -* Jeśli Twoja odpowiedź rozwiązała problem, możesz poprosić o: - - * W Dyskusjach na GitHubie: oznaczenie komentarza jako **odpowiedź**. - * W Problemach na GitHubie: **zamknięcie** problemu. - -## Obserwuj repozytorium na GitHubie - -Możesz "obserwować" FastAPI na GitHubie (klikając przycisk "obserwuj" w prawym górnym rogu): https://github.com/fastapi/fastapi. 👀 - -Jeśli wybierzesz "Obserwuj" zamiast "Tylko wydania", otrzymasz powiadomienia, gdy ktoś utworzy nowy problem lub pytanie. Możesz również określić, że chcesz być powiadamiany tylko o nowych problemach, dyskusjach, PR-ach itp. - -Następnie możesz spróbować pomóc rozwiązać te problemy. - -## Zadawaj pytania - -Możesz utworzyć nowe pytanie w repozytorium na GitHubie, na przykład aby: - -* Zadać **pytanie** lub zapytać o **problem**. -* Zaproponować nową **funkcję**. - -**Uwaga**: jeśli to zrobisz, poproszę Cię również o pomoc innym. 😉 - -## Przeglądaj Pull Requesty - -Możesz pomóc mi w przeglądaniu pull requestów autorstwa innych osób. - -Jak wcześniej wspomniałem, postaraj się być jak najbardziej życzliwy. 🤗 - ---- - -Oto, co warto mieć na uwadze podczas oceny pull requestu: - -### Zrozum problem - -* Najpierw upewnij się, że **rozumiesz problem**, który próbuje rozwiązać pull request. Może być osadzony w większym kontekście w GitHubowej dyskusji lub problemie. - -* Jest też duża szansa, że pull request nie jest konieczny, ponieważ problem można rozwiązać w **inny sposób**. Wtedy możesz to zasugerować lub o to zapytać. - -### Nie martw się stylem - -* Nie przejmuj się zbytnio rzeczami takimi jak style wiadomości commitów, przy wcielaniu pull requesta łączę commity i modyfikuję opis sumarycznego commita ręcznie. - -* Nie przejmuj się również stylem kodu, automatyczne narzędzia w repozytorium sprawdzają to samodzielnie. - -A jeśli istnieje jakaś konkretna potrzeba dotycząca stylu lub spójności, sam poproszę o zmiany lub dodam commity z takimi zmianami. - -### Sprawdź kod - -* Przeczytaj kod, zastanów się czy ma sens, **uruchom go lokalnie** i potwierdź czy faktycznie rozwiązuje problem. - -* Następnie dodaj **komentarz** z informacją o tym, że sprawdziłeś kod, dzięki temu będę miał pewność, że faktycznie go sprawdziłeś. - -/// info - -Niestety, nie mogę ślepo ufać PR-om, nawet jeśli mają kilka zatwierdzeń. - -Kilka razy zdarzyło się, że PR-y miały 3, 5 lub więcej zatwierdzeń (prawdopodobnie dlatego, że opis obiecuje rozwiązanie ważnego problemu), ale gdy sam sprawdziłem danego PR-a, okazał się być zbugowany lub nie rozwiązywał problemu, który rzekomo miał rozwiązywać. 😅 - -Dlatego tak ważne jest, abyś faktycznie przeczytał i uruchomił kod oraz napisał w komentarzu, że to zrobiłeś. 🤓 - -/// - -* Jeśli PR można uprościć w jakiś sposób, możesz o to poprosić, ale nie ma potrzeby być zbyt wybrednym, może być wiele subiektywnych punktów widzenia (a ja też będę miał swój 🙈), więc lepiej żebyś skupił się na kluczowych rzeczach. - -### Testy - -* Pomóż mi sprawdzić, czy PR ma **testy**. - -* Sprawdź, czy testy **nie przechodzą** przed PR. 🚨 - -* Następnie sprawdź, czy testy **przechodzą** po PR. ✅ - -* Wiele PR-ów nie ma testów, możesz **przypomnieć** im o dodaniu testów, a nawet **zaproponować** samemu jakieś testy. To jedna z rzeczy, które pochłaniają najwięcej czasu i możesz w tym bardzo pomóc. - -* Następnie skomentuj również to, czego spróbowałeś, wtedy będę wiedział, że to sprawdziłeś. 🤓 - -## Utwórz Pull Request - -Możesz [wnieść wkład](contributing.md){.internal-link target=_blank} do kodu źródłowego za pomocą Pull Requestu, na przykład: - -* Naprawić literówkę, którą znalazłeś w dokumentacji. -* Podzielić się artykułem, filmem lub podcastem, który stworzyłeś lub znalazłeś na temat FastAPI, edytując ten plik. - * Upewnij się, że dodajesz swój link na początku odpowiedniej sekcji. -* Pomóc w [tłumaczeniu dokumentacji](contributing.md#translations){.internal-link target=_blank} na Twój język. - * Możesz również pomóc w weryfikacji tłumaczeń stworzonych przez innych. -* Zaproponować nowe sekcje dokumentacji. -* Naprawić istniejący problem/błąd. - * Upewnij się, że dodajesz testy. -* Dodać nową funkcję. - * Upewnij się, że dodajesz testy. - * Upewnij się, że dodajesz dokumentację, jeśli jest to istotne. - -## Pomóż w utrzymaniu FastAPI - -Pomóż mi utrzymać **FastAPI**! 🤓 - -Jest wiele pracy do zrobienia, a w większości przypadków **TY** możesz to zrobić. - -Główne zadania, które możesz wykonać teraz to: - -* [Pomóc innym z pytaniami na GitHubie](#pomagaj-innym-odpowiadajac-na-ich-pytania-na-githubie){.internal-link target=_blank} (zobacz sekcję powyżej). -* [Oceniać Pull Requesty](#przegladaj-pull-requesty){.internal-link target=_blank} (zobacz sekcję powyżej). - -Te dwie czynności **zajmują najwięcej czasu**. To główna praca związana z utrzymaniem FastAPI. - -Jeśli możesz mi w tym pomóc, **pomożesz mi utrzymać FastAPI** i zapewnisz że będzie **rozwijać się szybciej i lepiej**. 🚀 - -## Dołącz do czatu - -Dołącz do 👥 serwera czatu na Discordzie 👥 i spędzaj czas z innymi w społeczności FastAPI. - -/// tip | Wskazówka - -Jeśli masz pytania, zadaj je w Dyskusjach na GitHubie, jest dużo większa szansa, że otrzymasz pomoc od [Ekspertów FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. - -Używaj czatu tylko do innych ogólnych rozmów. - -/// - -### Nie zadawaj pytań na czacie - -Miej na uwadze, że ponieważ czaty pozwalają na bardziej "swobodną rozmowę", łatwo jest zadawać pytania, które są zbyt ogólne i trudniejsze do odpowiedzi, więc możesz nie otrzymać odpowiedzi. - -Na GitHubie szablon poprowadzi Cię do napisania odpowiedniego pytania, dzięki czemu łatwiej uzyskasz dobrą odpowiedź, a nawet rozwiążesz problem samodzielnie, zanim zapytasz. Ponadto na GitHubie mogę się upewnić, że zawsze odpowiadam na wszystko, nawet jeśli zajmuje to trochę czasu. Osobiście nie mogę tego zrobić z systemami czatu. 😅 - -Rozmów w systemach czatu nie można tak łatwo przeszukiwać, jak na GitHubie, więc pytania i odpowiedzi mogą zaginąć w rozmowie. A tylko te na GitHubie liczą się do zostania [Ekspertem FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, więc najprawdopodobniej otrzymasz więcej uwagi na GitHubie. - -Z drugiej strony w systemach czatu są tysiące użytkowników, więc jest duża szansa, że znajdziesz tam kogoś do rozmowy, prawie w każdej chwili. 😄 - -## Wspieraj autora - -Możesz również finansowo wesprzeć autora (mnie) poprzez sponsoring na GitHubie. - -Tam możesz postawić mi kawę ☕️ aby podziękować. 😄 - -Możesz także zostać srebrnym lub złotym sponsorem FastAPI. 🏅🎉 - -## Wspieraj narzędzia, które napędzają FastAPI - -Jak widziałeś w dokumentacji, FastAPI stoi na ramionach gigantów, Starlette i Pydantic. - -Możesz również wesprzeć: - -* Samuel Colvin (Pydantic) -* Encode (Starlette, Uvicorn) - ---- - -Dziękuję! 🚀 diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md deleted file mode 100644 index 976d610d4..000000000 --- a/docs/pl/docs/index.md +++ /dev/null @@ -1,467 +0,0 @@ -# FastAPI - - - -

- FastAPI -

-

- FastAPI to szybki, prosty w nauce i gotowy do użycia w produkcji framework -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Dokumentacja**: https://fastapi.tiangolo.com - -**Kod żródłowy**: https://github.com/fastapi/fastapi - ---- - -FastAPI to nowoczesny, wydajny framework webowy do budowania API z użyciem Pythona bazujący na standardowym typowaniu Pythona. - -Kluczowe cechy: - -* **Wydajność**: FastAPI jest bardzo wydajny, na równi z **NodeJS** oraz **Go** (dzięki Starlette i Pydantic). [Jeden z najszybszych dostępnych frameworków Pythonowych](#wydajnosc). -* **Szybkość kodowania**: Przyśpiesza szybkość pisania nowych funkcjonalności o około 200% do 300%. * -* **Mniejsza ilość błędów**: Zmniejsza ilość ludzkich (dewelopera) błędy o około 40%. * -* **Intuicyjność**: Wspaniałe wsparcie dla edytorów kodu. Dostępne wszędzie automatyczne uzupełnianie kodu. Krótszy czas debugowania. -* **Łatwość**: Zaprojektowany by być prosty i łatwy do nauczenia. Mniej czasu spędzonego na czytanie dokumentacji. -* **Kompaktowość**: Minimalizacja powtarzającego się kodu. Wiele funkcjonalności dla każdej deklaracji parametru. Mniej błędów. -* **Solidność**: Kod gotowy dla środowiska produkcyjnego. Wraz z automatyczną interaktywną dokumentacją. -* **Bazujący na standardach**: Oparty na (i w pełni kompatybilny z) otwartych standardach API: OpenAPI (wcześniej znane jako Swagger) oraz JSON Schema. - -* oszacowania bazowane na testach wykonanych przez wewnętrzny zespół deweloperów, budujących aplikacie używane na środowisku produkcyjnym. - -## Sponsorzy - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Inni sponsorzy - -## Opinie - -"_[...] 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._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" - -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -## **Typer**, FastAPI aplikacji konsolowych - - - -Jeżeli tworzysz aplikacje CLI, która ma być używana w terminalu zamiast API, sprawdź **Typer**. - -**Typer** to młodsze rodzeństwo FastAPI. Jego celem jest pozostanie **FastAPI aplikacji konsolowych** . ⌨️ 🚀 - -## Wymagania - -FastAPI oparty jest na: - -* Starlette dla części webowej. -* Pydantic dla części obsługujących dane. - -## Instalacja - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
- -Na serwerze produkcyjnym będziesz także potrzebował serwera ASGI, np. Uvicorn lub Hypercorn. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## Przykład - -### Stwórz - -* Utwórz plik o nazwie `main.py` z: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Albo użyj async def... - -Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Przypis**: - -Jeżeli nie znasz, sprawdź sekcję _"In a hurry?"_ o `async` i `await` w dokumentacji. - -
- -### Uruchom - -Uruchom serwer używając: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-O komendzie uvicorn main:app --reload... -Komenda `uvicorn main:app` odnosi się do: - -* `main`: plik `main.py` ("moduł" w Pythonie). -* `app`: obiekt stworzony w `main.py` w lini `app = FastAPI()`. -* `--reload`: spraw by serwer resetował się po każdej zmianie w kodzie. Używaj tego tylko w środowisku deweloperskim. - -
- -### Wypróbuj - -Otwórz link http://127.0.0.1:8000/items/5?q=somequery w przeglądarce. - -Zobaczysz następującą odpowiedź JSON: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -Właśnie stworzyłeś API które: - -* Otrzymuje żądania HTTP w _ścieżce_ `/` i `/items/{item_id}`. -* Obie _ścieżki_ używają operacji `GET` (znane także jako _metody_ HTTP). -* _Ścieżka_ `/items/{item_id}` ma _parametr ścieżki_ `item_id` który powinien być obiektem typu `int`. -* _Ścieżka_ `/items/{item_id}` ma opcjonalny _parametr zapytania_ typu `str` o nazwie `q`. - -### Interaktywna dokumentacja API - -Otwórz teraz stronę http://127.0.0.1:8000/docs. - -Zobaczysz automatyczną interaktywną dokumentację API (dostarczoną z pomocą Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternatywna dokumentacja API - -Otwórz teraz http://127.0.0.1:8000/redoc. - -Zobaczysz alternatywną, lecz wciąż automatyczną dokumentację (wygenerowaną z pomocą ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Aktualizacja przykładu - -Zmodyfikuj teraz plik `main.py`, aby otrzmywał treść (body) żądania `PUT`. - -Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -Serwer powinien przeładować się automatycznie (ponieważ dodałeś `--reload` do komendy `uvicorn` powyżej). - -### Zaktualizowana interaktywna dokumentacja API - -Wejdź teraz na http://127.0.0.1:8000/docs. - -* Interaktywna dokumentacja API zaktualizuje sie automatycznie, także z nową treścią żądania (body): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Kliknij przycisk "Try it out" (wypróbuj), pozwoli Ci to wypełnić parametry i bezpośrednio użyć API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Kliknij potem przycisk "Execute" (wykonaj), interfejs użytkownika połączy się z API, wyśle parametry, otrzyma odpowiedź i wyświetli ją na ekranie: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Zaktualizowana alternatywna dokumentacja API - -Otwórz teraz http://127.0.0.1:8000/redoc. - -* Alternatywna dokumentacja również pokaże zaktualizowane parametry i treść żądania (body): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Podsumowanie - -Podsumowując, musiałeś zadeklarować typy parametrów, treści żądania (body) itp. tylko **raz**, i są one dostępne jako parametry funkcji. - -Robisz to tak samo jak ze standardowymi typami w Pythonie. - -Nie musisz sie uczyć żadnej nowej składni, metod lub klas ze specyficznych bibliotek itp. - -Po prostu standardowy **Python**. - -Na przykład, dla danych typu `int`: - -```Python -item_id: int -``` - -albo dla bardziej złożonego obiektu `Item`: - -```Python -item: Item -``` - -...i z pojedyńczą deklaracją otrzymujesz: - -* Wsparcie edytorów kodu, wliczając: - * Auto-uzupełnianie. - * Sprawdzanie typów. -* Walidacja danych: - * Automatyczne i przejrzyste błędy gdy dane są niepoprawne. - * Walidacja nawet dla głęboko zagnieżdżonych obiektów JSON. -* Konwersja danych wejściowych: przychodzących z sieci na Pythonowe typy. Pozwala na przetwarzanie danych: - * JSON. - * Parametrów ścieżki. - * Parametrów zapytania. - * Dane cookies. - * Dane nagłówków (headers). - * Formularze. - * Pliki. -* Konwersja danych wyjściowych: wychodzących z Pythona do sieci (jako JSON): - * Przetwarzanie Pythonowych typów (`str`, `int`, `float`, `bool`, `list`, itp). - * Obiekty `datetime`. - * Obiekty `UUID`. - * Modele baz danych. - * ...i wiele więcej. -* Automatyczne interaktywne dokumentacje API, wliczając 2 alternatywne interfejsy użytkownika: - * Swagger UI. - * ReDoc. - ---- - -Wracając do poprzedniego przykładu, **FastAPI** : - -* Potwierdzi, że w ścieżce jest `item_id` dla żądań `GET` i `PUT`. -* Potwierdzi, że `item_id` jest typu `int` dla żądań `GET` i `PUT`. - * Jeżeli nie jest, odbiorca zobaczy przydatną, przejrzystą wiadomość z błędem. -* Sprawdzi czy w ścieżce jest opcjonalny parametr zapytania `q` (np. `http://127.0.0.1:8000/items/foo?q=somequery`) dla żądania `GET`. - * Jako że parametr `q` jest zadeklarowany jako `= None`, jest on opcjonalny. - * Gdyby tego `None` nie było, parametr ten byłby wymagany (tak jak treść żądania w żądaniu `PUT`). -* Dla żądania `PUT` z ścieżką `/items/{item_id}`, odczyta treść żądania jako JSON: - * Sprawdzi czy posiada wymagany atrybut `name`, który powinien być typu `str`. - * Sprawdzi czy posiada wymagany atrybut `price`, który musi być typu `float`. - * Sprawdzi czy posiada opcjonalny atrybut `is_offer`, który (jeżeli obecny) powinien być typu `bool`. - * To wszystko będzie również działać dla głęboko zagnieżdżonych obiektów JSON. -* Automatycznie konwertuje z i do JSON. -* Dokumentuje wszystko w OpenAPI, które może być używane przez: - * Interaktywne systemy dokumentacji. - * Systemy automatycznego generowania kodu klienckiego, dla wielu języków. -* Dostarczy bezpośrednio 2 interaktywne dokumentacje webowe. - ---- - -To dopiero początek, ale już masz mniej-więcej pojęcie jak to wszystko działa. - -Spróbuj zmienić linijkę: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...z: - -```Python - ... "item_name": item.name ... -``` - -...na: - -```Python - ... "item_price": item.price ... -``` - -...i zobacz jak edytor kodu automatycznie uzupełni atrybuty i będzie znał ich typy: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Dla bardziej kompletnych przykładów posiadających więcej funkcjonalności, zobacz Tutorial - User Guide. - -**Uwaga Spoiler**: tutorial - user guide zawiera: - -* Deklaracje **parametrów** z innych miejsc takich jak: **nagłówki**, **pliki cookies**, **formularze** i **pliki**. -* Jak ustawić **ograniczenia walidacyjne** takie jak `maksymalna długość` lub `regex`. -* Potężny i łatwy w użyciu system **Dependency Injection**. -* Zabezpieczenia i autentykacja, wliczając wsparcie dla **OAuth2** z **tokenami JWT** oraz autoryzacją **HTTP Basic**. -* Bardziej zaawansowane (ale równie proste) techniki deklarowania **głęboko zagnieżdżonych modeli JSON** (dzięki Pydantic). -* Wiele dodatkowych funkcji (dzięki Starlette) takie jak: - * **WebSockety** - * **GraphQL** - * bardzo proste testy bazujące na HTTPX oraz `pytest` - * **CORS** - * **Sesje cookie** - * ...i więcej. - -## Wydajność - -Niezależne benchmarki TechEmpower pokazują, że **FastAPI** (uruchomiony na serwerze Uvicorn) jest jednym z najszybszych dostępnych Pythonowych frameworków, zaraz po Starlette i Uvicorn (używanymi wewnątrznie przez FastAPI). (*) - -Aby dowiedzieć się o tym więcej, zobacz sekcję Benchmarks. - -## Opcjonalne zależności - -Używane przez Pydantic: - -* email-validator - dla walidacji adresów email. - -Używane przez Starlette: - -* httpx - Wymagane jeżeli chcesz korzystać z `TestClient`. -* aiofiles - Wymagane jeżeli chcesz korzystać z `FileResponse` albo `StaticFiles`. -* jinja2 - Wymagane jeżeli chcesz używać domyślnej konfiguracji szablonów. -* python-multipart - Wymagane jeżelich chcesz wsparcie "parsowania" formularzy, używając `request.form()`. -* itsdangerous - Wymagany dla wsparcia `SessionMiddleware`. -* pyyaml - Wymagane dla wsparcia `SchemaGenerator` z Starlette (z FastAPI prawdopodobnie tego nie potrzebujesz). -* graphene - Wymagane dla wsparcia `GraphQLApp`. - -Używane przez FastAPI / Starlette: - -* uvicorn - jako serwer, który ładuje i obsługuje Twoją aplikację. -* orjson - Wymagane jeżeli chcesz używać `ORJSONResponse`. -* ujson - Wymagane jeżeli chcesz korzystać z `UJSONResponse`. - -Możesz zainstalować wszystkie te aplikacje przy pomocy `pip install fastapi[all]`. - -## Licencja - -Ten projekt jest na licencji MIT. diff --git a/docs/pl/docs/tutorial/first-steps.md b/docs/pl/docs/tutorial/first-steps.md deleted file mode 100644 index 8fa4c75ad..000000000 --- a/docs/pl/docs/tutorial/first-steps.md +++ /dev/null @@ -1,335 +0,0 @@ -# Pierwsze kroki - -Najprostszy plik FastAPI może wyglądać tak: - -{* ../../docs_src/first_steps/tutorial001.py *} - -Skopiuj to do pliku `main.py`. - -Uruchom serwer: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -/// note - -Polecenie `uvicorn main:app` odnosi się do: - -* `main`: plik `main.py` ("moduł" Python). -* `app`: obiekt utworzony w pliku `main.py` w lini `app = FastAPI()`. -* `--reload`: sprawia, że serwer uruchamia się ponownie po zmianie kodu. Używany tylko w trakcie tworzenia oprogramowania. - -/// - -Na wyjściu znajduje się linia z czymś w rodzaju: - -```hl_lines="4" -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -Ta linia pokazuje adres URL, pod którym Twoja aplikacja jest obsługiwana, na Twoim lokalnym komputerze. - -### Sprawdź to - -Otwórz w swojej przeglądarce http://127.0.0.1:8000. - -Zobaczysz odpowiedź w formacie JSON: - -```JSON -{"message": "Hello World"} -``` - -### Interaktywna dokumentacja API - -Przejdź teraz do http://127.0.0.1:8000/docs. - -Zobaczysz automatyczną i interaktywną dokumentację API (dostarczoną przez Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternatywna dokumentacja API - -Teraz przejdź do http://127.0.0.1:8000/redoc. - -Zobaczysz alternatywną automatycznie wygenerowaną dokumentację API (dostarczoną przez ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -### OpenAPI - -**FastAPI** generuje "schemat" z całym Twoim API przy użyciu standardu **OpenAPI** służącego do definiowania API. - -#### Schema - -"Schema" jest definicją lub opisem czegoś. Nie jest to kod, który go implementuje, ale po prostu abstrakcyjny opis. - -#### API "Schema" - -W typ przypadku, OpenAPI to specyfikacja, która dyktuje sposób definiowania schematu interfejsu API. - -Definicja schematu zawiera ścieżki API, możliwe parametry, które są przyjmowane przez endpointy, itp. - -#### "Schemat" danych - -Termin "schemat" może również odnosić się do wyglądu niektórych danych, takich jak zawartość JSON. - -W takim przypadku będzie to oznaczać atrybuty JSON, ich typy danych itp. - -#### OpenAPI i JSON Schema - -OpenAPI definiuje API Schema dla Twojego API, który zawiera definicje (lub "schematy") danych wysyłanych i odbieranych przez Twój interfejs API przy użyciu **JSON Schema**, standardu dla schematów danych w formacie JSON. - -#### Sprawdź `openapi.json` - -Jeśli jesteś ciekawy, jak wygląda surowy schemat OpenAPI, FastAPI automatycznie generuje JSON Schema z opisami wszystkich Twoich API. - -Możesz to zobaczyć bezpośrednio pod adresem: http://127.0.0.1:8000/openapi.json. - -Zobaczysz JSON zaczynający się od czegoś takiego: - -```JSON -{ - "openapi": "3.0.2", - "info": { - "title": "FastAPI", - "version": "0.1.0" - }, - "paths": { - "/items/": { - "get": { - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - - - -... -``` - -#### Do czego służy OpenAPI - -Schemat OpenAPI jest tym, co zasila dwa dołączone interaktywne systemy dokumentacji. - -Istnieją dziesiątki alternatyw, wszystkie oparte na OpenAPI. Możesz łatwo dodać dowolną z nich do swojej aplikacji zbudowanej za pomocą **FastAPI**. - -Możesz go również użyć do automatycznego generowania kodu dla klientów, którzy komunikują się z Twoim API. Na przykład aplikacje frontendowe, mobilne lub IoT. - -## Przypomnijmy, krok po kroku - -### Krok 1: zaimportuj `FastAPI` - -{* ../../docs_src/first_steps/tutorial001.py hl[1] *} - -`FastAPI` jest klasą, która zapewnia wszystkie funkcjonalności Twojego API. - -/// note | Szczegóły techniczne - -`FastAPI` jest klasą, która dziedziczy bezpośrednio z `Starlette`. - -Oznacza to, że możesz korzystać ze wszystkich funkcjonalności Starlette również w `FastAPI`. - -/// - -### Krok 2: utwórz instancję `FastAPI` - -{*../../docs_src/first_steps/tutorial001.py hl[3] *} - -Zmienna `app` będzie tutaj "instancją" klasy `FastAPI`. - -Będzie to główny punkt interakcji przy tworzeniu całego interfejsu API. - -Ta zmienna `app` jest tą samą zmienną, do której odnosi się `uvicorn` w poleceniu: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -Jeśli stworzysz swoją aplikację, np.: - -{* ../../docs_src/first_steps/tutorial002.py hl[3] *} - -I umieścisz to w pliku `main.py`, to będziesz mógł tak wywołać `uvicorn`: - -
- -```console -$ uvicorn main:my_awesome_api --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -### Krok 3: wykonaj *operację na ścieżce* - -#### Ścieżka - -"Ścieżka" tutaj odnosi się do ostatniej części adresu URL, zaczynając od pierwszego `/`. - -Więc, w adresie URL takim jak: - -``` -https://example.com/items/foo -``` - -...ścieżką będzie: - -``` -/items/foo -``` - -/// info - -"Ścieżka" jest zazwyczaj nazywana "path", "endpoint" lub "route'. - -/// - -Podczas budowania API, "ścieżka" jest głównym sposobem na oddzielenie "odpowiedzialności" i „zasobów”. - -#### Operacje - -"Operacje" tutaj odnoszą się do jednej z "metod" HTTP. - -Jedna z: - -* `POST` -* `GET` -* `PUT` -* `DELETE` - -...i te bardziej egzotyczne: - -* `OPTIONS` -* `HEAD` -* `PATCH` -* `TRACE` - -W protokole HTTP można komunikować się z każdą ścieżką za pomocą jednej (lub więcej) "metod". - ---- - -Podczas tworzenia API zwykle używasz tych metod HTTP do wykonania określonej akcji. - -Zazwyczaj używasz: - -* `POST`: do tworzenia danych. -* `GET`: do odczytywania danych. -* `PUT`: do aktualizacji danych. -* `DELETE`: do usuwania danych. - -Tak więc w OpenAPI każda z metod HTTP nazywana jest "operacją". - -Będziemy je również nazywali "**operacjami**". - -#### Zdefiniuj *dekorator operacji na ścieżce* - -{* ../../docs_src/first_steps/tutorial001.py hl[6] *} - -`@app.get("/")` mówi **FastAPI** że funkcja poniżej odpowiada za obsługę żądań, które trafiają do: - -* ścieżki `/` -* używając operacji get - -/// info | `@decorator` Info - -Składnia `@something` jest w Pythonie nazywana "dekoratorem". - -Umieszczasz to na szczycie funkcji. Jak ładną ozdobną czapkę (chyba stąd wzięła się nazwa). - -"Dekorator" przyjmuje funkcję znajdującą się poniżej jego i coś z nią robi. - -W naszym przypadku dekorator mówi **FastAPI**, że poniższa funkcja odpowiada **ścieżce** `/` z **operacją** `get`. - -Jest to "**dekorator operacji na ścieżce**". - -/// - -Możesz również użyć innej operacji: - -* `@app.post()` -* `@app.put()` -* `@app.delete()` - -Oraz tych bardziej egzotycznych: - -* `@app.options()` -* `@app.head()` -* `@app.patch()` -* `@app.trace()` - -/// tip - -Możesz dowolnie używać każdej operacji (metody HTTP). - -**FastAPI** nie narzuca żadnego konkretnego znaczenia. - -Informacje tutaj są przedstawione jako wskazówka, a nie wymóg. - -Na przykład, używając GraphQL, normalnie wykonujesz wszystkie akcje używając tylko operacji `POST`. - -/// - -### Krok 4: zdefiniuj **funkcję obsługującą ścieżkę** - -To jest nasza "**funkcja obsługująca ścieżkę**": - -* **ścieżka**: to `/`. -* **operacja**: to `get`. -* **funkcja**: to funkcja poniżej "dekoratora" (poniżej `@app.get("/")`). - -{* ../../docs_src/first_steps/tutorial001.py hl[7] *} - -Jest to funkcja Python. - -Zostanie ona wywołana przez **FastAPI** za każdym razem, gdy otrzyma żądanie do adresu URL "`/`" przy użyciu operacji `GET`. - -W tym przypadku jest to funkcja "asynchroniczna". - ---- - -Możesz również zdefiniować to jako normalną funkcję zamiast `async def`: - -{* ../../docs_src/first_steps/tutorial003.py hl[7] *} - -/// note - -Jeśli nie znasz różnicy, sprawdź [Async: *"In a hurry?"*](../async.md#in-a-hurry){.internal-link target=_blank}. - -/// - -### Krok 5: zwróć zawartość - -{* ../../docs_src/first_steps/tutorial001.py hl[8] *} - -Możesz zwrócić `dict`, `list`, pojedynczą wartość jako `str`, `int`, itp. - -Możesz również zwrócić modele Pydantic (więcej o tym później). - -Istnieje wiele innych obiektów i modeli, które zostaną automatycznie skonwertowane do formatu JSON (w tym ORM itp.). Spróbuj użyć swoich ulubionych, jest bardzo prawdopodobne, że są już obsługiwane. - -## Podsumowanie - -* Zaimportuj `FastAPI`. -* Stwórz instancję `app`. -* Dodaj **dekorator operacji na ścieżce** (taki jak `@app.get("/")`). -* Napisz **funkcję obsługującą ścieżkę** (taką jak `def root(): ...` powyżej). -* Uruchom serwer deweloperski (`uvicorn main:app --reload`). diff --git a/docs/pl/docs/tutorial/index.md b/docs/pl/docs/tutorial/index.md deleted file mode 100644 index 66f7c6d62..000000000 --- a/docs/pl/docs/tutorial/index.md +++ /dev/null @@ -1,83 +0,0 @@ -# Samouczek - -Ten samouczek pokaże Ci, krok po kroku, jak używać większości funkcji **FastAPI**. - -Każda część korzysta z poprzednich, ale jest jednocześnie osobnym tematem. Możesz przejść bezpośrednio do każdego rozdziału, jeśli szukasz rozwiązania konkretnego problemu. - -Samouczek jest tak zbudowany, żeby służył jako punkt odniesienia w przyszłości. - -Możesz wracać i sprawdzać dokładnie to czego potrzebujesz. - -## Wykonywanie kodu - -Wszystkie fragmenty kodu mogą być skopiowane bezpośrednio i użyte (są poprawnymi i przetestowanymi plikami). - -Żeby wykonać każdy przykład skopiuj kod to pliku `main.py` i uruchom `uvicorn` za pomocą: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -**BARDZO zalecamy** pisanie bądź kopiowanie kodu, edycję, a następnie wykonywanie go lokalnie. - -Użycie w Twoim edytorze jest tym, co pokazuje prawdziwe korzyści z FastAPI, pozwala zobaczyć jak mało kodu musisz napisać, wszystkie funkcje, takie jak kontrola typów, automatyczne uzupełnianie, itd. - ---- - -## Instalacja FastAPI - -Jako pierwszy krok zainstaluj FastAPI. - -Na potrzeby samouczka możesz zainstalować również wszystkie opcjonalne biblioteki: - -
- -```console -$ pip install "fastapi[all]" - ----> 100% -``` - -
- -...wliczając w to `uvicorn`, który będzie służył jako serwer wykonujacy Twój kod. - -/// note - -Możesz również wykonać instalację "krok po kroku". - -Prawdopodobnie zechcesz to zrobić, kiedy będziesz wdrażać swoją aplikację w środowisku produkcyjnym: - -``` -pip install fastapi -``` - -Zainstaluj też `uvicorn`, który będzie służył jako serwer: - -``` -pip install "uvicorn[standard]" -``` - -Tak samo możesz zainstalować wszystkie dodatkowe biblioteki, których chcesz użyć. - -/// - -## Zaawansowany poradnik - -Jest też **Zaawansowany poradnik**, który możesz przeczytać po lekturze tego **Samouczka**. - -**Zaawansowany poradnik** opiera się na tym samouczku, używa tych samych pojęć, żeby pokazać Ci kilka dodatkowych funkcji. - -Najpierw jednak powinieneś przeczytać **Samouczek** (czytasz go teraz). - -Ten rozdział jest zaprojektowany tak, że możesz stworzyć kompletną aplikację używając tylko informacji tutaj zawartych, a następnie rozszerzać ją na różne sposoby, w zależności od potrzeb, używając kilku dodatkowych pomysłów z **Zaawansowanego poradnika**. diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/pl/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/ur/docs/benchmarks.md b/docs/ur/docs/benchmarks.md deleted file mode 100644 index 8d583de2f..000000000 --- a/docs/ur/docs/benchmarks.md +++ /dev/null @@ -1,51 +0,0 @@ -# بینچ مارکس -انڈیپنڈنٹ ٹیک امپور بینچ مارک **FASTAPI** Uvicorn کے تحت چلنے والی ایپلی کیشنز کو ایک تیز رفتار Python فریم ورک میں سے ایک ، صرف Starlette اور Uvicorn کے نیچے ( FASTAPI کے ذریعہ اندرونی طور پر استعمال کیا جاتا ہے ) (*) - -لیکن جب بینچ مارک اور موازنہ کی جانچ پڑتال کرتے ہو تو آپ کو مندرجہ ذیل بات ذہن میں رکھنی چاہئے. - -## بینچ مارک اور رفتار - -جب آپ بینچ مارک کی جانچ کرتے ہیں تو ، مساوی کے مقابلے میں مختلف اقسام کے متعدد اوزار دیکھنا عام ہے. - -خاص طور پر ، Uvicorn, Starlette اور FastAPI کو دیکھنے کے لئے ( بہت سے دوسرے ٹولز ) کے ساتھ موازنہ کیا گیا. - -ٹول کے ذریعہ حل ہونے والا آسان مسئلہ ، اس کی بہتر کارکردگی ہوگی. اور زیادہ تر بینچ مارک ٹول کے ذریعہ فراہم کردہ اضافی خصوصیات کی جانچ نہیں کرتے ہیں. - -درجہ بندی کی طرح ہے: - -
    -
  • سرور ASGI :Uvicorn
  • -
      -
    • Starlette: (Uvicorn استعمال کرتا ہے) ایک ویب مائیکرو فریم ورک
    • -
        -
      • FastAPI: (Starlette کا استعمال کرتا ہے) ایک API مائکرو فریم ورک جس میں APIs بنانے کے لیے کئی اضافی خصوصیات ہیں، ڈیٹا کی توثیق وغیرہ کے ساتھ۔
      • -
      -
    -
- -
    -
  • Uvicorn:
  • -
      -
    • بہترین کارکردگی ہوگی، کیونکہ اس میں سرور کے علاوہ زیادہ اضافی کوڈ نہیں ہے۔
    • -
    • آپ براہ راست Uvicorn میں درخواست نہیں لکھیں گے۔ اس کا مطلب یہ ہوگا کہ آپ کے کوڈ میں کم و بیش، کم از کم، Starlette (یا FastAPI) کی طرف سے فراہم کردہ تمام کوڈ شامل کرنا ہوں گے۔ اور اگر آپ نے ایسا کیا تو، آپ کی حتمی ایپلیکیشن کا وہی اوور ہیڈ ہوگا جیسا کہ ایک فریم ورک استعمال کرنے اور آپ کے ایپ کوڈ اور کیڑے کو کم سے کم کرنا۔
    • -
    • اگر آپ Uvicorn کا موازنہ کر رہے ہیں تو اس کا موازنہ Daphne، Hypercorn، uWSGI وغیرہ ایپلیکیشن سرورز سے کریں۔
    • -
    -
-
    -
  • Starlette:
  • -
      -
    • Uvicorn کے بعد اگلی بہترین کارکردگی ہوگی۔ درحقیقت، Starlette چلانے کے لیے Uvicorn کا استعمال کرتی ہے۔ لہذا، یہ شاید زیادہ کوڈ پر عمل درآمد کرکے Uvicorn سے "سست" ہوسکتا ہے۔
    • -
    • لیکن یہ آپ کو آسان ویب ایپلیکیشنز بنانے کے لیے ٹولز فراہم کرتا ہے، راستوں پر مبنی روٹنگ کے ساتھ، وغیرہ۔>
    • -
    • اگر آپ سٹارلیٹ کا موازنہ کر رہے ہیں تو اس کا موازنہ Sanic، Flask، Django وغیرہ سے کریں۔ ویب فریم ورکس (یا مائیکرو فریم ورکس)
    • -
    -
-
    -
  • FastAPI:
  • -
      -
    • جس طرح سے Uvicorn Starlette کا استعمال کرتا ہے اور اس سے تیز نہیں ہو سکتا، Starlette FastAPI کا استعمال کرتا ہے، اس لیے یہ اس سے تیز نہیں ہو سکتا۔
    • -
    • Starlette FastAPI کے اوپری حصے میں مزید خصوصیات فراہم کرتا ہے۔ وہ خصوصیات جن کی آپ کو APIs بناتے وقت تقریباً ہمیشہ ضرورت ہوتی ہے، جیسے ڈیٹا کی توثیق اور سیریلائزیشن۔ اور اسے استعمال کرنے سے، آپ کو خودکار دستاویزات مفت میں مل جاتی ہیں (خودکار دستاویزات چلنے والی ایپلی کیشنز میں اوور ہیڈ کو بھی شامل نہیں کرتی ہیں، یہ اسٹارٹ اپ پر تیار ہوتی ہیں)۔
    • -
    • اگر آپ نے FastAPI کا استعمال نہیں کیا ہے اور Starlette کو براہ راست استعمال کیا ہے (یا کوئی دوسرا ٹول، جیسے Sanic، Flask، Responder، وغیرہ) آپ کو تمام ڈیٹا کی توثیق اور سیریلائزیشن کو خود نافذ کرنا ہوگا۔ لہذا، آپ کی حتمی ایپلیکیشن اب بھی وہی اوور ہیڈ ہوگی جیسا کہ اسے FastAPI کا استعمال کرتے ہوئے بنایا گیا تھا۔ اور بہت سے معاملات میں، یہ ڈیٹا کی توثیق اور سیریلائزیشن ایپلی کیشنز میں لکھے گئے کوڈ کی سب سے بڑی مقدار ہے۔
    • -
    • لہذا، FastAPI کا استعمال کرکے آپ ترقیاتی وقت، Bugs، کوڈ کی لائنوں کی بچت کر رہے ہیں، اور شاید آپ کو وہی کارکردگی (یا بہتر) ملے گی اگر آپ اسے استعمال نہیں کرتے (جیسا کہ آپ کو یہ سب اپنے کوڈ میں لاگو کرنا ہوگا۔ )>
    • -
    • اگر آپ FastAPI کا موازنہ کر رہے ہیں، تو اس کا موازنہ ویب ایپلیکیشن فریم ورک (یا ٹولز کے سیٹ) سے کریں جو ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات فراہم کرتا ہے، جیسے Flask-apispec، NestJS، Molten، وغیرہ۔ مربوط خودکار ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات کے ساتھ فریم ورک۔
    • -
    -
diff --git a/docs/ur/mkdocs.yml b/docs/ur/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/ur/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml diff --git a/docs/yo/docs/index.md b/docs/yo/docs/index.md deleted file mode 100644 index eb8873ae8..000000000 --- a/docs/yo/docs/index.md +++ /dev/null @@ -1,474 +0,0 @@ -# FastAPI - - - -

- FastAPI -

-

- Ìlànà wẹ́ẹ́bù FastAPI, iṣẹ́ gíga, ó rọrùn láti kọ̀, o yára láti kóòdù, ó sì ṣetán fún iṣelọpọ ní lílo -

-

- - Test - - - Coverage - - - Package version - - - Supported Python versions - -

- ---- - -**Àkọsílẹ̀**: https://fastapi.tiangolo.com - -**Orisun Kóòdù**: https://github.com/fastapi/fastapi - ---- - -FastAPI jẹ́ ìgbàlódé, tí ó yára (iṣẹ-giga), ìlànà wẹ́ẹ́bù fún kikọ àwọn API pẹ̀lú Python èyí tí ó da lori àwọn ìtọ́kasí àmì irúfẹ́ Python. - -Àwọn ẹya pàtàkì ni: - -* **Ó yára**: Iṣẹ tí ó ga púpọ̀, tí ó wa ni ibamu pẹ̀lú **NodeJS** àti **Go** (ọpẹ si Starlette àti Pydantic). [Ọkan nínú àwọn ìlànà Python ti o yára jùlọ ti o wa](#isesi). -* **Ó yára láti kóòdù**: O mu iyara pọ si láti kọ àwọn ẹya tuntun kóòdù nipasẹ "Igba ìdá ọgọ́rùn-ún" (i.e. 200%) si "ọ̀ọ́dúrún ìdá ọgọ́rùn-ún" (i.e. 300%). -* **Àìtọ́ kékeré**: O n din aṣiṣe ku bi ọgbon ìdá ọgọ́rùn-ún (i.e. 40%) ti eda eniyan (oṣiṣẹ kóòdù) fa. * -* **Ọgbọ́n àti ìmọ̀**: Atilẹyin olootu nla. Ìparí nibi gbogbo. Àkókò díẹ̀ nipa wíwá ibi tí ìṣòro kóòdù wà. -* **Irọrun**: A kọ kí ó le rọrun láti lo àti láti kọ ẹkọ nínú rè. Ó máa fún ọ ní àkókò díẹ̀ látı ka àkọsílẹ. -* **Ó kúkurú ní kikọ**: Ó dín àtúnkọ àti àtúntò kóòdù kù. Ìkéde àṣàyàn kọ̀ọ̀kan nínú rẹ̀ ní ọ̀pọ̀lọpọ̀ àwọn ìlò. O ṣe iranlọwọ láti má ṣe ní ọ̀pọ̀lọpọ̀ àṣìṣe. -* **Ó lágbára**: Ó ń ṣe àgbéjáde kóòdù tí ó ṣetán fún ìṣelọ́pọ̀. Pẹ̀lú àkọsílẹ̀ tí ó máa ṣàlàyé ara rẹ̀ fún ẹ ní ìbáṣepọ̀ aládàáṣiṣẹ́ pẹ̀lú rè. -* **Ajohunše/Ìtọ́kasí**: Ó da lori (àti ibamu ni kikun pẹ̀lú) àwọn ìmọ ajohunše/ìtọ́kasí fún àwọn API: OpenAPI (èyí tí a mọ tẹlẹ si Swagger) àti JSON Schema. - -* iṣiro yi da lori àwọn idanwo tí ẹgbẹ ìdàgbàsókè FastAPI ṣe, nígbàtí wọn kọ àwọn ohun elo iṣelọpọ kóòdù pẹ̀lú rẹ. - -## Àwọn onígbọ̀wọ́ - - - -{% if sponsors %} -{% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - -{% endfor %} -{% endif %} - - - -Àwọn onígbọ̀wọ́ míràn - -## Àwọn ero àti èsì - -"_[...] Mò ń lo **FastAPI** púpọ̀ ní lẹ́nu àìpẹ́ yìí. [...] Mo n gbero láti lo o pẹ̀lú àwọn ẹgbẹ mi fún gbogbo iṣẹ **ML wa ni Microsoft**. Diẹ nínú wọn ni afikun ti ifilelẹ àwọn ẹya ara ti ọja **Windows** wa pẹ̀lú àwọn ti **Office**._" - -
Kabir Khan - Microsoft (ref)
- ---- - -"_A gba àwọn ohun èlò ìwé afọwọkọ **FastAPI** tí kò yí padà láti ṣẹ̀dá olùpín **REST** tí a lè béèrè lọ́wọ́ rẹ̀ láti gba **àsọtẹ́lẹ̀**. [fún Ludwig]_" - -
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
- ---- - -"_**Netflix** ni inudidun láti kede itusilẹ orisun kóòdù ti ìlànà iṣọkan **iṣakoso Ìṣòro** wa: **Ìfiránṣẹ́**! [a kọ pẹ̀lú **FastAPI**]_" - -
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
- ---- - -"_Inú mi dùn púpọ̀ nípa **FastAPI**. Ó mú inú ẹnì dùn púpọ̀!_" - -
Brian Okken - Python Bytes podcast host (ref)
- ---- - -"_Ní tòótọ́, ohun tí o kọ dára ó sì tún dán. Ní ọ̀pọ̀lọpọ̀ ọ̀nà, ohun tí mo fẹ́ kí **Hug** jẹ́ nìyẹn - ó wúni lórí gan-an láti rí ẹnìkan tí ó kọ́ nǹkan bí èyí._" - -
Timothy Crosley - Hug creator (ref)
- ---- - -"_Ti o ba n wa láti kọ ọkan **ìlànà igbalode** fún kikọ àwọn REST API, ṣayẹwo **FastAPI** [...] Ó yára, ó rọrùn láti lò, ó sì rọrùn láti kọ́[...]_" - -"_A ti yipada si **FastAPI** fún **APIs** wa [...] Mo lérò pé wà á fẹ́ràn rẹ̀ [...]_" - -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
- ---- - -"_Ti ẹnikẹni ba n wa láti kọ iṣelọpọ API pẹ̀lú Python, èmi yóò ṣe'dúró fún **FastAPI**. Ó jẹ́ ohun tí **àgbékalẹ̀ rẹ̀ lẹ́wà**, **ó rọrùn láti lò** àti wipe ó ni **ìwọ̀n gíga**, o tí dí **bọtini paati** nínú alakọkọ API ìdàgbàsókè kikọ fún wa, àti pe o ni ipa lori adaṣiṣẹ àti àwọn iṣẹ gẹ́gẹ́ bíi Onímọ̀-ẹ̀rọ TAC tí órí Íńtánẹ́ẹ̀tì_" - -
Deon Pillsbury - Cisco (ref)
- ---- - -## **Typer**, FastAPI ti CLIs - - - -Ti o ba n kọ ohun èlò CLI láti ṣeé lọ nínú ohun èlò lori ebute kọmputa dipo API, ṣayẹwo **Typer**. - -**Typer** jẹ́ àbúrò ìyá FastAPI kékeré. Àti pé wọ́n kọ́ láti jẹ́ **FastAPI ti CLIs**. ⌨️ 🚀 - -## Èròjà - -FastAPI dúró lórí àwọn èjìká tí àwọn òmíràn: - -* Starlette fún àwọn ẹ̀yà ayélujára. -* Pydantic fún àwọn ẹ̀yà àkójọf'áyẹ̀wò. - -## Fifi sórí ẹrọ - -
- -```console -$ pip install fastapi - ----> 100% -``` - -
-Iwọ yóò tún nílò olupin ASGI, fún iṣelọpọ bii Uvicorn tabi Hypercorn. - -
- -```console -$ pip install "uvicorn[standard]" - ----> 100% -``` - -
- -## Àpẹẹrẹ - -### Ṣẹ̀dá rẹ̀ - -* Ṣẹ̀dá fáìlì `main.py (èyí tíí ṣe, akọkọ.py)` pẹ̀lú: - -```Python -from typing import Union - -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: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
-Tàbí lò async def... - -Tí kóòdù rẹ̀ bá ń lò `async` / `await`, lò `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Akiyesi**: - -Tí o kò bá mọ̀, ṣàyẹ̀wò ibi tí a ti ní _"In a hurry?"_ (i.e. _"Ní kíákíá?"_) nípa `async` and `await` nínú àkọsílẹ̀. - -
- -### Mu ṣiṣẹ - -Mú olupin ṣiṣẹ pẹ̀lú: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
- -
-Nipa aṣẹ kóòdù náà uvicorn main:app --reload... - -Àṣẹ `uvicorn main:app` ń tọ́ka sí: - -* `main`: fáìlì náà 'main.py' (Python "module"). -* `app` jẹ object( i.e. nǹkan) tí a ṣẹ̀dá nínú `main.py` pẹ̀lú ilà `app = FastAPI()`. -* `--reload`: èyí yóò jẹ́ ki olupin tún bẹ̀rẹ̀ lẹ́hìn àwọn àyípadà kóòdù. Jọ̀wọ́, ṣe èyí fún ìdàgbàsókè kóòdù nìkan, má ṣe é ṣe lori àgbéjáde kóòdù tabi fún iṣelọpọ kóòdù. - - -
- -### Ṣayẹwo rẹ - -Ṣii aṣàwákiri kọ̀ǹpútà rẹ ni http://127.0.0.1:8000/items/5?q=somequery. - -Ìwọ yóò sì rí ìdáhùn JSON bíi: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -O tí ṣẹ̀dá API èyí tí yóò: - -* Gbà àwọn ìbéèrè HTTP ni àwọn _ipa ọ̀nà_ `/` àti `/items/{item_id}`. -* Èyí tí àwọn _ipa ọ̀nà_ (i.e. _paths_) méjèèjì gbà àwọn iṣẹ `GET` (a tun mọ si _àwọn ọna_ HTTP). -* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní _àwọn ohun-ini ipa ọ̀nà_ tí ó yẹ kí ó jẹ́ `int` i.e. `ÒǸKÀ`. -* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní àṣàyàn `str` _àwọn ohun-ini_ (i.e. _query parameter_) `q`. - -### Ìbáṣepọ̀ àkọsílẹ̀ API - -Ní báyìí, lọ sí http://127.0.0.1:8000/docs. - -Lẹ́yìn náà, iwọ yóò rí ìdáhùn àkọsílẹ̀ API tí ó jẹ́ ìbáṣepọ̀ alaifọwọyi/aládàáṣiṣẹ́ (tí a pèṣè nípaṣẹ̀ Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Ìdàkejì àkọsílẹ̀ API - -Ní báyìí, lọ sí http://127.0.0.1:8000/redoc. - -Wà á rí àwọn àkọsílẹ̀ aládàáṣiṣẹ́ mìíràn (tí a pese nipasẹ ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Àpẹẹrẹ ìgbésókè mìíràn - -Ní báyìí ṣe àtúnṣe fáìlì `main.py` láti gba kókó èsì láti inú ìbéèrè `PUT`. - -Ní báyìí, ṣe ìkéde kókó èsì API nínú kóòdù rẹ nipa lílo àwọn ìtọ́kasí àmì irúfẹ́ Python, ọpẹ́ pàtàkìsi sí Pydantic. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -Olupin yóò tún ṣe àtúnṣe laifọwọyi/aládàáṣiṣẹ́ (nítorí wípé ó se àfikún `-reload` si àṣẹ kóòdù `uvicorn` lókè). - -### Ìbáṣepọ̀ ìgbésókè àkọsílẹ̀ API - -Ní báyìí, lọ sí http://127.0.0.1:8000/docs. - -* Ìbáṣepọ̀ àkọsílẹ̀ API yóò ṣe imudojuiwọn àkọsílẹ̀ API laifọwọyi, pẹ̀lú kókó èsì ìdáhùn API tuntun: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Tẹ bọtini "Gbiyanju rẹ" i.e. "Try it out", yóò gbà ọ́ láàyè láti jẹ́ kí ó tẹ́ àlàyé tí ó nílò kí ó le sọ̀rọ̀ tààrà pẹ̀lú API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Lẹhinna tẹ bọtini "Ṣiṣe" i.e. "Execute", olùmúlò (i.e. user interface) yóò sọrọ pẹ̀lú API rẹ, yóò ṣe afiranṣẹ àwọn èròjà, pàápàá jùlọ yóò gba àwọn àbájáde yóò si ṣafihan wọn loju ìbòjú: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Ìdàkejì ìgbésókè àkọsílẹ̀ API - -Ní báyìí, lọ sí http://127.0.0.1:8000/redoc. - -* Ìdàkejì àkọsílẹ̀ API yóò ṣ'afihan ìbéèrè èròjà/pàrámítà tuntun àti kókó èsì ti API: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Àtúnyẹ̀wò - -Ni akopọ, ìwọ yóò kéde ni **kete** àwọn iru èròjà/pàrámítà, kókó èsì API, abbl (i.e. àti bẹbẹ lọ), bi àwọn èròjà iṣẹ. - -O ṣe ìyẹn pẹ̀lú irúfẹ́ àmì ìtọ́kasí ìgbàlódé Python. - -O ò nílò láti kọ́ síńtáàsì tuntun, ìlànà tàbí ọ̀wọ́ kíláàsì kan pàtó, abbl (i.e. àti bẹbẹ lọ). - -Ìtọ́kasí **Python** - -Fún àpẹẹrẹ, fún `int`: - -```Python -item_id: int -``` - -tàbí fún àwòṣe `Item` tí ó nira díẹ̀ síi: - -```Python -item: Item -``` - -... àti pẹ̀lú ìkéde kan ṣoṣo yẹn ìwọ yóò gbà: - -* Atilẹyin olootu, pẹ̀lú: - * Pipari. - * Àyẹ̀wò irúfẹ́ àmì ìtọ́kasí. -* Ìfọwọ́sí àkójọf'áyẹ̀wò (i.e. data): - * Aṣiṣe alaifọwọyi/aládàáṣiṣẹ́ àti aṣiṣe ti ó hàn kedere nígbàtí àwọn àkójọf'áyẹ̀wò (i.e. data) kò wulo tabi tí kò fẹsẹ̀ múlẹ̀. - * Ìfọwọ́sí fún ohun elo JSON tí ó jìn gan-an. -* Ìyípadà tí input àkójọf'áyẹ̀wò: tí ó wà láti nẹtiwọọki si àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python. Ó ń ka láti: - * JSON. - * èròjà ọ̀nà tí ò gbé gbà. - * èròjà ìbéèrè. - * Àwọn Kúkì - * Àwọn Àkọlé - * Àwọn Fọọmu - * Àwọn Fáìlì -* Ìyípadà èsì àkójọf'áyẹ̀wò: yíyípadà láti àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python si nẹtiwọọki (gẹ́gẹ́ bí JSON): - * Yí irúfẹ́ àmì ìtọ́kasí padà (`str`, `int`, `float`, `bool`, `list`, abbl i.e. àti bèbè ló). - * Àwọn ohun èlò `datetime`. - * Àwọn ohun èlò `UUID`. - * Àwọn awoṣẹ́ ibi ìpamọ́ àkójọf'áyẹ̀wò. - * ...àti ọ̀pọ̀lọpọ̀ díẹ̀ síi. -* Ìbáṣepọ̀ àkọsílẹ̀ API aládàáṣiṣẹ́, pẹ̀lú ìdàkejì àgbékalẹ̀-àwọn-olùmúlò (i.e user interfaces) méjì: - * Àgbékalẹ̀-olùmúlò Swagger. - * ReDoc. - ---- - -Nisinsin yi, tí ó padà sí àpẹẹrẹ ti tẹ́lẹ̀, **FastAPI** yóò: - -* Fọwọ́ sí i pé `item_id` wà nínú ọ̀nà ìbéèrè HTTP fún `GET` àti `PUT`. -* Fọwọ́ sí i pé `item_id` jẹ́ irúfẹ́ àmì ìtọ́kasí `int` fún ìbéèrè HTTP `GET` àti `PUT`. - * Tí kìí bá ṣe bẹ, oníbàárà yóò ríi àṣìṣe tí ó wúlò, kedere. -* Ṣàyẹ̀wò bóyá ìbéèrè àṣàyàn pàrámítà kan wà tí orúkọ rẹ̀ ń jẹ́ `q` (gẹ́gẹ́ bíi `http://127.0.0.1:8000/items/foo?q=somequery`) fún ìbéèrè HTTP `GET`. - * Bí wọ́n ṣe kéde pàrámítà `q` pẹ̀lú `= None`, ó jẹ́ àṣàyàn (i.e optional). - * Láìsí `None` yóò nílò (gẹ́gẹ́ bí kókó èsì ìbéèrè HTTP ṣe wà pẹ̀lú `PUT`). -* Fún àwọn ìbéèrè HTTP `PUT` sí `/items/{item_id}`, kà kókó èsì ìbéèrè HTTP gẹ́gẹ́ bí JSON: - * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `name` i.e. `orúkọ` tí ó yẹ kí ó jẹ́ `str`. - * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `price` i.e. `iye` tí ó gbọ́dọ̀ jẹ́ `float`. - * Ṣàyẹ̀wò pé ó ní àbùdá àṣàyàn `is_offer`, tí ó yẹ kí ó jẹ́ `bool`, tí ó bá wà níbẹ̀. - * Gbogbo èyí yóò tún ṣiṣẹ́ fún àwọn ohun èlò JSON tí ó jìn gidi gan-an. -* Yìí padà láti àti sí JSON lai fi ọwọ́ yi. -* Ṣe àkọsílẹ̀ ohun gbogbo pẹ̀lú OpenAPI, èyí tí yóò wà ní lílo nípaṣẹ̀: - * Àwọn ètò àkọsílẹ̀ ìbáṣepọ̀. - * Aládàáṣiṣẹ́ oníbárà èlètò tíí ṣẹ̀dá kóòdù, fún ọ̀pọ̀lọpọ̀ àwọn èdè. -* Pese àkọsílẹ̀ òní ìbáṣepọ̀ ti àwọn àgbékalẹ̀ ayélujára méjì tààrà. - ---- - -A ń ṣẹ̀ṣẹ̀ ń mú ẹyẹ bọ́ làpò ní, ṣùgbọ́n ó ti ni òye bí gbogbo rẹ̀ ṣe ń ṣiṣẹ́. - -Gbiyanju láti yí ìlà padà pẹ̀lú: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...láti: - -```Python - ... "item_name": item.name ... -``` - -...ṣí: - -```Python - ... "item_price": item.price ... -``` - -.. kí o sì wo bí olóòtú rẹ yóò ṣe parí àwọn àbùdá náà fúnra rẹ̀, yóò sì mọ irúfẹ́ wọn: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -Fún àpẹẹrẹ pípé síi pẹ̀lú àwọn àbùdá mìíràn, wo Ìdánilẹ́kọ̀ọ́ - Ìtọ́sọ́nà Olùmúlò. - -**Itaniji gẹ́gẹ́ bí isọ'ye**: ìdánilẹ́kọ̀ọ́ - itọsọna olùmúlò pẹ̀lú: - -* Ìkéde àṣàyàn **pàrámítà** láti àwọn oriṣiriṣi ibòmíràn gẹ́gẹ́ bíi: àwọn **àkọlé èsì API**, **kúkì**, **ààyè fọọmu**, àti **fáìlì**. -* Bíi ó ṣe lé ṣètò **àwọn ìdíwọ́ ìfọwọ́sí** bí `maximum_length` tàbí `regex`. -* Ó lágbára púpọ̀ ó sì rọrùn láti lo ètò **Àfikún Ìgbẹ́kẹ̀lé Kóòdù**. -* Ààbò àti ìfọwọ́sowọ́pọ̀, pẹ̀lú àtìlẹ́yìn fún **OAuth2** pẹ̀lú **àmì JWT** àti **HTTP Ipilẹ ìfọwọ́sowọ́pọ̀**. -* Àwọn ìlànà ìlọsíwájú (ṣùgbọ́n tí ó rọrùn bákan náà) fún ìkéde **àwọn àwòṣe JSON tó jinlẹ̀** (ọpẹ́ pàtàkìsi sí Pydantic). -* Iṣọpọ **GraphQL** pẹ̀lú Strawberry àti àwọn ohun èlò ìwé kóòdù afọwọkọ mìíràn tí kò yí padà. -* Ọpọlọpọ àwọn àfikún àwọn ẹ̀yà (ọpẹ́ pàtàkìsi sí Starlette) bí: - * **WebSockets** - * àwọn ìdánwò tí ó rọrùn púpọ̀ lórí HTTPX àti `pytest` - * **CORS** - * **Cookie Sessions** - * ...àti síwájú síi. - -## Ìṣesí - -Àwọn àlá TechEmpower fi hàn pé **FastAPI** ń ṣiṣẹ́ lábẹ́ Uvicorn gẹ́gẹ́ bí ọ̀kan lára àwọn ìlànà Python tí ó yára jùlọ tí ó wà, ní ìsàlẹ̀ Starlette àti Uvicorn fúnra wọn (tí FastAPI ń lò fúnra rẹ̀). (*) - -Láti ní òye síi nípa rẹ̀, wo abala àwọn Àlá. - -## Àṣàyàn Àwọn Àfikún Ìgbẹ́kẹ̀lé Kóòdù - -Èyí tí Pydantic ń lò: - -* email-validator - fún ifọwọsi ímeèlì. -* pydantic-settings - fún ètò ìsàkóso. -* pydantic-extra-types - fún àfikún oríṣi láti lọ pẹ̀lú Pydantic. - -Èyí tí Starlette ń lò: - -* httpx - Nílò tí ó bá fẹ́ láti lọ `TestClient`. -* jinja2 - Nílò tí ó bá fẹ́ láti lọ iṣeto awoṣe aiyipada. -* python-multipart - Nílò tí ó bá fẹ́ láti ṣe àtìlẹ́yìn fún "àyẹ̀wò" fọọmu, pẹ̀lú `request.form()`. -* itsdangerous - Nílò fún àtìlẹ́yìn `SessionMiddleware`. -* pyyaml - Nílò fún àtìlẹ́yìn Starlette's `SchemaGenerator` (ó ṣe ṣe kí ó má nílò rẹ̀ fún FastAPI). - -Èyí tí FastAPI / Starlette ń lò: - -* uvicorn - Fún olupin tí yóò sẹ́ àmúyẹ àti tí yóò ṣe ìpèsè fún iṣẹ́ rẹ tàbí ohun èlò rẹ. -* orjson - Nílò tí ó bá fẹ́ láti lọ `ORJSONResponse`. -* ujson - Nílò tí ó bá fẹ́ láti lọ `UJSONResponse`. - -Ó lè fi gbogbo àwọn wọ̀nyí sórí ẹrọ pẹ̀lú `pip install "fastapi[all]"`. - -## Iwe-aṣẹ - -Iṣẹ́ yìí ni iwe-aṣẹ lábẹ́ àwọn òfin tí iwe-aṣẹ MIT. diff --git a/docs/yo/mkdocs.yml b/docs/yo/mkdocs.yml deleted file mode 100644 index de18856f4..000000000 --- a/docs/yo/mkdocs.yml +++ /dev/null @@ -1 +0,0 @@ -INHERIT: ../en/mkdocs.yml From 3d70b26788e2a626ecd166ca5da4e78cc69cb7bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 Sep 2025 06:26:25 +0000 Subject: [PATCH 12/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 95ee46fad..367746176 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Translations + +* 🌐 Remove configuration files for inactive translations. PR [#14130](https://github.com/fastapi/fastapi/pull/14130) by [@tiangolo](https://github.com/tiangolo). + ### Internal * 👷 Update docs previews comment, single comment, add failure status. PR [#14129](https://github.com/fastapi/fastapi/pull/14129) by [@tiangolo](https://github.com/tiangolo). From 977abe239662203ab0ea3b089092f94d3526e8fd Mon Sep 17 00:00:00 2001 From: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:24:39 +0200 Subject: [PATCH 13/38] =?UTF-8?q?=F0=9F=8C=90=20Update=20Russian=20transla?= =?UTF-8?q?tions=20for=20existing=20pages=20(LLM-generated)=20(#14123)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Russian translations for modified pages * docs: fix translation for multiprocessing * Update Russian translations for other existing pages * Apply changes from latest PRs: 13917 and 14099 --------- Co-authored-by: vldmrdev <70532790+vldmrdev@users.noreply.github.com> --- docs/ru/docs/about/index.md | 4 +- .../docs/advanced/additional-status-codes.md | 30 +- docs/ru/docs/advanced/async-tests.md | 14 +- docs/ru/docs/advanced/index.md | 8 +- .../advanced/response-change-status-code.md | 20 +- docs/ru/docs/advanced/response-cookies.md | 31 +- docs/ru/docs/advanced/response-directly.md | 12 +- docs/ru/docs/advanced/websockets.md | 42 +- docs/ru/docs/alternatives.md | 456 ++++++------- docs/ru/docs/async.md | 483 ++++++------- docs/ru/docs/benchmarks.md | 45 +- docs/ru/docs/deployment/concepts.md | 322 +++++---- docs/ru/docs/deployment/docker.md | 643 ++++++++---------- docs/ru/docs/deployment/https.md | 238 ++++--- docs/ru/docs/deployment/index.md | 10 +- docs/ru/docs/deployment/manually.md | 202 +++--- docs/ru/docs/deployment/versions.md | 44 +- docs/ru/docs/environment-variables.md | 23 +- docs/ru/docs/fastapi-cli.md | 18 +- docs/ru/docs/features.md | 133 ++-- docs/ru/docs/help-fastapi.md | 242 ++++--- docs/ru/docs/history-design-future.md | 28 +- docs/ru/docs/index.md | 321 +++++---- docs/ru/docs/learn/index.md | 2 +- docs/ru/docs/project-generation.md | 102 +-- docs/ru/docs/python-types.md | 501 ++++++++++---- docs/ru/docs/tutorial/background-tasks.md | 80 +-- docs/ru/docs/tutorial/bigger-applications.md | 53 +- docs/ru/docs/tutorial/body-fields.md | 21 +- docs/ru/docs/tutorial/body-multiple-params.md | 32 +- docs/ru/docs/tutorial/body-nested-models.md | 100 +-- docs/ru/docs/tutorial/body-updates.md | 42 +- docs/ru/docs/tutorial/body.md | 170 ++--- docs/ru/docs/tutorial/cookie-param-models.md | 12 +- docs/ru/docs/tutorial/cookie-params.md | 24 +- docs/ru/docs/tutorial/cors.md | 57 +- docs/ru/docs/tutorial/debugging.md | 10 +- .../dependencies/classes-as-dependencies.md | 123 ++-- ...pendencies-in-path-operation-decorators.md | 18 +- .../dependencies/dependencies-with-yield.md | 193 +++--- .../dependencies/global-dependencies.md | 10 +- docs/ru/docs/tutorial/dependencies/index.md | 194 +++--- .../tutorial/dependencies/sub-dependencies.md | 18 +- docs/ru/docs/tutorial/encoder.md | 12 +- docs/ru/docs/tutorial/extra-data-types.md | 18 +- docs/ru/docs/tutorial/extra-models.md | 40 +- docs/ru/docs/tutorial/first-steps.md | 264 ++++--- docs/ru/docs/tutorial/handling-errors.md | 34 +- docs/ru/docs/tutorial/header-param-models.md | 12 +- docs/ru/docs/tutorial/header-params.md | 14 +- docs/ru/docs/tutorial/index.md | 94 +-- docs/ru/docs/tutorial/metadata.md | 44 +- docs/ru/docs/tutorial/middleware.md | 35 +- .../tutorial/path-operation-configuration.md | 22 +- .../path-params-numeric-validations.md | 58 +- docs/ru/docs/tutorial/path-params.md | 87 +-- docs/ru/docs/tutorial/query-param-models.md | 12 +- .../tutorial/query-params-str-validations.md | 403 +++++------ docs/ru/docs/tutorial/query-params.md | 46 +- docs/ru/docs/tutorial/request-files.md | 39 +- docs/ru/docs/tutorial/request-form-models.md | 18 +- .../docs/tutorial/request-forms-and-files.md | 22 +- docs/ru/docs/tutorial/request-forms.md | 38 +- docs/ru/docs/tutorial/response-model.md | 270 ++++---- docs/ru/docs/tutorial/response-status-code.md | 38 +- docs/ru/docs/tutorial/schema-extra-example.md | 210 ++++-- docs/ru/docs/tutorial/security/first-steps.md | 152 +++-- .../tutorial/security/get-current-user.md | 82 +-- docs/ru/docs/tutorial/security/oauth2-jwt.md | 68 +- .../docs/tutorial/security/simple-oauth2.md | 165 ++--- docs/ru/docs/tutorial/sql-databases.md | 223 +++--- docs/ru/docs/tutorial/static-files.md | 18 +- docs/ru/docs/tutorial/testing.md | 40 +- docs/ru/docs/virtual-environments.md | 333 ++++----- 74 files changed, 4157 insertions(+), 3885 deletions(-) diff --git a/docs/ru/docs/about/index.md b/docs/ru/docs/about/index.md index 1015b667a..4f48266a7 100644 --- a/docs/ru/docs/about/index.md +++ b/docs/ru/docs/about/index.md @@ -1,3 +1,3 @@ -# О проекте +# О проекте { #about } -FastAPI: внутреннее устройство, повлиявшие технологии и всё такое прочее. 🤓 +О FastAPI, его дизайне, источниках вдохновения и многом другом. 🤓 diff --git a/docs/ru/docs/advanced/additional-status-codes.md b/docs/ru/docs/advanced/additional-status-codes.md index aab1f8ee3..7c73cf5d5 100644 --- a/docs/ru/docs/advanced/additional-status-codes.md +++ b/docs/ru/docs/advanced/additional-status-codes.md @@ -1,28 +1,28 @@ -# Дополнительные статус коды +# Дополнительные статус-коды { #additional-status-codes } -По умолчанию **FastAPI** возвращает ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`. +По умолчанию **FastAPI** будет возвращать ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`. -Он будет использовать код статуса по умолчанию или тот, который вы укажете в вашей *операции пути*. +Он будет использовать статус-код по умолчанию или тот, который вы укажете в вашей *операции пути*. -## Дополнительные статус коды +## Дополнительные статус-коды { #additional-status-codes_1 } -Если вы хотите возвращать дополнительный статус код помимо основного, вы можете сделать это, возвращая объект `Response` напрямую, как `JSONResponse`, и устанавливая нужный статус код напрямую. +Если вы хотите возвращать дополнительные статус-коды помимо основного, вы можете сделать это, возвращая `Response` напрямую, например `JSONResponse`, и устанавливая дополнительный статус-код напрямую. -Например, скажем, вы хотите создать *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP-код 200 "OK" при успешном выполнении. +Например, предположим, что вы хотите иметь *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP статус-код 200 «OK» при успешном выполнении. -Но вы также хотите, чтобы она принимала новые элементы. И если элемент ранее не существовал, он создаётся, и возвращался HTTP-код 201 "Created". +Но вы также хотите, чтобы она принимала новые элементы. И если элементы ранее не существовали, она создаёт их и возвращает HTTP статус-код 201 «Created». -Чтобы реализовать это, импортируйте `JSONResponse` и возвращайте ваш контент напрямую, устанавливая нужный `status_code`: +Чтобы добиться этого, импортируйте `JSONResponse` и верните туда свой контент напрямую, установив нужный вам `status_code`: {* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *} /// warning | Внимание -Когда вы возвращаете объект `Response` напрямую, как в примере выше, он будет возвращён как есть. +Когда вы возвращаете `Response` напрямую, как в примере выше, он будет возвращён как есть. -Он не будет сериализован при помощи модели и т.д. +Он не будет сериализован с помощью модели и т.п. -Убедитесь, что в нём содержатся именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`). +Убедитесь, что в нём именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`). /// @@ -30,12 +30,12 @@ Вы также можете использовать `from starlette.responses import JSONResponse`. -**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства, как разработчика. Но большинство доступных Response-классов поступают напрямую из Starlette. То же самое касается и `status`. +**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства как разработчика. Но большинство доступных Response-классов приходят напрямую из Starlette. То же самое со `status`. /// -## OpenAPI и документация API +## OpenAPI и документация API { #openapi-and-api-docs } -Если вы возвращаете дополнительные коды статусов и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что FastAPI не может заранее знать, что вы собираетесь вернуть. +Если вы возвращаете дополнительные статус-коды и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что у FastAPI нет способа заранее знать, что вы собираетесь вернуть. -Но вы можете задокументировать это в вашем коде, используя: [Дополнительные ответы в OpenAPI](additional-responses.md){.internal-link target=_blank}. +Но вы можете задокументировать это в своём коде, используя: [Дополнительные ответы](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/advanced/async-tests.md b/docs/ru/docs/advanced/async-tests.md index 7849ad109..5062bc52e 100644 --- a/docs/ru/docs/advanced/async-tests.md +++ b/docs/ru/docs/advanced/async-tests.md @@ -1,4 +1,4 @@ -# Асинхронное тестирование +# Асинхронное тестирование { #async-tests } Вы уже видели как тестировать **FastAPI** приложение, используя имеющийся класс `TestClient`. К этому моменту вы видели только как писать тесты в синхронном стиле без использования `async` функций. @@ -6,11 +6,11 @@ Давайте рассмотрим, как мы можем это реализовать. -## pytest.mark.anyio +## pytest.mark.anyio { #pytest-mark-anyio } Если мы хотим вызывать асинхронные функции в наших тестах, то наши тестовые функции должны быть асинхронными. AnyIO предоставляет для этого отличный плагин, который позволяет нам указывать, какие тестовые функции должны вызываться асинхронно. -## HTTPX +## HTTPX { #httpx } Даже если **FastAPI** приложение использует обычные функции `def` вместо `async def`, это все равно `async` приложение 'под капотом'. @@ -18,7 +18,7 @@ `TestClient` основан на HTTPX, и, к счастью, мы можем использовать его (`HTTPX`) напрямую для тестирования API. -## Пример +## Пример { #example } В качестве простого примера, давайте рассмотрим файловую структуру, схожую с описанной в [Большие приложения](../tutorial/bigger-applications.md){.internal-link target=_blank} и [Тестирование](../tutorial/testing.md){.internal-link target=_blank}: @@ -38,7 +38,7 @@ {* ../../docs_src/async_tests/test_main.py *} -## Запуск тестов +## Запуск тестов { #run-it } Вы можете запустить свои тесты как обычно: @@ -52,7 +52,7 @@ $ pytest
-## Подробнее +## Подробнее { #in-detail } Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно: @@ -88,7 +88,7 @@ response = client.get('/') /// -## Вызов других асинхронных функций +## Вызов других асинхронных функций { #other-asynchronous-function-calls } Теперь тестовая функция стала асинхронной, поэтому внутри нее вы можете вызывать также и другие `async` функции, не связанные с отправлением запросов в ваше FastAPI приложение. Как если бы вы вызывали их в любом другом месте вашего кода. diff --git a/docs/ru/docs/advanced/index.md b/docs/ru/docs/advanced/index.md index b5cb733e7..c0a52c6c1 100644 --- a/docs/ru/docs/advanced/index.md +++ b/docs/ru/docs/advanced/index.md @@ -1,12 +1,12 @@ -# Расширенное руководство пользователя +# Расширенное руководство пользователя { #advanced-user-guide } -## Дополнительные возможности +## Дополнительные возможности { #additional-features } Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**. В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности. -/// tip +/// tip | Совет Следующие разделы **не обязательно являются "продвинутыми"**. @@ -14,7 +14,7 @@ /// -## Сначала прочитайте Учебник - Руководство пользователя +## Сначала прочитайте Учебник - Руководство пользователя { #read-the-tutorial-first } Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md index 37dade99f..e9e1c9470 100644 --- a/docs/ru/docs/advanced/response-change-status-code.md +++ b/docs/ru/docs/advanced/response-change-status-code.md @@ -1,22 +1,22 @@ -# Response - Изменение cтатус кода +# Response - Изменение статус-кода { #response-change-status-code } -Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}. +Вы, вероятно, уже читали о том, что можно установить [статус-код ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}. -Но в некоторых случаях вам нужно вернуть код состояния, отличный от установленного по умолчанию. +Но в некоторых случаях нужно вернуть другой статус-код, отличный от значения по умолчанию. -## Пример использования +## Пример использования { #use-case } -Например, представьте, что вы хотите возвращать HTTP код состояния "OK" `200` по умолчанию. +Например, представьте, что вы хотите по умолчанию возвращать HTTP статус-код «OK» `200`. -Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`. +Но если данные не существовали, вы хотите создать их и вернуть HTTP статус-код «CREATED» `201`. При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`. Для таких случаев вы можете использовать параметр `Response`. -## Использование параметра `Response` +## Использование параметра `Response` { #use-a-response-parameter } -Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers). +Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (как и для cookies и HTTP-заголовков). И затем вы можете установить `status_code` в этом *временном* объекте ответа. @@ -26,6 +26,6 @@ И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта. -**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`. +**FastAPI** будет использовать этот *временный* ответ для извлечения статус-кода (а также cookies и HTTP-заголовков) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`. -Вы также можете объявить параметр `Response` в зависимостях и установить код состояния в них. Но помните, что последнее установленное значение будет иметь приоритет. +Вы также можете объявить параметр `Response` в зависимостях и установить в них статус-код. Но помните, что последнее установленное значение будет иметь приоритет. diff --git a/docs/ru/docs/advanced/response-cookies.md b/docs/ru/docs/advanced/response-cookies.md index e04ff577c..3aa32b9bb 100644 --- a/docs/ru/docs/advanced/response-cookies.md +++ b/docs/ru/docs/advanced/response-cookies.md @@ -1,9 +1,8 @@ +# Cookies в ответе { #response-cookies } -# Cookies в ответе +## Использование параметра `Response` { #use-a-response-parameter } -## Использование параметра `Response` - -Вы можете объявить параметр типа `Response` в вашей функции эндпоинта. +Вы можете объявить параметр типа `Response` в вашей функции-обработчике пути. Затем установить cookies в этом временном объекте ответа. @@ -13,36 +12,40 @@ Если вы указали `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта. -**FastAPI** извлечет cookies (а также заголовки и коды состояния) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`. +**FastAPI** извлечет cookies (а также HTTP-заголовки и статус-код) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`. -Вы также можете объявить параметр типа Response в зависимостях и устанавливать cookies (и заголовки) там. +Вы также можете объявить параметр типа `Response` в зависимостях и устанавливать cookies (и HTTP-заголовки) там. -## Возвращение `Response` напрямую +## Возвращение `Response` напрямую { #return-a-response-directly } -Вы также можете установить cookies, если возвращаете `Response` напрямую в вашем коде. +Вы также можете установить Cookies, если возвращаете `Response` напрямую в вашем коде. -Для этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md){.target=_blank}. +Для этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md){.internal-link target=_blank}. Затем установите cookies и верните этот объект: {* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} -/// tip | Примечание -Имейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, **FastAPI** отправит его без дополнительной обработки. +/// tip | Совет -Убедитесь, что ваши данные имеют корректный тип. Например, они должны быть совместимы с JSON, если вы используете `JSONResponse`. +Имейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, FastAPI вернёт его напрямую. + +Убедитесь, что ваши данные имеют корректный тип. Например, они должны быть совместимы с JSON, если вы возвращаете `JSONResponse`. Также убедитесь, что вы не отправляете данные, которые должны были быть отфильтрованы через `response_model`. + /// -### Дополнительная информация +### Дополнительная информация { #more-info } /// note | Технические детали + Вы также можете использовать `from starlette.responses import Response` или `from starlette.responses import JSONResponse`. **FastAPI** предоставляет `fastapi.responses`, которые являются теми же объектами, что и `starlette.responses`, просто для удобства. Однако большинство доступных типов ответов поступает непосредственно из **Starlette**. -Для установки заголовков и cookies `Response` используется часто, поэтому **FastAPI** также предоставляет его через `fastapi.responses`. +И так как `Response` часто используется для установки HTTP-заголовков и cookies, **FastAPI** также предоставляет его как `fastapi.Response`. + /// Чтобы увидеть все доступные параметры и настройки, ознакомьтесь с документацией Starlette. diff --git a/docs/ru/docs/advanced/response-directly.md b/docs/ru/docs/advanced/response-directly.md index ee83d22b1..febd40ed4 100644 --- a/docs/ru/docs/advanced/response-directly.md +++ b/docs/ru/docs/advanced/response-directly.md @@ -1,4 +1,4 @@ -# Возврат ответа напрямую +# Возврат ответа напрямую { #return-a-response-directly } Когда вы создаёте **FastAPI** *операцию пути*, вы можете возвращать из неё любые данные: `dict`, `list`, Pydantic-модель, модель базы данных и т.д. @@ -8,9 +8,9 @@ Но вы можете возвращать `JSONResponse` напрямую из ваших *операций пути*. -Это может быть полезно, например, если нужно вернуть пользовательские заголовки или куки. +Это может быть полезно, например, если нужно вернуть пользовательские HTTP-заголовки или cookie. -## Возврат `Response` +## Возврат `Response` { #return-a-response } На самом деле, вы можете возвращать любой объект `Response` или его подкласс. @@ -26,7 +26,7 @@ Это даёт вам большую гибкость. Вы можете возвращать любые типы данных, переопределять любые объявления или валидацию данных и т.д. -## Использование `jsonable_encoder` в `Response` +## Использование `jsonable_encoder` в `Response` { #using-the-jsonable-encoder-in-a-response } Поскольку **FastAPI** не изменяет объект `Response`, который вы возвращаете, вы должны убедиться, что его содержимое готово к отправке. @@ -44,7 +44,7 @@ /// -## Возврат пользовательского `Response` +## Возврат пользовательского `Response` { #returning-a-custom-response } Пример выше показывает все необходимые части, но он пока не очень полезен, так как вы могли бы просто вернуть `item` напрямую, и **FastAPI** поместил бы его в `JSONResponse`, преобразовав в `dict` и т.д. Всё это происходит по умолчанию. @@ -56,7 +56,7 @@ {* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} -## Примечания +## Примечания { #notes } Когда вы возвращаете объект `Response` напрямую, его данные не валидируются, не преобразуются (не сериализуются) и не документируются автоматически. diff --git a/docs/ru/docs/advanced/websockets.md b/docs/ru/docs/advanced/websockets.md index bc9dfcbff..b73fa1ddb 100644 --- a/docs/ru/docs/advanced/websockets.md +++ b/docs/ru/docs/advanced/websockets.md @@ -1,10 +1,10 @@ -# Веб-сокеты +# Веб-сокеты { #websockets } Вы можете использовать веб-сокеты в **FastAPI**. -## Установка `WebSockets` +## Установка `websockets` { #install-websockets } -Убедитесь, что [виртуальная среда](../virtual-environments.md){.internal-link target=_blank} создана, активируйте её и установите `websockets`: +Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его и установили `websockets` (библиотека Python, упрощающая работу с протоколом "WebSocket"):
@@ -16,31 +16,31 @@ $ pip install websockets
-## Клиент WebSockets +## Клиент WebSockets { #websockets-client } -### Рабочее приложение +### В продакшн { #in-production } -Скорее всего, в вашей реальной продуктовой системе есть фронтенд, реализованный при помощи современных фреймворков React, Vue.js или Angular. +В продакшн у вас, вероятно, есть фронтенд, созданный с помощью современного фреймворка вроде React, Vue.js или Angular. -И наверняка для взаимодействия с бекендом через веб-сокеты вы будете использовать средства фронтенда. +И для взаимодействия с бекендом по WebSocket вы, скорее всего, будете использовать инструменты вашего фронтенда. -Также у вас может быть нативное мобильное приложение, коммуницирующее непосредственно с веб-сокетами на бекенд-сервере. +Также у вас может быть нативное мобильное приложение, которое напрямую, нативным кодом, взаимодействует с вашим WebSocket-бекендом. -Либо вы можете сделать какой-либо другой способ взаимодействия с веб-сокетами. +Либо у вас может быть любой другой способ взаимодействия с WebSocket-эндпоинтом. --- -Но для этого примера мы воспользуемся очень простым HTML документом с небольшими вставками JavaScript кода. +Но для этого примера мы воспользуемся очень простым HTML‑документом с небольшим JavaScript, всё внутри одной длинной строки. -Конечно же это неоптимально, и на практике так делать не стоит. +Конечно же, это неоптимально, и вы бы не использовали это в продакшн. -В реальных приложениях стоит воспользоваться одним из вышеупомянутых способов. +В продакшн у вас был бы один из вариантов выше. -Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб-сокетов и получить рабочий код: +Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код: {* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *} -## Создание `websocket` +## Создание `websocket` { #create-a-websocket } Создайте `websocket` в своем **FastAPI** приложении: @@ -54,7 +54,7 @@ $ pip install websockets /// -## Ожидание и отправка сообщений +## Ожидание и отправка сообщений { #await-for-messages-and-send-messages } Через эндпоинт веб-сокета вы можете получать и отправлять сообщения. @@ -62,7 +62,7 @@ $ pip install websockets Вы можете получать и отправлять двоичные, текстовые и JSON данные. -## Проверка в действии +## Проверка в действии { #try-it } Если ваш файл называется `main.py`, то запустите приложение командой: @@ -96,7 +96,7 @@ $ fastapi dev main.py И все они будут использовать одно и то же веб-сокет соединение. -## Использование `Depends` и не только +## Использование `Depends` и не только { #using-depends-and-others } Вы можете импортировать из `fastapi` и использовать в эндпоинте вебсокета: @@ -119,7 +119,7 @@ $ fastapi dev main.py /// -### Веб-сокеты с зависимостями: проверка в действии +### Веб-сокеты с зависимостями: проверка в действии { #try-the-websockets-with-dependencies } Если ваш файл называется `main.py`, то запустите приложение командой: @@ -150,7 +150,7 @@ $ fastapi dev main.py -## Обработка отключений и работа с несколькими клиентами +## Обработка отключений и работа с несколькими клиентами { #handling-disconnections-and-multiple-clients } Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере: @@ -168,7 +168,7 @@ $ fastapi dev main.py Client #1596980209979 left the chat ``` -/// tip | Примечание +/// tip | Подсказка Приложение выше - это всего лишь простой минимальный пример, демонстрирующий обработку и передачу сообщений нескольким веб-сокет соединениям. @@ -178,7 +178,7 @@ Client #1596980209979 left the chat /// -## Дополнительная информация +## Дополнительная информация { #more-info } Для более глубокого изучения темы воспользуйтесь документацией Starlette: diff --git a/docs/ru/docs/alternatives.md b/docs/ru/docs/alternatives.md index 3c5147e79..6380bcc45 100644 --- a/docs/ru/docs/alternatives.md +++ b/docs/ru/docs/alternatives.md @@ -1,104 +1,94 @@ -# Альтернативы, источники вдохновения и сравнения +# Альтернативы, источники вдохновения и сравнения { #alternatives-inspiration-and-comparisons } -Что вдохновило на создание **FastAPI**, сравнение его с альтернативами и чему он научился у них. +Что вдохновило **FastAPI**, сравнение с альтернативами и чему он у них научился. -## Введение +## Введение { #intro } -**FastAPI** не существовал бы, если б не было более ранних работ других людей. +**FastAPI** не существовал бы без предыдущих работ других людей. -Они создали большое количество инструментов, которые вдохновили меня на создание **FastAPI**. +Было создано множество инструментов, которые вдохновили на его появление. -Я всячески избегал создания нового фреймворка в течение нескольких лет. -Сначала я пытался собрать все нужные функции, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов. +Я несколько лет избегал создания нового фреймворка. Сначала пытался закрыть все возможности, которые сейчас предоставляет **FastAPI**, с помощью множества разных фреймворков, плагинов и инструментов. -Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти функции сразу. -Взять самые лучшие идеи из предыдущих инструментов и, используя новые возможности Python (которых не было до версии 3.6, то есть подсказки типов), объединить их. +Но в какой-то момент не осталось другого варианта, кроме как создать что-то, что включает все эти возможности, взяв лучшие идеи из прежних инструментов и совместив их максимально удачным образом, используя возможности языка, которых прежде не было (аннотации типов в Python 3.6+). -## Предшествующие инструменты +## Предшествующие инструменты { #previous-tools } -### Django +### Django { #django } -Это самый популярный Python-фреймворк, и он пользуется доверием. -Он используется для создания проектов типа Instagram. +Это самый популярный Python-фреймворк, ему широко доверяют. Он используется для построения систем вроде Instagram. -Django довольно тесно связан с реляционными базами данных (такими как MySQL или PostgreSQL), потому использовать NoSQL базы данных (например, Couchbase, MongoDB, Cassandra и т.п.) в качестве основного хранилища данных - непросто. +Он относительно тесно связан с реляционными базами данных (например, MySQL или PostgreSQL), поэтому использовать NoSQL-базу данных (например, Couchbase, MongoDB, Cassandra и т. п.) в качестве основного хранилища не очень просто. -Он был создан для генерации HTML-страниц на сервере, а не для создания API, используемых современными веб-интерфейсами (React, Vue.js, Angular и т.п.) или другими системами (например, IoT) взаимодействующими с сервером. +Он был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами IoT), которые с ним общаются. -### Django REST Framework +### Django REST Framework { #django-rest-framework } -Фреймворк Django REST был создан, как гибкий инструментарий для создания веб-API на основе Django. +Django REST Framework был создан как гибкий набор инструментов для построения веб-API поверх Django, чтобы улучшить его возможности в части API. -DRF использовался многими компаниями, включая Mozilla, Red Hat и Eventbrite. +Он используется многими компаниями, включая Mozilla, Red Hat и Eventbrite. -Это был один из первых примеров **автоматического документирования API** и это была одна из первых идей, вдохновивших на создание **FastAPI**. +Это был один из первых примеров **автоматической документации API**, и именно эта идея одной из первых вдохновила на «поиск» **FastAPI**. /// note | Заметка -Django REST Framework был создан Tom Christie. -Он же создал Starlette и Uvicorn, на которых основан **FastAPI**. +Django REST Framework был создан Томом Кристи. Он же создал Starlette и Uvicorn, на которых основан **FastAPI**. /// -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Должно быть автоматическое создание документации API с пользовательским веб-интерфейсом. +Наличие пользовательского веб-интерфейса с автоматической документацией API. /// -### Flask +### Flask { #flask } -Flask - это "микрофреймворк", в нём нет интеграции с базами данных и многих других вещей, которые предустановлены в Django. +Flask — это «микрофреймворк», он не включает интеграции с базами данных и многие другие вещи, которые в Django идут «из коробки». -Его простота и гибкость дают широкие возможности, такие как использование баз данных NoSQL в качестве основной системы хранения данных. +Эта простота и гибкость позволяет, например, использовать NoSQL-базы в качестве основной системы хранения данных. -Он очень прост, его изучение интуитивно понятно, хотя в некоторых местах документация довольно техническая. +Он очень прост, его относительно легко интуитивно освоить, хотя местами документация довольно техническая. -Flask часто используется и для приложений, которым не нужна база данных, настройки прав доступа для пользователей и прочие из множества функций, предварительно встроенных в Django. -Хотя многие из этих функций могут быть добавлены с помощью плагинов. +Его также часто используют для приложений, которым не нужна база данных, управление пользователями или многие другие функции, предварительно встроенные в Django. Хотя многие из этих возможностей можно добавить плагинами. -Такое разделение на части и то, что это "микрофреймворк", который можно расширить, добавляя необходимые возможности, было ключевой особенностью, которую я хотел сохранить. +Такое разбиение на части и то, что это «микрофреймворк», который можно расширять ровно под нужды, — ключевая особенность, которую хотелось сохранить. -Простота Flask, показалась мне подходящей для создания API. -Но ещё нужно было найти "Django REST Framework" для Flask. +С учётом простоты Flask он казался хорошим вариантом для создания API. Следующим было найти «Django REST Framework» для Flask. -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -Это будет микрофреймворк. К нему легко будет добавить необходимые инструменты и части. +Быть микро-фреймворком. Облегчить комбинирование необходимых инструментов и компонентов. -Должна быть простая и лёгкая в использовании система маршрутизации запросов. +Иметь простую и удобную систему маршрутизации. /// -### Requests +### Requests { #requests } -На самом деле **FastAPI** не является альтернативой **Requests**. -Их область применения очень разная. +**FastAPI** на самом деле не альтернатива **Requests**. Их области применения очень различны. -В принципе, можно использовать Requests *внутри* приложения FastAPI. +Обычно Requests используют даже внутри приложения FastAPI. -Но всё же я использовал в FastAPI некоторые идеи из Requests. +И всё же **FastAPI** во многом вдохновлялся Requests. -**Requests** - это библиотека для взаимодействия с API в качестве клиента, -в то время как **FastAPI** - это библиотека для *создания* API (то есть сервера). +**Requests** — это библиотека для взаимодействия с API (как клиент), а **FastAPI** — библиотека для создания API (как сервер). -Они, так или иначе, диаметрально противоположны и дополняют друг друга. +Они, в каком-то смысле, находятся на противоположных концах и дополняют друг друга. -Requests имеет очень простой и понятный дизайн, очень прост в использовании и имеет разумные значения по умолчанию. -И в то же время он очень мощный и настраиваемый. +Requests имеет очень простой и понятный дизайн, им очень легко пользоваться, есть разумные значения по умолчанию. И при этом он очень мощный и настраиваемый. -Вот почему на официальном сайте написано: +Именно поэтому на официальном сайте сказано: -> Requests - один из самых загружаемых пакетов Python всех времен +> Requests — один из самых загружаемых Python-пакетов всех времён - -Использовать его очень просто. Например, чтобы выполнить запрос `GET`, Вы бы написали: +Пользоваться им очень просто. Например, чтобы сделать запрос `GET`, вы бы написали: ```Python response = requests.get("http://example.com/some/url") ``` -Противоположная *операция пути* в FastAPI может выглядеть следующим образом: +Соответствующая в FastAPI API-операция пути могла бы выглядеть так: ```Python hl_lines="1" @app.get("/some/url") @@ -106,428 +96,390 @@ def read_url(): return {"message": "Hello World"} ``` -Глядите, как похоже `requests.get(...)` и `@app.get(...)`. +Посмотрите, насколько похожи `requests.get(...)` и `@app.get(...)`. -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -* Должен быть простой и понятный API. -* Нужно использовать названия HTTP-методов (операций) для упрощения понимания происходящего. -* Должны быть разумные настройки по умолчанию и широкие возможности их кастомизации. +* Иметь простой и понятный API. +* Использовать названия HTTP-методов (операций) напрямую, простым и интуитивным образом. +* Иметь разумные значения по умолчанию, но и мощные настройки. /// -### Swagger / OpenAPI +### Swagger / OpenAPI { #swagger-openapi } -Главной функцией, которую я хотел унаследовать от Django REST Framework, была автоматическая документация API. +Главной возможностью, которую хотелось взять из Django REST Framework, была автоматическая документация API. -Но потом я обнаружил, что существует стандарт документирования API, использующий JSON (или YAML, расширение JSON) под названием Swagger. +Затем я обнаружил, что есть стандарт для документирования API с использованием JSON (или YAML — расширения JSON), под названием Swagger. -И к нему уже был создан пользовательский веб-интерфейс. -Таким образом, возможность генерировать документацию Swagger для API позволила бы использовать этот интерфейс. +И уже существовал веб-интерфейс для Swagger API. Поэтому возможность генерировать документацию Swagger для API позволила бы автоматически использовать этот веб-интерфейс. В какой-то момент Swagger был передан Linux Foundation и переименован в OpenAPI. -Вот почему, когда говорят о версии 2.0, обычно говорят "Swagger", а для версии 3+ "OpenAPI". +Вот почему, говоря о версии 2.0, обычно говорят «Swagger», а о версии 3+ — «OpenAPI». -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -Использовать открытые стандарты для спецификаций API вместо самодельных схем. +Использовать открытый стандарт для спецификаций API вместо самодельной схемы. -Совместимость с основанными на стандартах пользовательскими интерфейсами: +И интегрировать основанные на стандартах инструменты пользовательского интерфейса: * Swagger UI * ReDoc -Они были выбраны за популярность и стабильность. -Но сделав беглый поиск, Вы можете найти десятки альтернативных пользовательских интерфейсов для OpenAPI, которые Вы можете использовать с **FastAPI**. +Эти два инструмента выбраны за популярность и стабильность, но даже при беглом поиске можно найти десятки альтернативных интерфейсов для OpenAPI (которые можно использовать с **FastAPI**). /// -### REST фреймворки для Flask +### REST-фреймворки для Flask { #flask-rest-frameworks } -Существует несколько REST фреймворков для Flask, но потратив время и усилия на их изучение, я обнаружил, что многие из них не обновляются или заброшены и имеют нерешённые проблемы из-за которых они непригодны к использованию. +Существует несколько REST-фреймворков для Flask, но, вложив время и усилия в исследование, я обнаружил, что многие из них прекращены или заброшены, с несколькими нерешёнными Issue (тикет\обращение), из-за которых они непригодны. -### Marshmallow +### Marshmallow { #marshmallow } -Одной из основных функций, необходимых системам API, является "сериализация" данных, то есть преобразование данных из кода (Python) во что-то, что может быть отправлено по сети. -Например, превращение объекта содержащего данные из базы данных в объект JSON, конвертация объекта `datetime` в строку и т.п. +Одна из основных возможностей, нужных системам API, — «сериализация» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п. -Еще одна важная функция, необходимая API — проверка данных, позволяющая убедиться, что данные действительны и соответствуют заданным параметрам. -Как пример, можно указать, что ожидаются данные типа `int`, а не какая-то произвольная строка. -Это особенно полезно для входящих данных. +Ещё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных. -Без системы проверки данных Вам пришлось бы прописывать все проверки вручную. +Без системы валидации данных вам пришлось бы выполнять все проверки вручную в коде. -Именно для обеспечения этих функций и была создана Marshmallow. -Это отличная библиотека и я много раз пользовался ею раньше. +Именно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше. -Но она была создана до того, как появились подсказки типов Python. -Итак, чтобы определить каждую схему, -Вам нужно использовать определенные утилиты и классы, предоставляемые Marshmallow. +Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой схемы нужно использовать специальные утилиты и классы, предоставляемые Marshmallow. -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Использовать код программы для автоматического создания "схем", определяющих типы данных и их проверку. +Использовать код для автоматического определения «схем», задающих типы данных и их валидацию. /// -### Webargs +### Webargs { #webargs } -Другая немаловажная функция API - парсинг данных из входящих запросов. +Ещё одна важная возможность для API — парсинг данных из входящих HTTP-запросов. -Webargs - это инструмент, который был создан для этого и поддерживает несколько фреймворков, включая Flask. +Webargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask. -Для проверки данных он использует Marshmallow и создан теми же авторами. +Он использует Marshmallow для валидации данных. И создан теми же разработчиками. -Это превосходный инструмент и я тоже часто пользовался им до **FastAPI**. +Это отличный инструмент, и я тоже много им пользовался до появления **FastAPI**. /// info | Информация -Webargs бы создан разработчиками Marshmallow. +Webargs был создан теми же разработчиками, что и Marshmallow. /// -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Должна быть автоматическая проверка входных данных. +Автоматическую валидацию входящих данных HTTP-запроса. /// -### APISpec +### APISpec { #apispec } -Marshmallow и Webargs осуществляют проверку, анализ и сериализацию данных как плагины. +Marshmallow и Webargs предоставляют валидацию, парсинг и сериализацию как плагины. -Но документации API всё ещё не было. Тогда был создан APISpec. +Но документации всё ещё не было. Тогда появился APISpec. -Это плагин для множества фреймворков, в том числе и для Starlette. +Это плагин для многих фреймворков (есть плагин и для Starlette). -Он работает так - Вы записываете определение схем, используя формат YAML, внутри докстринга каждой функции, обрабатывающей маршрут. +Он работает так: вы пишете определение схемы в формате YAML внутри докстринга каждой функции, обрабатывающей маршрут. -Используя эти докстринги, он генерирует схему OpenAPI. +И он генерирует схемы OpenAPI. -Так это работает для Flask, Starlette, Responder и т.п. +Так это работает во Flask, Starlette, Responder и т. д. -Но теперь у нас возникает новая проблема - наличие постороннего микро-синтаксиса внутри кода Python (большие YAML). +Но у нас снова возникает проблема: появляется микро-синтаксис внутри строки Python (большой YAML). -Редактор кода не особо может помочь в такой парадигме. -А изменив какие-то параметры или схемы для Marshmallow можно забыть отредактировать докстринг с YAML и сгенерированная схема становится недействительной. +Редактор кода мало чем может помочь. И если мы изменим параметры или схемы Marshmallow и забудем также изменить YAML в докстринге, сгенерированная схема устареет. /// info | Информация -APISpec тоже был создан авторами Marshmallow. +APISpec был создан теми же разработчиками, что и Marshmallow. /// -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Необходима поддержка открытого стандарта для API - OpenAPI. +Поддержку открытого стандарта для API — OpenAPI. /// -### Flask-apispec +### Flask-apispec { #flask-apispec } -Это плагин для Flask, который связан с Webargs, Marshmallow и APISpec. +Это плагин для Flask, который связывает Webargs, Marshmallow и APISpec. -Он получает информацию от Webargs и Marshmallow, а затем использует APISpec для автоматического создания схемы OpenAPI. +Он использует информацию из Webargs и Marshmallow, чтобы автоматически генерировать схемы OpenAPI с помощью APISpec. -Это отличный, но крайне недооценённый инструмент. -Он должен быть более популярен, чем многие плагины для Flask. -Возможно, это связано с тем, что его документация слишком скудна и абстрактна. +Отличный и недооценённый инструмент. Он заслуживает большей популярности, чем многие плагины для Flask. Возможно, из-за слишком краткой и абстрактной документации. -Он избавил от необходимости писать чужеродный синтаксис YAML внутри докстрингов. +Это решило проблему необходимости писать YAML (ещё один синтаксис) в докстрингах Python. -Такое сочетание Flask, Flask-apispec, Marshmallow и Webargs было моим любимым стеком при построении бэкенда до появления **FastAPI**. +Комбинация Flask, Flask-apispec с Marshmallow и Webargs была моим любимым бэкенд-стеком до создания **FastAPI**. -Использование этого стека привело к созданию нескольких генераторов проектов. Я и некоторые другие команды до сих пор используем их: +Его использование привело к созданию нескольких full-stack генераторов на Flask. Это основные стеки, которые я (и несколько внешних команд) использовали до сих пор: * https://github.com/tiangolo/full-stack * https://github.com/tiangolo/full-stack-flask-couchbase * https://github.com/tiangolo/full-stack-flask-couchdb -Эти генераторы проектов также стали основой для [Генераторов проектов с **FastAPI**](project-generation.md){.internal-link target=_blank}. +И эти же full-stack генераторы стали основой для [Генераторов проектов **FastAPI**](project-generation.md){.internal-link target=_blank}. /// info | Информация -Как ни странно, но Flask-apispec тоже создан авторами Marshmallow. +Flask-apispec был создан теми же разработчиками, что и Marshmallow. /// -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Схема OpenAPI должна создаваться автоматически и использовать тот же код, который осуществляет сериализацию и проверку данных. +Автоматическую генерацию схемы OpenAPI из того же кода, который определяет сериализацию и валидацию. /// -### NestJSAngular) +### NestJSAngular) { #nestjs-and-angular } -Здесь даже не используется Python. NestJS - этот фреймворк написанный на JavaScript (TypeScript), основанный на NodeJS и вдохновлённый Angular. +Это даже не Python. NestJS — это JavaScript/TypeScript-фреймворк на NodeJS, вдохновлённый Angular. -Он позволяет получить нечто похожее на то, что можно сделать с помощью Flask-apispec. +Он достигает чего-то отчасти похожего на то, что можно сделать с Flask-apispec. -В него встроена система внедрения зависимостей, ещё одна идея взятая от Angular. -Однако требуется предварительная регистрация "внедрений" (как и во всех других известных мне системах внедрения зависимостей), что увеличивает количество и повторяемость кода. +В нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода. -Так как параметры в нём описываются с помощью типов TypeScript (аналогично подсказкам типов в Python), поддержка редактора работает довольно хорошо. +Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора весьма хороша. -Но поскольку данные из TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на подсказки типов для определения проверки данных, сериализации и документации. -Из-за этого и некоторых дизайнерских решений, для валидации, сериализации и автоматической генерации схем, приходится во многих местах добавлять декораторы. -Таким образом, это становится довольно многословным. +Но так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным. -Кроме того, он не очень хорошо справляется с вложенными моделями. -Если в запросе имеется объект JSON, внутренние поля которого, в свою очередь, являются вложенными объектами JSON, это не может быть должным образом задокументировано и проверено. +Он плохо справляется с вложенными моделями. Если JSON-тело запроса — это объект JSON, содержащий внутренние поля, которые сами являются вложенными объектами JSON, это нельзя как следует задокументировать и провалидировать. -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -Нужно использовать подсказки типов, чтоб воспользоваться поддержкой редактора кода. +Использовать типы Python для отличной поддержки в редакторе кода. -Нужна мощная система внедрения зависимостей. Необходим способ для уменьшения повторов кода. +Иметь мощную систему внедрения зависимостей. Найти способ минимизировать повторение кода. /// -### Sanic +### Sanic { #sanic } -Sanic был одним из первых чрезвычайно быстрых Python-фреймворков основанных на `asyncio`. -Он был сделан очень похожим на Flask. +Это был один из первых чрезвычайно быстрых Python-фреймворков на основе `asyncio`. Он был сделан очень похожим на Flask. /// note | Технические детали -В нём использован `uvloop` вместо стандартного цикла событий `asyncio`, что и сделало его таким быстрым. +Он использовал `uvloop` вместо стандартного цикла `asyncio` в Python. Это и сделало его таким быстрым. -Он явно вдохновил создателей Uvicorn и Starlette, которые в настоящее время быстрее Sanic в открытых бенчмарках. +Он явно вдохновил Uvicorn и Starlette, которые сейчас быстрее Sanic в открытых бенчмарках. /// -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -Должна быть сумасшедшая производительность. +Поиск способа достичь сумасшедшей производительности. -Для этого **FastAPI** основан на Starlette, самом быстром из доступных фреймворков (по замерам незаинтересованных лиц). +Именно поэтому **FastAPI** основан на Starlette, так как это самый быстрый доступный фреймворк (по данным сторонних бенчмарков). /// -### Falcon +### Falcon { #falcon } -Falcon - ещё один высокопроизводительный Python-фреймворк. -В нём минимум функций и он создан, чтоб быть основой для других фреймворков, например, Hug. +Falcon — ещё один высокопроизводительный Python-фреймворк, он минималистичен и служит основой для других фреймворков, таких как Hug. -Функции в нём получают два параметра - "запрос к серверу" и "ответ сервера". -Затем Вы "читаете" часть запроса и "пишите" часть ответа. -Из-за такой конструкции невозможно объявить параметры запроса и тела сообщения со стандартными подсказками типов Python в качестве параметров функции. +Он спроектирован так, что функции получают два параметра: «request» и «response». Затем вы «читаете» части из запроса и «пишете» части в ответ. Из‑за такого дизайна невозможно объявить параметры запроса и тело запроса стандартными аннотациями типов Python как параметры функции. -Таким образом, и валидацию данных, и их сериализацию, и документацию нужно прописывать вручную. -Либо эти функции должны быть встроены во фреймворк, сконструированный поверх Falcon, как в Hug. -Такая же особенность присутствует и в других фреймворках, вдохновлённых идеей Falcon, использовать только один объект запроса и один объект ответа. +Поэтому валидация данных, сериализация и документация должны выполняться в коде вручную, не автоматически. Либо должны быть реализованы во фреймворке поверх Falcon, как в Hug. Та же особенность есть и в других фреймворках, вдохновлённых дизайном Falcon — с одним объектом запроса и одним объектом ответа в параметрах. -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Найдите способы добиться отличной производительности. +Поиск способов получить отличную производительность. -Объявлять параметры `ответа сервера` в функциях, как в Hug. +Вместе с Hug (так как Hug основан на Falcon) вдохновило **FastAPI** объявлять параметр `response` в функциях. -Хотя в FastAPI это необязательно и используется в основном для установки заголовков, куки и альтернативных кодов состояния. +Хотя в FastAPI это необязательно, и используется в основном для установки HTTP-заголовков, cookie и альтернативных статус-кодов. /// -### Molten +### Molten { #molten } -Molten мне попался на начальной стадии написания **FastAPI**. В нём были похожие идеи: +Я обнаружил Molten на ранних этапах создания **FastAPI**. И у него были очень похожие идеи: -* Использование подсказок типов. -* Валидация и документация исходя из этих подсказок. +* Основан на аннотациях типов Python. +* Валидация и документация из этих типов. * Система внедрения зависимостей. -В нём не используются сторонние библиотеки (такие, как Pydantic) для валидации, сериализации и документации. -Поэтому переиспользовать эти определения типов непросто. +Он не использует стороннюю библиотеку для валидации, сериализации и документации, такую как Pydantic, — у него своя. Поэтому такие определения типов данных будет сложнее переиспользовать. -Также требуется более подробная конфигурация и используется стандарт WSGI, который не предназначен для использования с высокопроизводительными инструментами, такими как Uvicorn, Starlette и Sanic, в отличие от ASGI. +Требуются более многословные конфигурации. И так как он основан на WSGI (вместо ASGI), он не предназначен для использования преимуществ высокой производительности инструментов вроде Uvicorn, Starlette и Sanic. -Его система внедрения зависимостей требует предварительной регистрации, и зависимости определяются, как объявления типов. -Из-за этого невозможно объявить более одного "компонента" (зависимости), который предоставляет определенный тип. +Система внедрения зависимостей требует предварительной регистрации зависимостей, а зависимости разрешаются по объявленным типам. Поэтому невозможно объявить более одного «компонента», предоставляющего определённый тип. -Маршруты объявляются в единственном месте с использованием функций, объявленных в других местах (вместо использования декораторов, в которые могут быть обёрнуты функции, обрабатывающие конкретные ресурсы). -Это больше похоже на Django, чем на Flask и Starlette. -Он разделяет в коде вещи, которые довольно тесно связаны. +Маршруты объявляются в одном месте, используя функции, объявленные в других местах (вместо декораторов, которые можно разместить прямо над функцией, обрабатывающей эндпоинт). Это ближе к тому, как это делает Django, чем Flask (и Starlette). Это разделяет в коде вещи, которые довольно тесно связаны. -/// check | Идея для **FastAPI** +/// check | Вдохновило **FastAPI** на -Определить дополнительные проверки типов данных, используя значения атрибутов модели "по умолчанию". -Это улучшает помощь редактора и раньше это не было доступно в Pydantic. +Определять дополнительные проверки типов данных, используя значение «по умолчанию» атрибутов модели. Это улучшает поддержку в редакторе кода, и раньше этого не было в Pydantic. -Фактически это подтолкнуло на обновление Pydantic для поддержки одинакового стиля проверок (теперь этот функционал уже доступен в Pydantic). +Фактически это вдохновило на обновление частей Pydantic, чтобы поддерживать такой же стиль объявления валидации (вся эта функциональность теперь уже есть в Pydantic). /// -### Hug +### Hug { #hug } -Hug был одним из первых фреймворков, реализовавших объявление параметров API с использованием подсказок типов Python. -Эта отличная идея была использована и другими инструментами. +Hug был одним из первых фреймворков, реализовавших объявление типов параметров API с использованием аннотаций типов Python. Это была отличная идея, которая вдохновила и другие инструменты. -При объявлении параметров вместо стандартных типов Python использовались собственные типы, но всё же это был огромный шаг вперед. +Он использовал собственные типы в объявлениях вместо стандартных типов Python, но это всё равно был огромный шаг вперёд. -Это также был один из первых фреймворков, генерировавших полную API-схему в формате JSON. +Он также был одним из первых фреймворков, генерировавших собственную схему, описывающую весь API в JSON. -Данная схема не придерживалась стандартов вроде OpenAPI и JSON Schema. -Поэтому было бы непросто совместить её с другими инструментами, такими как Swagger UI. -Но опять же, это была очень инновационная идея. +Он не был основан на стандартах вроде OpenAPI и JSON Schema. Поэтому интегрировать его с другими инструментами, такими как Swagger UI, было бы непросто. Но, опять же, это была очень инновационная идея. -Ещё у него есть интересная и необычная функция: используя один и тот же фреймворк можно создавать и API, и CLI. +У него есть интересная и необычная особенность: с помощью одного и того же фреймворка можно создавать и API, и CLI. -Поскольку он основан на WSGI, старом стандарте для синхронных веб-фреймворков, он не может работать с веб-сокетами и другими модными штуками, но всё равно обладает высокой производительностью. +Так как он основан на предыдущем стандарте для синхронных веб-фреймворков Python (WSGI), он не может работать с WebSocket и прочим, хотя также демонстрирует высокую производительность. /// info | Информация -Hug создан Timothy Crosley, автором `isort`, отличного инструмента для автоматической сортировки импортов в Python-файлах. +Hug был создан Тимоти Кросли, тем же автором `isort`, отличного инструмента для автоматической сортировки импортов в файлах Python. /// -/// check | Идеи для **FastAPI** +/// check | Идеи, вдохновившие **FastAPI** -Hug повлиял на создание некоторых частей APIStar и был одним из инструментов, которые я счел наиболее многообещающими, наряду с APIStar. +Hug вдохновил части APIStar и был одним из наиболее многообещающих инструментов, которые я нашёл, наряду с APIStar. -Hug натолкнул на мысли использовать в **FastAPI** подсказки типов Python для автоматического создания схемы, определяющей API и его параметры. +Hug помог вдохновить **FastAPI** использовать аннотации типов Python для объявления параметров и автоматически генерировать схему, определяющую API. -Hug вдохновил **FastAPI** объявить параметр `ответа` в функциях для установки заголовков и куки. +Hug вдохновил **FastAPI** объявлять параметр `response` в функциях для установки HTTP-заголовков и cookie. /// -### APIStar (<= 0.5) +### APIStar (<= 0.5) { #apistar-0-5 } -Непосредственно перед тем, как принять решение о создании **FastAPI**, я обнаружил **APIStar**. -В нем было почти все, что я искал и у него был отличный дизайн. +Прямо перед решением строить **FastAPI** я нашёл сервер **APIStar**. В нём было почти всё, что я искал, и отличный дизайн. -Это была одна из первых реализаций фреймворка, использующего подсказки типов для объявления параметров и запросов, которые я когда-либо видел (до NestJS и Molten). -Я нашёл его примерно в то же время, что и Hug, но APIStar использовал стандарт OpenAPI. +Это была одна из первых реализаций фреймворка, использующего аннотации типов Python для объявления параметров и запросов (до NestJS и Molten), которые я видел. Я обнаружил его примерно в то же время, что и Hug. Но APIStar использовал стандарт OpenAPI. -В нём были автоматические проверка и сериализация данных и генерация схемы OpenAPI основанные на подсказках типов в нескольких местах. +В нём были автоматические валидация данных, сериализация данных и генерация схемы OpenAPI на основе тех же аннотаций типов в нескольких местах. -При определении схемы тела сообщения не использовались подсказки типов, как в Pydantic, это больше похоже на Marshmallow, поэтому помощь редактора была недостаточно хорошей, но всё же APIStar был лучшим доступным вариантом. +Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом. -На тот момент у него были лучшие показатели производительности (проигрывающие только Starlette). +На тот момент у него были лучшие показатели в бенчмарках (его превосходил только Starlette). -Изначально у него не было автоматической документации API для веб-интерфейса, но я знал, что могу добавить к нему Swagger UI. +Сначала у него не было веб‑UI для автоматической документации API, но я знал, что могу добавить к нему Swagger UI. -В APIStar была система внедрения зависимостей, которая тоже требовала предварительную регистрацию компонентов, как и ранее описанные инструменты. -Но, тем не менее, это была отличная штука. +У него была система внедрения зависимостей. Она требовала предварительной регистрации компонентов, как и другие инструменты, обсуждавшиеся выше. Но всё же это была отличная возможность. -Я не смог использовать его в полноценном проекте, так как были проблемы со встраиванием функций безопасности в схему OpenAPI, из-за которых невозможно было встроить все функции, применяемые в генераторах проектов на основе Flask-apispec. -Я добавил в свой список задач создание пул-реквеста, добавляющего эту функциональность. +Мне так и не удалось использовать его в полном проекте, поскольку не было интеграции с системой безопасности, поэтому я не мог заменить все возможности, которые имел с full-stack генераторами на основе Flask-apispec. В моём бэклоге было создать пулл-реквест (запрос на изменение), добавляющий эту функциональность. -В дальнейшем фокус проекта сместился. +Затем фокус проекта сместился. -Это больше не был API-фреймворк, так как автор сосредоточился на Starlette. +Это перестал быть веб-фреймворк для API, так как автору нужно было сосредоточиться на Starlette. -Ныне APIStar - это набор инструментов для проверки спецификаций OpenAPI. +Сейчас APIStar — это набор инструментов для валидации спецификаций OpenAPI, а не веб-фреймворк. /// info | Информация -APIStar был создан Tom Christie. Тот самый парень, который создал: +APIStar был создан Томом Кристи. Тем самым человеком, который создал: * Django REST Framework * Starlette (на котором основан **FastAPI**) -* Uvicorn (используемый в Starlette и **FastAPI**) +* Uvicorn (используется Starlette и **FastAPI**) /// -/// check | Идеи для **FastAPI** +/// check | Вдохновило **FastAPI** на -Воплощение. +Существование. -Мне казалось блестящей идеей объявлять множество функций (проверка данных, сериализация, документация) с помощью одних и тех же типов Python, которые при этом обеспечивают ещё и помощь редактора кода. +Идея объявлять сразу несколько вещей (валидацию данных, сериализацию и документацию) с помощью одних и тех же типов Python, которые одновременно обеспечивают отличную поддержку в редакторе кода, показалась мне блестящей. -После долгих поисков среди похожих друг на друга фреймворков и сравнения их различий, APIStar стал самым лучшим выбором. +После долгих поисков похожего фреймворка и тестирования множества альтернатив APIStar был лучшим доступным вариантом. -Но APIStar перестал быть фреймворком для создания веб-сервера, зато появился Starlette, новая и лучшая основа для построения подобных систем. -Это была последняя капля, сподвигнувшая на создание **FastAPI**. +Затем APIStar перестал существовать как сервер, а был создан Starlette — новая и лучшая основа для такой системы. Это стало окончательным вдохновением для создания **FastAPI**. -Я считаю **FastAPI** "духовным преемником" APIStar, улучившим его возможности благодаря урокам, извлечённым из всех упомянутых выше инструментов. +Я считаю **FastAPI** «духовным преемником» APIStar, который улучшает и расширяет возможности, систему типов и другие части, опираясь на уроки от всех этих предыдущих инструментов. /// -## Что используется в **FastAPI** +## Что используется в **FastAPI** { #used-by-fastapi } -### Pydantic +### Pydantic { #pydantic } -Pydantic - это библиотека для валидации данных, сериализации и документирования (используя JSON Schema), основываясь на подсказках типов Python, что делает его чрезвычайно интуитивным. +Pydantic — это библиотека для определения валидации данных, сериализации и документации (с использованием JSON Schema) на основе аннотаций типов Python. -Его можно сравнить с Marshmallow, хотя в бенчмарках Pydantic быстрее, чем Marshmallow. -И он основан на тех же подсказках типов, которые отлично поддерживаются редакторами кода. +Благодаря этому он чрезвычайно интуитивен. -/// check | **FastAPI** использует Pydantic +Его можно сравнить с Marshmallow. Хотя в бенчмарках он быстрее Marshmallow. И поскольку он основан на тех же аннотациях типов Python, поддержка в редакторе кода отличная. -Для проверки данных, сериализации данных и автоматической документации моделей (на основе JSON Schema). +/// check | **FastAPI** использует его для -Затем **FastAPI** берёт эти схемы JSON и помещает их в схему OpenAPI, не касаясь других вещей, которые он делает. +Обработки всей валидации данных, сериализации данных и автоматической документации моделей (на основе JSON Schema). + +Затем **FastAPI** берёт эти данные JSON Schema и помещает их в OpenAPI, помимо всех прочих функций. /// -### Starlette +### Starlette { #starlette } -Starlette - это легковесный ASGI фреймворк/набор инструментов, который идеален для построения высокопроизводительных асинхронных сервисов. +Starlette — это лёгкий ASGI фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов. -Starlette очень простой и интуитивный. -Он разработан таким образом, чтобы быть легко расширяемым и иметь модульные компоненты. +Он очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными. В нём есть: * Впечатляющая производительность. -* Поддержка веб-сокетов. -* Фоновые задачи. -* Обработка событий при старте и финише приложения. -* Тестовый клиент на основе HTTPX. -* Поддержка CORS, сжатие GZip, статические файлы, потоковая передача данных. -* Поддержка сессий и куки. +* Поддержка WebSocket. +* Фоновые задачи, выполняемые в том же процессе. +* События запуска и завершения. +* Тестовый клиент на базе HTTPX. +* CORS, GZip, статические файлы, потоковые ответы. +* Поддержка сессий и cookie. * 100% покрытие тестами. -* 100% аннотированный код. -* Несколько жёстких зависимостей. +* 100% кодовой базы с аннотациями типов. +* Мало жёстких зависимостей. -В настоящее время Starlette показывает самую высокую скорость среди Python-фреймворков в тестовых замерах. -Быстрее только Uvicorn, который является сервером, а не фреймворком. +В настоящее время Starlette — самый быстрый из протестированных Python-фреймворков. Его превосходит только Uvicorn, который не фреймворк, а сервер. -Starlette обеспечивает весь функционал микрофреймворка, но не предоставляет автоматическую валидацию данных, сериализацию и документацию. +Starlette предоставляет весь базовый функционал веб-микрофреймворка. -**FastAPI** добавляет эти функции используя подсказки типов Python и Pydantic. -Ещё **FastAPI** добавляет систему внедрения зависимостей, утилиты безопасности, генерацию схемы OpenAPI и т.д. +Но он не предоставляет автоматическую валидацию данных, сериализацию или документацию. + +Это одна из главных вещей, которые **FastAPI** добавляет поверх, всё на основе аннотаций типов Python (с использованием Pydantic). Плюс система внедрения зависимостей, утилиты безопасности, генерация схемы OpenAPI и т. д. /// note | Технические детали -ASGI - это новый "стандарт" разработанный участниками команды Django. -Он пока что не является "стандартом в Python" (то есть принятым PEP), но процесс принятия запущен. +ASGI — это новый «стандарт», разрабатываемый участниками core-команды Django. Он всё ещё не является «стандартом Python» (PEP), хотя процесс идёт. -Тем не менее он уже используется в качестве "стандарта" несколькими инструментами. -Это значительно улучшает совместимость, поскольку Вы можете переключиться с Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или Вы можете добавить ASGI-совместимые инструменты, такие как `python-socketio`. +Тем не менее его уже используют как «стандарт» несколько инструментов. Это сильно улучшает совместимость: вы можете заменить Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или добавить совместимые с ASGI инструменты, такие как `python-socketio`. /// -/// check | **FastAPI** использует Starlette +/// check | **FastAPI** использует его для -В качестве ядра веб-сервиса для обработки запросов, добавив некоторые функции сверху. +Обработки всех основных веб-частей. Добавляя возможности поверх. -Класс `FastAPI` наследуется напрямую от класса `Starlette`. +Класс `FastAPI` напрямую наследуется от класса `Starlette`. -Таким образом, всё что Вы могли делать со Starlette, Вы можете делать с **FastAPI**, по сути это прокачанный Starlette. +Так что всё, что вы можете сделать со Starlette, вы можете сделать напрямую с **FastAPI**, по сути это «Starlette на стероидах». /// -### Uvicorn +### Uvicorn { #uvicorn } -Uvicorn - это молниеносный ASGI-сервер, построенный на uvloop и httptools. +Uvicorn — молниеносный ASGI-сервер, построенный на uvloop и httptools. -Uvicorn является сервером, а не фреймворком. -Например, он не предоставляет инструментов для маршрутизации запросов по ресурсам. -Для этого нужна надстройка, такая как Starlette (или **FastAPI**). +Это не веб-фреймворк, а сервер. Например, он не предоставляет инструменты для маршрутизации по путям. Это предоставляет сверху фреймворк, такой как Starlette (или **FastAPI**). -Он рекомендуется в качестве сервера для Starlette и **FastAPI**. +Это рекомендуемый сервер для Starlette и **FastAPI**. -/// check | **FastAPI** рекомендует его +/// check | **FastAPI** рекомендует его как -Как основной сервер для запуска приложения **FastAPI**. +Основной веб-сервер для запуска приложений **FastAPI**. -Вы можете объединить его с Gunicorn, чтобы иметь асинхронный многопроцессный сервер. +Также вы можете использовать опцию командной строки `--workers`, чтобы получить асинхронный многопроцессный сервер. -Узнать больше деталей можно в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}. +Подробнее см. раздел [Развёртывание](deployment/index.md){.internal-link target=_blank}. /// -## Тестовые замеры и скорость +## Бенчмарки и скорость { #benchmarks-and-speed } -Чтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, ознакомьтесь с разделом [Тестовые замеры](benchmarks.md){.internal-link target=_blank}. +Чтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, см. раздел о [Бенчмарках](benchmarks.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index 813836d36..15d4e108a 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -1,18 +1,18 @@ -# Конкурентность и async / await +# Конкурентность и async / await { #concurrency-and-async-await } -Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций обработки пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма. +Подробности о синтаксисе `async def` для *функций-обработчиков пути* и немного фона об асинхронном коде, конкурентности и параллелизме. -## Нет времени? +## Нет времени? { #in-a-hurry } -TL;DR: +TL;DR: -Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `await`: +Если вы используете сторонние библиотеки, которые нужно вызывать с `await`, например: ```Python results = await some_library() ``` -В этом случае *функции обработки пути* необходимо объявлять с использованием синтаксиса `async def`: +Тогда объявляйте *функции-обработчики пути* с `async def`, например: ```Python hl_lines="2" @app.get('/') @@ -21,18 +21,15 @@ async def read_results(): return results ``` -/// note +/// note | Примечание -`await` можно использовать только внутри функций, объявленных с использованием `async def`. +`await` можно использовать только внутри функций, объявленных с `async def`. /// --- -Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует -(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await` -(что относится сейчас к большинству библиотек для работы с базами данных), то -объявляйте *функции обработки пути* обычным образом с помощью `def`, например: +Если вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т.д.) и не поддерживает использование `await` (сейчас это относится к большинству библиотек для БД), тогда объявляйте *функции-обработчики пути* как обычно, просто с `def`, например: ```Python hl_lines="2" @app.get('/') @@ -43,310 +40,283 @@ def results(): --- -Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно, -ожидать ответа, используйте `async def`. +Если вашему приложению (по какой-то причине) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужен `await`. --- -Если вы не уверены, используйте обычный синтаксис `def`. +Если вы просто не уверены, используйте обычный `def`. --- -**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути* -и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно. +**Примечание**: вы можете смешивать `def` и `async def` в *функциях-обработчиках пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо. -В любом из описанных случаев FastAPI работает асинхронно и очень быстро. +В любом из случаев выше FastAPI всё равно работает асинхронно и очень быстро. -Однако придерживаясь указанных советов, можно получить дополнительную оптимизацию производительности. +Но следуя этим шагам, он сможет выполнить некоторые оптимизации производительности. -## Технические подробности +## Технические подробности { #technical-details } -Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**. +Современные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**. -Ниже разберём эту фразу по частям: +Разберём эту фразу по частям в разделах ниже: * **Асинхронный код** * **`async` и `await`** * **Сопрограммы** -## Асинхронный код +## Асинхронный код { #asynchronous-code } -Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, -что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝. +Асинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝. -И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач. +И пока мы ждём завершения работы с «медленныи файлом» 📝, компьютер может заняться другой работой. -Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач. +Затем компьютер/программа 🤖 будет возвращаться каждый раз, когда появится возможность (пока снова где-то идёт ожидание), или когда 🤖 завершит всю текущую работу. И он 🤖 проверит, не завершилась ли какая-либо из задач, которых он ждал, и сделает то, что нужно. -Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия. +Далее он 🤖 возьмёт первую завершившуюся задачу (скажем, наш «медленный файл» 📝) и продолжит делать с ней то, что требуется. -Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям I/O (по сравнению со скоростью работы процессора и оперативной памяти), например: +Это «ожидание чего-то ещё» обычно относится к операциям I/O, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание: -* отправка данных от клиента по сети -* получение клиентом данных, отправленных вашей программой по сети -* чтение системой содержимого файла с диска и передача этих данных программе -* запись на диск данных, которые программа передала системе -* обращение к удалённому API -* ожидание завершения операции с базой данных -* получение результатов запроса к базе данных -* и т. д. +* отправки данных клиентом по сети +* получения клиентом данных, отправленных вашей программой по сети +* чтения системой содержимого файла на диске и передачи этих данных вашей программе +* записи на диск содержимого, которое ваша программа передала системе +* операции удалённого API +* завершения операции базы данных +* возврата результатов запроса к базе данных +* и т.д. -Поскольку в основном время тратится на ожидание выполнения операций I/O, -их обычно называют операциями, ограниченными скоростью ввода-вывода. +Поскольку основное время выполнения уходит на ожидание операций I/O, их называют операциями, «ограниченными вводом-выводом» (I/O bound). -Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, -будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу. +Это называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу. -Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), -пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, -забрать результаты выполнения и начать их обрабатывать. +Вместо этого, в «асинхронной» системе, уже завершившаяся задача может немного подождать (несколько микросекунд) в очереди, пока компьютер/программа завершит то, чем занимался, и затем вернётся, чтобы забрать результаты и продолжить работу с ними. -"Синхронное" исполнение (в противовес "асинхронному") также называют "последовательным", -потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, -даже если в процессе приходится ждать. +Для «синхронного» (в противоположность «асинхронному») исполнения часто используют термин «последовательный», потому что компьютер/программа выполняет все шаги по порядку, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание. -### Конкурентность и бургеры +### Конкурентность и бургеры { #concurrency-and-burgers } -Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**. +Та идея **асинхронного** кода, описанная выше, иногда также называется **«конкурентностью»**. Она отличается от **«параллелизма»**. -Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время. +И **конкурентность**, и **параллелизм** относятся к «разным вещам, происходящим примерно одновременно». -Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное. +Но различия между *конкурентностью* и *параллелизмом* довольно существенные. -Чтобы это понять, представьте такую картину: +Чтобы их увидеть, представьте следующую историю про бургеры: -### Конкурентные бургеры +### Конкурентные бургеры { #concurrent-burgers } - +Вы идёте со своей возлюбленной за фастфудом, вы стоите в очереди, пока кассир принимает заказы у людей перед вами. 😍 -Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами. + -Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе. +Наконец ваша очередь: вы заказываете 2 очень «навороченных» бургера — для вашей возлюбленной и для себя. 🍔🍔 -Отдаёте деньги 💸. + -Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔 -(но пока они заняты бургерами предыдущих клиентов). +Кассир говорит что-то повару на кухне, чтобы они знали, что нужно приготовить ваши бургеры (хотя сейчас они готовят бургеры для предыдущих клиентов). -Кассир 💁 отдаёт вам чек с номером заказа. + -В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍 -(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨). +Вы платите. 💸 -Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время, -восхищаясь её великолепием, красотой и умом ✨😍✨. +Кассир выдаёт вам номер вашей очереди. -Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете, -какой номер горит над прилавком, и не подошла ли уже ваша очередь. + -И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик. +Пока вы ждёте, вы вместе со своей возлюбленной идёте и выбираете столик, садитесь и долго болтаете (ваши бургеры очень «навороченные», поэтому им нужно время на приготовление). -Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨. +Сидя за столиком со своей возлюбленной в ожидании бургеров, вы можете провести это время, восхищаясь тем, какая она классная, милая и умная ✨😍✨. + + + +Пока вы ждёте и разговариваете, время от времени вы поглядываете на номер на табло, чтобы понять, не подошла ли уже ваша очередь. + +И вот в какой-то момент ваша очередь наступает. Вы подходите к стойке, забираете свои бургеры и возвращаетесь к столику. + + + +Вы со своей возлюбленной едите бургеры и отлично проводите время. ✨ + + + +/// info | Информация + +Прекрасные иллюстрации от Ketrina Thompson. 🎨 + +/// --- -А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖. +Представьте, что в этой истории вы — компьютер/программа 🤖. -В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. -Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного. +Пока вы стоите в очереди, вы просто бездействуете 😴, ждёте своей очереди и не делаете ничего особо «продуктивного». Но очередь движется быстро, потому что кассир только принимает заказы (а не готовит их), так что это нормально. -Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д. +Когда приходит ваша очередь, вы выполняете действительно «продуктивную» работу: просматриваете меню, решаете, чего хотите, учитываете выбор своей возлюбленной, платите, проверяете, что дали правильную купюру/карту, что сумма списана корректно, что в заказе верные позиции и т.д. -И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, -поскольку теперь нужно ждать 🕙, когда заказ приготовят. +Но затем, хотя у вас ещё нет бургеров, ваша «работа» с кассиром поставлена «на паузу» ⏸, потому что нужно подождать 🕙, пока бургеры будут готовы. -Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание -на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень -"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍. +Но, отойдя от стойки и сев за столик с номерком, вы можете переключить 🔀 внимание на свою возлюбленную и «поработать» ⏯ 🤓 над этим. Снова очень «продуктивно» — флирт с вашей возлюбленной 😍. -В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой. +Потом кассир 💁 «говорит»: «Я закончил делать бургеры», — выводя ваш номер на табло, но вы не подпрыгиваете как сумасшедший в ту же секунду, как только номер сменился на ваш. Вы знаете, что ваши бургеры никто не украдёт, потому что у вас есть номер вашей очереди, а у других — их. -Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), -и мило улыбнувшись, скажете, что идёте забирать заказ ⏸. +Поэтому вы дожидаетесь, пока ваша возлюбленная закончит историю (завершится текущая работа ⏯ / выполняемая задача 🤓), мягко улыбаетесь и говорите, что идёте за бургерами ⏸. -И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. -В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. +Затем вы идёте к стойке 🔀, к исходной задаче, которая теперь завершена ⏯, забираете бургеры, благодарите и несёте их к столику. На этом шаг/задача взаимодействия со стойкой завершён ⏹. Это, в свою очередь, создаёт новую задачу — «есть бургеры» 🔀 ⏯, но предыдущая «получить бургеры» — завершена ⏹. -### Параллельные бургеры +### Параллельные бургеры { #parallel-burgers } -Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры". +Теперь представим, что это не «Конкурентные бургеры», а «Параллельные бургеры». -И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔. +Вы идёте со своей возлюбленной за параллельным фастфудом. -Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами. +Вы стоите в очереди, пока несколько (скажем, 8) кассиров, которые одновременно являются поварами, принимают заказы у людей перед вами. -При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый -из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ. +Все перед вами ждут, пока их бургеры будут готовы, не отходя от стойки, потому что каждый из 8 кассиров сразу идёт готовить бургер перед тем, как принять следующий заказ. -Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе. + -Ни о чём не жалея, расплачиваетесь 💸. +Наконец ваша очередь: вы заказываете 2 очень «навороченных» бургера — для вашей возлюбленной и для себя. -И кассир уходит на кухню 👨‍🍳. +Вы платите 💸. -Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет. + -Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь, -у вас не получается уделять должного внимание своей даме сердца 😞. +Кассир уходит на кухню. -Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки, -когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой. +Вы ждёте, стоя у стойки 🕙, чтобы никто не забрал ваши бургеры раньше вас, так как никаких номерков нет. -Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой. + -Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик. +Так как вы со своей возлюбленной заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они появятся, вы не можете уделить внимание своей возлюбленной. 😞 -Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹. +Это «синхронная» работа, вы «синхронизированы» с кассиром/поваром 👨‍🍳. Вам нужно ждать 🕙 и находиться там в точный момент, когда кассир/повар 👨‍🍳 закончит бургеры и вручит их вам, иначе их может забрать кто-то другой. -Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞. + + +Затем ваш кассир/повар 👨‍🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 у стойки. + + + +Вы берёте бургеры и идёте со своей возлюбленной к столику. + +Вы просто их съедаете — и всё. ⏹ + + + +Разговоров и флирта было немного, потому что большую часть времени вы ждали 🕙 у стойки. 😞 + +/// info | Информация + +Прекрасные иллюстрации от Ketrina Thompson. 🎨 + +/// --- -В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), -на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе". +В этом сценарии «параллельных бургеров» вы — компьютер/программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба ждут 🕙 и уделяют внимание ⏯ тому, чтобы «ждать у стойки» 🕙 долгое время. -В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. -Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳. +В ресторане 8 процессоров (кассиров/поваров). Тогда как в «конкурентных бургерах» могло быть только 2 (один кассир и один повар). -Несмотря на обилие работников, опыт в итоге получился не из лучших 😞. +И всё же финальный опыт — не самый лучший. 😞 --- -Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире. +Это была параллельная версия истории про бургеры. 🍔 -Вот более реалистичный пример. Представьте себе банк. +Для более «жизненного» примера представьте банк. -До недавних пор в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙. +До недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙. -Каждый кассир обслуживал одного клиента, потом следующего 👨‍💼⏯. +Все кассиры делают всю работу с одним клиентом за другим 👨‍💼⏯. -Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь. +И вам приходится долго 🕙 стоять в очереди, иначе вы потеряете свою очередь. -Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги. +Вы вряд ли захотите взять свою возлюбленную 😍 с собой, чтобы заняться делами в банке 🏦. -### Выводы о бургерах +### Вывод про бургеры { #burger-conclusion } -В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, -поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯. +В этом сценарии «фастфуда с вашей возлюбленной», так как много ожидания 🕙, гораздо логичнее иметь конкурентную систему ⏸🔀⏯. -И то же самое с большинством веб-приложений. +Так обстоит дело и с большинством веб-приложений. -Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению. +Очень много пользователей, но ваш сервер ждёт 🕙, пока их не самое хорошее соединение отправит их запросы. -Потом снова ждать 🕙, пока вернётся ответ. +А затем снова ждёт 🕙, пока отправятся ответы. - -Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени. +Это «ожидание» 🕙 измеряется микросекундами, но если всё сложить, то в сумме получается много ожидания. -Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API. +Вот почему асинхронный ⏸🔀⏯ код очень уместен для веб-API. -Большинство популярных фреймворков (включая Flask и Django) создавались -до появления в Python новых возможностей асинхронного программирования. Поэтому -их можно разворачивать с поддержкой параллельного исполнения или асинхронного -программирования старого типа, которое не настолько эффективно. +Именно такая асинхронность сделала NodeJS популярным (хотя NodeJS — не параллельный), и это сильная сторона Go как языка программирования. -При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером -(ASGI) -была разработана командой Django для внедрения поддержки веб-сокетов. +Того же уровня производительности вы получаете с **FastAPI**. -Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), -и в этом преимущество Go как языка программирования. +А так как можно одновременно использовать параллелизм и асинхронность, вы получаете производительность выше, чем у большинства протестированных фреймворков на NodeJS и на уровне Go, который — компилируемый язык, ближе к C (всё благодаря Starlette). -И тот же уровень производительности даёт **FastAPI**. +### Конкурентность лучше параллелизма? { #is-concurrency-better-than-parallelism } -Поскольку можно использовать преимущества параллелизма и асинхронности вместе, -вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков -и на уровне с Go, который является компилируемым языком близким к C (всё благодаря Starlette). +Нет! Мораль истории не в этом. -### Получается, конкурентность лучше параллелизма? +Конкурентность отличается от параллелизма. И она лучше в **конкретных** сценариях, где много ожидания. Поэтому при разработке веб-приложений она обычно намного лучше параллелизма. Но не во всём. -Нет! Мораль истории совсем не в этом. +Чтобы уравновесить это, представьте такую короткую историю: -Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание. -Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях. - -Давайте посмотрим с другой стороны, представьте такую картину: - -> Вам нужно убраться в большом грязном доме. +> Вам нужно убрать большой грязный дом. *Да, это вся история*. --- -Тут не нужно нигде ждать 🕙, просто есть куча работы в разных частях дома. +Здесь нигде нет ожидания 🕙, просто очень много работы в разных местах дома. -Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня, -но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете. +Можно организовать «очереди» как в примере с бургерами — сначала гостиная, потом кухня, — но так как вы ничего не ждёте 🕙, а просто убираете и убираете, очереди ни на что не повлияют. -И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё, -и работы будет сделано тоже одинаковое количество. +На завершение уйдёт одинаковое время — с очередями (конкурентностью) и без них — и объём выполненной работы будет одинаковым. -Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, -и каждый из них (вместе с вами) взялся бы за свой участок дома, -с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**. +Но в этом случае, если бы вы могли привести 8 бывших кассиров/поваров, а теперь — уборщиков, и каждый из них (плюс вы) взял бы свою зону дома для уборки, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и завершить гораздо быстрее. -В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы. +В этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы. -И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание), -а работу в компьютере делает ЦП, -такие задачи называют ограниченными производительностью процессора. +И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет CPU, такие задачи называют «ограниченными процессором» (CPU bound). --- -Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления. +Типичные примеры CPU-bound операций — те, которые требуют сложной математической обработки. Например: -* Обработка **звука** или **изображений**. -* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета, -обработка обычно требует проведения расчётов по всем пикселям сразу. -* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов". -Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить. -* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание. -Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется -специальный процессор для создания и / или использования построенных таким образом моделей. +* Обработка **аудио** или **изображений**. +* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения/цвета; обычно требуется вычислить что-то для всех этих пикселей одновременно. +* **Машинное обучение**: обычно требует множества умножений «матриц» и «векторов». Представьте огромную таблицу с числами и умножение всех этих чисел «одновременно». +* **Глубокое обучение**: это подполе Машинного обучения, так что всё вышесказанное применимо. Просто это не одна таблица чисел, а их огромный набор, и во многих случаях вы используете специальный процессор, чтобы строить и/или использовать такие модели. -### Конкурентность + параллелизм: Веб + машинное обучение +### Конкурентность + параллелизм: Веб + Машинное обучение { #concurrency-parallelism-web-machine-learning } -**FastAPI** предоставляет возможности конкуретного программирования, -которое очень распространено в веб-разработке (именно этим славится NodeJS). +С **FastAPI** вы можете использовать преимущества конкурентности, что очень распространено в веб-разработке (это та же основная «фишка» NodeJS). -Кроме того вы сможете использовать все преимущества параллелизма и -многопроцессорности (когда несколько процессов работают параллельно), -если рабочая нагрузка предполагает **ограничение по процессору**, -как, например, в системах машинного обучения. +Но вы также можете использовать выгоды параллелизма и многопроцессности (когда несколько процессов работают параллельно) для рабочих нагрузок, **ограниченных процессором** (CPU bound), как в системах Машинного обучения. -Необходимо также отметить, что Python является главным языком в области -**дата-сайенс**, -машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI -отличным вариантом (среди многих других) для разработки веб-API и приложений -в области дата-сайенс / машинного обучения. +Плюс к этому простой факт, что Python — основной язык для **Data Science**, Машинного обучения и особенно Глубокого обучения, делает FastAPI очень хорошим выбором для веб-API и приложений в области Data Science / Машинного обучения (среди многих других). -Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}. +Как добиться такого параллелизма в продакшн, см. раздел [Развёртывание](deployment/index.md){.internal-link target=_blank}. -## `async` и `await` +## `async` и `await` { #async-and-await } -В современных версиях Python разработка асинхронного кода реализована очень интуитивно. -Он выглядит как обычный "последовательный" код и самостоятельно выполняет "ожидание", когда это необходимо. +В современных версиях Python есть очень интуитивный способ определять асинхронный код. Это делает его похожим на обычный «последовательный» код, а «ожидание» выполняется за вас в нужные моменты. -Если некая операция требует ожидания перед тем, как вернуть результат, и -поддерживает современные возможности Python, код можно написать следующим образом: +Когда есть операция, которой нужно подождать перед тем, как вернуть результат, и она поддерживает эти новые возможности Python, вы можете написать так: ```Python burgers = await get_burgers(2) ``` -Главное здесь слово `await`. Оно сообщает интерпретатору, что необходимо дождаться ⏸ -пока `get_burgers(2)` закончит свои дела 🕙, и только после этого сохранить результат в `burgers`. -Зная это, Python может пока переключиться на выполнение других задач 🔀 ⏯ -(например получение следующего запроса). +Ключ здесь — `await`. Он говорит Python, что нужно подождать ⏸, пока `get_burgers(2)` закончит своё дело 🕙, прежде чем сохранять результат в `burgers`. Благодаря этому Python будет знать, что за это время можно заняться чем-то ещё 🔀 ⏯ (например, принять другой запрос). -Чтобы ключевое слово `await` сработало, оно должно находиться внутри функции, -которая поддерживает асинхронность. Для этого вам просто нужно объявить её как `async def`: +Чтобы `await` работал, он должен находиться внутри функции, которая поддерживает такую асинхронность. Для этого просто объявите её с `async def`: ```Python hl_lines="1" async def get_burgers(number: int): - # Готовим бургеры по специальному асинхронному рецепту + # Сделать что-то асинхронное, чтобы приготовить бургеры return burgers ``` @@ -355,26 +325,22 @@ async def get_burgers(number: int): ```Python hl_lines="2" # Это не асинхронный код def get_sequential_burgers(number: int): - # Готовим бургеры последовательно по шагам + # Сделать что-то последовательное, чтобы приготовить бургеры return burgers ``` -Объявление `async def` указывает интерпретатору, что внутри этой функции -следует ожидать выражений `await`, и что можно поставить выполнение такой функции на "паузу" ⏸ и -переключиться на другие задачи 🔀, с тем чтобы вернуться сюда позже. +С `async def` Python знает, что внутри этой функции нужно учитывать выражения `await` и что выполнение такой функции можно «приостанавливать» ⏸ и идти делать что-то ещё 🔀, чтобы потом вернуться. -Если вы хотите вызвать функцию с `async def`, вам нужно "ожидать" её. -Поэтому такое не сработает: +Когда вы хотите вызвать функцию, объявленную с `async def`, нужно её «ожидать». Поэтому вот так не сработает: ```Python -# Это не заработает, поскольку get_burgers объявлена с использованием async def +# Это не сработает, потому что get_burgers определена с: async def burgers = get_burgers(2) ``` --- -Если сторонняя библиотека требует вызывать её с ключевым словом `await`, -необходимо писать *функции обработки пути* с использованием `async def`, например: +Итак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функцию-обработчик пути*, которая её использует, с `async def`, например: ```Python hl_lines="2-3" @app.get('/burgers') @@ -383,129 +349,96 @@ async def read_burgers(): return burgers ``` -### Технические подробности +### Более технические подробности { #more-technical-details } -Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`. +Вы могли заметить, что `await` можно использовать только внутри функций, определённых с `async def`. - -Но выполнение такой функции необходимо "ожидать" с помощью `await`. -Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`. +Но при этом функции, определённые с `async def`, нужно «ожидать». Значит, функции с `async def` тоже можно вызывать только из функций, определённых с `async def`. -Но как же тогда появилась первая курица? В смысле... как нам вызвать первую асинхронную функцию? +Так что же с «яйцом и курицей» — как вызвать первую `async` функцию? -При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*, -и дальше с этим разберётся FastAPI. +Если вы работаете с **FastAPI**, вам не о чем беспокоиться, потому что этой «первой» функцией будет ваша *функция-обработчик пути*, а FastAPI знает, как сделать всё правильно. -Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI. +Но если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать. -### Пишите свой асинхронный код +### Пишите свой асинхронный код { #write-your-own-async-code } -Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой asyncio в Python, так и с Trio. +Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми и со стандартной библиотекой Python asyncio, и с Trio. -В частности, вы можете напрямую использовать AnyIO в тех проектах, где требуется более сложная логика работы с конкурентностью. +В частности, вы можете напрямую использовать AnyIO для продвинутых сценариев конкурентности, где в вашем коде нужны более сложные паттерны. -Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*). +И даже если вы не используете FastAPI, вы можете писать свои асинхронные приложения с AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например, *структурную конкурентность*). -### Другие виды асинхронного программирования +Я создал ещё одну библиотеку поверх AnyIO, тонкий слой, чтобы немного улучшить аннотации типов и получить более качественное **автозавершение**, **ошибки прямо в редакторе** и т.д. Там также есть дружелюбное введение и руководство, чтобы помочь вам **понять** и писать **свой собственный асинхронный код**: Asyncer. Она особенно полезна, если вам нужно **комбинировать асинхронный код с обычным** (блокирующим/синхронным) кодом. -Стиль написания кода с `async` и `await` появился в языке Python относительно недавно. +### Другие формы асинхронного кода { #other-forms-of-asynchronous-code } -Но он сильно облегчает работу с асинхронным кодом. +Такой стиль использования `async` и `await` относительно новый в языке. -Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS). +Но он сильно упрощает работу с асинхронным кодом. -До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать. +Такой же (или почти такой же) синтаксис недавно появился в современных версиях JavaScript (в браузере и NodeJS). -В предыдущих версиях Python для этого использовались потоки или Gevent. Но такой код намного сложнее понимать, отлаживать и мысленно представлять. +До этого работа с асинхронным кодом была заметно сложнее и труднее для понимания. -Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели -"обратные вызовы". Что выливалось в -"ад обратных вызовов". +В предыдущих версиях Python можно было использовать потоки или Gevent. Но такой код гораздо сложнее понимать, отлаживать и держать в голове. -## Сопрограммы +В прежних версиях NodeJS/браузерного JavaScript вы бы использовали «callbacks» (обратные вызовы), что приводит к «callback hell» (ад обратных вызовов). -**Корути́на** (или же сопрограмма) — это крутое словечко для именования той сущности, -которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию, -но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`. +## Сопрограммы { #coroutines } -Всю функциональность асинхронного программирования с использованием `async` и `await` -часто обобщают словом "корутины". Они аналогичны "горутинам", ключевой особенности -языка Go. +**Сопрограмма** (coroutine) — это просто «навороченное» слово для того, что возвращает функция `async def`. Python знает, что это похоже на функцию: её можно запустить, она когда-нибудь завершится, но её выполнение может приостанавливаться ⏸ внутри, когда встречается `await`. -## Заключение +Часто всю функциональность использования асинхронного кода с `async` и `await` кратко называют «сопрограммами». Это сопоставимо с ключевой особенностью Go — «goroutines». -В самом начале была такая фраза: +## Заключение { #conclusion } -> Современные версии Python поддерживают разработку так называемого -**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием -синтаксиса **`async` и `await`**. +Вернёмся к той же фразе: -Теперь всё должно звучать понятнее. ✨ +> Современные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**. -На этом основана работа FastAPI (посредством Starlette), и именно это -обеспечивает его высокую производительность. +Теперь это должно звучать понятнее. ✨ -## Очень технические подробности +Именно это «движет» FastAPI (через Starlette) и обеспечивает столь впечатляющую производительность. -/// warning +## Очень технические подробности { #very-technical-details } -Этот раздел читать не обязательно. +/// warning | Предупреждение -Здесь приводятся подробности внутреннего устройства **FastAPI**. +Скорее всего, этот раздел можно пропустить. -Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.) -и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`, -читайте дальше. +Здесь — очень технические подробности о том, как **FastAPI** работает «под капотом». + +Если у вас есть достаточно технических знаний (сопрограммы, потоки, блокировки и т.д.) и вам интересно, как FastAPI обрабатывает `async def` по сравнению с обычным `def`, — вперёд. /// -### Функции обработки пути +### Функции-обработчики пути { #path-operation-functions } -Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def` -вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем -пуле потоков, а не напрямую (это бы заблокировало сервер). +Когда вы объявляете *функцию-обработчик пути* обычным `def` вместо `async def`, она запускается во внешнем пуле потоков, который затем «ожидается», вместо прямого вызова (прямой вызов заблокировал бы сервер). -Если ранее вы использовали другой асинхронный фреймворк, который работает иначе, -и привыкли объявлять простые вычислительные *функции* через `def` ради -незначительного прироста скорости (порядка 100 наносекунд), обратите внимание, -что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит -`async def`, если только *функция обработки пути* не использует код, приводящий -к блокировке I/O. - +Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий I/O. - -Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](index.md#_11){.internal-link target=_blank} -другого фреймворка (или хотя бы на уровне с ним). +Тем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance){.internal-link target=_blank} (или как минимум сопоставим) с вашим предыдущим фреймворком. -### Зависимости +### Зависимости { #dependencies } -То же относится к зависимостям. Если это обычная функция `def`, а не `async def`, -она запускается во внешнем пуле потоков. +То же относится к [зависимостям](tutorial/dependencies/index.md){.internal-link target=_blank}. Если зависимость — это обычная функция `def`, а не `async def`, она запускается во внешнем пуле потоков. -### Подзависимости +### Подзависимости { #sub-dependencies } -Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей -(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`, -другие обычным образом через `def`, и такая схема вполне работоспособна. Функции, -объявленные с помощью `def` будут запускаться на внешнем потоке (из пула), -а не с помощью `await`. +У вас может быть несколько зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}, которые требуют друг друга (в виде параметров определений функций): часть из них может быть объявлена с `async def`, а часть — обычным `def`. Всё будет работать, а те, что объявлены обычным `def`, будут вызываться во внешнем потоке (из пула), а не «ожидаться». -### Другие служебные функции +### Другие служебные функции { #other-utility-functions } -Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять -с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы -их запускаете. +Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять обычным `def` или `async def`, и FastAPI не будет влиять на то, как вы их вызываете. -Этим они отличаются от функций, которые FastAPI вызывает самостоятельно: -*функции обработки пути* и зависимости. +В отличие от функций, которые FastAPI вызывает за вас: *функции-обработчики пути* и зависимости. -Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую -(как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с -помощью `async def`, её вызов должен осуществляться с ожиданием через `await`. +Если служебная функция — обычная функция с `def`, она будет вызвана напрямую (как вы и пишете в коде), не в пуле потоков; если функция объявлена с `async def`, тогда при её вызове в вашем коде вы должны использовать `await`. --- - -Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали. +Снова: это очень технические подробности, полезные, вероятно, только если вы целенаправленно их ищете. -В противном случае просто ознакомьтесь с основными принципами в разделе выше: Нет времени?. +Иначе вам достаточно руководствоваться рекомендациями из раздела выше: Нет времени?. diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md index 259dca8e6..612b39f70 100644 --- a/docs/ru/docs/benchmarks.md +++ b/docs/ru/docs/benchmarks.md @@ -1,37 +1,34 @@ -# Замеры производительности +# Бенчмарки (тесты производительности) { #benchmarks } -Независимые тесты производительности приложений от TechEmpower показывают, что **FastAPI** под управлением Uvicorn один из самых быстрых Python-фреймворков и уступает только Starlette и Uvicorn (которые используются в FastAPI). (*) +Независимые бенчмарки TechEmpower показывают, что приложения **FastAPI** под управлением Uvicorn — одни из самых быстрых Python‑фреймворков, уступающие только Starlette и самому Uvicorn (используются внутри FastAPI). -Но при просмотре и сравнении замеров производительности следует иметь в виду нижеописанное. +Но при просмотре бенчмарков и сравнений следует иметь в виду следующее. -## Замеры производительности и скорости +## Бенчмарки и скорость { #benchmarks-and-speed } -В подобных тестах часто можно увидеть, что инструменты разного типа сравнивают друг с другом, как аналогичные. +При проверке бенчмарков часто можно увидеть, что инструменты разных типов сравнивают как эквивалентные. -В частности, сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов). +В частности, часто сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов). -Чем проще проблема, которую решает инструмент, тем выше его производительность. И большинство тестов не проверяют дополнительные функции, предоставляемые инструментом. +Чем проще задача, которую решает инструмент, тем выше его производительность. И большинство бенчмарков не тестируют дополнительные возможности, предоставляемые инструментом. -Иерархия инструментов имеет следующий вид: +Иерархия выглядит так: * **Uvicorn**: ASGI-сервер - * **Starlette** (использует Uvicorn): веб-микрофреймворк - * **FastAPI** (использует Starlette): API-микрофреймворк с дополнительными функциями для создания API, с валидацией данных и т.д. + * **Starlette**: (использует Uvicorn) веб-микрофреймворк + * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п. * **Uvicorn**: - * Будет иметь наилучшую производительность, так как не имеет большого количества дополнительного кода, кроме самого сервера. - * Вы не будете писать приложение на Uvicorn напрямую. Это означало бы, что Ваш код должен включать как минимум весь - код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки. - * Uvicorn подлежит сравнению с Daphne, Hypercorn, uWSGI и другими веб-серверами. - + * Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода. + * Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки. + * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений. * **Starlette**: - * Будет уступать Uvicorn по производительности. Фактически Starlette управляется Uvicorn и из-за выполнения большего количества кода он не может быть быстрее, чем Uvicorn. - * Зато он предоставляет Вам инструменты для создания простых веб-приложений с обработкой маршрутов URL и т.д. - * Starlette следует сравнивать с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками). - + * Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода. + * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п. + * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками). * **FastAPI**: - * Так же как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, то есть он не может быть быстрее Starlette. - * FastAPI предоставляет больше возможностей поверх Starlette, которые наверняка Вам понадобятся при создании API, такие как проверка данных и сериализация. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске). - * Если Вы не используете FastAPI, а используете Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. - * Таким образом, используя FastAPI Вы потратите меньше времени на разработку, уменьшите количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своем коде). - * FastAPI должно сравнивать с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные. + * Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его. + * FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске). + * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. + * Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде). + * Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. diff --git a/docs/ru/docs/deployment/concepts.md b/docs/ru/docs/deployment/concepts.md index acfa1f4fe..207d1604d 100644 --- a/docs/ru/docs/deployment/concepts.md +++ b/docs/ru/docs/deployment/concepts.md @@ -1,323 +1,321 @@ -# Концепции развёртывания +# Концепции развёртывания { #deployments-concepts } -Существует несколько концепций, применяемых для развёртывания приложений **FastAPI**, равно как и для любых других типов веб-приложений, среди которых вы можете выбрать **наиболее подходящий** способ. +При развёртывании приложения **FastAPI** (и вообще любого веб‑API) есть несколько концепций, о которых стоит думать — с их помощью можно выбрать **наиболее подходящий** способ **развёртывания вашего приложения**. -Самые важные из них: +Некоторые из важных концепций: -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения. +* Безопасность — HTTPS +* Запуск при старте +* Перезапуски +* Репликация (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -Рассмотрим ниже влияние каждого из них на процесс **развёртывания**. +Посмотрим, как они влияют на **развёртывания**. -Наша конечная цель - **обслуживать клиентов вашего API безопасно** и **бесперебойно**, с максимально эффективным использованием **вычислительных ресурсов** (например, удалённых серверов/виртуальных машин). 🚀 +В конечном итоге цель — **обслуживать клиентов вашего API** безопасно, **избегать перебоев** и максимально эффективно использовать **вычислительные ресурсы** (например, удалённые серверы/виртуальные машины). 🚀 -Здесь я немного расскажу Вам об этих **концепциях** и надеюсь, что у вас сложится **интуитивное понимание**, какой способ выбрать при развертывании вашего API в различных окружениях, возможно, даже **ещё не существующих**. +Здесь я немного расскажу о этих **концепциях**, чтобы у вас появилась **интуиция**, как развёртывать ваш API в разных окружениях, возможно даже в **будущих**, которых ещё не существует. -Ознакомившись с этими концепциями, вы сможете **оценить и выбрать** лучший способ развёртывании **Вашего API**. +Учитывая эти концепции, вы сможете **оценить и спроектировать** лучший способ развёртывания **своих API**. -В последующих главах я предоставлю Вам **конкретные рецепты** развёртывания приложения FastAPI. +В следующих главах я дам более **конкретные рецепты** по развёртыванию приложений FastAPI. -А сейчас давайте остановимся на важных **идеях этих концепций**. Эти идеи можно также применить и к другим типам веб-приложений. 💡 +А пока давайте разберём важные **идеи**. Эти концепции применимы и к другим типам веб‑API. 💡 -## Использование более безопасного протокола HTTPS +## Безопасность — HTTPS { #security-https } -В [предыдущей главе об HTTPS](https.md){.internal-link target=_blank} мы рассмотрели, как HTTPS обеспечивает шифрование для вашего API. +В [предыдущей главе про HTTPS](https.md){.internal-link target=_blank} мы разобрались, как HTTPS обеспечивает шифрование для вашего API. -Также мы заметили, что обычно для работы с HTTPS вашему приложению нужен **дополнительный** компонент - **прокси-сервер завершения работы TLS**. +Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**. -И если прокси-сервер не умеет сам **обновлять сертификаты HTTPS**, то нужен ещё один компонент для этого действия. +И должен быть компонент, отвечающий за **обновление HTTPS‑сертификатов** — это может быть тот же самый компонент или отдельный. -### Примеры инструментов для работы с HTTPS +### Примеры инструментов для HTTPS { #example-tools-for-https } -Вот некоторые инструменты, которые вы можете применять как прокси-серверы: +Некоторые инструменты, которые можно использовать как TLS Termination Proxy: * Traefik - * С автоматическим обновлением сертификатов ✨ + * Автоматически обновляет сертификаты ✨ * Caddy - * С автоматическим обновлением сертификатов ✨ + * Автоматически обновляет сертификаты ✨ * Nginx - * С дополнительным компонентом типа Certbot для обновления сертификатов + * С внешним компонентом (например, Certbot) для обновления сертификатов * HAProxy - * С дополнительным компонентом типа Certbot для обновления сертификатов -* Kubernetes с Ingress Controller похожим на Nginx - * С дополнительным компонентом типа cert-manager для обновления сертификатов -* Использование услуг облачного провайдера (читайте ниже 👇) + * С внешним компонентом (например, Certbot) для обновления сертификатов +* Kubernetes с Ingress Controller (например, Nginx) + * С внешним компонентом (например, cert-manager) для обновления сертификатов +* Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇) -В последнем варианте вы можете воспользоваться услугами **облачного сервиса**, который сделает большую часть работы, включая настройку HTTPS. Это может наложить дополнительные ограничения или потребовать дополнительную плату и т.п. Зато Вам не понадобится самостоятельно заниматься настройками прокси-сервера. +Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать TLS Termination Proxy. -В дальнейшем я покажу Вам некоторые конкретные примеры их применения. +В следующих главах я покажу конкретные примеры. --- -Следующие концепции рассматривают применение программы, запускающей Ваш API (такой как Uvicorn). +Далее рассмотрим концепции, связанные с программой, которая запускает ваш реальный API (например, Uvicorn). -## Программа и процесс +## Программа и процесс { #program-and-process } -Мы часто будем встречать слова **процесс** и **программа**, потому следует уяснить отличия между ними. +Мы часто будем говорить о работающем "**процессе**", поэтому полезно чётко понимать, что это значит и чем отличается от "**программы**". -### Что такое программа +### Что такое программа { #what-is-a-program } -Термином **программа** обычно описывают множество вещей: +Словом **программа** обычно называют разные вещи: -* **Код**, который вы написали, в нашем случае **Python-файлы**. -* **Файл**, который может быть **исполнен** операционной системой, например `python`, `python.exe` или `uvicorn`. -* Конкретная программа, **запущенная** операционной системой и использующая центральный процессор и память. В таком случае это также называется **процесс**. +* **Код**, который вы пишете, то есть **Python‑файлы**. +* **Файл**, который может быть **запущен** операционной системой, например: `python`, `python.exe` или `uvicorn`. +* Конкретную программу в момент, когда она **работает** в операционной системе, используя CPU и память. Это также называют **процессом**. -### Что такое процесс +### Что такое процесс { #what-is-a-process } -Термин **процесс** имеет более узкое толкование, подразумевая что-то, запущенное операционной системой (как в последнем пункте из вышестоящего абзаца): +Слово **процесс** обычно используют более конкретно — только для того, что реально выполняется в операционной системе (как в последнем пункте выше): -* Конкретная программа, **запущенная** операционной системой. - * Это не имеет отношения к какому-либо файлу или коду, но нечто **определённое**, управляемое и **выполняемое** операционной системой. -* Любая программа, любой код, **могут делать что-то** только когда они **выполняются**. То есть, когда являются **работающим процессом**. -* Процесс может быть **прерван** (или "убит") Вами или вашей операционной системой. В результате чего он перестанет исполняться и **не будет продолжать делать что-либо**. -* Каждое приложение, которое вы запустили на своём компьютере, каждая программа, каждое "окно" запускает какой-то процесс. И обычно на включенном компьютере **одновременно** запущено множество процессов. -* И **одна программа** может запустить **несколько параллельных процессов**. +* Конкретная программа в момент, когда она **запущена** в операционной системе. + * Речь не о файле и не о коде, а **конкретно** о том, что **исполняется** и управляется операционной системой. +* Любая программа, любой код **могут что‑то делать** только когда **исполняются**, то есть когда есть **работающий процесс**. +* Процесс можно **завершить** (или «убить») вами или операционной системой. В этот момент он перестаёт выполняться и **больше ничего делать не может**. +* У каждого запущенного приложения на вашем компьютере есть свой процесс; у каждой программы, у каждого окна и т.д. Обычно одновременно **работает много процессов**, пока компьютер включён. +* Могут **одновременно** работать **несколько процессов** одной и той же **программы**. -Если вы заглянете в "диспетчер задач" или "системный монитор" (или аналогичные инструменты) вашей операционной системы, то увидите множество работающих процессов. +Если вы посмотрите «диспетчер задач» или «системный монитор» (или аналогичные инструменты) в вашей операционной системе, то увидите множество работающих процессов. -Вполне вероятно, что вы увидите несколько процессов с одним и тем же названием браузерной программы (Firefox, Chrome, Edge и т. Д.). Обычно браузеры запускают один процесс на вкладку и вдобавок некоторые дополнительные процессы. +Например, вы, скорее всего, увидите несколько процессов одного и того же браузера (Firefox, Chrome, Edge и т.д.). Обычно браузеры запускают один процесс на вкладку плюс дополнительные процессы. --- -Теперь, когда нам известна разница между **процессом** и **программой**, давайте продолжим обсуждение развёртывания. +Теперь, когда мы понимаем разницу между **процессом** и **программой**, продолжим разговор о развёртываниях. -## Настройки запуска приложения +## Запуск при старте { #running-on-startup } -В большинстве случаев когда вы создаёте веб-приложение, то желаете, чтоб оно **работало постоянно** и непрерывно, предоставляя клиентам доступ в любое время. Хотя иногда у вас могут быть причины, чтоб оно запускалось только при определённых условиях. +В большинстве случаев, создавая веб‑API, вы хотите, чтобы он **работал постоянно**, без перерывов, чтобы клиенты всегда могли к нему обратиться. Разве что у вас есть особые причины запускать его только при определённых условиях, но обычно вы хотите, чтобы он был постоянно запущен и **доступен**. -### Удалённый сервер +### На удалённом сервере { #in-a-remote-server } -Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самое простое, что можно сделать, запустить Uvicorn (или его аналог) вручную, как вы делаете при локальной разработке. +Когда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самый простой вариант — вручную использовать `fastapi run` (он использует Uvicorn) или что‑то похожее, как вы делаете при локальной разработке. -Это рабочий способ и он полезен **во время разработки**. +Это будет работать и полезно **во время разработки**. -Но если вы потеряете соединение с сервером, то не сможете отслеживать - работает ли всё ещё **запущенный Вами процесс**. +Но если соединение с сервером прервётся, **запущенный процесс**, скорее всего, завершится. -И если сервер перезагрузится (например, после обновления или каких-то действий облачного провайдера), вы скорее всего **этого не заметите**, чтобы снова запустить процесс вручную. Вследствие этого Ваш API останется мёртвым. 😱 +А если сервер перезагрузится (например, после обновлений или миграций у облачного провайдера), вы, вероятно, **даже не заметите этого**. Из‑за этого вы не узнаете, что нужно вручную перезапустить процесс — и ваш API просто будет «мёртв». 😱 -### Автоматический запуск программ +### Автоматический запуск при старте { #run-automatically-on-startup } -Вероятно вы захотите, чтоб Ваша серверная программа (такая, как Uvicorn) стартовала автоматически при включении сервера, без **человеческого вмешательства** и всегда могла управлять Вашим API (так как Uvicorn запускает приложение FastAPI). +Как правило, вы захотите, чтобы серверная программа (например, Uvicorn) запускалась автоматически при старте сервера и без **участия человека**, чтобы всегда был процесс, запущенный с вашим API (например, Uvicorn, запускающий ваше приложение FastAPI). -### Отдельная программа +### Отдельная программа { #separate-program } -Для этого у обычно используют отдельную программу, которая следит за тем, чтобы Ваши приложения запускались при включении сервера. Такой подход гарантирует, что другие компоненты или приложения также будут запущены, например, база данных +Чтобы этого добиться, обычно используют **отдельную программу**, которая гарантирует запуск вашего приложения при старте. Во многих случаях она также запускает и другие компоненты/приложения, например базу данных. -### Примеры инструментов, управляющих запуском программ +### Примеры инструментов для запуска при старте { #example-tools-to-run-at-startup } -Вот несколько примеров, которые могут справиться с такой задачей: +Примеры инструментов, которые могут с этим справиться: * Docker * Kubernetes * Docker Compose -* Docker в режиме Swarm +* Docker в режиме Swarm (Swarm Mode) * Systemd * Supervisor -* Использование услуг облачного провайдера +* Обработка внутри облачного провайдера как часть его услуг * Прочие... -Я покажу Вам некоторые примеры их использования в следующих главах. +Более конкретные примеры будут в следующих главах. -## Перезапуск +## Перезапуски { #restarts } -Вы, вероятно, также захотите, чтоб ваше приложение **перезапускалось**, если в нём произошёл сбой. +Подобно тому как вы обеспечиваете запуск приложения при старте, вы, вероятно, захотите обеспечить его **перезапуск** после сбоев. -### Мы ошибаемся +### Мы ошибаемся { #we-make-mistakes } -Все люди совершают **ошибки**. Программное обеспечение почти *всегда* содержит **баги** спрятавшиеся в разных местах. 🐛 +Мы, люди, постоянно совершаем **ошибки**. В программном обеспечении почти всегда есть **баги**, скрытые в разных местах. 🐛 -И мы, будучи разработчиками, продолжаем улучшать код, когда обнаруживаем в нём баги или добавляем новый функционал (возможно, добавляя при этом баги 😅). +И мы, как разработчики, продолжаем улучшать код — находим баги и добавляем новые возможности (иногда добавляя новые баги 😅). -### Небольшие ошибки обрабатываются автоматически +### Небольшие ошибки обрабатываются автоматически { #small-errors-automatically-handled } -Когда вы создаёте свои API на основе FastAPI и допускаете в коде ошибку, то FastAPI обычно остановит её распространение внутри одного запроса, при обработке которого она возникла. 🛡 +Создавая веб‑API с FastAPI, если в нашем коде возникает ошибка, FastAPI обычно «локализует» её в пределах одного запроса, который эту ошибку вызвал. 🛡 -Клиент получит ошибку **500 Internal Server Error** в ответ на свой запрос, но приложение не сломается и будет продолжать работать с последующими запросами. +Клиент получит **500 Internal Server Error** для этого запроса, но приложение продолжит работать для последующих запросов, а не «упадёт» целиком. -### Большие ошибки - Падение приложений +### Большие ошибки — падения { #bigger-errors-crashes } -Тем не менее, может случиться так, что ошибка вызовет **сбой всего приложения** или даже сбой в Uvicorn, а то и в самом Python. 💥 +Тем не менее возможны случаи, когда код **роняет всё приложение**, приводя к сбою Uvicorn и Python. 💥 -Но мы всё ещё хотим, чтобы приложение **продолжало работать** несмотря на эту единственную ошибку, обрабатывая, как минимум, запросы к *операциям пути* не имеющим ошибок. +И вы, скорее всего, не захотите, чтобы приложение оставалось «мёртвым» из‑за ошибки в одном месте — вы захотите, чтобы оно **продолжало работать** хотя бы для *операций пути*, которые не сломаны. -### Перезапуск после падения +### Перезапуск после падения { #restart-after-crash } -Для случаев, когда ошибки приводят к сбою в запущенном **процессе**, Вам понадобится добавить компонент, который **перезапустит** процесс хотя бы пару раз... +В случаях действительно серьёзных ошибок, которые роняют работающий **процесс**, вам понадобится внешний компонент, отвечающий за **перезапуск** процесса, как минимум пару раз... -/// tip | Заметка +/// tip | Совет -... Если приложение падает сразу же после запуска, вероятно бесполезно его бесконечно перезапускать. Но полагаю, вы заметите такое поведение во время разработки или, по крайней мере, сразу после развёртывания. +...Хотя если приложение **падает сразу же**, вероятно, нет смысла перезапускать его бесконечно. Но такие случаи вы, скорее всего, заметите во время разработки или как минимум сразу после развёртывания. -Так что давайте сосредоточимся на конкретных случаях, когда приложение может полностью выйти из строя, но всё ещё есть смысл его запустить заново. +Давайте сосредоточимся на основных сценариях, когда в каких‑то конкретных ситуациях **в будущем** приложение может падать целиком, и при этом имеет смысл его перезапускать. /// -Возможно вы захотите, чтоб был некий **внешний компонент**, ответственный за перезапуск вашего приложения даже если уже не работает Uvicorn или Python. То есть ничего из того, что написано в вашем коде внутри приложения, не может быть выполнено в принципе. +Скорее всего, вы захотите, чтобы перезапуском вашего приложения занимался **внешний компонент**, потому что к тому моменту Uvicorn и Python уже упали, и внутри того же кода вашего приложения сделать уже ничего нельзя. -### Примеры инструментов для автоматического перезапуска +### Примеры инструментов для автоматического перезапуска { #example-tools-to-restart-automatically } -В большинстве случаев инструменты **запускающие программы при старте сервера** умеют **перезапускать** эти программы. +В большинстве случаев тот же инструмент, который **запускает программу при старте**, умеет обрабатывать и автоматические **перезапуски**. -В качестве примера можно взять те же: +Например, это может быть: * Docker * Kubernetes * Docker Compose -* Docker в режиме Swarm +* Docker в режиме Swarm (Swarm Mode) * Systemd * Supervisor -* Использование услуг облачного провайдера +* Обработка внутри облачного провайдера как часть его услуг * Прочие... -## Запуск нескольких экземпляров приложения (Репликация) - Процессы и память +## Репликация — процессы и память { #replication-processes-and-memory } -Приложение FastAPI, управляемое серверной программой (такой как Uvicorn), запускается как **один процесс** и может обслуживать множество клиентов одновременно. +В приложении FastAPI, используя серверную программу (например, команду `fastapi`, которая запускает Uvicorn), запуск в **одном процессе** уже позволяет обслуживать нескольких клиентов одновременно. -Но часто Вам может понадобиться несколько одновременно работающих одинаковых процессов. +Но во многих случаях вы захотите одновременно запустить несколько процессов‑воркеров. -### Множество процессов - Воркеры (Workers) +### Несколько процессов — Воркеры { #multiple-processes-workers } -Если количество Ваших клиентов больше, чем может обслужить один процесс (допустим, что виртуальная машина не слишком мощная), но при этом Вам доступно **несколько ядер процессора**, то вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределить запросы между этими процессами. +Если клиентов больше, чем способен обслужить один процесс (например, если виртуальная машина не слишком мощная), и на сервере есть **несколько ядер CPU**, вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределять запросы между ними. -**Несколько запущенных процессов** одной и той же API-программы часто называют **воркерами**. +Когда вы запускаете **несколько процессов** одной и той же программы API, их обычно называют **воркерами**. -### Процессы и порты́ +### Процессы‑воркеры и порты { #worker-processes-and-ports } -Помните ли Вы, как на странице [Об HTTPS](https.md){.internal-link target=_blank} мы обсуждали, что на сервере только один процесс может слушать одну комбинацию IP-адреса и порта? +Помните из раздела [Об HTTPS](https.md){.internal-link target=_blank}, что на сервере только один процесс может слушать конкретную комбинацию порта и IP‑адреса? -С тех пор ничего не изменилось. +Это по‑прежнему так. -Соответственно, чтобы иметь возможность работать с **несколькими процессами** одновременно, должен быть **один процесс, прослушивающий порт** и затем каким-либо образом передающий данные каждому рабочему процессу. +Поэтому, чтобы одновременно работало **несколько процессов**, должен быть **один процесс, слушающий порт**, который затем каким‑то образом передаёт коммуникацию каждому воркер‑процессу. -### У каждого процесса своя память +### Память на процесс { #memory-per-process } -Работающая программа загружает в память данные, необходимые для её работы, например, переменные содержащие модели машинного обучения или большие файлы. Каждая переменная **потребляет некоторое количество оперативной памяти (RAM)** сервера. +Когда программа загружает что‑то в память (например, модель машинного обучения в переменную или содержимое большого файла в переменную), всё это **потребляет часть памяти (RAM)** сервера. -Обычно процессы **не делятся памятью друг с другом**. Сие означает, что каждый работающий процесс имеет свои данные, переменные и свой кусок памяти. И если для выполнения вашего кода процессу нужно много памяти, то **каждый такой же процесс** запущенный дополнительно, потребует такого же количества памяти. +И разные процессы обычно **не делят память**. Это значит, что у каждого процесса свои переменные и своя память. Если ваш код потребляет много памяти, то **каждый процесс** будет потреблять сопоставимый объём памяти. -### Память сервера +### Память сервера { #server-memory } -Допустим, что Ваш код загружает модель машинного обучения **размером 1 ГБ**. Когда вы запустите своё API как один процесс, он займёт в оперативной памяти не менее 1 ГБ. А если вы запустите **4 таких же процесса** (4 воркера), то каждый из них займёт 1 ГБ оперативной памяти. В результате вашему API потребуется **4 ГБ оперативной памяти (RAM)**. +Например, если ваш код загружает модель Машинного обучения размером **1 ГБ**, то при запуске одного процесса с вашим API он будет использовать как минимум 1 ГБ RAM. А если вы запустите **4 процесса** (4 воркера), каждый процесс будет использовать 1 ГБ RAM. Всего ваш API будет потреблять **4 ГБ RAM**. -И если Ваш удалённый сервер или виртуальная машина располагает только 3 ГБ памяти, то попытка загрузить в неё 4 ГБ данных вызовет проблемы. 🚨 +И если у вашего удалённого сервера или виртуальной машины только 3 ГБ RAM, попытка загрузить более 4 ГБ вызовет проблемы. 🚨 -### Множество процессов - Пример +### Несколько процессов — пример { #multiple-processes-an-example } -В этом примере **менеджер процессов** запустит и будет управлять двумя **воркерами**. +В этом примере есть **процесс‑менеджер**, который запускает и контролирует два **процесса‑воркера**. -Менеджер процессов будет слушать определённый **сокет** (IP:порт) и передавать данные работающим процессам. +Процесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам. -Каждый из этих процессов будет запускать ваше приложение для обработки полученного **запроса** и возвращения вычисленного **ответа** и они будут использовать оперативную память. +Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **запроса** и возврата **ответа**, и загружать всё, что вы кладёте в переменные, в RAM. -Безусловно, на этом же сервере будут работать и **другие процессы**, которые не относятся к вашему приложению. +Конечно, на той же машине помимо вашего приложения, скорее всего, будут работать и **другие процессы**. -Интересная деталь заключается в том, что процент **использования центрального процессора (CPU)** каждым процессом может сильно меняться с течением времени, но объём занимаемой **оперативной памяти (RAM)** остаётся относительно **стабильным**. +Интересная деталь: процент **использования CPU** каждым процессом со временем может сильно **меняться**, но **память (RAM)** обычно остаётся более‑менее **стабильной**. -Если у вас есть API, который каждый раз выполняет сопоставимый объем вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *также будет стабильной* (вместо того, чтобы постоянно быстро увеличиваться и уменьшаться). +Если у вас API, который каждый раз выполняет сопоставимый объём вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *тоже будет стабильной* (вместо того, чтобы быстро и постоянно «скакать»). -### Примеры стратегий и инструментов для запуска нескольких экземпляров приложения +### Примеры инструментов и стратегий репликации { #examples-of-replication-tools-and-strategies } -Существует несколько подходов для достижения целей репликации и я расскажу Вам больше о конкретных стратегиях в следующих главах, например, когда речь пойдет о Docker и контейнерах. +Есть несколько подходов для достижения этого, и я расскажу больше о конкретных стратегиях в следующих главах, например, говоря о Docker и контейнерах. -Основное ограничение при этом - только **один** компонент может работать с определённым **портом публичного IP**. И должен быть способ **передачи** данных между этим компонентом и копиями **процессов/воркеров**. +Главное ограничение: должен быть **один** компонент, который обрабатывает **порт** на **публичном IP**. И у него должен быть способ **передавать** коммуникацию реплицированным **процессам/воркерам**. -Вот некоторые возможные комбинации и стратегии: +Некоторые возможные комбинации и стратегии: -* **Gunicorn** управляющий **воркерами Uvicorn** - * Gunicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **множества работающих процессов Uvicorn**. -* **Uvicorn** управляющий **воркерами Uvicorn** - * Один процесс Uvicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Он будет запускать **множество работающих процессов Uvicorn**. -* **Kubernetes** и аналогичные **контейнерные системы** - * Какой-то компонент в **Kubernetes** будет слушать **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**. -* **Облачные сервисы**, которые позаботятся обо всём за Вас - * Возможно, что облачный сервис умеет **управлять запуском дополнительных экземпляров приложения**. Вероятно, он потребует, чтоб вы указали - какой **процесс** или **образ** следует клонировать. Скорее всего, вы укажете **один процесс Uvicorn** и облачный сервис будет запускать его копии при необходимости. +* **Uvicorn** с `--workers` + * Один **процесс‑менеджер** Uvicorn будет слушать **IP** и **порт** и запускать **несколько процессов‑воркеров Uvicorn**. +* **Kubernetes** и другие распределённые **контейнерные системы** + * Некий компонент на уровне **Kubernetes** будет слушать **IP** и **порт**. Репликация достигается с помощью **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**. +* **Облачные сервисы**, которые берут это на себя + * Облачный сервис, скорее всего, **возьмёт репликацию на себя**. Он, возможно, позволит указать **процесс для запуска** или **образ контейнера**. В любом случае это, скорее всего, будет **один процесс Uvicorn**, а сервис займётся его репликацией. -/// tip | Заметка +/// tip | Совет -Если вы не знаете, что такое **контейнеры**, Docker или Kubernetes, не переживайте. +Не беспокойтесь, если некоторые пункты про **контейнеры**, Docker или Kubernetes пока кажутся неочевидными. -Я поведаю Вам о контейнерах, образах, Docker, Kubernetes и т.п. в главе: [FastAPI внутри контейнеров - Docker](docker.md){.internal-link target=_blank}. +Я расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md){.internal-link target=_blank}. /// -## Шаги, предшествующие запуску +## Предварительные шаги перед запуском { #previous-steps-before-starting } -Часто бывает, что Вам необходимо произвести какие-то подготовительные шаги **перед запуском** своего приложения. +Во многих случаях вы захотите выполнить некоторые шаги **перед запуском** приложения. Например, запустить **миграции базы данных**. -Но в большинстве случаев такие действия достаточно произвести **однократно**. +Но чаще всего эти шаги нужно выполнять только **один раз**. -Поэтому Вам нужен будет **один процесс**, выполняющий эти **подготовительные шаги** до запуска приложения. +Поэтому вы захотите иметь **один процесс**, который выполнит эти **предварительные шаги**, прежде чем запускать приложение. -Также Вам нужно будет убедиться, что этот процесс выполнил подготовительные шаги *даже* если впоследствии вы запустите **несколько процессов** (несколько воркеров) самого приложения. Если бы эти шаги выполнялись в каждом **клонированном процессе**, они бы **дублировали** работу, пытаясь выполнить её **параллельно**. И если бы эта работа была бы чем-то деликатным, вроде миграции базы данных, то это может вызвать конфликты между ними. +И вам нужно будет убедиться, что это делает один процесс **даже** если потом вы запускаете **несколько процессов** (несколько воркеров) самого приложения. Если эти шаги выполнят **несколько процессов**, они **дублируют** работу, запустив её **параллельно**, и, если речь о чём‑то деликатном (например, миграции БД), это может вызвать конфликты. -Безусловно, возможны случаи, когда нет проблем при выполнении предварительной подготовки параллельно или несколько раз. Тогда Вам повезло, работать с ними намного проще. +Конечно, бывают случаи, когда нет проблем, если предварительные шаги выполняются несколько раз — тогда всё проще. -/// tip | Заметка +/// tip | Совет -Имейте в виду, что в некоторых случаях запуск вашего приложения **может не требовать каких-либо предварительных шагов вовсе**. +Также учтите, что в зависимости от вашей схемы развёртывания в некоторых случаях **предварительные шаги могут вовсе не требоваться**. -Что ж, тогда Вам не нужно беспокоиться об этом. 🤷 +Тогда об этом можно не беспокоиться. 🤷 /// -### Примеры стратегий запуска предварительных шагов +### Примеры стратегий для предварительных шагов { #examples-of-previous-steps-strategies } -Существует **сильная зависимость** от того, как вы **развёртываете свою систему**, запускаете программы, обрабатываете перезапуски и т.д. +Это будет **сильно зависеть** от того, как вы **развёртываете систему**, как запускаете программы, обрабатываете перезапуски и т.д. -Вот некоторые возможные идеи: +Некоторые возможные идеи: -* При использовании Kubernetes нужно предусмотреть "инициализирующий контейнер", запускаемый до контейнера с приложением. -* Bash-скрипт, выполняющий предварительные шаги, а затем запускающий приложение. - * При этом Вам всё ещё нужно найти способ - как запускать/перезапускать *такой* bash-скрипт, обнаруживать ошибки и т.п. +* «Init Container» в Kubernetes, который запускается перед контейнером с приложением +* Bash‑скрипт, который выполняет предварительные шаги, а затем запускает приложение + * При этом всё равно нужен способ запускать/перезапускать *этот* bash‑скрипт, обнаруживать ошибки и т.п. -/// tip | Заметка +/// tip | Совет -Я приведу Вам больше конкретных примеров работы с контейнерами в главе: [FastAPI внутри контейнеров - Docker](docker.md){.internal-link target=_blank}. +Я приведу более конкретные примеры с контейнерами в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md){.internal-link target=_blank}. /// -## Утилизация ресурсов +## Использование ресурсов { #resource-utilization } -Ваш сервер располагает ресурсами, которые Ваши программы могут потреблять или **утилизировать**, а именно - время работы центрального процессора и объём оперативной памяти. +Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM). -Как много системных ресурсов вы предполагаете потребить/утилизировать? Если не задумываться, то можно ответить - "немного", но на самом деле Вы, вероятно, захотите использовать **максимально возможное количество**. +Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**. -Если вы платите за содержание трёх серверов, но используете лишь малую часть системных ресурсов каждого из них, то вы **выбрасываете деньги на ветер**, а также **впустую тратите электроэнергию** и т.п. +Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п. -В таком случае было бы лучше обойтись двумя серверами, но более полно утилизировать их ресурсы (центральный процессор, оперативную память, жёсткий диск, сети передачи данных и т.д). +В таком случае лучше иметь 2 сервера и использовать более высокий процент их ресурсов (CPU, память, диск, сетевую полосу и т.д.). -С другой стороны, если вы располагаете только двумя серверами и используете **на 100% их процессоры и память**, но какой-либо процесс запросит дополнительную память, то операционная система сервера будет использовать жёсткий диск для расширения оперативной памяти (а диск работает в тысячи раз медленнее), а то вовсе **упадёт**. Или если какому-то процессу понадобится произвести вычисления, то ему придётся подождать, пока процессор освободится. +С другой стороны, если у вас 2 сервера и вы используете **100% их CPU и RAM**, в какой‑то момент один процесс попросит больше памяти, и сервер начнёт использовать диск как «память» (что в тысячи раз медленнее) или даже **упадёт**. Или процессу понадобятся вычисления, но ему придётся ждать освобождения CPU. -В такой ситуации лучше подключить **ещё один сервер** и перераспределить процессы между серверами, чтоб всем **хватало памяти и процессорного времени**. +В таком случае лучше добавить **ещё один сервер** и запустить часть процессов на нём, чтобы у всех было **достаточно RAM и времени CPU**. -Также есть вероятность, что по какой-то причине возник **всплеск** запросов к вашему API. Возможно, это был вирус, боты или другие сервисы начали пользоваться им. И для таких происшествий вы можете захотеть иметь дополнительные ресурсы. +Также возможен **всплеск** использования вашего API: он мог «взорваться» по популярности, или какие‑то сервисы/боты начали его активно использовать. На такие случаи стоит иметь запас ресурсов. -При настройке логики развёртываний, вы можете указать **целевое значение** утилизации ресурсов, допустим, **от 50% до 90%**. Обычно эти метрики и используют. +Можно задать **целевое значение**, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание. -Вы можете использовать простые инструменты, такие как `htop`, для отслеживания загрузки центрального процессора и оперативной памяти сервера, в том числе каждым процессом. Или более сложные системы мониторинга нескольких серверов. +Можно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные распределённые системы мониторинга. -## Резюме +## Резюме { #recap } -Вы прочитали некоторые из основных концепций, которые необходимо иметь в виду при принятии решения о развертывании приложений: +Здесь вы прочитали о некоторых основных концепциях, которые, вероятно, стоит учитывать при выборе способа развёртывания приложения: -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения. +* Безопасность — HTTPS +* Запуск при старте +* Перезапуски +* Репликация (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -Осознание этих идей и того, как их применять, должно дать Вам интуитивное понимание, необходимое для принятия решений при настройке развертываний. 🤓 +Понимание этих идей и того, как их применять, даст вам интуицию, необходимую для принятия решений при настройке и доработке ваших развёртываний. 🤓 -В следующих разделах я приведу более конкретные примеры возможных стратегий, которым вы можете следовать. 🚀 +В следующих разделах я приведу более конкретные примеры возможных стратегий. 🚀 diff --git a/docs/ru/docs/deployment/docker.md b/docs/ru/docs/deployment/docker.md index c72f67172..3937b0165 100644 --- a/docs/ru/docs/deployment/docker.md +++ b/docs/ru/docs/deployment/docker.md @@ -1,17 +1,17 @@ -# FastAPI и Docker-контейнеры +# FastAPI в контейнерах — Docker { #fastapi-in-containers-docker } -При развёртывании приложений FastAPI, часто начинают с создания **образа контейнера на основе Linux**. Обычно для этого используют **Docker**. Затем можно развернуть такой контейнер на сервере одним из нескольких способов. +При развёртывании приложений FastAPI распространённый подход — собирать **образ контейнера на Linux**. Обычно это делают с помощью **Docker**. Затем такой образ контейнера можно развернуть несколькими способами. -Использование контейнеров на основе Linux имеет ряд преимуществ, включая **безопасность**, **воспроизводимость**, **простоту** и прочие. +Использование Linux-контейнеров даёт ряд преимуществ: **безопасность**, **воспроизводимость**, **простоту** и другие. /// tip | Подсказка -Торопитесь или уже знакомы с этой технологией? Перепрыгните на раздел [Создать Docker-образ для FastAPI 👇](#docker-fastapi) +Нет времени и вы уже знакомы с этим? Перейдите к [`Dockerfile` ниже 👇](#build-a-docker-image-for-fastapi). ///
-Развернуть Dockerfile 👀 +Предпросмотр Dockerfile 👀 ```Dockerfile FROM python:3.9 @@ -24,130 +24,125 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt COPY ./app /code/app -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +CMD ["fastapi", "run", "app/main.py", "--port", "80"] -# Если используете прокси-сервер, такой как Nginx или Traefik, добавьте --proxy-headers -# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"] +# Если запускаете за прокси, например Nginx или Traefik, добавьте --proxy-headers +# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"] ```
-## Что такое "контейнер" +## Что такое контейнер { #what-is-a-container } -Контейнеризация - это **легковесный** способ упаковать приложение, включая все его зависимости и необходимые файлы, чтобы изолировать его от других контейнеров (других приложений и компонентов) работающих на этой же системе. +Контейнеры (в основном Linux-контейнеры) — это очень **легковесный** способ упаковать приложения вместе со всеми их зависимостями и необходимыми файлами, изолировав их от других контейнеров (других приложений или компонентов) в той же системе. -Контейнеры, основанные на Linux, запускаются используя ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это значит, что они очень легковесные (по сравнению с полноценными виртуальными машинами, полностью эмулирующими работу операционной системы). +Linux-контейнеры запускаются, используя то же ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это означает, что они очень легковесные (по сравнению с полноценными виртуальными машинами, эмулирующими целую операционную систему). -Благодаря этому, контейнеры потребляют **малое количество ресурсов**, сравнимое с процессом запущенным напрямую (виртуальная машина потребует гораздо больше ресурсов). +Таким образом, контейнеры потребляют **малое количество ресурсов**, сопоставимое с запуском процессов напрямую (виртуальная машина потребовала бы намного больше ресурсов). -Контейнеры также имеют собственные запущенные **изолированные** процессы (но часто только один процесс), файловую систему и сеть, что упрощает развёртывание, разработку, управление доступом и т.п. +У контейнеров также есть собственные **изолированные** выполняемые процессы (обычно всего один процесс), файловая система и сеть, что упрощает развёртывание, безопасность, разработку и т.д. -## Что такое "образ контейнера" +## Что такое образ контейнера { #what-is-a-container-image } -Для запуска **контейнера** нужен **образ контейнера**. +**Контейнер** запускается из **образа контейнера**. -Образ контейнера - это **замороженная** версия всех файлов, переменных окружения, программ и команд по умолчанию, необходимых для работы приложения. **Замороженный** - означает, что **образ** не запущен и не выполняется, это всего лишь упакованные вместе файлы и метаданные. +Образ контейнера — это **статическая** версия всех файлов, переменных окружения и команды/программы по умолчанию, которые должны присутствовать в контейнере. Здесь **статическая** означает, что **образ** не запущен, он не выполняется — это только упакованные файлы и метаданные. -В отличие от **образа контейнера**, хранящего неизменное содержимое, под термином **контейнер** подразумевают запущенный образ, то есть объёкт, который **исполняется**. +В противоположность «**образу контейнера**» (хранящему статическое содержимое), «**контейнер**» обычно означает запущенный экземпляр, то, что **выполняется**. -Когда **контейнер** запущен (на основании **образа**), он может создавать и изменять файлы, переменные окружения и т.д. Эти изменения будут существовать только внутри контейнера, но не будут сохраняться в образе контейнера (не будут сохранены на диск). +Когда **контейнер** запущен (на основе **образа контейнера**), он может создавать или изменять файлы, переменные окружения и т.д.. Эти изменения существуют только внутри контейнера и не сохраняются в исходном образе контейнера (не записываются на диск). -Образ контейнера можно сравнить с файлом, содержащем **программу**, например, как файл `main.py`. +Образ контейнера можно сравнить с **файлами программы**, например `python` и каким-то файлом `main.py`. -И **контейнер** (в отличие от **образа**) - это на самом деле выполняемый экземпляр образа, примерно как **процесс**. По факту, контейнер запущен только когда запущены его процессы (чаще, всего один процесс) и остановлен, когда запущенных процессов нет. +А сам **контейнер** (в отличие от **образа контейнера**) — это фактически запущенный экземпляр образа, сопоставимый с **процессом**. По сути, контейнер работает только тогда, когда в нём есть **запущенный процесс** (и обычно это один процесс). Контейнер останавливается, когда в нём не остаётся запущенных процессов. -## Образы контейнеров +## Образы контейнеров { #container-images } -Docker является одним из основных инструментов для создания **образов** и **контейнеров** и управления ими. +Docker — один из основных инструментов для создания и управления **образами контейнеров** и **контейнерами**. -Существует общедоступный Docker Hub с подготовленными **официальными образами** многих инструментов, окружений, баз данных и приложений. +Существует публичный Docker Hub с готовыми **официальными образами** для многих инструментов, окружений, баз данных и приложений. -К примеру, есть официальный образ Python. +Например, есть официальный образ Python. -Также там представлены и другие полезные образы, такие как базы данных: +А также множество образов для разных вещей, например баз данных: * PostgreSQL * MySQL * MongoDB -* Redis +* Redis, и т.д. -и т.п. +Используя готовые образы, очень легко **комбинировать** разные инструменты и использовать их. Например, чтобы попробовать новую базу данных. В большинстве случаев можно воспользоваться **официальными образами** и просто настроить их через переменные окружения. -Использование подготовленных образов значительно упрощает **комбинирование** и использование разных инструментов. Например, вы можете попытаться использовать новую базу данных. В большинстве случаев можно использовать **официальный образ** и всего лишь указать переменные окружения. +Таким образом, во многих случаях вы можете изучить контейнеры и Docker и переиспользовать эти знания с множеством различных инструментов и компонентов. -Таким образом, вы можете изучить, что такое контейнеризация и Docker, и использовать полученные знания с разными инструментами и компонентами. +Например, вы можете запустить **несколько контейнеров**: с базой данных, Python-приложением, веб-сервером с фронтендом на React и связать их через внутреннюю сеть. -Так, вы можете запустить одновременно **множество контейнеров** с базой данных, Python-приложением, веб-сервером, React-приложением и соединить их вместе через внутреннюю сеть. +Все системы управления контейнерами (такие как Docker или Kubernetes) имеют интегрированные возможности для такого сетевого взаимодействия. -Все системы управления контейнерами (такие, как Docker или Kubernetes) имеют встроенные возможности для организации такого сетевого взаимодействия. +## Контейнеры и процессы { #containers-and-processes } -## Контейнеры и процессы +**Образ контейнера** обычно включает в свои метаданные программу или команду по умолчанию, которую следует запускать при старте **контейнера**, а также параметры, передаваемые этой программе. Это очень похоже на запуск команды в терминале. -Обычно **образ контейнера** содержит метаданные предустановленной программы или команду, которую следует выполнить при запуске **контейнера**. Также он может содержать параметры, передаваемые предустановленной программе. Похоже на то, как если бы вы запускали такую программу через терминал. +Когда **контейнер** стартует, он выполняет указанную команду/программу (хотя вы можете переопределить это и запустить другую команду/программу). -Когда **контейнер** запущен, он будет выполнять прописанные в нём команды и программы. Но вы можете изменить его так, чтоб он выполнял другие команды и программы. +Контейнер работает до тех пор, пока работает его **главный процесс** (команда или программа). -Контейнер будет работать до тех пор, пока выполняется его **главный процесс** (команда или программа). +Обычно в контейнере есть **один процесс**, но главный процесс может запускать подпроцессы, и тогда в том же контейнере будет **несколько процессов**. -В контейнере обычно выполняется **только один процесс**, но от его имени можно запустить другие процессы, тогда в этом же в контейнере будет выполняться **множество процессов**. +Нельзя иметь работающий контейнер без **хотя бы одного запущенного процесса**. Если главный процесс останавливается, контейнер останавливается. -Контейнер не считается запущенным, если в нём **не выполняется хотя бы один процесс**. Если главный процесс остановлен, значит и контейнер остановлен. +## Создать Docker-образ для FastAPI { #build-a-docker-image-for-fastapi } -## Создать Docker-образ для FastAPI +Итак, давайте что-нибудь соберём! 🚀 -Что ж, давайте ужё создадим что-нибудь! 🚀 +Я покажу, как собрать **Docker-образ** для FastAPI **с нуля** на основе **официального образа Python**. -Я покажу Вам, как собирать **Docker-образ** для FastAPI **с нуля**, основываясь на **официальном образе Python**. +Именно так стоит делать в **большинстве случаев**, например: -Такой подход сгодится для **большинства случаев**, например: +* При использовании **Kubernetes** или похожих инструментов +* При запуске на **Raspberry Pi** +* При использовании облачного сервиса, который запускает для вас образ контейнера и т.п. -* Использование с **Kubernetes** или аналогичным инструментом -* Запуск в **Raspberry Pi** -* Использование в облачных сервисах, запускающих образы контейнеров для вас и т.п. +### Зависимости пакетов { #package-requirements } -### Установить зависимости +Обычно **зависимости** вашего приложения описаны в каком-то файле. -Обычно вашему приложению необходимы **дополнительные библиотеки**, список которых находится в отдельном файле. +Конкретный формат зависит в основном от инструмента, которым вы **устанавливаете** эти зависимости. -На название и содержание такого файла влияет выбранный Вами инструмент **установки** этих библиотек (зависимостей). +Чаще всего используется файл `requirements.txt` с именами пакетов и их версиями по одному на строку. -Чаще всего это простой файл `requirements.txt` с построчным перечислением библиотек и их версий. +Разумеется, вы будете придерживаться тех же идей, что описаны здесь: [О версиях FastAPI](versions.md){.internal-link target=_blank}, чтобы задать диапазоны версий. -При этом Вы, для выбора версий, будете использовать те же идеи, что упомянуты на странице [О версиях FastAPI](versions.md){.internal-link target=_blank}. - -Ваш файл `requirements.txt` может выглядеть как-то так: +Например, ваш `requirements.txt` может выглядеть так: ``` -fastapi>=0.68.0,<0.69.0 -pydantic>=1.8.0,<2.0.0 -uvicorn>=0.15.0,<0.16.0 +fastapi[standard]>=0.113.0,<0.114.0 +pydantic>=2.7.0,<3.0.0 ``` -Устанавливать зависимости проще всего с помощью `pip`: +И обычно вы установите эти зависимости командой `pip`, например:
```console $ pip install -r requirements.txt ---> 100% -Successfully installed fastapi pydantic uvicorn +Successfully installed fastapi pydantic ```
/// info | Информация -Существуют и другие инструменты управления зависимостями. - -В этом же разделе, но позже, я покажу вам пример использования Poetry. 👇 +Существуют и другие форматы и инструменты для описания и установки зависимостей. /// -### Создать приложение **FastAPI** +### Создать код **FastAPI** { #create-the-fastapi-code } * Создайте директорию `app` и перейдите в неё. * Создайте пустой файл `__init__.py`. -* Создайте файл `main.py` и заполните его: +* Создайте файл `main.py` со следующим содержимым: ```Python from typing import Union @@ -167,77 +162,109 @@ def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` -### Dockerfile +### Dockerfile { #dockerfile } -В этой же директории создайте файл `Dockerfile` и заполните его: +Теперь в той же директории проекта создайте файл `Dockerfile`: ```{ .dockerfile .annotate } -# (1) +# (1)! FROM python:3.9 -# (2) +# (2)! WORKDIR /code -# (3) +# (3)! COPY ./requirements.txt /code/requirements.txt -# (4) +# (4)! RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt -# (5) +# (5)! COPY ./app /code/app -# (6) -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +# (6)! +CMD ["fastapi", "run", "app/main.py", "--port", "80"] ``` -1. Начните с официального образа Python, который будет основой для образа приложения. +1. Начинаем с официального базового образа Python. -2. Укажите, что в дальнейшем команды запускаемые в контейнере, будут выполняться в директории `/code`. +2. Устанавливаем текущую рабочую директорию в `/code`. - Инструкция создаст эту директорию внутри контейнера и мы поместим в неё файл `requirements.txt` и директорию `app`. + Здесь мы разместим файл `requirements.txt` и директорию `app`. -3. Скопируете файл с зависимостями из текущей директории в `/code`. +3. Копируем файл с зависимостями в директорию `/code`. - Сначала копируйте **только** файл с зависимостями. + Сначала копируйте **только** файл с зависимостями, не остальной код. - Этот файл **изменяется довольно редко**, Docker ищет изменения при постройке образа и если не находит, то использует **кэш**, в котором хранятся предыдущие версии сборки образа. + Так как этот файл **меняется нечасто**, Docker определит это и использует **кэш** на этом шаге, что позволит использовать кэш и на следующем шаге. -4. Установите библиотеки перечисленные в файле с зависимостями. +4. Устанавливаем зависимости из файла с требованиями. - Опция `--no-cache-dir` указывает `pip` не сохранять загружаемые библиотеки на локальной машине для использования их в случае повторной загрузки. В контейнере, в случае пересборки этого шага, они всё равно будут удалены. + Опция `--no-cache-dir` указывает `pip` не сохранять загруженные пакеты локально, т.к. это нужно только если `pip` будет запускаться снова для установки тех же пакетов, а при работе с контейнерами это обычно не требуется. /// note | Заметка - Опция `--no-cache-dir` нужна только для `pip`, она никак не влияет на Docker или контейнеры. + `--no-cache-dir` относится только к `pip` и не имеет отношения к Docker или контейнерам. /// - Опция `--upgrade` указывает `pip` обновить библиотеки, емли они уже установлены. + Опция `--upgrade` указывает `pip` обновлять пакеты, если они уже установлены. - Как и в предыдущем шаге с копированием файла, этот шаг также будет использовать **кэш Docker** в случае отсутствия изменений. + Поскольку предыдущий шаг с копированием файла может быть обработан **кэшем Docker**, этот шаг также **использует кэш Docker**, когда это возможно. - Использование кэша, особенно на этом шаге, позволит вам **сэкономить** кучу времени при повторной сборке образа, так как зависимости будут сохранены в кеше, а не **загружаться и устанавливаться каждый раз**. + Использование кэша на этом шаге **сэкономит** вам много **времени** при повторных сборках образа во время разработки, вместо того чтобы **загружать и устанавливать** все зависимости **каждый раз**. -5. Скопируйте директорию `./app` внутрь директории `/code` (в контейнере). +5. Копируем директорию `./app` внутрь директории `/code`. - Так как в этой директории расположен код, который **часто изменяется**, то использование **кэша** на этом шаге будет наименее эффективно, а значит лучше поместить этот шаг **ближе к концу** `Dockerfile`, дабы не терять выгоду от оптимизации предыдущих шагов. + Так как здесь весь код, который **меняется чаще всего**, кэш Docker **вряд ли** будет использоваться для этого шагa или **последующих шагов**. -6. Укажите **команду**, запускающую сервер `uvicorn`. + Поэтому важно разместить этот шаг **ближе к концу** `Dockerfile`, чтобы оптимизировать время сборки образа контейнера. - `CMD` принимает список строк, разделённых запятыми, но при выполнении объединит их через пробел, собрав из них одну команду, которую вы могли бы написать в терминале. +6. Указываем **команду** для запуска `fastapi run`, под капотом используется Uvicorn. - Эта команда будет выполнена в **текущей рабочей директории**, а именно в директории `/code`, которая указана в команде `WORKDIR /code`. + `CMD` принимает список строк, каждая из которых — это то, что вы бы ввели в командной строке, разделяя пробелами. - Так как команда выполняется внутри директории `/code`, в которую мы поместили папку `./app` с приложением, то **Uvicorn** сможет найти и **импортировать** объект `app` из файла `app.main`. + Эта команда будет выполнена из **текущей рабочей директории**, той самой `/code`, которую вы задали выше `WORKDIR /code`. /// tip | Подсказка -Если ткнёте на кружок с плюсом, то увидите пояснения. 👆 +Посмотрите, что делает каждая строка, кликнув по номеру рядом со строкой. 👆 /// -На данном этапе структура проекта должны выглядеть так: +/// warning | Предупреждение + +Всегда используйте **exec-форму** инструкции `CMD`, как описано ниже. + +/// + +#### Используйте `CMD` — exec-форма { #use-cmd-exec-form } + +Инструкцию Docker `CMD` можно писать в двух формах: + +✅ **Exec**-форма: + +```Dockerfile +# ✅ Делайте так +CMD ["fastapi", "run", "app/main.py", "--port", "80"] +``` + +⛔️ **Shell**-форма: + +```Dockerfile +# ⛔️ Не делайте так +CMD fastapi run app/main.py --port 80 +``` + +Обязательно используйте **exec**-форму, чтобы FastAPI мог корректно завершаться и чтобы срабатывали [события lifespan](../advanced/events.md){.internal-link target=_blank}. + +Подробнее об этом читайте в документации Docker о shell- и exec-формах. + +Это особенно заметно при использовании `docker compose`. См. раздел FAQ Docker Compose с техническими подробностями: Почему мои сервисы пересоздаются или останавливаются 10 секунд?. + +#### Структура директорий { #directory-structure } + +Теперь у вас должна быть такая структура: ``` . @@ -248,53 +275,52 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] └── requirements.txt ``` -#### Использование прокси-сервера +#### За прокси-сервером TLS терминации { #behind-a-tls-termination-proxy } -Если вы запускаете контейнер за прокси-сервером завершения TLS (балансирующего нагрузку), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`, которая укажет Uvicorn, что он работает позади прокси-сервера и может доверять заголовкам отправляемым им. +Если вы запускаете контейнер за прокси-сервером завершения TLS (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам. ```Dockerfile -CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"] +CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"] ``` -#### Кэш Docker'а +#### Кэш Docker { #docker-cache } -В нашем `Dockerfile` использована полезная хитрость, когда сначала копируется **только файл с зависимостями**, а не вся папка с кодом приложения. +В этом `Dockerfile` есть важная хитрость: мы сначала копируем **только файл с зависимостями**, а не весь код. Вот зачем. ```Dockerfile COPY ./requirements.txt /code/requirements.txt ``` -Docker и подобные ему инструменты **создают** образы контейнеров **пошагово**, добавляя **один слой над другим**, начиная с первой строки `Dockerfile` и добавляя файлы, создаваемые при выполнении каждой инструкции из `Dockerfile`. +Docker и подобные инструменты **строят** образы контейнеров **инкрементально**, добавляя **слой за слоем**, начиная с первой строки `Dockerfile` и добавляя любые файлы, создаваемые каждой инструкцией `Dockerfile`. -При создании образа используется **внутренний кэш** и если в файлах нет изменений с момента последней сборки образа, то будет **переиспользован** ранее созданный слой образа, а не повторное копирование файлов и создание слоя с нуля. -Заметьте, что так как слой следующего шага зависит от слоя предыдущего, то изменения внесённые в промежуточный слой, также повлияют на последующие. +Docker и подобные инструменты также используют **внутренний кэш** при сборке образа: если файл не изменился с момента предыдущей сборки, будет **переиспользован слой**, созданный в прошлый раз, вместо повторного копирования файла и создания нового слоя с нуля. -Избегание копирования файлов не обязательно улучшит ситуацию, но использование кэша на одном шаге, позволит **использовать кэш и на следующих шагах**. Например, можно использовать кэш при установке зависимостей: +Само по себе избегание копирования всех файлов не всегда даёт много, но благодаря использованию кэша на этом шаге Docker сможет **использовать кэш и на следующем шаге**. Например, на шаге установки зависимостей: ```Dockerfile RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt ``` -Файл со списком зависимостей **изменяется довольно редко**. Так что выполнив команду копирования только этого файла, Docker сможет **использовать кэш** на этом шаге. +Файл с зависимостями **меняется нечасто**. Поэтому, копируя только его, Docker сможет **использовать кэш** для этого шага. -А затем **использовать кэш и на следующем шаге**, загружающем и устанавливающем зависимости. И вот тут-то мы и **сэкономим много времени**. ✨ ...а не будем томиться в тягостном ожидании. 😪😆 +А затем Docker сможет **использовать кэш и на следующем шаге**, где скачиваются и устанавливаются зависимости. Здесь мы как раз **экономим много времени**. ✨ ...и не скучаем в ожидании. 😪😆 -Для загрузки и установки необходимых библиотек **может понадобиться несколько минут**, но использование **кэша** занимает несколько **секунд** максимум. +Скачивание и установка зависимостей **может занять минуты**, но использование **кэша** — **секунды**. -И так как во время разработки вы будете часто пересобирать контейнер для проверки работоспособности внесённых изменений, то сэкономленные минуты сложатся в часы, а то и дни. +Поскольку во время разработки вы будете пересобирать образ снова и снова, чтобы проверить изменения в коде, суммарно это сэкономит немало времени. -Так как папка с кодом приложения **изменяется чаще всего**, то мы расположили её в конце `Dockerfile`, ведь после внесённых в код изменений кэш не будет использован на этом и следующих шагах. +Затем, ближе к концу `Dockerfile`, мы копируем весь код. Так как он **меняется чаще всего**, мы ставим этот шаг в конец, потому что почти всегда всё, что после него, уже не сможет использовать кэш. ```Dockerfile COPY ./app /code/app ``` -### Создать Docker-образ +### Собрать Docker-образ { #build-the-docker-image } -Теперь, когда все файлы на своих местах, давайте создадим образ контейнера. +Теперь, когда все файлы на месте, соберём образ контейнера. -* Перейдите в директорию проекта (в ту, где расположены `Dockerfile` и папка `app` с приложением). -* Создай образ приложения FastAPI: +* Перейдите в директорию проекта (где ваш `Dockerfile` и директория `app`). +* Соберите образ FastAPI:
@@ -308,15 +334,15 @@ $ docker build -t myimage . /// tip | Подсказка -Обратите внимание, что в конце написана точка - `.`, это то же самое что и `./`, тем самым мы указываем Docker директорию, из которой нужно выполнять сборку образа контейнера. +Обратите внимание на точку `.` в конце — это то же самое, что `./`. Так мы указываем Docker, из какой директории собирать образ контейнера. -В данном случае это та же самая директория (`.`). +В данном случае это текущая директория (`.`). /// -### Запуск Docker-контейнера +### Запустить Docker-контейнер { #start-the-docker-container } -* Запустите контейнер, основанный на вашем образе: +* Запустите контейнер на основе вашего образа:
@@ -326,35 +352,35 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-## Проверка +## Проверка { #check-it } -Вы можете проверить, что Ваш Docker-контейнер работает перейдя по ссылке: http://192.168.99.100/items/5?q=somequery или http://127.0.0.1/items/5?q=somequery (или похожей, которую использует Ваш Docker-хост). +Проверьте работу по адресу вашего Docker-хоста, например: http://192.168.99.100/items/5?q=somequery или http://127.0.0.1/items/5?q=somequery (или аналогичный URL вашего Docker-хоста). -Там вы увидите: +Вы увидите что-то вроде: ```JSON {"item_id": 5, "q": "somequery"} ``` -## Интерактивная документация API +## Интерактивная документация API { #interactive-api-docs } -Теперь перейдите по ссылке http://192.168.99.100/docs или http://127.0.0.1/docs (или похожей, которую использует Ваш Docker-хост). +Теперь зайдите на http://192.168.99.100/docs или http://127.0.0.1/docs (или аналогичный URL вашего Docker-хоста). -Здесь вы увидите автоматическую интерактивную документацию API (предоставляемую Swagger UI): +Вы увидите автоматическую интерактивную документацию API (на базе Swagger UI): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -## Альтернативная документация API +## Альтернативная документация API { #alternative-api-docs } -Также вы можете перейти по ссылке http://192.168.99.100/redoc or http://127.0.0.1/redoc (или похожей, которую использует Ваш Docker-хост). +Также можно открыть http://192.168.99.100/redoc или http://127.0.0.1/redoc (или аналогичный URL вашего Docker-хоста). -Здесь вы увидите альтернативную автоматическую документацию API (предоставляемую ReDoc): +Вы увидите альтернативную автоматическую документацию (на базе ReDoc): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Создание Docker-образа на основе однофайлового приложения FastAPI +## Собрать Docker-образ для однофайлового FastAPI { #build-a-docker-image-with-a-single-file-fastapi } -Если ваше приложение FastAPI помещено в один файл, например, `main.py` и структура Ваших файлов похожа на эту: +Если ваше приложение FastAPI — один файл, например `main.py` без директории `./app`, структура файлов может быть такой: ``` . @@ -363,7 +389,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage └── requirements.txt ``` -Вам нужно изменить в `Dockerfile` соответствующие пути копирования файлов: +Тогда в `Dockerfile` нужно изменить пути копирования: ```{ .dockerfile .annotate hl_lines="10 13" } FROM python:3.9 @@ -374,360 +400,221 @@ COPY ./requirements.txt /code/requirements.txt RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt -# (1) +# (1)! COPY ./main.py /code/ -# (2) -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] +# (2)! +CMD ["fastapi", "run", "main.py", "--port", "80"] ``` -1. Скопируйте непосредственно файл `main.py` в директорию `/code` (не указывайте `./app`). +1. Копируем файл `main.py` напрямую в `/code` (без директории `./app`). -2. При запуске Uvicorn укажите ему, что объект `app` нужно импортировать из файла `main` (вместо импортирования из `app.main`). +2. Используем `fastapi run` для запуска приложения из одного файла `main.py`. -Настройте Uvicorn на использование `main` вместо `app.main` для импорта объекта `app`. +Когда вы передаёте файл в `fastapi run`, он автоматически определит, что это одиночный файл, а не часть пакета, и поймёт, как его импортировать и запустить ваше FastAPI-приложение. 😎 -## Концепции развёртывания +## Концепции развертывания { #deployment-concepts } -Давайте вспомним о [Концепциях развёртывания](concepts.md){.internal-link target=_blank} и применим их к контейнерам. +Ещё раз рассмотрим [концепции развертывания](concepts.md){.internal-link target=_blank} применительно к контейнерам. -Контейнеры - это, в основном, инструмент упрощающий **сборку и развёртывание** приложения и они не обязывают к применению какой-то определённой **концепции развёртывания**, а значит мы можем выбирать нужную стратегию. +Контейнеры главным образом упрощают **сборку и развёртывание** приложения, но не навязывают конкретный подход к этим **концепциям развертывания**, и существует несколько стратегий. -**Хорошая новость** в том, что независимо от выбранной стратегии, мы всё равно можем покрыть все концепции развёртывания. 🎉 +**Хорошая новость** в том, что при любой стратегии есть способ охватить все концепции развертывания. 🎉 -Рассмотрим эти **концепции развёртывания** применительно к контейнерам: +Рассмотрим эти **концепции развертывания** в терминах контейнеров: -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения +* HTTPS +* Запуск при старте +* Перезапуски +* Репликация (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -## Использование более безопасного протокола HTTPS +## HTTPS { #https } -Если мы определимся, что **образ контейнера** будет содержать только приложение FastAPI, то работу с HTTPS можно организовать **снаружи** контейнера при помощи другого инструмента. +Если мы рассматриваем только **образ контейнера** для приложения FastAPI (и далее запущенный **контейнер**), то HTTPS обычно обрабатывается **внешним** инструментом. -Это может быть другой контейнер, в котором есть, например, Traefik, работающий с **HTTPS** и **самостоятельно** обновляющий **сертификаты**. +Это может быть другой контейнер, например с Traefik, который берёт на себя **HTTPS** и **автоматическое** получение **сертификатов**. /// tip | Подсказка -Traefik совместим с Docker, Kubernetes и им подобными инструментами. Он очень прост в установке и настройке использования HTTPS для Ваших контейнеров. +У Traefik есть интеграции с Docker, Kubernetes и другими, поэтому очень легко настроить и сконфигурировать HTTPS для ваших контейнеров. /// -В качестве альтернативы, работу с HTTPS можно доверить облачному провайдеру, если он предоставляет такую услугу. +В качестве альтернативы HTTPS может быть реализован как сервис облачного провайдера (при этом приложение всё равно работает в контейнере). -## Настройки запуска и перезагрузки приложения +## Запуск при старте и перезапуски { #running-on-startup-and-restarts } -Обычно **запуском контейнера с приложением** занимается какой-то отдельный инструмент. +Обычно есть другой инструмент, отвечающий за **запуск и работу** вашего контейнера. -Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный провайдер** и т.п. +Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный сервис** и т.п. -В большинстве случаев это простейшие настройки запуска и перезагрузки приложения (при падении). Например, команде запуска Docker-контейнера можно добавить опцию `--restart`. +В большинстве (или во всех) случаев есть простая опция, чтобы включить запуск контейнера при старте системы и перезапуски при сбоях. Например, в Docker это опция командной строки `--restart`. -Управление запуском и перезагрузкой приложений без использования контейнеров - весьма затруднительно. Но при **работе с контейнерами** - это всего лишь функционал доступный по умолчанию. ✨ +Без контейнеров обеспечить запуск при старте и перезапуски может быть сложно. Но при **работе с контейнерами** в большинстве случаев этот функционал доступен по умолчанию. ✨ -## Запуск нескольких экземпляров приложения - Указание количества процессов +## Репликация — количество процессов { #replication-number-of-processes } -Если у вас есть кластер машин под управлением **Kubernetes**, Docker Swarm Mode, Nomad или аналогичной сложной системой оркестрации контейнеров, скорее всего, вместо использования менеджера процессов (типа Gunicorn и его воркеры) в каждом контейнере, вы захотите **управлять количеством запущенных экземпляров приложения** на **уровне кластера**. +Если у вас есть кластер машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере. -В любую из этих систем управления контейнерами обычно встроен способ управления **количеством запущенных контейнеров** для распределения **нагрузки** от входящих запросов на **уровне кластера**. +Одна из таких систем управления распределёнными контейнерами, как Kubernetes, обычно имеет встроенный способ управлять **репликацией контейнеров**, поддерживая **балансировку нагрузки** для входящих запросов — всё это на **уровне кластера**. -В такой ситуации Вы, вероятно, захотите создать **образ Docker**, как [описано выше](#dockerfile), с установленными зависимостями и запускающий **один процесс Uvicorn** вместо того, чтобы запускать Gunicorn управляющий несколькими воркерами Uvicorn. +В таких случаях вы, скорее всего, захотите собрать **Docker-образ с нуля**, как [описано выше](#dockerfile), установить зависимости и запускать **один процесс Uvicorn** вместо множества воркеров Uvicorn. -### Балансировщик нагрузки +### Балансировщик нагрузки { #load-balancer } -Обычно при использовании контейнеров один компонент **прослушивает главный порт**. Это может быть контейнер содержащий **прокси-сервер завершения работы TLS** для работы с **HTTPS** или что-то подобное. +При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси завершения TLS** для обработки **HTTPS** или похожий инструмент. -Поскольку этот компонент **принимает запросы** и равномерно **распределяет** их между компонентами, его также называют **балансировщиком нагрузки**. +Поскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**. /// tip | Подсказка -**Прокси-сервер завершения работы TLS** одновременно может быть **балансировщиком нагрузки**. +Тот же компонент **прокси завершения TLS**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**. /// -Система оркестрации, которую вы используете для запуска и управления контейнерами, имеет встроенный инструмент **сетевого взаимодействия** (например, для передачи HTTP-запросов) между контейнерами с Вашими приложениями и **балансировщиком нагрузки** (который также может быть **прокси-сервером**). +При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси завершения TLS**) к контейнеру(-ам) с вашим приложением. -### Один балансировщик - Множество контейнеров +### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers } -При работе с **Kubernetes** или аналогичными системами оркестрации использование их внутренней сети позволяет иметь один **балансировщик нагрузки**, который прослушивает **главный** порт и передаёт запросы **множеству запущенных контейнеров** с Вашими приложениями. +При работе с **Kubernetes** или похожими системами управления распределёнными контейнерами их внутренние механизмы сети позволяют одному **балансировщику нагрузки**, слушающему главный **порт**, передавать запросы в **несколько контейнеров**, где запущено ваше приложение. -В каждом из контейнеров обычно работает **только один процесс** (например, процесс Uvicorn управляющий Вашим приложением FastAPI). Контейнеры могут быть **идентичными**, запущенными на основе одного и того же образа, но у каждого будут свои отдельные процесс, память и т.п. Таким образом мы получаем преимущества **распараллеливания** работы по **разным ядрам** процессора или даже **разным машинам**. +Каждый такой контейнер с вашим приложением обычно имеет **только один процесс** (например, процесс Uvicorn с вашим приложением FastAPI). Все они — **одинаковые контейнеры**, запускающие одно и то же, но у каждого свой процесс, память и т.п. Так вы используете **параллелизм** по **разным ядрам** CPU или даже **разным машинам**. -Система управления контейнерами с **балансировщиком нагрузки** будет **распределять запросы** к контейнерам с приложениями **по очереди**. То есть каждый запрос будет обработан одним из множества **одинаковых контейнеров** с одним и тем же приложением. +Система распределённых контейнеров с **балансировщиком нагрузки** будет **распределять запросы** между контейнерами с вашим приложением **по очереди**. То есть каждый запрос может обрабатываться одним из нескольких **реплицированных контейнеров**. -**Балансировщик нагрузки** может обрабатывать запросы к *разным* приложениям, расположенным в вашем кластере (например, если у них разные домены или префиксы пути) и передавать запросы нужному контейнеру с требуемым приложением. +Обычно такой **балансировщик нагрузки** может также обрабатывать запросы к *другим* приложениям в вашем кластере (например, к другому домену или под другим префиксом пути URL) и направлять их к нужным контейнерам этого *другого* приложения. -### Один процесс на контейнер +### Один процесс на контейнер { #one-process-per-container } -В этом варианте **в одном контейнере будет запущен только один процесс (Uvicorn)**, а управление изменением количества запущенных копий приложения происходит на уровне кластера. +В таком сценарии, скорее всего, вы захотите иметь **один (Uvicorn) процесс на контейнер**, так как репликация уже управляется на уровне кластера. -Здесь **не нужен** менеджер процессов типа Gunicorn, управляющий процессами Uvicorn, или же Uvicorn, управляющий другими процессами Uvicorn. Достаточно **только одного процесса Uvicorn** на контейнер (но запуск нескольких процессов не запрещён). +Поэтому в контейнере **не нужно** поднимать несколько воркеров, например через опцию командной строки `--workers`. Нужен **один процесс Uvicorn** на контейнер (но, возможно, несколько контейнеров). -Использование менеджера процессов (Gunicorn или Uvicorn) внутри контейнера только добавляет **излишнее усложнение**, так как управление следует осуществлять системой оркестрации. +Наличие отдельного менеджера процессов внутри контейнера (как при нескольких воркерах) только добавит **лишнюю сложность**, которую, вероятно, уже берёт на себя ваша кластерная система. -### Множество процессов внутри контейнера для особых случаев +### Контейнеры с несколькими процессами и особые случаи { #containers-with-multiple-processes-and-special-cases } -Безусловно, бывают **особые случаи**, когда может понадобиться внутри контейнера запускать **менеджер процессов Gunicorn**, управляющий несколькими **процессами Uvicorn**. +Конечно, есть **особые случаи**, когда может понадобиться **контейнер** с несколькими **воркерами Uvicorn** внутри. -Для таких случаев вы можете использовать **официальный Docker-образ** (прим. пер: - *здесь и далее на этой странице, если вы встретите сочетание "официальный Docker-образ" без уточнений, то автор имеет в виду именно предоставляемый им образ*), где в качестве менеджера процессов используется **Gunicorn**, запускающий несколько **процессов Uvicorn** и некоторые настройки по умолчанию, автоматически устанавливающие количество запущенных процессов в зависимости от количества ядер вашего процессора. Я расскажу вам об этом подробнее тут: [Официальный Docker-образ со встроенными Gunicorn и Uvicorn](#docker-gunicorn-uvicorn). +В таких случаях вы можете использовать опцию командной строки `--workers`, чтобы указать нужное количество воркеров: -Некоторые примеры подобных случаев: +```{ .dockerfile .annotate } +FROM python:3.9 -#### Простое приложение +WORKDIR /code -Вы можете использовать менеджер процессов внутри контейнера, если ваше приложение **настолько простое**, что у вас нет необходимости (по крайней мере, пока нет) в тщательных настройках количества процессов и вам достаточно имеющихся настроек по умолчанию (если используется официальный Docker-образ) для запуска приложения **только на одном сервере**, а не в кластере. +COPY ./requirements.txt /code/requirements.txt -#### Docker Compose +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt -С помощью **Docker Compose** можно разворачивать несколько контейнеров на **одном сервере** (не кластере), но при это у вас не будет простого способа управления количеством запущенных контейнеров с одновременным сохранением общей сети и **балансировки нагрузки**. +COPY ./app /code/app -В этом случае можно использовать **менеджер процессов**, управляющий **несколькими процессами**, внутри **одного контейнера**. +# (1)! +CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"] +``` -#### Prometheus и прочие причины +1. Здесь мы используем опцию `--workers`, чтобы установить число воркеров равным 4. -У вас могут быть и **другие причины**, когда использование **множества процессов** внутри **одного контейнера** будет проще, нежели запуск **нескольких контейнеров** с **единственным процессом** в каждом из них. +Примеры, когда это может быть уместно: -Например (в зависимости от конфигурации), у вас могут быть инструменты подобные экспортёру Prometheus, которые должны иметь доступ к **каждому запросу** приходящему в контейнер. +#### Простое приложение { #a-simple-app } -Если у вас будет **несколько контейнеров**, то Prometheus, по умолчанию, **при сборе метрик** получит их **только с одного контейнера**, который обрабатывает конкретный запрос, вместо **сбора метрик** со всех работающих контейнеров. +Вам может понадобиться менеджер процессов в контейнере, если приложение **достаточно простое**, чтобы запускаться на **одном сервере**, а не в кластере. -В таком случае может быть проще иметь **один контейнер** со **множеством процессов**, с нужным инструментом (таким как экспортёр Prometheus) в этом же контейнере и собирающем метрики со всех внутренних процессов этого контейнера. +#### Docker Compose { #docker-compose } + +Вы можете развёртывать на **одном сервере** (не кластере) с **Docker Compose**, и у вас не будет простого способа управлять репликацией контейнеров (в Docker Compose), сохраняя общую сеть и **балансировку нагрузки**. + +Тогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркеров** внутри. --- -Самое главное - **ни одно** из перечисленных правил не является **высеченным на камне** и вы не обязаны слепо их повторять. вы можете использовать эти идеи при **рассмотрении вашего конкретного случая** и самостоятельно решать, какая из концепции подходит лучше: +Главное — **ни одно** из этих правил не является **строго обязательным**. Используйте эти идеи, чтобы **оценить свой конкретный случай** и решить, какой подход лучше для вашей системы, учитывая: -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения +* Безопасность — HTTPS +* Запуск при старте +* Перезапуски +* Репликацию (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -## Управление памятью +## Память { #memory } -При **запуске одного процесса на контейнер** вы получаете относительно понятный, стабильный и ограниченный объём памяти, потребляемый одним контейнером. +Если вы запускаете **один процесс на контейнер**, у каждого контейнера будет более-менее чётко определённый, стабильный и ограниченный объём потребляемой памяти (контейнеров может быть несколько при репликации). -Вы можете установить аналогичные ограничения по памяти при конфигурировании своей системы управления контейнерами (например, **Kubernetes**). Таким образом система сможет **изменять количество контейнеров** на **доступных ей машинах** приводя в соответствие количество памяти нужной контейнерам с количеством памяти доступной в кластере (наборе доступных машин). +Затем вы можете задать такие же лимиты и требования по памяти в конфигурации вашей системы управления контейнерами (например, в **Kubernetes**). Так система сможет **реплицировать контейнеры** на **доступных машинах**, учитывая объём необходимой памяти и доступной памяти в машинах кластера. -Если у вас **простенькое** приложение, вероятно у вас не будет **необходимости** устанавливать жёсткие ограничения на выделяемую ему память. Но если приложение **использует много памяти** (например, оно использует модели **машинного обучения**), вам следует проверить, как много памяти ему требуется и отрегулировать **количество контейнеров** запущенных на **каждой машине** (может быть даже добавить машин в кластер). +Если приложение **простое**, это, вероятно, **не будет проблемой**, и жёсткие лимиты памяти можно не указывать. Но если вы **используете много памяти** (например, с моделями **Машинного обучения**), проверьте, сколько памяти потребляется, и отрегулируйте **число контейнеров** на **каждой машине** (и, возможно, добавьте машины в кластер). -Если вы запускаете **несколько процессов в контейнере**, то должны быть уверены, что эти процессы не **займут памяти больше**, чем доступно для контейнера. +Если вы запускаете **несколько процессов в контейнере**, нужно убедиться, что их суммарное потребление **не превысит доступную память**. -## Подготовительные шаги при запуске контейнеров +## Предварительные шаги перед запуском и контейнеры { #previous-steps-before-starting-and-containers } -Есть два основных подхода, которые вы можете использовать при запуске контейнеров (Docker, Kubernetes и т.п.). +Если вы используете контейнеры (например, Docker, Kubernetes), есть два основных подхода. -### Множество контейнеров +### Несколько контейнеров { #multiple-containers } -Когда вы запускаете **множество контейнеров**, в каждом из которых работает **только один процесс** (например, в кластере **Kubernetes**), может возникнуть необходимость иметь **отдельный контейнер**, который осуществит **предварительные шаги перед запуском** остальных контейнеров (например, применяет миграции к базе данных). +Если у вас **несколько контейнеров**, и, вероятно, каждый запускает **один процесс** (например, в кластере **Kubernetes**), то вы, скорее всего, захотите иметь **отдельный контейнер**, выполняющий **предварительные шаги** в одном контейнере и одном процессе **до** запуска реплицированных контейнеров-воркеров. /// info | Информация -При использовании Kubernetes, это может быть Инициализирующий контейнер. +Если вы используете Kubernetes, это, вероятно, будет Init Container. /// -При отсутствии такой необходимости (допустим, не нужно применять миграции к базе данных, а только проверить, что она готова принимать соединения), вы можете проводить такую проверку в каждом контейнере перед запуском его основного процесса и запускать все контейнеры **одновременно**. +Если в вашем случае нет проблемы с тем, чтобы выполнять эти предварительные шаги **многократно и параллельно** (например, вы не запускаете миграции БД, а только проверяете готовность БД), вы можете просто выполнить их в каждом контейнере прямо перед стартом основного процесса. -### Только один контейнер +### Один контейнер { #single-container } -Если у вас несложное приложение для работы которого достаточно **одного контейнера**, но в котором работает **несколько процессов** (или один процесс), то прохождение предварительных шагов можно осуществить в этом же контейнере до запуска основного процесса. Официальный Docker-образ поддерживает такие действия. +Если у вас простая схема с **одним контейнером**, который затем запускает несколько **воркеров** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением. -## Официальный Docker-образ с Gunicorn и Uvicorn +### Базовый Docker-образ { #base-docker-image } -Я подготовил для вас Docker-образ, в который включён Gunicorn управляющий процессами (воркерами) Uvicorn, в соответствии с концепциями рассмотренными в предыдущей главе: [Рабочие процессы сервера (воркеры) - Gunicorn совместно с Uvicorn](server-workers.md){.internal-link target=_blank}. +Ранее существовал официальный Docker-образ FastAPI: tiangolo/uvicorn-gunicorn-fastapi. Сейчас он помечен как устаревший. ⛔️ -Этот образ может быть полезен для ситуаций описанных тут: [Множество процессов внутри контейнера для особых случаев](#_11). +Скорее всего, вам **не стоит** использовать этот базовый образ (или какой-либо аналогичный). -* tiangolo/uvicorn-gunicorn-fastapi. +Если вы используете **Kubernetes** (или другое) и уже настраиваете **репликацию** на уровне кластера через несколько **контейнеров**, в этих случаях лучше **собрать образ с нуля**, как описано выше: [Создать Docker-образ для FastAPI](#build-a-docker-image-for-fastapi). -/// warning | Предупреждение +А если вам нужны несколько воркеров, просто используйте опцию командной строки `--workers`. -Скорее всего у вас **нет необходимости** в использовании этого образа или подобного ему и лучше создать свой образ с нуля как описано тут: [Создать Docker-образ для FastAPI](#docker-fastapi). +/// note | Технические подробности + +Этот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркеров Uvicorn. + +Но теперь, когда Uvicorn (и команда `fastapi`) поддерживают `--workers`, нет причин использовать базовый Docker-образ вместо сборки своего (кода получается примерно столько же 😅). /// -В этом образе есть **автоматический** механизм подстройки для запуска **необходимого количества процессов** в соответствии с доступным количеством ядер процессора. +## Развёртывание образа контейнера { #deploy-the-container-image } -В нём установлены **разумные значения по умолчанию**, но можно изменять и обновлять конфигурацию с помощью **переменных окружения** или конфигурационных файлов. - -Он также поддерживает прохождение **Подготовительных шагов при запуске контейнеров** при помощи скрипта. - -/// tip | Подсказка - -Для просмотра всех возможных настроек перейдите на страницу этого Docker-образа: tiangolo/uvicorn-gunicorn-fastapi. - -/// - -### Количество процессов в официальном Docker-образе - -**Количество процессов** в этом образе **вычисляется автоматически** и зависит от доступного количества **ядер** центрального процессора. - -Это означает, что он будет пытаться **выжать** из процессора как можно больше **производительности**. - -Но вы можете изменять и обновлять конфигурацию с помощью **переменных окружения** и т.п. - -Поскольку количество процессов зависит от процессора, на котором работает контейнер, **объём потребляемой памяти** также будет зависеть от этого. - -А значит, если вашему приложению требуется много оперативной памяти (например, оно использует модели машинного обучения) и Ваш сервер имеет центральный процессор с большим количеством ядер, но **не слишком большим объёмом оперативной памяти**, то может дойти до того, что контейнер попытается занять памяти больше, чем доступно, из-за чего будет падение производительности (или сервер вовсе упадёт). 🚨 - - -### Написание `Dockerfile` - -Итак, теперь мы можем написать `Dockerfile` основанный на этом официальном Docker-образе: - -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 - -COPY ./requirements.txt /app/requirements.txt - -RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt - -COPY ./app /app -``` - -### Большие приложения - -Если вы успели ознакомиться с разделом [Приложения содержащие много файлов](../tutorial/bigger-applications.md){.internal-link target=_blank}, состоящие из множества файлов, Ваш Dockerfile может выглядеть так: - -```Dockerfile hl_lines="7" -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 - -COPY ./requirements.txt /app/requirements.txt - -RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt - -COPY ./app /app/app -``` - -### Как им пользоваться - -Если вы используете **Kubernetes** (или что-то вроде того), скорее всего вам **не нужно** использовать официальный Docker-образ (или другой похожий) в качестве основы, так как управление **количеством запущенных контейнеров** должно быть настроено на уровне кластера. В таком случае лучше **создать образ с нуля**, как описано в разделе Создать [Docker-образ для FastAPI](#docker-fastapi). - -Официальный образ может быть полезен в отдельных случаях, описанных выше в разделе [Множество процессов внутри контейнера для особых случаев](#_11). Например, если ваше приложение **достаточно простое**, не требует запуска в кластере и способно уместиться в один контейнер, то его настройки по умолчанию будут работать довольно хорошо. Или же вы развертываете его с помощью **Docker Compose**, работаете на одном сервере и т. д - -## Развёртывание образа контейнера - -После создания образа контейнера существует несколько способов его развёртывания. +После того как у вас есть образ контейнера (Docker), его можно развёртывать несколькими способами. Например: -* С использованием **Docker Compose** при развёртывании на одном сервере -* С использованием **Kubernetes** в кластере -* С использованием режима Docker Swarm в кластере -* С использованием других инструментов, таких как Nomad -* С использованием облачного сервиса, который будет управлять разворачиванием вашего контейнера +* С **Docker Compose** на одном сервере +* В кластере **Kubernetes** +* В кластере Docker Swarm Mode +* С другим инструментом, например Nomad +* С облачным сервисом, который принимает ваш образ контейнера и разворачивает его -## Docker-образ и Poetry +## Docker-образ с `uv` { #docker-image-with-uv } -Если вы пользуетесь Poetry для управления зависимостями вашего проекта, то можете использовать многоэтапную сборку образа: +Если вы используете uv для установки и управления проектом, следуйте их руководству по Docker для uv. -```{ .dockerfile .annotate } -# (1) -FROM python:3.9 as requirements-stage +## Резюме { #recap } -# (2) -WORKDIR /tmp +Используя системы контейнеризации (например, **Docker** и **Kubernetes**), довольно просто закрыть все **концепции развертывания**: -# (3) -RUN pip install poetry +* HTTPS +* Запуск при старте +* Перезапуски +* Репликация (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -# (4) -COPY ./pyproject.toml ./poetry.lock* /tmp/ +В большинстве случаев вы, вероятно, не захотите использовать какой-либо базовый образ, а вместо этого **соберёте образ контейнера с нуля** на основе официального Docker-образа Python. -# (5) -RUN poetry export -f requirements.txt --output requirements.txt --without-hashes - -# (6) -FROM python:3.9 - -# (7) -WORKDIR /code - -# (8) -COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt - -# (9) -RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt - -# (10) -COPY ./app /code/app - -# (11) -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] -``` - -1. Это первый этап, которому мы дадим имя `requirements-stage`. - -2. Установите директорию `/tmp` в качестве рабочей директории. - - В ней будет создан файл `requirements.txt` - -3. На этом шаге установите Poetry. - -4. Скопируйте файлы `pyproject.toml` и `poetry.lock` в директорию `/tmp`. - - Поскольку название файла написано как `./poetry.lock*` (с `*` в конце), то ничего не сломается, если такой файл не будет найден. - -5. Создайте файл `requirements.txt`. - -6. Это второй (и последний) этап сборки, который и создаст окончательный образ контейнера. - -7. Установите директорию `/code` в качестве рабочей. - -8. Скопируйте файл `requirements.txt` в директорию `/code`. - - Этот файл находится в образе, созданном на предыдущем этапе, которому мы дали имя requirements-stage, потому при копировании нужно написать `--from-requirements-stage`. - -9. Установите зависимости, указанные в файле `requirements.txt`. - -10. Скопируйте папку `app` в папку `/code`. - -11. Запустите `uvicorn`, указав ему использовать объект `app`, расположенный в `app.main`. - -/// tip | Подсказка - -Если ткнёте на кружок с плюсом, то увидите объяснения, что происходит в этой строке. - -/// - -**Этапы сборки Docker-образа** являются частью `Dockerfile` и работают как **временные образы контейнеров**. Они нужны только для создания файлов, используемых в дальнейших этапах. - -Первый этап был нужен только для **установки Poetry** и **создания файла `requirements.txt`**, в которым прописаны зависимости вашего проекта, взятые из файла `pyproject.toml`. - -На **следующем этапе** `pip` будет использовать файл `requirements.txt`. - -В итоговом образе будет содержаться **только последний этап сборки**, предыдущие этапы будут отброшены. - -При использовании Poetry, имеет смысл использовать **многоэтапную сборку Docker-образа**, потому что на самом деле вам не нужен Poetry и его зависимости в окончательном образе контейнера, вам **нужен только** сгенерированный файл `requirements.txt` для установки зависимостей вашего проекта. - -А на последнем этапе, придерживаясь описанных ранее правил, создаётся итоговый образ - -### Использование прокси-сервера завершения TLS и Poetry - -И снова повторюсь, если используете прокси-сервер (балансировщик нагрузки), такой как Nginx или Traefik, добавьте в команду запуска опцию `--proxy-headers`: - -```Dockerfile -CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"] -``` - -## Резюме - -При помощи систем контейнеризации (таких, как **Docker** и **Kubernetes**), становится довольно просто обрабатывать все **концепции развертывания**: - -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения - -В большинстве случаев Вам, вероятно, не нужно использовать какой-либо базовый образ, **лучше создать образ контейнера с нуля** на основе официального Docker-образа Python. - -Позаботившись о **порядке написания** инструкций в `Dockerfile`, вы сможете использовать **кэш Docker'а**, **минимизировав время сборки**, максимально повысив свою производительность (и не заскучать). 😎 - -В некоторых особых случаях вы можете использовать официальный образ Docker для FastAPI. 🤓 +Заботясь о **порядке** инструкций в `Dockerfile`и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎 diff --git a/docs/ru/docs/deployment/https.md b/docs/ru/docs/deployment/https.md index d8877a9a1..05a03255e 100644 --- a/docs/ru/docs/deployment/https.md +++ b/docs/ru/docs/deployment/https.md @@ -1,207 +1,231 @@ -# Об HTTPS +# Об HTTPS { #about-https } -Обычно представляется, что HTTPS это некая опция, которая либо "включена", либо нет. +Легко предположить, что HTTPS — это что-то, что просто «включено» или нет. -Но всё несколько сложнее. +Но на самом деле всё гораздо сложнее. -/// tip | Заметка +/// tip | Совет -Если вы торопитесь или вам не интересно, можете перейти на следующую страницу этого пошагового руководства по размещению приложений на серверах с использованием различных технологий. +Если вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами. /// -Чтобы **изучить основы HTTPS** для клиента, перейдите по ссылке https://howhttps.works/. +Чтобы **изучить основы HTTPS** с точки зрения пользователя, загляните на https://howhttps.works/. -Здесь же представлены некоторые концепции, которые **разработчик** должен иметь в виду при размышлениях об HTTPS: +Теперь, со стороны **разработчика**, вот несколько вещей, которые стоит держать в голове, размышляя об HTTPS: -* Протокол HTTPS предполагает, что **серверу** нужно **располагать "сертификатами"** сгенерированными **третьей стороной**. - * На самом деле эти сертификаты **приобретены** у третьей стороны, а не "сгенерированы". -* У сертификатов есть **срок годности**. - * Срок годности **истекает**. - * По истечении срока годности их нужно **обновить**, то есть **снова получить** у третьей стороны. -* Шифрование соединения происходит **на уровне протокола TCP**. - * Протокол TCP находится на один уровень **ниже протокола HTTP**. - * Поэтому **проверка сертификатов и шифрование** происходит **до HTTP**. -* **TCP не знает о "доменах"**, но знает об IP-адресах. - * Информация о **запрашиваемом домене** извлекается из запроса **на уровне HTTP**. -* **Сертификаты HTTPS** "сертифицируют" **конкретный домен**, но проверка сертификатов и шифрование данных происходит на уровне протокола TCP, то есть **до того**, как станет известен домен-получатель данных. -* **По умолчанию** это означает, что у вас может быть **только один сертификат HTTPS на один IP-адрес**. - * Не важно, насколько большой у вас сервер и насколько маленькие приложения на нём могут быть. - * Однако, у этой проблемы есть **решение**. -* Существует **расширение** протокола **TLS** (который работает на уровне TCP, то есть до HTTP) называемое **SNI**. - * Расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько сертификатов HTTPS** и обслуживать **множество HTTPS-доменов/приложений**. - * Чтобы эта конструкция работала, **один** её компонент (программа) запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все сертификаты HTTPS** для этого сервера. -* **После** установления защищённого соединения, протоколом передачи данных **остаётся HTTP**. - * Но данные теперь **зашифрованы**, несмотря на то, что они передаются по **протоколу HTTP**. +* Для HTTPS **серверу** нужно **иметь «сертификаты»**, сгенерированные **третьей стороной**. + * Эти сертификаты на самом деле **приобретаются** у третьей стороны, а не «генерируются». +* У сертификатов есть **срок действия**. + * Они **истекают**. + * После этого их нужно **обновлять**, то есть **получать заново** у третьей стороны. +* Шифрование соединения происходит на **уровне TCP**. + * Это на один уровень **ниже HTTP**. + * Поэтому **сертификаты и шифрование** обрабатываются **до HTTP**. +* **TCP не знает о «доменах»**. Только об IP-адресах. + * Информация о **конкретном домене** передаётся в **данных HTTP**. +* **HTTPS-сертификаты** «сертифицируют» **определённый домен**, но протокол и шифрование происходят на уровне TCP, **до того как** становится известен домен, с которым идёт работа. +* **По умолчанию** это означает, что вы можете иметь **лишь один HTTPS-сертификат на один IP-адрес**. + * Неважно, насколько мощный у вас сервер или насколько маленькие приложения на нём работают. + * Однако у этого есть **решение**. +* Есть **расширение** протокола **TLS** (того самого, что занимается шифрованием на уровне TCP, до HTTP) под названием **SNI**. + * Это расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько HTTPS-сертификатов** и обслуживать **несколько HTTPS-доменов/приложений**. + * Чтобы это работало, **один** компонент (программа), запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все HTTPS-сертификаты** на этом сервере. +* **После** установления защищённого соединения, протокол обмена данными — **всё ещё HTTP**. + * Содержимое **зашифровано**, несмотря на то, что оно отправляется по **протоколу HTTP**. -Обычной практикой является иметь **одну программу/HTTP-сервер** запущенную на сервере (машине, хосте и т.д.) и **ответственную за всю работу с HTTPS**: +Обычно на сервере (машине, хосте и т.п.) запускают **одну программу/HTTP‑сервер**, которая **управляет всей частью, связанной с HTTPS**: принимает **зашифрованные HTTPS-запросы**, отправляет **расшифрованные HTTP-запросы** в само HTTP‑приложение, работающее на том же сервере (в нашем случае это приложение **FastAPI**), получает **HTTP-ответ** от приложения, **шифрует его** с использованием подходящего **HTTPS‑сертификата** и отправляет клиенту по **HTTPS**. Такой сервер часто называют **прокси‑сервером TLS-терминации**. -* получение **зашифрованных HTTPS-запросов** -* отправка **расшифрованных HTTP запросов** в соответствующее HTTP-приложение, работающее на том же сервере (в нашем случае, это приложение **FastAPI**) -* получение **HTTP-ответа** от приложения -* **шифрование ответа** используя подходящий **сертификат HTTPS** -* отправка зашифрованного **HTTPS-ответа клиенту**. -Такой сервер часто называют **Прокси-сервер завершения работы TLS** или просто "прокси-сервер". +Некоторые варианты, которые вы можете использовать как прокси‑сервер TLS-терминации: -Вот некоторые варианты, которые вы можете использовать в качестве такого прокси-сервера: - -* Traefik (может обновлять сертификаты) -* Caddy (может обновлять сертификаты) +* Traefik (умеет обновлять сертификаты) +* Caddy (умеет обновлять сертификаты) * Nginx * HAProxy -## Let's Encrypt (центр сертификации) +## Let's Encrypt { #lets-encrypt } -До появления Let's Encrypt **сертификаты HTTPS** приходилось покупать у третьих сторон. +До появления Let's Encrypt эти **HTTPS-сертификаты** продавались доверенными третьими сторонами. -Процесс получения такого сертификата был трудоёмким, требовал предоставления подтверждающих документов и сертификаты стоили дорого. +Процесс получения таких сертификатов был неудобным, требовал бумажной волокиты, а сами сертификаты были довольно дорогими. -Но затем консорциумом Linux Foundation был создан проект **Let's Encrypt**. +Затем появился **Let's Encrypt**. -Он автоматически предоставляет **бесплатные сертификаты HTTPS**. Эти сертификаты используют все стандартные криптографические способы шифрования. Они имеют небольшой срок годности (около 3 месяцев), благодаря чему они даже **более безопасны**. +Это проект Linux Foundation. Он предоставляет **HTTPS‑сертификаты бесплатно**, в автоматическом режиме. Эти сертификаты используют стандартные криптографические механизмы и имеют короткий срок действия (около 3 месяцев), поэтому **безопасность фактически выше** благодаря уменьшенному сроку жизни. -При запросе на получение сертификата, он автоматически генерируется и домен проверяется на безопасность. Это позволяет обновлять сертификаты автоматически. +Домены безопасно проверяются, а сертификаты выдаются автоматически. Это также позволяет автоматизировать процесс их продления. -Суть идеи в автоматическом получении и обновлении этих сертификатов, чтобы все могли пользоваться **безопасным HTTPS. Бесплатно. В любое время.** +Идея — автоматизировать получение и продление сертификатов, чтобы у вас был **безопасный HTTPS, бесплатно и навсегда**. -## HTTPS для разработчиков +## HTTPS для разработчиков { #https-for-developers } -Ниже, шаг за шагом, с заострением внимания на идеях, важных для разработчика, описано, как может выглядеть HTTPS API. +Ниже приведён пример того, как может выглядеть HTTPS‑API, шаг за шагом, с акцентом на идеях, важных для разработчиков. -### Имя домена +### Имя домена { #domain-name } -Чаще всего, всё начинается с **приобретения имени домена**. Затем нужно настроить DNS-сервер (вероятно у того же провайдера, который выдал вам домен). +Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера). -Далее, возможно, вы получаете "облачный" сервер (виртуальную машину) или что-то типа этого, у которого есть постоянный **публичный IP-адрес**. +Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет постоянный **публичный IP-адрес**. -На DNS-сервере (серверах) вам следует настроить соответствующую ресурсную запись ("`запись A`"), указав, что **Ваш домен** связан с публичным **IP-адресом вашего сервера**. +На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**. -Обычно эту запись достаточно указать один раз, при первоначальной настройке всего сервера. +Обычно это делается один раз — при первоначальной настройке всего. -/// tip | Заметка +/// tip | Совет -Уровни протоколов, работающих с именами доменов, намного ниже HTTPS, но об этом следует упомянуть здесь, так как всё зависит от доменов и IP-адресов. +Часть про доменное имя относится к этапам задолго до HTTPS, но так как всё зависит от домена и IP‑адреса, здесь стоит это упомянуть. /// -### DNS +### DNS { #dns } -Теперь давайте сфокусируемся на работе с HTTPS. +Теперь сфокусируемся на собственно частях, связанных с HTTPS. -Всё начинается с того, что браузер спрашивает у **DNS-серверов**, какой **IP-адрес связан с доменом**, для примера возьмём домен `someapp.example.com`. +Сначала браузер спросит у **DNS‑серверов**, какой **IP соответствует домену**, в нашем примере `someapp.example.com`. -DNS-сервера присылают браузеру определённый **IP-адрес**, тот самый публичный IP-адрес вашего сервера, который вы указали в ресурсной "записи А" при настройке. +DNS‑серверы ответят браузеру, какой **конкретный IP‑адрес** использовать. Это будет публичный IP‑адрес вашего сервера, который вы указали в настройках DNS. -### Рукопожатие TLS +### Начало TLS-рукопожатия { #tls-handshake-start } -В дальнейшем браузер будет взаимодействовать с этим IP-адресом через **port 443** (общепринятый номер порта для HTTPS). +Далее браузер будет общаться с этим IP‑адресом на **порту 443** (порт HTTPS). -Первым шагом будет установление соединения между клиентом (браузером) и сервером и выбор криптографического ключа (для шифрования). +Первая часть взаимодействия — установить соединение между клиентом и сервером и договориться о криптографических ключах и т.п. -Эта часть клиент-серверного взаимодействия устанавливает TLS-соединение и называется **TLS-рукопожатием**. +Это взаимодействие клиента и сервера для установления TLS‑соединения называется **TLS‑рукопожатием**. -### TLS с расширением SNI +### TLS с расширением SNI { #tls-with-sni-extension } -На сервере **только один процесс** может прослушивать определённый **порт** определённого **IP-адреса**. На сервере могут быть и другие процессы, слушающие другие порты этого же IP-адреса, но никакой процесс не может быть привязан к уже занятой комбинации IP-адрес:порт. Эта комбинация называется "сокет". +На сервере **только один процесс** может слушать конкретный **порт** на конкретном **IP‑адресе**. Могут быть другие процессы, слушающие другие порты на том же IP‑адресе, но не более одного процесса на каждую комбинацию IP‑адреса и порта. -По умолчанию TLS (HTTPS) использует порт `443`. Потому этот же порт будем использовать и мы. +По умолчанию TLS (HTTPS) использует порт `443`. Значит, он нам и нужен. -И раз уж только один процесс может слушать этот порт, то это будет процесс **прокси-сервера завершения работы TLS**. +Так как только один процесс может слушать этот порт, делать это будет **прокси‑сервер TLS-терминации**. -Прокси-сервер завершения работы TLS будет иметь доступ к одному или нескольким **TLS-сертификатам** (сертификаты HTTPS). +У прокси‑сервера TLS-терминации будет доступ к одному или нескольким **TLS‑сертификатам** (HTTPS‑сертификатам). -Используя **расширение SNI** упомянутое выше, прокси-сервер из имеющихся сертификатов TLS (HTTPS) выберет тот, который соответствует имени домена, указанному в запросе от клиента. +Используя **расширение SNI**, упомянутое выше, прокси‑сервер TLS-терминации определит, какой из доступных TLS (HTTPS)‑сертификатов нужно использовать для этого соединения, выбрав тот, который соответствует домену, ожидаемому клиентом. -То есть будет выбран сертификат для домена `someapp.example.com`. +В нашем случае это будет сертификат для `someapp.example.com`. -Клиент уже **доверяет** тому, кто выдал этот TLS-сертификат (в нашем случае - Let's Encrypt, но мы ещё обсудим это), потому может **проверить**, действителен ли полученный от сервера сертификат. +Клиент уже **доверяет** организации, выдавшей этот TLS‑сертификат (в нашем случае — Let's Encrypt, но об этом позже), поэтому может **проверить**, что сертификат действителен. -Затем, используя этот сертификат, клиент и прокси-сервер **выбирают способ шифрования** данных для устанавливаемого **TCP-соединения**. На этом операция **TLS-рукопожатия** завершена. +Затем, используя сертификат, клиент и прокси‑сервер TLS-терминации **договариваются о способе шифрования** остальной **TCP‑коммуникации**. На этом **TLS‑рукопожатие** завершено. -В дальнейшем клиент и сервер будут взаимодействовать по **зашифрованному TCP-соединению**, как предлагается в протоколе TLS. И на основе этого TCP-соедениния будет создано **HTTP-соединение**. +После этого у клиента и сервера есть **зашифрованное TCP‑соединение** — это и предоставляет TLS. И они могут использовать это соединение, чтобы начать собственно **HTTP‑обмен**. -Таким образом, **HTTPS** это тот же **HTTP**, но внутри **безопасного TLS-соединения** вместо чистого (незашифрованного) TCP-соединения. +Собственно, **HTTPS** — это обычный **HTTP** внутри **защищённого TLS‑соединения**, вместо чистого (незашифрованного) TCP‑соединения. -/// tip | Заметка +/// tip | Совет -Обратите внимание, что шифрование происходит на **уровне TCP**, а не на более высоком уровне HTTP. +Обратите внимание, что шифрование обмена происходит на **уровне TCP**, а не на уровне HTTP. /// -### HTTPS-запрос +### HTTPS‑запрос { #https-request } -Теперь, когда между клиентом и сервером (в нашем случае, браузером и прокси-сервером) создано **зашифрованное TCP-соединение**, они могут начать **обмен данными по протоколу HTTP**. +Теперь, когда у клиента и сервера (конкретно у браузера и прокси‑сервера TLS-терминации) есть **зашифрованное TCP‑соединение**, они могут начать **HTTP‑обмен**. -Так клиент отправляет **HTTPS-запрос**. То есть обычный HTTP-запрос, но через зашифрованное TLS-содинение. +Клиент отправляет **HTTPS‑запрос**. Это обычный HTTP‑запрос через зашифрованное TLS‑соединение. -### Расшифровка запроса +### Расшифровка запроса { #decrypt-the-request } -Прокси-сервер, используя согласованный с клиентом ключ, расшифрует полученный **зашифрованный запрос** и передаст **обычный (незашифрованный) HTTP-запрос** процессу, запускающему приложение (например, процессу Uvicorn запускающему приложение FastAPI). +Прокси‑сервер TLS-терминации использует согласованное шифрование, чтобы **расшифровать запрос**, и передаёт **обычный (расшифрованный) HTTP‑запрос** процессу, запускающему приложение (например, процессу с Uvicorn, который запускает приложение FastAPI). -### HTTP-ответ +### HTTP‑ответ { #http-response } -Приложение обработает запрос и вернёт **обычный (незашифрованный) HTTP-ответ** прокси-серверу. +Приложение обработает запрос и отправит **обычный (незашифрованный) HTTP‑ответ** прокси‑серверу TLS-терминации. -### HTTPS-ответ +### HTTPS‑ответ { #https-response } -Пркоси-сервер **зашифрует ответ** используя ранее согласованный с клиентом способ шифрования (которые содержатся в сертификате для домена `someapp.example.com`) и отправит его браузеру. +Затем прокси‑сервер TLS-терминации **зашифрует ответ** с использованием ранее согласованного способа шифрования (который начали использовать для сертификата для `someapp.example.com`) и отправит его обратно в браузер. -Наконец, браузер проверит ответ, в том числе, что тот зашифрован с нужным ключом, **расшифрует его** и обработает. +Далее браузер проверит, что ответ корректен и зашифрован правильным криптографическим ключом и т.п., затем **расшифрует ответ** и обработает его. -Клиент (браузер) знает, что ответ пришёл от правильного сервера, так как использует методы шифрования, согласованные ими раннее через **HTTPS-сертификат**. +Клиент (браузер) узнает, что ответ пришёл от правильного сервера, потому что используется способ шифрования, о котором они договорились ранее с помощью **HTTPS‑сертификата**. -### Множество приложений +### Несколько приложений { #multiple-applications } -На одном и том же сервере (или серверах) можно разместить **множество приложений**, например, другие программы с API или базы данных. +На одном и том же сервере (или серверах) могут работать **несколько приложений**, например другие программы с API или база данных. -Напомню, что только один процесс (например, прокси-сервер) может прослушивать определённый порт определённого IP-адреса. -Но другие процессы и приложения тоже могут работать на этом же сервере (серверах), если они не пытаются использовать уже занятую **комбинацию IP-адреса и порта** (сокет). +Только один процесс может обрабатывать конкретную комбинацию IP и порта (в нашем примере — прокси‑сервер TLS-терминации), но остальные приложения/процессы тоже могут работать на сервере(ах), пока они не пытаются использовать ту же **комбинацию публичного IP и порта**. -Таким образом, сервер завершения TLS может обрабатывать HTTPS-запросы и использовать сертификаты для **множества доменов** или приложений и передавать запросы правильным адресатам (другим приложениям). +Таким образом, прокси‑сервер TLS-терминации может обрабатывать HTTPS и сертификаты для **нескольких доменов** (для нескольких приложений), а затем передавать запросы нужному приложению в каждом случае. -### Обновление сертификата +### Продление сертификата { #certificate-renewal } -В недалёком будущем любой сертификат станет **просроченным** (примерно через три месяца после получения). +Со временем каждый сертификат **истечёт** (примерно через 3 месяца после получения). -Когда это произойдёт, можно запустить другую программу, которая подключится к Let's Encrypt и обновит сертификат(ы). Существуют прокси-серверы, которые могут сделать это действие самостоятельно. +Затем будет другая программа (иногда это отдельная программа, иногда — тот же прокси‑сервер TLS-терминации), которая свяжется с Let's Encrypt и продлит сертификат(ы). -**TLS-сертификаты** не привязаны к IP-адресу, но **связаны с именем домена**. +**TLS‑сертификаты** **связаны с именем домена**, а не с IP‑адресом. -Так что при обновлении сертификатов программа должна **подтвердить** центру сертификации (Let's Encrypt), что обновление запросил **"владелец", который контролирует этот домен**. +Поэтому, чтобы продлить сертификаты, программа продления должна **доказать** удостоверяющему центру (Let's Encrypt), что она действительно **«владеет» и контролирует этот домен**. -Есть несколько путей осуществления этого. Самые популярные из них: +Для этого, учитывая разные потребности приложений, есть несколько способов. Популярные из них: -* **Изменение записей DNS**. - * Для такого варианта Ваша программа обновления должна уметь работать с API DNS-провайдера, обслуживающего Ваши DNS-записи. Не у всех провайдеров есть такой API, так что этот способ не всегда применим. -* **Запуск в качестве программы-сервера** (как минимум, на время обновления сертификатов) на публичном IP-адресе домена. - * Как уже не раз упоминалось, только один процесс может прослушивать определённый порт определённого IP-адреса. - * Это одна из причин использования прокси-сервера ещё и в качестве программы обновления сертификатов. - * В случае, если обновлением сертификатов занимается другая программа, вам понадобится остановить прокси-сервер, запустить программу обновления сертификатов на сокете, предназначенном для прокси-сервера, настроить прокси-сервер на работу с новыми сертификатами и перезапустить его. Эта схема далека от идеальной, так как Ваши приложения будут недоступны на время отключения прокси-сервера. +* **Изменить некоторые DNS‑записи**. + * Для этого программа продления должна поддерживать API DNS‑провайдера, поэтому, в зависимости от используемого провайдера DNS, этот вариант может быть доступен или нет. +* **Запуститься как сервер** (как минимум на время получения сертификатов) на публичном IP‑адресе, связанном с доменом. + * Как сказано выше, только один процесс может слушать конкретный IP и порт. + * Это одна из причин, почему очень удобно, когда тот же прокси‑сервер TLS-терминации также занимается процессом продления сертификатов. + * В противном случае вам, возможно, придётся временно остановить прокси‑сервер TLS-терминации, запустить программу продления для получения сертификатов, затем настроить их в прокси‑сервере TLS-терминации и перезапустить его. Это не идеально, так как ваше приложение(я) будут недоступны, пока прокси‑сервер TLS-терминации остановлен. -Весь этот процесс обновления, одновременный с обслуживанием запросов, является одной из основных причин, по которой желательно иметь **отдельную систему для работы с HTTPS** в виде прокси-сервера завершения TLS, а не просто использовать сертификаты TLS непосредственно с сервером приложений (например, Uvicorn). +Весь этот процесс продления, совмещённый с обслуживанием приложения, — одна из главных причин иметь **отдельную систему для работы с HTTPS** в виде прокси‑сервера TLS-терминации, вместо использования TLS‑сертификатов напрямую в сервере приложения (например, Uvicorn). -## Резюме +## Пересылаемые HTTP-заголовки прокси { #proxy-forwarded-headers } -Наличие **HTTPS** очень важно и довольно **критично** в большинстве случаев. Однако, Вам, как разработчику, не нужно тратить много сил на это, достаточно **понимать эти концепции** и принципы их работы. +Когда вы используете прокси для обработки HTTPS, ваш **сервер приложения** (например, Uvicorn через FastAPI CLI) ничего не знает о процессе HTTPS, он общается обычным HTTP с **прокси‑сервером TLS-терминации**. -Но узнав базовые основы **HTTPS** вы можете легко совмещать разные инструменты, которые помогут вам в дальнейшей разработке. +Обычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **проксирован**. -В следующих главах я покажу вам несколько примеров, как настраивать **HTTPS** для приложений **FastAPI**. 🔒 +/// note | Технические детали + +Заголовки прокси: + +* X-Forwarded-For +* X-Forwarded-Proto +* X-Forwarded-Host + +/// + +Тем не менее, так как **сервер приложения** не знает, что он находится за доверенным **прокси**, по умолчанию он не будет доверять этим заголовкам. + +Но вы можете настроить **сервер приложения**, чтобы он доверял *пересылаемым* заголовкам, отправленным **прокси**. Если вы используете FastAPI CLI, вы можете использовать *опцию CLI* `--forwarded-allow-ips`, чтобы указать, с каких IP‑адресов следует доверять этим *пересылаемым* заголовкам. + +Например, если **сервер приложения** получает запросы только от доверенного **прокси**, вы можете установить `--forwarded-allow-ips="*"`, чтобы доверять всем входящим IP, так как он всё равно будет получать запросы только с IP‑адреса, используемого **прокси**. + +Таким образом, приложение сможет знать свой публичный URL, использует ли оно HTTPS, какой домен и т.п. + +Это будет полезно, например, для корректной обработки редиректов. + +/// tip | Совет + +Подробнее об этом вы можете узнать в документации: [За прокси — Включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} + +/// + +## Резюме { #recap } + +Наличие **HTTPS** очень важно и во многих случаях довольно **критично**. Большая часть усилий, которые вам, как разработчику, нужно приложить вокруг HTTPS, — это просто **понимание этих концепций** и того, как они работают. + +Зная базовую информацию о **HTTPS для разработчиков**, вы сможете легко комбинировать и настраивать разные инструменты, чтобы управлять всем этим простым способом. + +В некоторых из следующих глав я покажу вам несколько конкретных примеров настройки **HTTPS** для приложений **FastAPI**. 🔒 diff --git a/docs/ru/docs/deployment/index.md b/docs/ru/docs/deployment/index.md index e88ddc3e2..c85fa0d52 100644 --- a/docs/ru/docs/deployment/index.md +++ b/docs/ru/docs/deployment/index.md @@ -1,16 +1,16 @@ -# Развёртывание +# Развёртывание { #deployment } Развернуть приложение **FastAPI** довольно просто. -## Да что такое это ваше - "развёртывание"?! +## Что означает развёртывание { #what-does-deployment-mean } Термин **развёртывание** (приложения) означает выполнение необходимых шагов, чтобы сделать приложение **доступным для пользователей**. -Обычно **веб-приложения** размещают на удалённом компьютере с серверной программой, которая обеспечивает хорошую производительность, стабильность и т. д., Чтобы ваши пользователи могли эффективно, беспрерывно и беспроблемно обращаться к приложению. +Для **веб-API** это обычно означает размещение его на **удалённой машине** с **серверной программой**, обеспечивающей хорошую производительность, стабильность и т.д., чтобы ваши **пользователи** могли **получать доступ** к приложению эффективно и без перебоев или проблем. -Это отличается от **разработки**, когда вы постоянно меняете код, делаете в нём намеренные ошибки и исправляете их, останавливаете и перезапускаете сервер разработки и т. д. +Это отличается от этапов **разработки**, когда вы постоянно меняете код, ломаете его и исправляете, останавливаете и перезапускаете сервер разработки и т.д. -## Стратегии развёртывания +## Стратегии развёртывания { #deployment-strategies } В зависимости от вашего конкретного случая, есть несколько способов сделать это. diff --git a/docs/ru/docs/deployment/manually.md b/docs/ru/docs/deployment/manually.md index 9b1d32be8..37fed5780 100644 --- a/docs/ru/docs/deployment/manually.md +++ b/docs/ru/docs/deployment/manually.md @@ -1,33 +1,82 @@ -# Запуск сервера вручную - Uvicorn +# Запуск сервера вручную { #run-a-server-manually } -Для запуска приложения **FastAPI** на удалённой серверной машине вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**. +## Используйте команду `fastapi run` { #use-the-fastapi-run-command } -Существует три наиболее распространённые альтернативы: +Коротко: используйте `fastapi run`, чтобы запустить ваше приложение FastAPI: -* Uvicorn: высокопроизводительный ASGI сервер. -* Hypercorn: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio. -* Daphne: ASGI сервер, созданный для Django Channels. +
-## Сервер как машина и сервер как программа +```console +$ fastapi run main.py -В этих терминах есть некоторые различия и вам следует запомнить их. 💡 + FastAPI Starting production server 🚀 -Слово "**сервер**" чаще всего используется в двух контекстах: + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp -- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина). -- программа, запущенная на таком компьютере (например, Uvicorn). + module 🐍 main.py -Просто запомните, если вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов. + code Importing the FastAPI app object from the module with + the following code: -Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором вы запускаете программы. + from main import app -## Установка программного сервера + app Using import string: main:app -Вы можете установить сервер, совместимый с протоколом ASGI, так: + server Server started at http://0.0.0.0:8000 + server Documentation at http://0.0.0.0:8000/docs -//// tab | Uvicorn + Logs: -* Uvicorn, очень быстрый ASGI сервер, основанный на библиотеках uvloop и httptools. + INFO Started server process [2306215] + INFO Waiting for application startup. + INFO Application startup complete. + INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C + to quit) +``` + +
+ +В большинстве случаев этого достаточно. 😎 + +Этой командой, например, можно запускать приложение **FastAPI** в контейнере, на сервере и т.д. + +## ASGI‑серверы { #asgi-servers } + +Давайте немного углубимся в детали. + +FastAPI использует стандарт для построения Python‑веб‑фреймворков и серверов под названием ASGI. FastAPI — ASGI-веб‑фреймворк. + +Главное, что вам нужно, чтобы запустить приложение **FastAPI** (или любое другое ASGI‑приложение) на удалённой серверной машине, — это программа ASGI‑сервера, такая как **Uvicorn**; именно он используется по умолчанию в команде `fastapi`. + +Есть несколько альтернатив, например: + +* Uvicorn: высокопроизводительный ASGI‑сервер. +* Hypercorn: ASGI‑сервер, среди прочего совместимый с HTTP/2 и Trio. +* Daphne: ASGI‑сервер, созданный для Django Channels. +* Granian: HTTP‑сервер на Rust для Python‑приложений. +* NGINX Unit: NGINX Unit — лёгкая и многофункциональная среда выполнения веб‑приложений. + +## Сервер как машина и сервер как программа { #server-machine-and-server-program } + +Есть небольшой нюанс в терминологии, о котором стоит помнить. 💡 + +Слово «сервер» обычно используют и для обозначения удалённого/облачного компьютера (физической или виртуальной машины), и для программы, работающей на этой машине (например, Uvicorn). + +Имейте в виду, что слово «сервер» в целом может означать любое из этих двух. + +Когда речь идёт об удалённой машине, её зачастую называют **сервер**, а также **машина**, **VM** (виртуальная машина), **нода**. Всё это — варианты названия удалённой машины, обычно под управлением Linux, на которой вы запускаете программы. + +## Установка серверной программы { #install-the-server-program } + +При установке FastAPI он поставляется с продакшн‑сервером Uvicorn, и вы можете запустить его командой `fastapi run`. + +Но вы также можете установить ASGI‑сервер вручную. + +Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите серверное приложение. + +Например, чтобы установить Uvicorn:
@@ -39,39 +88,21 @@ $ pip install "uvicorn[standard]"
-/// tip | Подсказка +Аналогично устанавливаются и другие ASGI‑серверы. -С опцией `standard`, Uvicorn будет устанавливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями. +/// tip | Совет -В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ. +С добавлением `standard` Uvicorn установит и будет использовать ряд рекомендованных дополнительных зависимостей. + +В их числе `uvloop` — высокопроизводительная замена `asyncio`, дающая серьёзный прирост производительности при параллельной работе. + +Если вы устанавливаете FastAPI, например так: `pip install "fastapi[standard]"`, вы уже получаете и `uvicorn[standard]`. /// -//// +## Запуск серверной программы { #run-the-server-program } -//// tab | Hypercorn - -* Hypercorn, ASGI сервер, поддерживающий протокол HTTP/2. - -
- -```console -$ pip install hypercorn - ----> 100% -``` - -
- -...или какой-либо другой ASGI сервер. - -//// - -## Запуск серверной программы - -Затем запустите ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`: - -//// tab | Uvicorn +Если вы установили ASGI‑сервер вручную, обычно нужно передать строку импорта в специальном формате, чтобы он смог импортировать ваше приложение FastAPI:
@@ -83,81 +114,44 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
-//// +/// note | Примечание -//// tab | Hypercorn +Команда `uvicorn main:app` означает: -
+* `main`: файл `main.py` (Python‑«модуль»). +* `app`: объект, созданный в `main.py` строкой `app = FastAPI()`. -```console -$ hypercorn main:app --bind 0.0.0.0:80 +Эквивалентно: -Running on 0.0.0.0:8080 over http (CTRL + C to quit) +```Python +from main import app ``` -
- -//// - -/// warning | Предупреждение - -Не забудьте удалить опцию `--reload`, если ранее пользовались ею. - -Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности. - -Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения. - /// -## Hypercorn с Trio +У каждого альтернативного ASGI‑сервера будет похожая команда; подробнее см. в их документации. -Starlette и **FastAPI** основаны на AnyIO, которая делает их совместимыми как с asyncio - стандартной библиотекой Python, так и с Trio. +/// warning | Предупреждение +Uvicorn и другие серверы поддерживают опцию `--reload`, полезную в период разработки. -Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с `uvloop`, высокопроизводительной заменой `asyncio`. +Опция `--reload` потребляет значительно больше ресурсов, менее стабильна и т.п. -Но если вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨ +Она сильно помогает во время **разработки**, но в **продакшн** её использовать **не следует**. -### Установка Hypercorn с Trio +/// -Для начала, вам нужно установить Hypercorn с поддержкой Trio: +## Концепции развёртывания { #deployment-concepts } -
+В этих примерах серверная программа (например, Uvicorn) запускает **один процесс**, слушающий все IP‑адреса (`0.0.0.0`) на заранее заданном порту (например, `80`). -```console -$ pip install "hypercorn[trio]" ----> 100% -``` +Это базовая идея. Но, вероятно, вам понадобится позаботиться и о некоторых дополнительных вещах, например: -
+* Безопасность — HTTPS +* Запуск при старте системы +* Перезапуски +* Репликация (количество запущенных процессов) +* Память +* Предварительные шаги перед запуском -### Запуск с Trio - -Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`: - -
- -```console -$ hypercorn main:app --worker-class trio -``` - -
- -Hypercorn, в свою очередь, запустит ваше приложение использующее Trio. - -Таким образом, вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉 - -## Концепции развёртывания - -В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`). - -Это основная идея. Но возможно, вы озаботитесь добавлением дополнительных возможностей, таких как: - -* Использование более безопасного протокола HTTPS -* Настройки запуска приложения -* Перезагрузка приложения -* Запуск нескольких экземпляров приложения -* Управление памятью -* Использование перечисленных функций перед запуском приложения. - -Я расскажу вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀 +В следующих главах я расскажу подробнее про каждую из этих концепций, о том, как о них думать, и приведу конкретные примеры со стратегиями, как с ними работать. 🚀 diff --git a/docs/ru/docs/deployment/versions.md b/docs/ru/docs/deployment/versions.md index e8db30ce8..58d5aa110 100644 --- a/docs/ru/docs/deployment/versions.md +++ b/docs/ru/docs/deployment/versions.md @@ -1,42 +1,42 @@ -# О версиях FastAPI +# О версиях FastAPI { #about-fastapi-versions } -**FastAPI** уже используется в продакшене во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Однако его разработка все еще продолжается. +**FastAPI** уже используется в продакшене во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами. Часто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться. -По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя соглашению о Семантическом Версионировании. +По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя Семантическому версионированию. -Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом. +Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом. -## Закрепите вашу версию `fastapi` +## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version } Первым делом вам следует "закрепить" конкретную последнюю используемую версию **FastAPI**, которая корректно работает с вашим приложением. -Например, в своём приложении вы используете версию `0.45.0`. +Например, в своём приложении вы используете версию `0.112.0`. Если вы используете файл `requirements.txt`, вы можете указать версию следующим способом: ```txt -fastapi==0.45.0 +fastapi[standard]==0.112.0 ``` -это означает, что вы будете использовать именно версию `0.45.0`. +это означает, что вы будете использовать именно версию `0.112.0`. Или вы можете закрепить версию следующим способом: ```txt -fastapi>=0.45.0,<0.46.0 +fastapi[standard]>=0.112.0,<0.113.0 ``` -это значит, что вы используете версии `0.45.0` или выше, но меньше чем `0.46.0`. Например, версия `0.45.2` все еще будет подходить. +это значит, что вы используете версии `0.112.0` или выше, но меньше чем `0.113.0`. Например, версия `0.112.2` всё ещё будет подходить. -Если вы используете любой другой инструмент для управления зависимостями, например Poetry, Pipenv или др., у них у всех имеется способ определения специфической версии для ваших пакетов. +Если вы используете любой другой инструмент для управления установками/зависимостями, например `uv`, Poetry, Pipenv или др., у них у всех имеется способ определения специфической версии для ваших пакетов. -## Доступные версии +## Доступные версии { #available-versions } -Вы можете посмотреть доступные версии (например, проверить последнюю на данный момент) в [примечаниях к выпуску](../release-notes.md){.internal-link target=_blank}. +Вы можете посмотреть доступные версии (например, проверить последнюю на данный момент) в [Примечаниях к выпуску](../release-notes.md){.internal-link target=_blank}. -## О версиях +## О версиях { #about-versions } Следуя соглашению о Семантическом Версионировании, любые версии ниже `1.0.0` потенциально могут добавить обратно несовместимые изменения. @@ -44,7 +44,7 @@ FastAPI следует соглашению в том, что любые изм /// tip | Подсказка -"ПАТЧ" - это последнее число. Например, в `0.2.3`, ПАТЧ-версия - это `3`. +"ПАТЧ" — это последнее число. Например, в `0.2.3`, ПАТЧ-версия — это `3`. /// @@ -58,11 +58,11 @@ fastapi>=0.45.0,<0.46.0 /// tip | Подсказка -"МИНОРНАЯ" версия - это число в середине. Например, в `0.2.3` МИНОРНАЯ версия - это `2`. +"МИНОРНАЯ" версия — это число в середине. Например, в `0.2.3` МИНОРНАЯ версия — это `2`. /// -## Обновление версий FastAPI +## Обновление версий FastAPI { #upgrading-the-fastapi-versions } Вам следует добавить тесты для вашего приложения. @@ -70,9 +70,9 @@ fastapi>=0.45.0,<0.46.0 После создания тестов вы можете обновить свою версию **FastAPI** до более новой. После этого следует убедиться, что ваш код работает корректно, запустив тесты. -Если все работает корректно, или после внесения необходимых изменений все ваши тесты проходят, только тогда вы можете закрепить вашу новую версию `fastapi`. +Если всё работает корректно, или после внесения необходимых изменений все ваши тесты проходят, только тогда вы можете закрепить вашу новую версию `fastapi`. -## О Starlette +## О Starlette { #about-starlette } Не следует закреплять версию `starlette`. @@ -80,14 +80,14 @@ fastapi>=0.45.0,<0.46.0 Так что решение об используемой версии Starlette, вы можете оставить **FastAPI**. -## О Pydantic +## О Pydantic { #about-pydantic } Pydantic включает свои собственные тесты для **FastAPI**, так что новые версии Pydantic (выше `1.0.0`) всегда совместимы с FastAPI. -Вы можете закрепить любую версию Pydantic, которая вам подходит, выше `1.0.0` и ниже `2.0.0`. +Вы можете закрепить любую версию Pydantic, которая вам подходит, выше `1.0.0`. Например: ```txt -pydantic>=1.2.0,<2.0.0 +pydantic>=2.7.0,<3.0.0 ``` diff --git a/docs/ru/docs/environment-variables.md b/docs/ru/docs/environment-variables.md index a6c7b0c77..6291b79d2 100644 --- a/docs/ru/docs/environment-variables.md +++ b/docs/ru/docs/environment-variables.md @@ -1,6 +1,6 @@ -# Переменные окружения +# Переменные окружения { #environment-variables } -/// tip +/// tip | Совет Если вы уже знаете, что такое «переменные окружения» и как их использовать, можете пропустить это. @@ -10,7 +10,7 @@ Переменные окружения могут быть полезны для работы с **настройками** приложений, как часть **установки** Python и т.д. -## Создание и использование переменных окружения +## Создание и использование переменных окружения { #create-and-use-env-vars } Можно **создавать** и использовать переменные окружения в **оболочке (терминале)**, не прибегая к помощи Python: @@ -50,7 +50,7 @@ Hello Wade Wilson //// -## Чтение переменных окружения в python +## Чтение переменных окружения в python { #read-env-vars-in-python } Так же существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**. @@ -63,11 +63,12 @@ name = os.getenv("MY_NAME", "World") print(f"Hello {name} from Python") ``` -/// tip +/// tip | Совет -Второй аргумент `os.getenv()` - это возвращаемое по умолчанию значение. +Второй аргумент `os.getenv()` - это возвращаемое по умолчанию значение. Если значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `«World»` в качестве значения по умолчанию. + /// Затем можно запустить эту программу на Python: @@ -150,13 +151,13 @@ Hello World from Python
-/// tip +/// tip | Совет Подробнее об этом можно прочитать на сайте The Twelve-Factor App: Config. /// -## Типизация и Валидация +## Типизация и Валидация { #types-and-validation } Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS). @@ -164,7 +165,7 @@ Hello World from Python Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md){.internal-link target=_blank}. -## Переменная окружения `PATH` +## Переменная окружения `PATH` { #path-environment-variable } Существует **специальная** переменная окружения **`PATH`**, которая используется операционными системами (Linux, macOS, Windows) для поиска программ для запуска. @@ -208,7 +209,7 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3 Если она ее находит, то **использует ее**. В противном случае она продолжает искать в **других каталогах**. -### Установка Python и обновление `PATH` +### Установка Python и обновление `PATH` { #installing-python-and-updating-the-path } При установке Python вас могут спросить, нужно ли обновить переменную окружения `PATH`. @@ -286,7 +287,7 @@ $ C:\opt\custompython\bin\python Эта информация будет полезна при изучении [Виртуальных окружений](virtual-environments.md){.internal-link target=_blank}. -## Вывод +## Вывод { #conclusion } Благодаря этому вы должны иметь базовое представление о том, что такое **переменные окружения** и как использовать их в Python. diff --git a/docs/ru/docs/fastapi-cli.md b/docs/ru/docs/fastapi-cli.md index c0be4a5df..156e3d200 100644 --- a/docs/ru/docs/fastapi-cli.md +++ b/docs/ru/docs/fastapi-cli.md @@ -1,4 +1,4 @@ -# FastAPI CLI +# FastAPI CLI { #fastapi-cli } **FastAPI CLI** это программа командной строки, которую вы можете использовать для запуска вашего FastAPI приложения, для управления FastAPI-проектом, а также для многих других вещей. @@ -50,26 +50,26 @@ $ fastapi dev Uvicorn, высокопроизводительный, готовый к работе в production сервер ASGI. 😎 +Внутри **FastAPI CLI** используется Uvicorn, высокопроизводительный, готовый к работе в продакшне ASGI-сервер. 😎 -## `fastapi dev` +## `fastapi dev` { #fastapi-dev } Вызов `fastapi dev` запускает режим разработки. -По умолчанию включена автоматическая перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`). +По умолчанию включена авто-перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`). -## `fastapi run` +## `fastapi run` { #fastapi-run } -Вызов `fastapi run` по умолчанию запускает FastAPI в режиме production. +Вызов `fastapi run` по умолчанию запускает FastAPI в режиме продакшн. -По умолчанию функция перезагрузки **auto-reload** отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров. +По умолчанию авто-перезагрузка (**auto-reload**) отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров. В большинстве случаев вы будете (и должны) использовать прокси-сервер ("termination proxy"), который будет поддерживать HTTPS поверх вашего приложения. Всё будет зависеть от того, как вы развертываете приложение: за вас это либо сделает ваш провайдер, либо вам придется сделать настройки самостоятельно. /// tip | Подсказка -Вы можете больше узнать об этом в документации по развертыванию приложений [deployment documentation](deployment/index.md){.internal-link target=_blank}. +Вы можете больше узнать об этом в [документации по развертыванию](deployment/index.md){.internal-link target=_blank}. /// diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md index 77d6b936a..91ffe331b 100644 --- a/docs/ru/docs/features.md +++ b/docs/ru/docs/features.md @@ -1,23 +1,21 @@ -# Основные свойства +# Возможности { #features } -## Основные свойства FastAPI +## Возможности FastAPI { #fastapi-features } **FastAPI** предлагает вам следующее: -### Использование открытых стандартов +### Основано на открытых стандартах { #based-on-open-standards } -* OpenAPI для создания API, включая объявления операций пути, параметров, тела запроса, безопасности и т.д. - - -* Автоматическое документирование моделей данных в соответствии с JSON Schema (так как спецификация OpenAPI сама основана на JSON Schema). -* Разработан, придерживаясь этих стандартов, после тщательного их изучения. Эти стандарты изначально включены во фреймфорк, а не являются дополнительной надстройкой. +* OpenAPI для создания API, включая объявления операций пути, параметров, тел запросов, безопасности и т. д. +* Автоматическая документация моделей данных с помощью JSON Schema (так как сама спецификация OpenAPI основана на JSON Schema). +* Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх. * Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках. -### Автоматически генерируемая документация +### Автоматическая документация { #automatic-docs } -Интерактивная документация для API и исследования пользовательских веб-интерфейсов. Поскольку этот фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из которых включены по умолчанию. +Интерактивная документация для API и исследовательские веб-интерфейсы. Поскольку фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из них включены по умолчанию. -* Swagger UI, с интерактивным взаимодействием, вызывает и тестирует ваш API прямо из браузера. +* Swagger UI, с интерактивным исследованием, вызовом и тестированием вашего API прямо из браузера. ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) @@ -25,22 +23,21 @@ ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Только современный Python +### Только современный Python { #just-modern-python } -Все эти возможности основаны на стандартных **аннотациях типов Python 3.8** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только лишь стандартный современный Python. +Все основано на стандартных **аннотациях типов Python** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только стандартный современный Python. -Если вам нужно освежить знания, как использовать аннотации типов в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Введение в аннотации типов Python¶ -](python-types.md){.internal-link target=_blank}. +Если вам нужно освежить знания о типах в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Типы Python](python-types.md){.internal-link target=_blank}. -Вы пишете на стандартном Python с аннотациями типов: +Вы пишете стандартный Python с типами: ```Python from datetime import date from pydantic import BaseModel -# Объявляем параметр user_id с типом `str` -# и получаем поддержку редактора внутри функции +# Объявляем параметр как `str` +# и получаем поддержку редактора кода внутри функции def main(user_id: str): return user_id @@ -70,17 +67,17 @@ my_second_user: User = User(**second_user_data) `**second_user_data` означает: -Передать ключи и значения словаря `second_user_data`, в качестве аргументов типа "ключ-значение", это эквивалентно: `User(id=4, name="Mary", joined="2018-11-30")` . +Передать ключи и значения словаря `second_user_data` в качестве аргументов "ключ-значение", эквивалентно: `User(id=4, name="Mary", joined="2018-11-30")` /// -### Поддержка редакторов (IDE) +### Поддержка редакторов (IDE) { #editor-support } Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода. -В опросе Python-разработчиков было выяснено, что наиболее часто используемой функцией редакторов, является "автодополнение". +В опросах Python‑разработчиков видно, что одной из самых часто используемых функций является «автозавершение». -Вся структура **FastAPI** основана на удовлетворении этой возможности. Автодополнение работает везде. +Вся структура **FastAPI** основана на удовлетворении этой возможности. Автозавершение работает везде. Вам редко нужно будет возвращаться к документации. @@ -94,23 +91,23 @@ my_second_user: User = User(**second_user_data) ![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) -Вы будете получать автодополнение кода даже там, где вы считали это невозможным раньше. -Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе. +Вы будете получать автозавершение кода даже там, где вы считали это невозможным раньше. Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе. -Больше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз, в попытках узнать - использовали вы ранее `username` или `user_name`. +Больше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз в попытках узнать — использовали вы ранее `username` или `user_name`. -### Краткость -FastAPI имеет продуманные значения **по умолчанию** для всего, с произвольными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно и определять необходимый вам API. +### Краткость { #short } -Но, по умолчанию, всё это **"и так работает"**. +FastAPI имеет продуманные значения **по умолчанию** для всего, с опциональными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно, и определять необходимый вам API. -### Проверка значений +Но по умолчанию всё **«просто работает»**. -* Проверка значений для большинства (или всех?) **типов данных** Python, включая: +### Проверка значений { #validation } + +* Проверка значений для большинства (или всех?) **типов данных** Python, включая: * Объекты JSON (`dict`). - * Массивы JSON (`list`) с установленными типами элементов. + * Массив JSON (`list`) с определёнными типами элементов. * Строковые (`str`) поля с ограничением минимальной и максимальной длины. - * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п. + * Числа (`int`, `float`) с минимальными и максимальными значениями и т. п. * Проверка для более экзотических типов, таких как: * URL. @@ -118,11 +115,11 @@ FastAPI имеет продуманные значения **по умолчан * UUID. * ...и другие. -Все проверки обрабатываются хорошо зарекомендовавшим себя и надежным **Pydantic**. +Все проверки обрабатываются хорошо зарекомендовавшим себя и надёжным **Pydantic**. -### Безопасность и аутентификация +### Безопасность и аутентификация { #security-and-authentication } -Встроеные функции безопасности и аутентификации. Без каких-либо компромиссов с базами данных или моделями данных. +Встроенные функции безопасности и аутентификации. Без каких‑либо компромиссов с базами данных или моделями данных. Все схемы безопасности, определённые в OpenAPI, включая: @@ -137,68 +134,68 @@ FastAPI имеет продуманные значения **по умолчан Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д. -### Внедрение зависимостей +### Внедрение зависимостей { #dependency-injection } FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему Внедрения зависимостей. -* Даже зависимости могут иметь зависимости, создавая иерархию или **"графы" зависимостей**. +* Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**. * Всё **автоматически обрабатывается** фреймворком. * Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией. -* **Автоматическая проверка** даже для параметров *операций пути*, определенных в зависимостях. -* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д. -* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но легкая интеграция со всеми ними. +* **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях. +* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т. д. +* **Никаких компромиссов** с базами данных, интерфейсами и т. д. Но при этом — лёгкая интеграция со всеми ними. -### Нет ограничений на "Плагины" +### Нет ограничений на "Плагины" { #unlimited-plug-ins } -Или, другими словами, нет сложностей с ними, импортируйте и используйте нужный вам код. +Или, другими словами, нет необходимости в них — просто импортируйте и используйте нужный вам код. -Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать "плагин" для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*. +Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать «плагин» для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*. -### Проверен +### Проверен { #tested } -* 100% покрытие тестами. -* 100% аннотирование типов в кодовой базе. -* Используется в реально работающих приложениях. +* 100% покрытие тестами. +* 100% аннотирование типов в кодовой базе. +* Используется в продакшн‑приложениях. -## Основные свойства Starlette +## Возможности Starlette { #starlette-features } -**FastAPI** основан на Starlette и полностью совместим с ним. Так что, любой дополнительный код Starlette, который у вас есть, будет также работать. +**FastAPI** основан на Starlette и полностью совместим с ним. Так что любой дополнительный код Starlette, который у вас есть, также будет работать. -На самом деле, `FastAPI` - это класс, унаследованный от `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же. +На самом деле, `FastAPI` — это подкласс `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же. -С **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI это всего лишь Starlette на стероидах): +С **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI — это всего лишь Starlette на стероидах): -* Серьёзно впечатляющая производительность. Это один из самых быстрых фреймворков на Python, наравне с приложениями использующими **NodeJS** или **Go**. +* Серьёзно впечатляющая производительность. Это один из самых быстрых фреймворков на Python, наравне с **NodeJS** и **Go**. * Поддержка **WebSocket**. -* Фоновые задачи для процессов. +* Фоновые задачи в том же процессе. * События запуска и выключения. -* Тестовый клиент построен на библиотеке HTTPX. +* Тестовый клиент построен на HTTPX. * **CORS**, GZip, статические файлы, потоковые ответы. * Поддержка **сессий и cookie**. * 100% покрытие тестами. * 100% аннотирование типов в кодовой базе. -## Особенности и возможности Pydantic +## Возможности Pydantic { #pydantic-features } -**FastAPI** основан на Pydantic и полностью совместим с ним. Так что, любой дополнительный код Pydantic, который у вас есть, будет также работать. +**FastAPI** полностью совместим с (и основан на) Pydantic. Поэтому любой дополнительный код Pydantic, который у вас есть, также будет работать. -Включая внешние библиотеки, также основанные на Pydantic, такие как: ORM'ы, ODM'ы для баз данных. +Включая внешние библиотеки, также основанные на Pydantic, такие как ORM’ы, ODM’ы для баз данных. Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически. И наоборот, во многих случаях вы можете просто передать объект, полученный из базы данных, **непосредственно клиенту**. -С **FastAPI** вы получаете все возможности **Pydantic** (так как, FastAPI основан на Pydantic, для обработки данных): +С **FastAPI** вы получаете все возможности **Pydantic** (так как FastAPI основан на Pydantic для обработки данных): -* **Никакой нервотрёпки** : - * Не нужно изучать новых схем в микроязыках. - * Если вы знаете аннотации типов в Python, вы знаете, как использовать Pydantic. -* Прекрасно сочетается с вашими **IDE/linter/мозгом**: - * Потому что структуры данных pydantic - это всего лишь экземпляры классов, определённых вами. Автодополнение, проверка кода, mypy и ваша интуиция - всё будет работать с вашими проверенными данными. -* Проверка **сложных структур**: - * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python). - * Валидаторы позволяют четко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema. - * У вас могут быть глубоко **вложенные объекты JSON** и все они будут проверены и аннотированы. +* **Никакой нервотрёпки**: + * Не нужно изучать новые схемы в микроязыках. + * Если вы знаете типы в Python, вы знаете, как использовать Pydantic. +* Прекрасно сочетается с вашим **IDE/linter/мозгом**: + * Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными. +* Валидация **сложных структур**: + * Использование иерархических моделей Pydantic; `List`, `Dict` и т. п. из модуля `typing` (входит в стандартную библиотеку Python). + * Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema. + * У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы. * **Расширяемость**: - * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели, с помощью проверочных декораторов. + * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели с помощью декораторов валидаторов. * 100% покрытие тестами. diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index 2f73c3c10..6bfabb96c 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/docs/ru/docs/help-fastapi.md @@ -1,261 +1,255 @@ -# Помочь FastAPI - Получить помощь +# Помочь FastAPI - Получить помощь { #help-fastapi-get-help } Нравится ли Вам **FastAPI**? -Хотели бы Вы помочь FastAPI, его пользователям и автору? +Хотели бы Вы помочь FastAPI, другим пользователям и автору? -Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь? +Или Вы хотите получить помощь по **FastAPI**? -Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов). +Есть несколько очень простых способов помочь (иногда достаточно всего лишь одного-двух кликов). И также есть несколько способов получить помощь. -## Подписаться на новостную рассылку +## Подписаться на новостную рассылку { #subscribe-to-the-newsletter } Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md){.internal-link target=_blank} и быть в курсе о: * Новостях о FastAPI и его друзьях 🚀 * Руководствах 📝 * Возможностях ✨ -* Исправлениях 🚨 +* Ломающих изменениях 🚨 * Подсказках и хитростях ✅ -## Подписаться на FastAPI в X (Twitter) +## Подписаться на FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter } Подписаться на @fastapi в **X (Twitter)** для получения наисвежайших новостей о **FastAPI**. 🐦 -## Добавить **FastAPI** звезду на GitHub +## Добавить **FastAPI** звезду на GitHub { #star-fastapi-in-github } -Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): https://github.com/fastapi/fastapi. ⭐️ +Вы можете добавить FastAPI "звезду" на GitHub (кликнув на кнопку звезды в правом верхнем углу): https://github.com/fastapi/fastapi. ⭐️ -Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих. +Чем больше звёзд, тем легче другим пользователям найти проект и увидеть, что он уже оказался полезным для многих. -## Отслеживать свежие выпуски в репозитории на GitHub +## Отслеживать свежие выпуски в репозитории на GitHub { #watch-the-github-repository-for-releases } -Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 -Там же Вы можете указать в настройках - "Releases only". +Там же Вы можете выбрать "Releases only". С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями. -## Связаться с автором +## Связаться с автором { #connect-with-the-author } -Можно связаться со мной (Себястьян Рамирез / `tiangolo`), автором FastAPI. +Можно связаться со мной (Sebastián Ramírez / `tiangolo`), автором. Вы можете: * Подписаться на меня на **GitHub**. * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам. - * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,. + * Подписаться, чтобы видеть, когда я создаю новый проект с открытым кодом. * Подписаться на меня в **X (Twitter)** или в Mastodon. - * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это). - * Получать уведомления, когда я делаю объявления и представляю новые инструменты. + * Поделиться со мной, как Вы используете FastAPI (я обожаю это читать). + * Узнавать, когда я делаю объявления или выпускаю новые инструменты. * Вы также можете подписаться на @fastapi в X (Twitter) (это отдельный аккаунт). -* Подписаться на меня в **Linkedin**. - * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую X (Twitter) 🤷‍♂). -* Читать, что я пишу (или подписаться на меня) в **Dev.to** или в **Medium**. - * Читать другие идеи, статьи и читать об инструментах созданных мной. - * Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое. +* Подписаться на меня в **LinkedIn**. + * Узнавать, когда я делаю объявления или выпускаю новые инструменты (хотя чаще я использую X (Twitter) 🤷‍♂). +* Читать, что я пишу (или подписаться на меня) на **Dev.to** или **Medium**. + * Читать другие идеи, статьи и о созданных мной инструментах. + * Подписаться, чтобы читать, когда я публикую что-то новое. -## Оставить сообщение в X (Twitter) о **FastAPI** +## Оставить сообщение в X (Twitter) о **FastAPI** { #tweet-about-fastapi } -Оставьте сообщение в X (Twitter) о **FastAPI** и позвольте мне и другим узнать - почему он Вам нравится. 🎉 +Оставьте сообщение в X (Twitter) о **FastAPI** и позвольте мне и другим узнать, почему он Вам нравится. 🎉 -Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п. +Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы его используете и т.д. -## Оставить голос за FastAPI +## Оставить голос за FastAPI { #vote-for-fastapi } * Голосуйте за **FastAPI** в Slant. -* Голосуйте за **FastAPI** в AlternativeTo. -* Расскажите, как Вы используете **FastAPI** на StackShare. +* Голосуйте за **FastAPI** в AlternativeTo. +* Расскажите, что Вы используете **FastAPI** на StackShare. -## Помочь другим с их проблемами на GitHub +## Помочь другим с вопросами на GitHub { #help-others-with-questions-in-github } -Вы можете посмотреть, какие проблемы испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓 +Вы можете попробовать помочь другим с их вопросами в: -Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. 🎉 +* GitHub Discussions +* GitHub Issues -Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗 +Во многих случаях Вы уже можете знать ответы на эти вопросы. 🤓 -Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге. +Если Вы много помогаете людям с их вопросами, Вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉 + +Только помните, самое важное — постарайтесь быть добрыми. Люди приходят со своими разочарованиями и часто задают вопросы не лучшим образом, но постарайтесь, насколько можете, быть доброжелательными. 🤗 + +Идея сообщества **FastAPI** — быть доброжелательным и гостеприимным. В то же время не допускайте травлю или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге. --- -Как помочь другим с их проблемами: +Как помочь другим с вопросами (в обсуждениях или Issues): -### Понять вопрос +### Понять вопрос { #understand-the-question } -* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего. +* Убедитесь, что поняли **цель** и кейс использования задающего вопрос. -* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**. +* Затем проверьте, что вопрос (в подавляющем большинстве это вопросы) сформулирован **ясно**. -* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**. +* Во многих случаях спрашивают о воображаемом решении пользователя, но может быть решение **получше**. Если Вы лучше поймёте проблему и кейс, сможете предложить **альтернативное решение**. -* Ежели вопрос Вам непонятен, запросите больше **деталей**. +* Если вопрос непонятен, запросите больше **деталей**. -### Воспроизвести проблему +### Воспроизвести проблему { #reproduce-the-problem } -В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего. +В большинстве случаев и вопросов есть что-то связанное с **исходным кодом** автора. -И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**. +Во многих случаях предоставляют только фрагмент кода, но этого недостаточно, чтобы **воспроизвести проблему**. -* Попросите предоставить минимальный воспроизводимый пример, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая. +* Попросите предоставить минимальный воспроизводимый пример, который Вы сможете **скопировать-вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, или лучше понять их кейс. -* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы. +* Если чувствуете себя особенно великодушными, можете попытаться **создать такой пример** сами, основываясь только на описании проблемы. Просто помните, что это может занять много времени, и, возможно, сначала лучше попросить уточнить проблему. -### Предложить решение +### Предложить решение { #suggest-solutions } -* После того как Вы поняли вопрос, Вы можете дать **ответ**. +* После того как Вы поняли вопрос, Вы можете дать возможный **ответ**. -* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать. +* Во многих случаях лучше понять **исходную проблему или кейс**, потому что может существовать способ решить её лучше, чем то, что пытаются сделать. -### Попросить закрыть проблему +### Попросить закрыть { #ask-to-close } -Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸 +Если Вам ответили, велика вероятность, что Вы решили их проблему, поздравляю, **Вы — герой**! 🦸 -* В таком случае, если вопрос решён, попросите **закрыть проблему**. +* Теперь, если проблема решена, можно попросить их: + * В GitHub Discussions: пометить комментарий как **answer** (ответ). + * В GitHub Issues: **закрыть** Issue. -## Отслеживать репозиторий на GitHub +## Отслеживать репозиторий на GitHub { #watch-the-github-repository } -Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 +Вы можете "отслеживать" FastAPI на GitHub (кликнув по кнопке "watch" наверху справа): https://github.com/fastapi/fastapi. 👀 -Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы. +Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления, когда кто-либо создаёт новый вопрос или Issue. Вы также можете указать, что хотите получать уведомления только о новых Issues, или обсуждениях, или пулл-реквестах и т.д. -Тогда Вы можете попробовать решить эту проблему. +Тогда Вы можете попробовать помочь им с решением этих вопросов. -## Запросить помощь с решением проблемы +## Задать вопросы { #ask-questions } -Вы можете создать новый запрос с просьбой о помощи в репозитории на GitHub, например: +Вы можете создать новый вопрос в репозитории GitHub, например: -* Задать **вопрос** или попросить помощи в решении **проблемы**. -* Предложить новое **улучшение**. +* Задать **вопрос** или спросить о **проблеме**. +* Предложить новую **возможность**. -**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉 +**Заметка**: если Вы это сделаете, то я попрошу Вас также помогать другим. 😉 -## Проверять пул-реквесты +## Проверять пулл-реквесты { #review-pull-requests } -Вы можете помочь мне проверять пул-реквесты других участников. +Вы можете помочь мне проверять пулл-реквесты других участников. -И повторюсь, постарайтесь быть доброжелательным. 🤗 +И, снова, постарайтесь быть доброжелательными. 🤗 --- -О том, что нужно иметь в виду при проверке пул-реквестов: +О том, что нужно иметь в виду и как проверять пулл-реквест: -### Понять проблему +### Понять проблему { #understand-the-problem } -* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение. +* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Возможно, это обсуждалось более подробно в GitHub Discussion или Issue. -* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт. +* Также есть вероятность, что пулл-реквест не нужен, так как проблему можно решить **другим путём**. Тогда Вы можете предложить или спросить об этом. -### Не переживайте о стиле +### Не переживайте о стиле { #dont-worry-about-style } -* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную. +* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах — при слиянии я выполню squash и настрою коммит вручную. -* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты. +* Также не беспокойтесь о правилах стиля, это уже проверяют автоматизированные инструменты. -И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями. +Если будет нужна какая-то другая стилистика или единообразие, я попрошу об этом напрямую или добавлю поверх свои коммиты с нужными изменениями. -### Проверить код +### Проверить код { #check-the-code } -* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу. +* Проверьте и прочитайте код, посмотрите, логичен ли он, **запустите его локально** и проверьте, действительно ли он решает проблему. -* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код. +* Затем оставьте **комментарий**, что Вы это сделали, так я пойму, что Вы действительно проверили код. /// info | Информация -К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений. +К сожалению, я не могу просто доверять PR-ам только потому, что у них есть несколько одобрений. -Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅 +Несколько раз было так, что у PR-ов было 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я их проверял, они оказывались сломанными, содержали баги или вовсе не решали заявленную проблему. 😅 -Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓 +Поэтому очень важно действительно прочитать и запустить код и сообщить мне об этом в комментарии. 🤓 /// -* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах. +* Если PR можно упростить, Вы можете попросить об этом, но не нужно быть слишком придирчивым — может быть много субъективных мнений (и у меня тоже 🙈), поэтому лучше сосредоточиться на фундаментальных вещах. -### Тестировать +### Тестировать { #tests } -* Помогите мне проверить, что у пул-реквеста есть **тесты**. +* Помогите мне проверить, что у PR есть **тесты**. -* Проверьте, что тесты **падали** до пул-реквеста. 🚨 +* Проверьте, что тесты **падают** до PR. 🚨 -* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅ +* Затем проверьте, что тесты **проходят** после PR. ✅ -* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим. +* Многие PR не имеют тестов — Вы можете **напомнить** добавить тесты или даже **предложить** некоторые тесты сами. Это одна из самых трудозатратных частей, и здесь Вы можете очень помочь. -* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓 +* Затем добавьте комментарий, что Вы попробовали, чтобы я знал, что Вы это проверили. 🤓 -## Создать пул-реквест +## Создать пулл-реквест { #create-a-pull-request } -Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например: +Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в исходный код пулл-реквестами, например: -* Исправить опечатку, которую Вы нашли в документации. -* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли изменив этот файл. - * Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела. -* Помочь с [переводом документации](contributing.md#_8){.internal-link target=_blank} на Ваш язык. - * Вы также можете проверять переводы сделанные другими. +* Исправить опечатку, найденную в документации. +* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, изменив этот файл. + * Убедитесь, что добавили свою ссылку в начало соответствующего раздела. +* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык. + * Вы также можете проверять переводы, сделанные другими. * Предложить новые разделы документации. -* Исправить существующуе проблемы/баги. +* Исправить существующую проблему/баг. * Убедитесь, что добавили тесты. * Добавить новую возможность. * Убедитесь, что добавили тесты. - * Убедитесь, что добавили документацию, если она необходима. + * Убедитесь, что добавили документацию, если это уместно. -## Помочь поддерживать FastAPI +## Помочь поддерживать FastAPI { #help-maintain-fastapi } Помогите мне поддерживать **FastAPI**! 🤓 -Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать. +Предстоит ещё много работы, и, по большей части, **ВЫ** можете её сделать. Основные задачи, которые Вы можете выполнить прямо сейчас: -* [Помочь другим с их проблемами на GitHub](#github_1){.internal-link target=_blank} (смотрите вышестоящую секцию). -* [Проверить пул-реквесты](#-){.internal-link target=_blank} (смотрите вышестоящую секцию). +* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (смотрите секцию выше). +* [Проверять пулл-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите секцию выше). -Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI. +Именно эти две задачи **забирают больше всего времени**. Это основная работа по поддержке FastAPI. -Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 +Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и делаете так, чтобы он продолжал **развиваться быстрее и лучше**. 🚀 -## Подключиться к чату +## Подключиться к чату { #join-the-chat } -Подключайтесь к 👥 чату в Discord 👥 и общайтесь с другими участниками сообщества FastAPI. +Подключайтесь к 👥 серверу чата в Discord 👥 и общайтесь с другими участниками сообщества FastAPI. /// tip | Подсказка -Вопросы по проблемам с фреймворком лучше задавать в GitHub issues, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#_3){.internal-link target=_blank}. +По вопросам — задавайте их в GitHub Discussions, так гораздо выше шанс, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. -Используйте этот чат только для бесед на отвлечённые темы. +Используйте чат только для прочих общих бесед. /// -### Не использовать чаты для вопросов +### Не используйте чат для вопросов { #dont-use-the-chat-for-questions } -Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы. +Имейте в виду, что в чатах, благодаря "свободному общению", легко задать вопросы, которые слишком общие и на которые сложнее ответить, поэтому Вы можете не получить ответы. -В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅 +На GitHub шаблон поможет Вам правильно сформулировать вопрос, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно ещё до того, как спросите. И на GitHub я могу следить за тем, чтобы всегда отвечать на всё, даже если это занимает время. А с чатами я не могу сделать этого лично. 😅 -Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#_3){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub. +Кроме того, переписка в чатах хуже ищется, чем на GitHub, поэтому вопросы и ответы могут теряться среди остальных сообщений. И только те, что на GitHub, учитываются для получения лычки [Эксперт FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, так что вероятнее всего Вы получите больше внимания именно на GitHub. -С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄 +С другой стороны, в чатах тысячи пользователей, так что почти всегда есть шанс найти там кого-то для разговора. 😄 -## Спонсировать автора +## Спонсировать автора { #sponsor-the-author } -Вы также можете оказать мне финансовую поддержку посредством спонсорства через GitHub. - -Там можно просто купить мне кофе ☕️ в знак благодарности. 😄 - -А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉 - -## Спонсировать инструменты, на которых зиждется мощь FastAPI - -Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic. - -Им тоже можно оказать спонсорскую поддержку: - -* Samuel Colvin (Pydantic) -* Encode (Starlette, Uvicorn) +Если Ваш **продукт/компания** зависят от **FastAPI** или связаны с ним и Вы хотите донести до пользователей информацию о себе, Вы можете спонсировать автора (меня) через GitHub Sponsors. В зависимости от уровня поддержки Вы можете получить дополнительные бонусы, например, бейдж в документации. 🎁 --- -Благодарствую! 🚀 +Спасибо! 🚀 diff --git a/docs/ru/docs/history-design-future.md b/docs/ru/docs/history-design-future.md index 96604e3a4..d679af3e3 100644 --- a/docs/ru/docs/history-design-future.md +++ b/docs/ru/docs/history-design-future.md @@ -1,4 +1,4 @@ -# История создания и дальнейшее развитие +# История, проектирование и будущее { #history-design-and-future } Однажды, один из пользователей **FastAPI** задал вопрос: @@ -6,7 +6,7 @@ Что ж, вот небольшая часть истории проекта. -## Альтернативы +## Альтернативы { #alternatives } В течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д. @@ -24,45 +24,47 @@ Я всячески избегал создания нового фреймворка в течение нескольких лет. Сначала я пытался собрать все нужные возможности, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов. -Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти возможности сразу. Взять самые лучшие идеи из предыдущих инструментов и, используя введённые в Python подсказки типов (которых не было до версии 3.6), объединить их. +Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти возможности сразу. Взять самые лучшие идеи из предыдущих инструментов и, используя введённые в Python аннотации типов (которых не было до версии 3.6), объединить их. -## Исследования +## Исследования { #investigation } Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом. -Например, стало ясно, что необходимо брать за основу стандартные подсказки типов Python, а самым лучшим подходом является использование уже существующих стандартов. +Например, стало ясно, что необходимо брать за основу стандартные аннотации типов Python. + +Также наилучшим подходом является использование уже существующих стандартов. Итак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий. -## Дизайн +## Проектирование { #design } Затем я потратил некоторое время на придумывание "API" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI). -Я проверил несколько идей на самых популярных редакторах кода среди Python-разработчиков: PyCharm, VS Code, Jedi. +Я проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi. -Данные по редакторам я взял из опроса Python-разработчиков, который охватываает около 80% пользователей. +Данные по редакторам я взял из опроса Python-разработчиков, который охватывает около 80% пользователей. Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов. -Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автодополнение, проверку типов и ошибок и т.д. +Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автозавершение, проверку типов и ошибок и т.д. И все это, чтобы все пользователи могли получать наилучший опыт разработки. -## Зависимости +## Зависимости { #requirements } Протестировав несколько вариантов, я решил, что в качестве основы буду использовать **Pydantic** и его преимущества. -По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить помощь редакторов (проверки типов, автозаполнение). +По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить поддержку в редакторах кода (проверки типов, автозавершение) на основе тестов в нескольких редакторах. В то же время, я принимал участие в разработке **Starlette**, ещё один из основных компонентов FastAPI. -## Разработка +## Разработка { #development } К тому времени, когда я начал создавать **FastAPI**, большинство необходимых деталей уже существовало, дизайн был определён, зависимости и прочие инструменты были готовы, а знания о стандартах и спецификациях были четкими и свежими. -## Будущее +## Будущее { #future } Сейчас уже ясно, что **FastAPI** со своими идеями стал полезен многим людям. diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 692c03ecb..1fcc9ea9d 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -1,4 +1,4 @@ -# FastAPI +# FastAPI { #fastapi }