mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-06 12:21:13 -05:00
Compare commits
2 Commits
master
...
update-out
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d332ecd97d | ||
|
|
b9f008da1c |
23
.github/workflows/test.yml
vendored
23
.github/workflows/test.yml
vendored
@@ -49,45 +49,31 @@ jobs:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
python-version: [ "3.14" ]
|
||||
uv-resolution:
|
||||
- highest
|
||||
starlette-src:
|
||||
- starlette-pypi
|
||||
- starlette-git
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.9"
|
||||
coverage: coverage
|
||||
uv-resolution: lowest-direct
|
||||
- os: macos-latest
|
||||
python-version: "3.10"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
- os: windows-latest
|
||||
python-version: "3.12"
|
||||
coverage: coverage
|
||||
uv-resolution: lowest-direct
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
# Ubuntu with 3.13 needs coverage for CodSpeed benchmarks
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
codspeed: codspeed
|
||||
- os: ubuntu-latest
|
||||
python-version: "3.14"
|
||||
coverage: coverage
|
||||
uv-resolution: highest
|
||||
starlette-src: starlette-git
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
UV_RESOLUTION: ${{ matrix.uv-resolution }}
|
||||
STARLETTE_SRC: ${{ matrix.starlette-src }}
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
@@ -106,14 +92,11 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
- name: Install Dependencies
|
||||
run: uv sync --no-dev --group tests --extra all
|
||||
- name: Install Starlette from source
|
||||
if: matrix.starlette-src == 'starlette-git'
|
||||
run: uv pip install "git+https://github.com/Kludex/starlette@main"
|
||||
run: uv sync --locked --no-dev --group tests --extra all
|
||||
- run: mkdir coverage
|
||||
- name: Test
|
||||
if: matrix.codspeed != 'codspeed'
|
||||
run: uv run --no-sync bash scripts/test.sh
|
||||
run: uv run bash scripts/test.sh
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
|
||||
@@ -125,7 +108,7 @@ jobs:
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
|
||||
with:
|
||||
mode: simulation
|
||||
run: uv run --no-sync coverage run -m pytest tests/ --codspeed
|
||||
run: uv run coverage run -m pytest tests/ --codspeed
|
||||
# Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow
|
||||
- name: Store coverage files
|
||||
if: matrix.coverage == 'coverage'
|
||||
|
||||
6
.github/workflows/translate.yml
vendored
6
.github/workflows/translate.yml
vendored
@@ -35,11 +35,6 @@ on:
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
max:
|
||||
description: Maximum number of items to translate (e.g. 10)
|
||||
type: number
|
||||
required: false
|
||||
default: 10
|
||||
|
||||
jobs:
|
||||
langs:
|
||||
@@ -120,4 +115,3 @@ jobs:
|
||||
EN_PATH: ${{ github.event.inputs.en_path }}
|
||||
COMMAND: ${{ matrix.command }}
|
||||
COMMIT_IN_PLACE: ${{ github.event.inputs.commit_in_place }}
|
||||
MAX: ${{ github.event.inputs.max }}
|
||||
|
||||
@@ -7,40 +7,6 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆️ Upgrade development dependencies. PR [#14854](https://github.com/fastapi/fastapi/pull/14854) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.3
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Re-implement `on_event` in FastAPI for compatibility with the next Starlette, while keeping backwards compatibility. PR [#14851](https://github.com/fastapi/fastapi/pull/14851) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆️ Upgrade Starlette supported version range to `starlette>=0.40.0,<1.0.0`. PR [#14853](https://github.com/fastapi/fastapi/pull/14853) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14834](https://github.com/fastapi/fastapi/pull/14834) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👷 Run tests with Starlette from git. PR [#14849](https://github.com/fastapi/fastapi/pull/14849) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Run tests with lower bound uv sync, upgrade `fastapi[all]` minimum dependencies: `ujson >=5.8.0`, `orjson >=3.9.3`. PR [#14846](https://github.com/fastapi/fastapi/pull/14846) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.2
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for PEP695 `TypeAliasType`. PR [#13920](https://github.com/fastapi/fastapi/pull/13920) by [@cstruct](https://github.com/cstruct).
|
||||
* ✨ Allow `Response` type hint as dependency annotation. PR [#14794](https://github.com/fastapi/fastapi/pull/14794) by [@jonathan-fulton](https://github.com/jonathan-fulton).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix using `Json[list[str]]` type (issue #10997). PR [#14616](https://github.com/fastapi/fastapi/pull/14616) by [@mkanetsuna](https://github.com/mkanetsuna).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for translations. PR [#14830](https://github.com/fastapi/fastapi/pull/14830) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -48,8 +14,6 @@ hide:
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Enable Traditional Chinese translations. PR [#14842](https://github.com/fastapi/fastapi/pull/14842) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Enable French docs translations. PR [#14841](https://github.com/fastapi/fastapi/pull/14841) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for fr (translate-page). PR [#14837](https://github.com/fastapi/fastapi/pull/14837) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14836](https://github.com/fastapi/fastapi/pull/14836) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14833](https://github.com/fastapi/fastapi/pull/14833) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -62,10 +26,6 @@ hide:
|
||||
* 🌐 Update translations for uk (update-outdated). PR [#14822](https://github.com/fastapi/fastapi/pull/14822) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Update docs and translations scripts, enable Turkish. PR [#14824](https://github.com/fastapi/fastapi/pull/14824) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔨 Add max pages to translate to configs. PR [#14840](https://github.com/fastapi/fastapi/pull/14840) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.1
|
||||
|
||||
### Features
|
||||
|
||||
@@ -317,8 +317,6 @@ extra:
|
||||
name: de - Deutsch
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
@@ -331,8 +329,6 @@ extra:
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh-hant/
|
||||
name: zh-hant - 繁體中文
|
||||
extra_css:
|
||||
- css/termynal.css
|
||||
- css/custom.css
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчика пути*:
|
||||
…и передаст возвращённое значение как значение зависимости в нашу *функцию-обработчике пути* в параметр `fixed_content_included`:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
|
||||
|
||||
|
||||
@@ -6,29 +6,13 @@
|
||||
|
||||
## Использование `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info | Информация
|
||||
|
||||
Для этого требуется установить `a2wsgi`, например с помощью `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Нужно импортировать `WSGIMiddleware` из `a2wsgi`.
|
||||
Нужно импортировать `WSGIMiddleware`.
|
||||
|
||||
Затем оберните WSGI‑приложение (например, Flask) в middleware (Промежуточный слой).
|
||||
|
||||
После этого смонтируйте его на путь.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
Ранее рекомендовалось использовать `WSGIMiddleware` из `fastapi.middleware.wsgi`, но теперь он помечен как устаревший.
|
||||
|
||||
Вместо него рекомендуется использовать пакет `a2wsgi`. Использование остаётся таким же.
|
||||
|
||||
Просто убедитесь, что пакет `a2wsgi` установлен, и импортируйте `WSGIMiddleware` из `a2wsgi`.
|
||||
|
||||
///
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
|
||||
## Проверьте { #check-it }
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ Successfully installed fastapi pydantic
|
||||
* Создайте файл `main.py` со следующим содержимым:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,7 +158,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
|
||||
Создайте файл `main.py` со следующим содержимым:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,7 +174,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -181,7 +183,9 @@ def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
Если ваш код использует `async` / `await`, используйте `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,7 +197,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -284,7 +288,9 @@ INFO: Application startup complete.
|
||||
|
||||
Объявите тело запроса, используя стандартные типы Python, спасибо Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +300,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool | None = None
|
||||
is_offer: Union[bool, None] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +309,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@
|
||||
Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Или в Python 3.9:
|
||||
Или в Python 3.10 и выше:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Например:
|
||||
@@ -116,7 +116,7 @@ q: Union[str, None] = None
|
||||
|
||||
/// info | Информация
|
||||
|
||||
`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`, `Path` и других, которые вы увидите позже.
|
||||
`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`,`Path` и других, которые вы увидите позже.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
Вы можете добавить параметры `summary` и `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
|
||||
## Описание из строк документации { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
Вы можете указать описание ответа с помощью параметра `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
|
||||
/// info | Дополнительная информация
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
///
|
||||
|
||||
/// check | Проверка
|
||||
/// check
|
||||
|
||||
OpenAPI указывает, что каждой *операции пути* необходимо описание ответа.
|
||||
|
||||
|
||||
@@ -78,13 +78,13 @@ Bu detaylar, özellikle 0.121.0'dan eski bir FastAPI uygulamanız varsa ve `yiel
|
||||
|
||||
### `yield` ve `scope` ile dependency'ler { #dependencies-with-yield-and-scope }
|
||||
|
||||
0.121.0 sürümünde FastAPI, `yield` kullanan dependency'ler için `Depends(scope="function")` desteğini ekledi.
|
||||
0.121.0 sürümünde FastAPI, `Depends(scope="function")` desteğini ekledi.
|
||||
|
||||
`Depends(scope="function")` kullanıldığında, `yield` sonrasındaki çıkış kodu, *path operation function* biter bitmez, response client'a geri gönderilmeden önce çalıştırılır.
|
||||
|
||||
`Depends(scope="request")` (varsayılan) kullanıldığında ise `yield` sonrasındaki çıkış kodu, response gönderildikten sonra çalıştırılır.
|
||||
|
||||
Daha fazlasını [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz.
|
||||
Daha fazlasını [`yield` ile Dependency'ler - Erken çıkış ve `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz.
|
||||
|
||||
### `yield` ve `StreamingResponse` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-streamingresponse-technical-details }
|
||||
|
||||
@@ -132,7 +132,7 @@ SQLModel (veya SQLAlchemy) kullanarak bu spesifik senaryoya sahipseniz, session'
|
||||
|
||||
Böylece session veritabanı bağlantısını serbest bırakır ve diğer request'ler bunu kullanabilir.
|
||||
|
||||
`yield` kullanan bir dependency'den erken çıkış gerektiren farklı bir kullanım senaryonuz varsa, lütfen kullanım senaryonuzla birlikte ve `yield` kullanan dependency'ler için erken kapatmadan neden fayda göreceğinizi açıklayarak bir <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Question</a> oluşturun.
|
||||
`yield` kullanan bir dependency'den erken çıkış gerektiren farklı bir kullanım senaryonuz varsa, lütfen kullanım senaryonuzla birlikte ve `yield` kullanan dependency'ler için erken kapatmadan neden fayda göreceğinizi açıklayarak bir <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Sorusu</a> oluşturun.
|
||||
|
||||
`yield` kullanan dependency'lerde erken kapatma için ikna edici kullanım senaryoları varsa, erken kapatmayı seçmeli (opt-in) hale getiren yeni bir yöntem eklemeyi düşünebilirim.
|
||||
|
||||
@@ -144,7 +144,7 @@ Bu davranış 0.110.0 sürümünde değiştirildi. Amaç, handler olmayan (inter
|
||||
|
||||
### Background Tasks ve `yield` ile dependency'ler, Teknik Detaylar { #background-tasks-and-dependencies-with-yield-technical-details }
|
||||
|
||||
FastAPI 0.106.0 öncesinde, `yield` sonrasında exception raise etmek mümkün değildi; çünkü `yield` kullanan dependency'lerdeki çıkış kodu response gönderildikten *sonra* çalıştırılıyordu. Bu nedenle [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} zaten çalışmış olurdu.
|
||||
FastAPI 0.106.0 öncesinde, `yield` sonrasında exception raise etmek mümkün değildi; çünkü `yield` kullanan dependency'lerdeki çıkış kodu response gönderildikten *sonra* çalıştırılıyordu. Bu nedenle [Exception Handler'ları](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} zaten çalışmış olurdu.
|
||||
|
||||
Bu tasarımın ana sebeplerinden biri, background task'lerin içinde dependency'lerin "yield ettiği" aynı objeleri kullanmaya izin vermekti; çünkü çıkış kodu, background task'ler bittikten sonra çalıştırılıyordu.
|
||||
|
||||
|
||||
@@ -1,483 +1,483 @@
|
||||
# Alternatifler, İlham Kaynakları ve Karşılaştırmalar
|
||||
# Alternatifler, İlham Kaynakları ve Karşılaştırmalar { #alternatives-inspiration-and-comparisons }
|
||||
|
||||
**FastAPI**'ya neler ilham verdi? Diğer alternatiflerle karşılaştırıldığında farkları neler? **FastAPI** diğer alternatiflerinden neler öğrendi?
|
||||
**FastAPI**'a nelerin ilham verdiği, alternatiflerle nasıl karşılaştırıldığı ve onlardan neler öğrendiği.
|
||||
|
||||
## Giriş
|
||||
## Giriş { #intro }
|
||||
|
||||
Başkalarının daha önceki çalışmaları olmasaydı, **FastAPI** var olmazdı.
|
||||
|
||||
Geçmişte oluşturulan pek çok araç **FastAPI**'a ilham kaynağı olmuştur.
|
||||
Önceden oluşturulan birçok araç, ortaya çıkışına ilham verdi.
|
||||
|
||||
Yıllardır yeni bir framework oluşturmaktan kaçınıyordum. Başlangıçta **FastAPI**'ın çözdüğü sorunları çözebilmek için pek çok farklı framework, <abbr title="Eklenti: Plug-In">eklenti</abbr> ve araç kullanmayı denedim.
|
||||
Yıllarca yeni bir framework oluşturmaktan kaçındım. Önce **FastAPI**’ın bugün kapsadığı özelliklerin tamamını, birçok farklı framework, eklenti ve araçla çözmeyi denedim.
|
||||
|
||||
Ancak bir noktada, geçmişteki diğer araçlardan en iyi fikirleri alarak bütün bu çözümleri kapsayan, ayrıca bütün bunları Python'ın daha önce mevcut olmayan özelliklerini (Python 3.6+ ile gelen <abbr title="Tip belirteçleri: Type Hints">tip belirteçleri</abbr>) kullanarak yapan bir şey üretmekten başka seçenek kalmamıştı.
|
||||
Ancak bir noktada, geçmişteki araçlardan en iyi fikirleri alıp, mümkün olan en iyi şekilde birleştiren ve daha önce mevcut olmayan dil özelliklerini (Python 3.6+ tip belirteçleri) kullanarak tüm bu özellikleri sağlayan bir şey geliştirmekten başka seçenek kalmadı.
|
||||
|
||||
## Daha Önce Geliştirilen Araçlar
|
||||
## Daha Önce Geliştirilen Araçlar { #previous-tools }
|
||||
|
||||
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a>
|
||||
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a> { #django }
|
||||
|
||||
Django geniş çapta güvenilen, Python ekosistemindeki en popüler web framework'üdür. Instagram gibi sistemleri geliştirmede kullanılmıştır.
|
||||
Python ekosistemindeki en popüler ve yaygın olarak güvenilen web framework’üdür. Instagram gibi sistemleri geliştirmede kullanılmıştır.
|
||||
|
||||
MySQL ve PostgreSQL gibi ilişkisel veritabanlarıyla nispeten sıkı bir şekilde bağlantılıdır. Bu nedenle Couchbase, MongoDB ve Cassandra gibi NoSQL veritabanlarını ana veritabanı motoru olarak kullanmak pek de kolay değil.
|
||||
MySQL veya PostgreSQL gibi ilişkisel veritabanlarıyla nispeten sıkı bağlıdır, bu nedenle Couchbase, MongoDB, Cassandra vb. gibi bir NoSQL veritabanını ana depolama motoru olarak kullanmak pek kolay değildir.
|
||||
|
||||
Modern ön uçlarda (React, Vue.js ve Angular gibi) veya diğer sistemler (örneğin <abbr title="Nesnelerin interneti: IoT (Internet of Things)">nesnelerin interneti</abbr> cihazları) tarafından kullanılan API'lar yerine arka uçta HTML üretmek için oluşturuldu.
|
||||
Modern bir ön uç (React, Vue.js, Angular gibi) veya onunla haberleşen diğer sistemler (ör. <abbr title="Internet of Things - Nesnelerin İnterneti">IoT</abbr> cihazları) tarafından tüketilen API’lar üretmekten ziyade, arka uçta HTML üretmek için oluşturulmuştur.
|
||||
|
||||
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a>
|
||||
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a> { #django-rest-framework }
|
||||
|
||||
Django REST framework'ü, Django'nun API kabiliyetlerini arttırmak için arka planda Django kullanan esnek bir araç grubu olarak oluşturuldu.
|
||||
Django REST Framework, Django üzerine kurulu esnek bir araç takımı olarak, Web API’lar geliştirmeyi ve Django’nun API kabiliyetlerini artırmayı hedefler.
|
||||
|
||||
Üstelik Mozilla, Red Hat ve Eventbrite gibi pek çok şirket tarafından kullanılıyor.
|
||||
Mozilla, Red Hat ve Eventbrite gibi birçok şirket tarafından kullanılmaktadır.
|
||||
|
||||
**Otomatik API dökümantasyonu**nun ilk örneklerinden biri olduğu için, **FastAPI** arayışına ilham veren ilk fikirlerden biri oldu.
|
||||
**Otomatik API dökümantasyonu**nun ilk örneklerinden biriydi ve bu, “**FastAPI** arayışına” ilham veren ilk fikirlerden biriydi.
|
||||
|
||||
/// note | Not
|
||||
|
||||
Django REST Framework'ü, aynı zamanda **FastAPI**'ın dayandığı Starlette ve Uvicorn'un da yaratıcısı olan Tom Christie tarafından geliştirildi.
|
||||
Django REST Framework, **FastAPI**'ın üzerine inşa edildiği Starlette ve Uvicorn'un da yaratıcısı olan Tom Christie tarafından geliştirildi.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Kullanıcılar için otomatik API dökümantasyonu sunan bir web arayüzüne sahip olmalı.
|
||||
Otomatik API dökümantasyonu sağlayan bir web arayüzü sunmak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a>
|
||||
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a> { #flask }
|
||||
|
||||
Flask bir <abbr title="Mikro Framework: Micro Framework">mikro framework</abbr> olduğundan Django gibi framework'lerin aksine veritabanı entegrasyonu gibi Django ile gelen pek çok özelliği direkt barındırmaz.
|
||||
Flask bir “mikroframework”tür, Django’da varsayılan gelen pek çok özelliği (veritabanı entegrasyonları vb.) içermez.
|
||||
|
||||
Sağladığı basitlik ve esneklik NoSQL veritabanlarını ana veritabanı sistemi olarak kullanmak gibi şeyler yapmaya olanak sağlar.
|
||||
Bu basitlik ve esneklik, NoSQL veritabanlarını ana veri depolama sistemi olarak kullanmak gibi şeyleri mümkün kılar.
|
||||
|
||||
Yapısı oldukça basit olduğundan öğrenmesi de nispeten basittir, tabii dökümantasyonu bazı noktalarda biraz teknik hale geliyor.
|
||||
Çok basit olduğu için öğrenmesi nispeten sezgiseldir, ancak dökümantasyon bazı noktalarda biraz teknikleşebilir.
|
||||
|
||||
Ayrıca Django ile birlikte gelen veritabanı, kullanıcı yönetimi ve diğer pek çok özelliğe ihtiyaç duymayan uygulamalarda da yaygın olarak kullanılıyor. Ancak bu tür özelliklerin pek çoğu <abbr title="Eklentiler: Plug-Ins">eklentiler</abbr> ile eklenebiliyor.
|
||||
Ayrıca veritabanı, kullanıcı yönetimi veya Django’da önceden gelen pek çok özelliğe ihtiyaç duymayan uygulamalar için de yaygın olarak kullanılır. Yine de bu özelliklerin çoğu eklentilerle eklenebilir.
|
||||
|
||||
Uygulama parçalarının böyle ayrılıyor oluşu ve istenilen özelliklerle genişletilebilecek bir <abbr title="Mikro Framework: Micro Framework">mikro framework</abbr> olmak tam da benim istediğim bir özellikti.
|
||||
Bileşenlerin ayrık olması ve gerekeni tam olarak kapsayacak şekilde genişletilebilen bir “mikroframework” olması, özellikle korumak istediğim bir özelliktir.
|
||||
|
||||
Flask'ın basitliği göz önünde bulundurulduğu zaman, API geliştirmek için iyi bir seçim gibi görünüyordu. Sıradaki şey ise Flask için bir "Django REST Framework"!
|
||||
Flask’ın sadeliği göz önüne alındığında, API geliştirmek için iyi bir aday gibi görünüyordu. Sırada, Flask için bir “Django REST Framework” bulmak vardı.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Gereken araçları ve parçaları birleştirip eşleştirmeyi kolaylaştıracak bir mikro framework olmalı.
|
||||
Gereken araç ve parçaları kolayca eşleştirip birleştirmeyi sağlayan bir mikroframework olmak.
|
||||
|
||||
Basit ve kullanması kolay bir <abbr title="Yönlendirme: Routing">yönlendirme sistemine</abbr> sahip olmalı.
|
||||
Basit ve kullanımı kolay bir yönlendirme (routing) sistemine sahip olmak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a>
|
||||
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a> { #requests }
|
||||
|
||||
**FastAPI** aslında **Requests**'in bir alternatifi değil. İkisininde kapsamı oldukça farklı.
|
||||
**FastAPI** aslında **Requests**’in bir alternatifi değildir. Kapsamları çok farklıdır.
|
||||
|
||||
Aslında Requests'i bir FastAPI uygulamasının *içinde* kullanmak daha olağan olurdu.
|
||||
Hatta bir FastAPI uygulamasının içinde Requests kullanmak yaygındır.
|
||||
|
||||
Ama yine de, FastAPI, Requests'ten oldukça ilham aldı.
|
||||
Yine de FastAPI, Requests’ten epey ilham almıştır.
|
||||
|
||||
**Requests**, <abbr title="API (Application Programming Interface): Uygulama Programlama Arayüzü">API'lar</abbr> ile bir istemci olarak *etkileşime geçmeyi* sağlayan bir kütüphaneyken **FastAPI** bir sunucu olarak <abbr title="API (Application Programming Interface): Uygulama Programlama Arayüzü">API'lar</abbr> oluşturmaya yarar.
|
||||
**Requests** bir kütüphane olarak API’larla (istemci olarak) etkileşime geçmeye yararken, **FastAPI** API’lar (sunucu olarak) geliştirmeye yarar.
|
||||
|
||||
Öyle ya da böyle zıt uçlarda olmalarına rağmen birbirlerini tamamlıyorlar.
|
||||
Yani daha çok zıt uçlardadırlar ama birbirlerini tamamlarlar.
|
||||
|
||||
Requests oldukça basit ve sezgisel bir tasarıma sahip, kullanması da mantıklı varsayılan değerlerle oldukça kolay. Ama aynı zamanda çok güçlü ve gayet özelleştirilebilir.
|
||||
Requests çok basit ve sezgisel bir tasarıma sahiptir, mantıklı varsayılanlarla kullanımı çok kolaydır. Aynı zamanda çok güçlü ve özelleştirilebilirdir.
|
||||
|
||||
Bu yüzden resmi web sitede de söylendiği gibi:
|
||||
Bu yüzden resmi web sitesinde de söylendiği gibi:
|
||||
|
||||
> Requests, tüm zamanların en çok indirilen Python <abbr title="Paket: Package">paketlerinden</abbr> biridir.
|
||||
> Requests, tüm zamanların en çok indirilen Python paketlerinden biridir
|
||||
|
||||
Kullanım şekli oldukça basit. Örneğin bir `GET` isteği yapmak için aşağıdaki yeterli:
|
||||
Kullanımı çok basittir. Örneğin bir `GET` isteği yapmak için:
|
||||
|
||||
```Python
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
Bunun FastAPI'deki API <abbr title="Yol İşlemi: Path Operation">*yol işlemi*</abbr> şöyle görünür:
|
||||
Buna karşılık bir FastAPI API *path operation*’ı şöyle olabilir:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
def read_url():
|
||||
return {"message": "Hello World!"}
|
||||
return {"message": "Hello World"}
|
||||
```
|
||||
|
||||
`requests.get(...)` ile `@app.get(...)` arasındaki benzerliklere bakın.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
* Basit ve sezgisel bir API'ya sahip olmalı.
|
||||
* HTTP metot isimlerini (işlemlerini) anlaşılır olacak bir şekilde, direkt kullanmalı.
|
||||
* Mantıklı varsayılan değerlere ve buna rağmen güçlü bir özelleştirme desteğine sahip olmalı.
|
||||
* Basit ve sezgisel bir API’ya sahip olmak.
|
||||
* HTTP metot isimlerini (işlemlerini) doğrudan, anlaşılır ve sezgisel bir şekilde kullanmak.
|
||||
* Mantıklı varsayılanlara sahip olmak ama güçlü özelleştirmeler de sunmak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a>
|
||||
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a> { #swagger-openapi }
|
||||
|
||||
Benim Django REST Framework'ünden istediğim ana özellik otomatik API dökümantasyonuydu.
|
||||
Django REST Framework’ünden istediğim ana özellik otomatik API dökümantasyonuydu.
|
||||
|
||||
Daha sonra API'ları dökümanlamak için Swagger adında JSON (veya JSON'un bir uzantısı olan YAML'ı) kullanan bir standart olduğunu buldum.
|
||||
Sonra API’ları JSON (veya JSON’un bir uzantısı olan YAML) kullanarak dökümante etmek için Swagger adlı bir standart olduğunu gördüm.
|
||||
|
||||
Üstelik Swagger API'ları için zaten halihazırda oluşturulmuş bir web arayüzü vardı. Yani, bir API için Swagger dökümantasyonu oluşturmak bu arayüzü otomatik olarak kullanabilmek demekti.
|
||||
Ve Swagger API’ları için zaten oluşturulmuş bir web arayüzü vardı. Yani bir API için Swagger dökümantasyonu üretebilmek, bu web arayüzünü otomatik kullanabilmek demekti.
|
||||
|
||||
Swagger bir noktada Linux Foundation'a verildi ve adı OpenAPI olarak değiştirildi.
|
||||
Bir noktada Swagger, Linux Foundation’a devredildi ve OpenAPI olarak yeniden adlandırıldı.
|
||||
|
||||
İşte bu yüzden versiyon 2.0 hakkında konuşurken "Swagger", versiyon 3 ve üzeri için ise "OpenAPI" adını kullanmak daha yaygın.
|
||||
Bu yüzden, 2.0 sürümü söz konusu olduğunda “Swagger”, 3+ sürümler için ise “OpenAPI” denmesi yaygındır.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
API spesifikasyonları için özel bir şema yerine bir <abbr title="Open Standard: Açık Standart, Açık kaynak olarak yayınlanan standart">açık standart</abbr> benimseyip kullanmalı.
|
||||
API spesifikasyonları için özel bir şema yerine açık bir standart benimsemek ve kullanmak.
|
||||
|
||||
Ayrıca standarda bağlı kullanıcı arayüzü araçlarını entegre etmeli:
|
||||
Ve standartlara dayalı kullanıcı arayüzü araçlarını entegre etmek:
|
||||
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>
|
||||
|
||||
Yukarıdaki ikisi oldukça popüler ve istikrarlı olduğu için seçildi, ancak hızlı bir araştırma yaparak **FastAPI** ile kullanabileceğiniz pek çok OpenAPI alternatifi arayüz bulabilirsiniz.
|
||||
Bu ikisi oldukça popüler ve istikrarlı oldukları için seçildi; hızlı bir aramayla OpenAPI için onlarca alternatif kullanıcı arayüzü bulabilirsiniz (**FastAPI** ile de kullanabilirsiniz).
|
||||
|
||||
///
|
||||
|
||||
### Flask REST framework'leri
|
||||
### Flask REST framework’leri { #flask-rest-frameworks }
|
||||
|
||||
Pek çok Flask REST framework'ü var, fakat bunları biraz araştırdıktan sonra pek çoğunun artık geliştirilmediğini ve göze batan bazı sorunlarının olduğunu gördüm.
|
||||
Birçok Flask REST framework’ü var; ancak zaman ayırıp inceledikten sonra çoğunun artık sürdürülmediğini veya bazı kritik sorunlar nedeniyle uygun olmadıklarını gördüm.
|
||||
|
||||
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a>
|
||||
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
|
||||
|
||||
API sistemlerine gereken ana özelliklerden biri de koddan veriyi alıp ağ üzerinde gönderilebilecek bir şeye çevirmek, yani veri <abbr title="Dönüşüm: serialization, marshalling olarak da biliniyor">dönüşümü</abbr>. Bu işleme veritabanındaki veriyi içeren bir objeyi JSON objesine çevirmek, `datetime` objelerini metinlere çevirmek gibi örnekler verilebilir.
|
||||
API sistemlerinin ihtiyaç duyduğu temel özelliklerden biri, koddan (Python) veriyi alıp ağ üzerinden gönderilebilecek bir şeye dönüştürmek, yani veri “<abbr title="marshalling, conversion olarak da adlandırılır">dönüşüm</abbr>”üdür. Örneğin, bir veritabanından gelen verileri içeren bir objeyi JSON objesine dönüştürmek, `datetime` objelerini string’e çevirmek vb.
|
||||
|
||||
API'lara gereken bir diğer büyük özellik ise veri doğrulamadır, yani verinin çeşitli parametrelere bağlı olarak doğru ve tutarlı olduğundan emin olmaktır. Örneğin bir alanın `int` olmasına karar verdiniz, daha sonra rastgele bir metin değeri almasını istemezsiniz. Bu özellikle sisteme dışarıdan gelen veri için kullanışlı bir özellik oluyor.
|
||||
API’ların ihtiyaç duyduğu bir diğer önemli özellik, veri doğrulamadır; belirli parametreler göz önüne alındığında verinin geçerli olduğundan emin olmak. Örneğin, bir alanın `int` olması ve rastgele bir metin olmaması. Bu özellikle dışarıdan gelen veriler için kullanışlıdır.
|
||||
|
||||
Bir veri doğrulama sistemi olmazsa bütün bu kontrolleri koda dökerek kendiniz yapmak zorunda kalırdınız.
|
||||
Bir veri doğrulama sistemi olmadan, tüm bu kontrolleri kod içinde el ile yapmanız gerekir.
|
||||
|
||||
Marshmallow bu özellikleri sağlamak için geliştirilmişti. Benim de geçmişte oldukça sık kullandığım harika bir kütüphanedir.
|
||||
Marshmallow, bu özellikleri sağlamak için inşa edildi. Harika bir kütüphanedir ve geçmişte çok kullandım.
|
||||
|
||||
Ama... Python'un tip belirteçleri gelmeden önce oluşturulmuştu. Yani her <abbr title="Verilerin nasıl oluşturulması gerektiğinin tanımı">şemayı</abbr> tanımlamak için Marshmallow'un sunduğu spesifik araçları ve sınıfları kullanmanız gerekiyordu.
|
||||
Ancak Python tip belirteçlerinden önce yazılmıştır. Dolayısıyla her <abbr title="verinin nasıl oluşturulması gerektiğinin tanımı">şemayı</abbr> tanımlamak için Marshmallow’un sağladığı belirli yardımcılar ve sınıflar kullanılır.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Kod kullanarak otomatik olarak veri tipini ve veri doğrulamayı belirten "şemalar" tanımlamalı.
|
||||
Kodla, veri tiplerini ve doğrulamayı otomatik sağlayan “şemalar” tanımlamak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a>
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
|
||||
|
||||
API'ların ihtiyacı olan bir diğer önemli özellik ise gelen isteklerdeki verileri Python objelerine <abbr title="Parsing: dönüştürmek, ayrıştırmak, çözümlemek">ayrıştırabilmektir</abbr>.
|
||||
API’ların ihtiyaç duyduğu bir diğer büyük özellik, gelen isteklerden veriyi <abbr title="okuyup Python verisine dönüştürmek">ayrıştırma</abbr>dır.
|
||||
|
||||
Webargs, Flask gibi bir kaç framework'ün üzerinde bunu sağlamak için geliştirilen bir araçtır.
|
||||
Webargs, Flask dahil birkaç framework’ün üzerinde bunu sağlamak için geliştirilmiş bir araçtır.
|
||||
|
||||
Veri doğrulama için arka planda Marshmallow kullanıyor, hatta aynı geliştiriciler tarafından oluşturuldu.
|
||||
Veri doğrulama için arka planda Marshmallow’u kullanır. Aynı geliştiriciler tarafından yazılmıştır.
|
||||
|
||||
Webargs da harika bir araç ve onu da geçmişte henüz **FastAPI** yokken çok kullandım.
|
||||
**FastAPI**’dan önce benim de çok kullandığım harika bir araçtır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Webargs aynı Marshmallow geliştirileri tarafından oluşturuldu.
|
||||
Webargs, Marshmallow geliştiricileri tarafından oluşturuldu.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Gelen istek verisi için otomatik veri doğrulamaya sahip olmalı.
|
||||
Gelen istek verisini otomatik doğrulamak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a>
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a> { #apispec }
|
||||
|
||||
Marshmallow ve Webargs <abbr title="Eklenti: Plug-In">eklentiler</abbr> olarak; veri doğrulama, ayrıştırma ve dönüştürmeyi sağlıyor.
|
||||
Marshmallow ve Webargs; doğrulama, ayrıştırma ve dönüşümü eklenti olarak sağlar.
|
||||
|
||||
Ancak dökümantasyondan hala ses seda yok. Daha sonrasında ise APISpec geldi.
|
||||
Ama dökümantasyon eksikti. Sonra APISpec geliştirildi.
|
||||
|
||||
APISpec pek çok framework için bir <abbr title="Eklenti: Plug-In">eklenti</abbr> olarak kullanılıyor (Starlette için de bir <abbr title="Eklenti: Plug-In">eklentisi</abbr> var).
|
||||
Birçok framework için bir eklentidir (Starlette için de bir eklenti vardır).
|
||||
|
||||
Şemanın tanımını <abbr title="Route: HTTP isteğinin gittiği yol">yol</abbr>'a istek geldiğinde çalışan her bir fonksiyonun <abbr title="Döküman dizesi: docstring">döküman dizesinin</abbr> içine YAML formatında olacak şekilde yazıyorsunuz o da OpenAPI şemaları üretiyor.
|
||||
Çalışma şekli: Her bir route’u işleyen fonksiyonun docstring’i içine YAML formatında şema tanımı yazarsınız.
|
||||
|
||||
Flask, Starlette, Responder ve benzerlerinde bu şekilde çalışıyor.
|
||||
Ve OpenAPI şemaları üretir.
|
||||
|
||||
Fakat sonrasında yine mikro sözdizimi problemiyle karşılaşıyoruz. Python metinlerinin içinde koskoca bir YAML oluyor.
|
||||
Flask, Starlette, Responder vb. için çalışma şekli böyledir.
|
||||
|
||||
Editör bu konuda pek yardımcı olamaz. Üstelik eğer parametreleri ya da Marshmallow şemalarını değiştirip YAML kodunu güncellemeyi unutursak artık döküman geçerliliğini yitiriyor.
|
||||
Ancak yine, Python metni içinde (kocaman bir YAML) mikro bir söz dizimi sorunu ortaya çıkar.
|
||||
|
||||
Editör bu konuda pek yardımcı olamaz. Parametreleri veya Marshmallow şemalarını değiştirip docstring’teki YAML’ı güncellemeyi unutursak, üretilen şema geçerliliğini yitirir.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
APISpec de aynı Marshmallow geliştiricileri tarafından oluşturuldu.
|
||||
APISpec, Marshmallow geliştiricileri tarafından oluşturuldu.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham verdi?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
API'lar için açık standart desteği olmalı (OpenAPI gibi).
|
||||
API’lar için açık standart olan OpenAPI’ı desteklemek.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a>
|
||||
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a> { #flask-apispec }
|
||||
|
||||
Flask-apispec ise Webargs, Marshmallow ve APISpec'i birbirine bağlayan bir Flask <abbr title="Eklenti: Plug-In">eklentisi</abbr>.
|
||||
Webargs, Marshmallow ve APISpec’i bir araya getiren bir Flask eklentisidir.
|
||||
|
||||
Webargs ve Marshmallow'daki bilgiyi APISpec ile otomatik OpenAPI şemaları üretmek için kullanıyor.
|
||||
Webargs ve Marshmallow’dan aldığı bilgiyi kullanarak, APISpec ile otomatik OpenAPI şemaları üretir.
|
||||
|
||||
Hak ettiği değeri görmeyen, harika bir araç. Piyasadaki çoğu Flask <abbr title="Eklenti: Plug-In">eklentisinden</abbr> çok daha popüler olmalı. Hak ettiği değeri görmüyor oluşunun sebebi ise dökümantasyonun çok kısa ve soyut olması olabilir.
|
||||
Harika ama yeterince değer görmeyen bir araçtır. Mevcut birçok Flask eklentisinden çok daha popüler olmalıydı. Muhtemelen dökümantasyonunun fazla kısa ve soyut olmasından kaynaklanıyor olabilir.
|
||||
|
||||
Böylece Flask-apispec, Python döküman dizilerine YAML gibi farklı bir syntax yazma sorununu çözmüş oldu.
|
||||
Python docstring’leri içine YAML (farklı bir söz dizimi) yazma ihtiyacını ortadan kaldırdı.
|
||||
|
||||
**FastAPI**'ı geliştirene dek benim favori arka uç kombinasyonum Flask'in yanında Marshmallow ve Webargs ile birlikte Flask-apispec idi.
|
||||
**FastAPI**’yı inşa edene kadar, Flask + Flask-apispec + Marshmallow + Webargs kombinasyonu benim favori arka uç stack’imdi.
|
||||
|
||||
Bunu kullanmak, bir kaç <abbr title="full-stack: Hem ön uç hem de arka uç geliştirme">full-stack</abbr> Flask projesi oluşturucusunun yaratılmasına yol açtı. Bunlar benim (ve bir kaç harici ekibin de) şimdiye kadar kullandığı asıl <abbr title="stack: Projeyi geliştirirken kullanılan araçlar dizisi">stack</abbr>ler:
|
||||
Bunu kullanmak, birkaç Flask full‑stack üreticisinin ortaya çıkmasına yol açtı. Şu ana kadar benim (ve birkaç harici ekibin) kullandığı ana stack’ler:
|
||||
|
||||
* <a href="https://github.com/tiangolo/full-stack" class="external-link" target="_blank">https://github.com/tiangolo/full-stack</a>
|
||||
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
|
||||
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
|
||||
|
||||
Aynı full-stack üreticiler [**FastAPI** Proje Üreticileri](project-generation.md){.internal-link target=_blank}'nin de temelini oluşturdu.
|
||||
Aynı full‑stack üreticiler, [**FastAPI** Proje Üreticileri](project-generation.md){.internal-link target=_blank}’nin de temelini oluşturdu.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Flask-apispec de aynı Marshmallow geliştiricileri tarafından üretildi.
|
||||
Flask-apispec, Marshmallow geliştiricileri tarafından oluşturuldu.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Veri dönüşümü ve veri doğrulamayı tanımlayan kodu kullanarak otomatik olarak OpenAPI şeması oluşturmalı.
|
||||
Veri dönüşümü ve doğrulamayı tanımlayan aynı koddan, OpenAPI şemasını otomatik üretmek.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (and <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>)
|
||||
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (ve <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>) { #nestjs-and-angular }
|
||||
|
||||
Bu Python teknolojisi bile değil. NestJS, Angulardan ilham almış olan bir JavaScript (TypeScript) NodeJS framework'ü.
|
||||
Bu Python bile değil; NestJS, Angular’dan ilham alan bir JavaScript (TypeScript) NodeJS framework’üdür.
|
||||
|
||||
Flask-apispec ile yapılabileceklere nispeten benzeyen bir şey elde ediyor.
|
||||
Flask-apispec ile yapılabilene kısmen benzer bir şey başarır.
|
||||
|
||||
Angular 2'den ilham alan, içine gömülü bir <abbr title="Bağımlılık enjeksiyonu: Dependency Injection">bağımlılık enjeksiyonu</abbr> sistemi var. Bildiğim diğer tüm bağımlılık enjeksiyonu sistemlerinde olduğu gibi"<abbr title="Injectable: dependency injection sistemi tarafından enjekte edilecek dependency (bağımlılık)">bağımlılık</abbr>"ları önceden kaydetmenizi gerektiriyor. Böylece projeyi daha detaylı hale getiriyor ve kod tekrarını da arttırıyor.
|
||||
Angular 2’den esinlenen, entegre bir bağımlılık enjeksiyonu sistemi vardır. “Injectable”ları önceden kaydetmeyi gerektirir (bildiğim diğer bağımlılık enjeksiyonu sistemlerinde olduğu gibi), bu da ayrıntıyı ve kod tekrarını artırır.
|
||||
|
||||
Parametreler TypeScript tipleri (Python tip belirteçlerine benzer) ile açıklandığından editör desteği oldukça iyi.
|
||||
Parametreler TypeScript tipleriyle (Python tip belirteçlerine benzer) açıklandığından, editör desteği oldukça iyidir.
|
||||
|
||||
Ama TypeScript verileri kod JavaScript'e derlendikten sonra korunmadığından, bunlara dayanarak aynı anda veri doğrulaması, veri dönüşümü ve dökümantasyon tanımlanamıyor. Bundan ve bazı tasarım tercihlerinden dolayı veri doğrulaması, dönüşümü ve otomatik şema üretimi için pek çok yere dekorator eklemek gerekiyor. Bu da projeyi oldukça detaylandırıyor.
|
||||
Ancak TypeScript tip bilgisi JavaScript’e derlemeden sonra korunmadığından, aynı anda tiplere dayanarak doğrulama, dönüşüm ve dökümantasyon tanımlanamaz. Bu ve bazı tasarım kararları nedeniyle doğrulama, dönüşüm ve otomatik şema üretimi için birçok yere dekoratör eklemek gerekir; proje oldukça ayrıntılı hâle gelir.
|
||||
|
||||
İç içe geçen derin modelleri pek iyi işleyemiyor. Yani eğer istekteki JSON gövdesi derin bir JSON objesiyse düzgün bir şekilde dökümante edilip doğrulanamıyor.
|
||||
İçiçe modelleri çok iyi işleyemez. Yani istek gövdesindeki JSON, içinde başka alanları ve onlar da içiçe JSON objelerini içeriyorsa, doğru şekilde dökümante edilip doğrulanamaz.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Güzel bir editör desteği için Python tiplerini kullanmalı.
|
||||
Harika editör desteği için Python tiplerini kullanmak.
|
||||
|
||||
Güçlü bir bağımlılık enjeksiyon sistemine sahip olmalı. Kod tekrarını minimuma indirecek bir yol bulmalı.
|
||||
Güçlü bir bağımlılık enjeksiyonu sistemine sahip olmak. Kod tekrarını en aza indirmenin bir yolunu bulmak.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a>
|
||||
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a> { #sanic }
|
||||
|
||||
Sanic, `asyncio`'ya dayanan son derece hızlı Python kütüphanelerinden biriydi. Flask'a epey benzeyecek şekilde geliştirilmişti.
|
||||
|
||||
/// note | Teknik detaylar
|
||||
|
||||
İçerisinde standart Python `asyncio` döngüsü yerine <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> kullanıldı. Hızının asıl kaynağı buydu.
|
||||
|
||||
Uvicorn ve Starlette'e ilham kaynağı olduğu oldukça açık, şu anda ikisi de açık karşılaştırmalarda Sanicten daha hızlı gözüküyor.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
|
||||
Uçuk performans sağlayacak bir yol bulmalı.
|
||||
|
||||
Tam da bu yüzden **FastAPI** Starlette'e dayanıyor, çünkü Starlette şu anda kullanılabilir en hızlı framework. (üçüncü parti karşılaştırmalı testlerine göre)
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a>
|
||||
|
||||
Falcon ise bir diğer yüksek performanslı Python framework'ü. Minimal olacak şekilde Hug gibi diğer framework'lerin temeli olabilmek için tasarlandı.
|
||||
|
||||
İki parametre kabul eden fonksiyonlar şeklinde tasarlandı, biri "istek" ve diğeri ise "cevap". Sonra isteğin çeşitli kısımlarını **okuyor**, cevaba ise bir şeyler **yazıyorsunuz**. Bu tasarımdan dolayı istek parametrelerini ve gövdelerini standart Python tip belirteçlerini kullanarak fonksiyon parametreleriyle belirtmek mümkün değil.
|
||||
|
||||
Yani veri doğrulama, veri dönüştürme ve dökümantasyonun hepsi kodda yer almalı, otomatik halledemiyoruz. Ya da Falcon üzerine bir framework olarak uygulanmaları gerekiyor, aynı Hug'da olduğu gibi. Bu ayrım Falcon'un tasarımından esinlenen, istek ve cevap objelerini parametre olarak işleyen diğer kütüphanelerde de yer alıyor.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
|
||||
Harika bir performans'a sahip olmanın yollarını bulmalı.
|
||||
|
||||
Hug ile birlikte (Hug zaten Falcon'a dayandığından) **FastAPI**'ın fonksiyonlarda `cevap` parametresi belirtmesinde ilham kaynağı oldu.
|
||||
|
||||
FastAPI'da opsiyonel olmasına rağmen, daha çok header'lar, çerezler ve alternatif durum kodları belirlemede kullanılıyor.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a>
|
||||
|
||||
**FastAPI**'ı geliştirmenin ilk aşamalarında Molten'ı keşfettim. Pek çok ortak fikrimiz vardı:
|
||||
|
||||
* Python'daki tip belirteçlerini baz alıyordu.
|
||||
* Bunlara bağlı olarak veri doğrulaması ve dökümantasyon sağlıyordu.
|
||||
* Bir <abbr title="Bağımlılık enjeksiyonu: Dependency Injection">bağımlılık enjeksiyonu</abbr> sistemi vardı.
|
||||
|
||||
Veri doğrulama, veri dönüştürme ve dökümantasyon için Pydantic gibi bir üçüncü parti kütüphane kullanmıyor, kendi içerisinde bunlara sahip. Yani bu veri tipi tanımlarını tekrar kullanmak pek de kolay değil.
|
||||
|
||||
Biraz daha detaylı ayarlamalara gerek duyuyor. Ayrıca <abbr title="ASGI (Asynchronous Server Gateway Interface): Asenkron Sunucu Ağ Geçidi Arabirimi, asenkron Python web uygulamaları geliştirmek için yeni standart.">ASGI</abbr> yerine <abbr title="WSGI (Web Server Gateway Interface): Web Sunucusu Ağ Geçidi Arabirimi, Pythonda senkron web uygulamaları geliştirmek için eski standart.">WSGI</abbr>'a dayanıyor. Yani Uvicorn, Starlette ve Sanic gibi araçların yüksek performansından faydalanacak şekilde tasarlanmamış.
|
||||
|
||||
<abbr title="Bağımlılık enjeksiyonu: Dependency Injection">Bağımlılık enjeksiyonu</abbr> sistemi bağımlılıkların önceden kaydedilmesini ve sonrasında belirlenen veri tiplerine göre çözülmesini gerektiriyor. Yani spesifik bir tip, birden fazla bileşen ile belirlenemiyor.
|
||||
|
||||
<abbr title="Route: HTTP isteğinin gittiği yol">Yol</abbr>'lar fonksiyonun üstünde endpoint'i işleyen dekoratörler yerine farklı yerlerde tanımlanan fonksiyonlarla belirlenir. Bu Flask (ve Starlette) yerine daha çok Django'nun yaklaşımına daha yakın bir metot. Bu, kodda nispeten birbiriyle sıkı ilişkili olan şeyleri ayırmaya sebep oluyor.
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
|
||||
Model özelliklerinin "standart" değerlerini kullanarak veri tipleri için ekstra veri doğrulama koşulları tanımlamalı. Bu editör desteğini geliştiriyor ve daha önceden Pydantic'te yoktu.
|
||||
|
||||
Bu aslında Pydantic'in de aynı doğrulama stiline geçmesinde ilham kaynağı oldu. Şu anda bütün bu özellikler Pydantic'in yapısında yer alıyor.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a>
|
||||
|
||||
Hug, Python tip belirteçlerini kullanarak API parametrelerinin tipini belirlemeyi uygulayan ilk framework'lerdendi. Bu, diğer araçlara da ilham kaynağı olan harika bir fikirdi.
|
||||
|
||||
Tip belirlerken standart Python veri tipleri yerine kendi özel tiplerini kullandı, yine de bu ileriye dönük devasa bir adımdı.
|
||||
|
||||
Hug ayrıca tüm API'ı JSON ile ifade eden özel bir şema oluşturan ilk framework'lerdendir.
|
||||
|
||||
OpenAPI veya JSON Şeması gibi bir standarda bağlı değildi. Yani Swagger UI gibi diğer araçlarla entegre etmek kolay olmazdı. Ama yine de, bu oldukça yenilikçi bir fikirdi.
|
||||
|
||||
Ayrıca ilginç ve çok rastlanmayan bir özelliği vardı: aynı framework'ü kullanarak hem API'lar hem de <abbr title="Command Line Tool (CLI): Komut satırı aracı">CLI</abbr>'lar oluşturmak mümkündü.
|
||||
|
||||
Senkron çalışan Python web framework'lerinin standardına (WSGI) dayandığından dolayı Websocket'leri ve diğer şeyleri işleyemiyor, ancak yine de yüksek performansa sahip.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Hug, Python dosyalarında bulunan dahil etme satırlarını otomatik olarak sıralayan harika bir araç olan <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a>'un geliştiricisi Timothy Crosley tarafından geliştirildi.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
|
||||
Hug, APIStar'ın çeşitli kısımlarında esin kaynağı oldu ve APIStar'la birlikte en umut verici bulduğum araçlardan biriydi.
|
||||
|
||||
**FastAPI**, Python tip belirteçlerini kullanarak parametre belirlemede ve API'ı otomatık tanımlayan bir şema üretmede de Hug'a esinlendi.
|
||||
|
||||
**FastAPI**'ın header ve çerez tanımlamak için fonksiyonlarda `response` parametresini belirtmesinde de Hug'dan ilham alındı.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5)
|
||||
|
||||
**FastAPI**'ı geliştirmeye başlamadan hemen önce **APIStar** sunucusunu buldum. Benim aradığım şeylerin neredeyse hepsine sahipti ve harika bir tasarımı vardı.
|
||||
|
||||
Benim şimdiye kadar gördüğüm Python tip belirteçlerini kullanarak parametre ve istekler belirlemeyi uygulayan ilk framework'lerdendi (Molten ve NestJS'den önce). APIStar'ı da aşağı yukarı Hug ile aynı zamanlarda buldum. Fakat APIStar OpenAPI standardını kullanıyordu.
|
||||
|
||||
Farklı yerlerdeki tip belirteçlerine bağlı olarak otomatik veri doğrulama, veri dönüştürme ve OpenAPI şeması oluşturma desteği sunuyordu.
|
||||
|
||||
Gövde şema tanımları Pydantic ile aynı Python tip belirteçlerini kullanmıyordu, biraz daha Marsmallow'a benziyordu. Dolayısıyla editör desteği de o kadar iyi olmazdı ama APIStar eldeki en iyi seçenekti.
|
||||
|
||||
O dönemlerde karşılaştırmalarda en iyi performansa sahipti (yalnızca Starlette'e kaybediyordu).
|
||||
|
||||
Başlangıçta otomatik API dökümantasyonu sunan bir web arayüzü yoktu, ama ben ona Swagger UI ekleyebileceğimi biliyordum.
|
||||
|
||||
Bağımlılık enjeksiyon sistemi vardı. Yukarıda bahsettiğim diğer araçlar gibi bundaki sistem de bileşenlerin önceden kaydedilmesini gerektiriyordu. Yine de harika bir özellikti.
|
||||
|
||||
Güvenlik entegrasyonu olmadığından dolayı APIStar'ı hiç bir zaman tam bir projede kullanamadım. Bu yüzden Flask-apispec'e bağlı full-stack proje üreticilerde sahip olduğum özellikleri tamamen değiştiremedim. Bu güvenlik entegrasyonunu ekleyen bir <abbr title="Pull request (PR): Git sistemlerinde projenin bir branch'ine yapılan değişikliğin sistemde diğer kullanıcılara ifade edilmesi">PR</abbr> oluşturmak da projelerim arasında yer alıyordu.
|
||||
|
||||
Sonrasında ise projenin odağı değişti.
|
||||
|
||||
Geliştiricinin Starlette'e odaklanması gerekince proje de artık bir API web framework'ü olmayı bıraktı.
|
||||
|
||||
Artık APIStar, OpenAPI özelliklerini doğrulamak için bir dizi araç sunan bir proje haline geldi.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
APIStar, aşağıdaki projeleri de üreten Tom Christie tarafından geliştirildi:
|
||||
|
||||
* Django REST Framework
|
||||
* **FastAPI**'ın da dayandığı Starlette
|
||||
* Starlette ve **FastAPI** tarafından da kullanılan Uvicorn
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a nasıl ilham oldu?
|
||||
|
||||
Var oldu.
|
||||
|
||||
Aynı Python veri tipleriyle birden fazla şeyi belirleme (veri doğrulama, veri dönüştürme ve dökümantasyon), bir yandan da harika bir editör desteği sunma, benim muhteşem bulduğum bir fikirdi.
|
||||
|
||||
Uzunca bir süre boyunca benzer bir framework arayıp pek çok farklı alternatifi denedikten sonra, APIStar en iyi seçenekti.
|
||||
|
||||
Sonra APIStar bir sunucu olmayı bıraktı ve Starlette oluşturuldu. Starlette, böyle bir sunucu sistemi için daha iyi bir temel sunuyordu. Bu da **FastAPI**'ın son esin kaynağıydı.
|
||||
|
||||
Ben bu önceki araçlardan öğrendiklerime dayanarak **FastAPI**'ın özelliklerini arttırıp geliştiriyor, <abbr title="Tip desteği (typing support): kod yapısında parametrelere, argümanlara ve objelerin özelliklerine veri tipi atamak">tip desteği</abbr> sistemi ve diğer kısımları iyileştiriyorum ancak yine de **FastAPI**'ı APIStar'ın "ruhani varisi" olarak görüyorum.
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI** Tarafından Kullanılanlar
|
||||
|
||||
### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
|
||||
Pydantic Python tip belirteçlerine dayanan; veri doğrulama, veri dönüştürme ve dökümantasyon tanımlamak (JSON Şema kullanarak) için bir kütüphanedir.
|
||||
|
||||
Tip belirteçleri kullanıyor olması onu aşırı sezgisel yapıyor.
|
||||
|
||||
Marshmallow ile karşılaştırılabilir. Ancak karşılaştırmalarda Marshmallowdan daha hızlı görünüyor. Aynı Python tip belirteçlerine dayanıyor ve editör desteği de harika.
|
||||
|
||||
/// check | **FastAPI** nerede kullanıyor?
|
||||
|
||||
Bütün veri doğrulama, veri dönüştürme ve JSON Şemasına bağlı otomatik model dökümantasyonunu halletmek için!
|
||||
|
||||
**FastAPI** yaptığı her şeyin yanı sıra bu JSON Şema verisini alıp daha sonra OpenAPI'ya yerleştiriyor.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
|
||||
Starlette hafif bir <abbr title="ASGI (Asynchronous Server Gateway Interface): Asenkron Sunucu Ağ Geçidi Arabirimi, asenkron Python web uygulamaları geliştirmek için yeni standart.">ASGI</abbr> framework'ü ve yüksek performanslı asyncio servisleri oluşturmak için ideal.
|
||||
|
||||
Kullanımı çok kolay ve sezgisel, kolaylıkla genişletilebilecek ve modüler bileşenlere sahip olacak şekilde tasarlandı.
|
||||
|
||||
Sahip olduğu bir kaç özellik:
|
||||
|
||||
* Cidden etkileyici bir performans.
|
||||
* WebSocket desteği.
|
||||
* İşlem-içi arka plan görevleri.
|
||||
* Başlatma ve kapatma olayları.
|
||||
* HTTPX ile geliştirilmiş bir test istemcisi.
|
||||
* CORS, GZip, Static Files ve Streaming cevapları desteği.
|
||||
* Session ve çerez desteği.
|
||||
* Kodun %100'ü test kapsamında.
|
||||
* Kodun %100'ü tip belirteçleriyle desteklenmiştir.
|
||||
* Yalnızca bir kaç zorunlu bağımlılığa sahip.
|
||||
|
||||
Starlette şu anda test edilen en hızlı Python framework'ü. Yalnızca bir sunucu olan Uvicorn'a yeniliyor, o da zaten bir framework değil.
|
||||
|
||||
Starlette bütün temel web mikro framework işlevselliğini sağlıyor.
|
||||
|
||||
Ancak otomatik veri doğrulama, veri dönüştürme ve dökümantasyon sağlamyor.
|
||||
|
||||
Bu, **FastAPI**'ın onun üzerine tamamen Python tip belirteçlerine bağlı olarak eklediği (Pydantic ile) ana şeylerden biri. **FastAPI** bunun yanında artı olarak bağımlılık enjeksiyonu sistemi, güvenlik araçları, OpenAPI şema üretimi ve benzeri özellikler de ekliyor.
|
||||
`asyncio` tabanlı, son derece hızlı ilk Python framework’lerinden biriydi. Flask’a oldukça benzer olacak şekilde geliştirilmişti.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
ASGI, Django'nun ana ekibi tarafından geliştirilen yeni bir "standart". Bir "Python standardı" (PEP) olma sürecinde fakat henüz bir standart değil.
|
||||
Varsayılan Python `asyncio` döngüsü yerine <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> kullanır; hızını esasen bu sağlar.
|
||||
|
||||
Bununla birlikte, halihazırda birçok araç tarafından bir "standart" olarak kullanılmakta. Bu, Uvicorn'u farklı ASGI sunucularıyla (Daphne veya Hypercorn gibi) değiştirebileceğiniz veya `python-socketio` gibi ASGI ile uyumlu araçları ekleyebileciğiniz için birlikte çalışılabilirliği büyük ölçüde arttırıyor.
|
||||
Açık kıyaslamalarda, bugün Uvicorn ve Starlette’in Sanic’ten daha hızlı olduğu görülür; Sanic bu ikisine ilham vermiştir.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI** nerede kullanıyor?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Tüm temel web kısımlarında üzerine özellikler eklenerek kullanılmakta.
|
||||
Çok yüksek performans elde etmenin bir yolunu bulmak.
|
||||
|
||||
`FastAPI` sınıfının kendisi direkt olarak `Starlette` sınıfını miras alıyor!
|
||||
|
||||
Yani, Starlette ile yapabileceğiniz her şeyi, Starlette'in bir nevi güçlendirilmiş hali olan **FastAPI** ile doğrudan yapabilirsiniz.
|
||||
Bu yüzden **FastAPI**, en hızlı framework olduğu için (üçüncü parti kıyaslamalara göre) Starlette üzerine kuruludur.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>
|
||||
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a> { #falcon }
|
||||
|
||||
Uvicorn, uvlook ile httptools üzerine kurulu ışık hzında bir ASGI sunucusudur.
|
||||
Falcon, başka bir yüksek performanslı Python framework’üdür; minimal olacak şekilde tasarlanmış ve Hug gibi diğer framework’lere temel olmuştur.
|
||||
|
||||
Bir web framework'ünden ziyade bir sunucudur, yani yollara bağlı yönlendirme yapmanızı sağlayan araçları yoktur. Bu daha çok Starlette (ya da **FastAPI**) gibi bir framework'ün sunucuya ek olarak sağladığı bir şeydir.
|
||||
İki parametre alan fonksiyonlar etrafında tasarlanmıştır: “request” ve “response”. İstekten parçalar “okur”, cevaba parçalar “yazarsınız”. Bu tasarım nedeniyle, fonksiyon parametreleriyle standart Python tip belirteçlerini kullanarak istek parametrelerini ve gövdelerini ilan etmek mümkün değildir.
|
||||
|
||||
Starlette ve **FastAPI** için tavsiye edilen sunucu Uvicorndur.
|
||||
Dolayısıyla veri doğrulama, dönüşüm ve dökümantasyon kodda yapılmalı; otomatik olmaz. Ya da Hug’da olduğu gibi Falcon’un üzerine bir framework olarak uygulanmalıdır. Falcon’un tasarımından etkilenen ve tek bir request objesi ile response objesini parametre olarak alan diğer framework’lerde de aynı ayrım vardır.
|
||||
|
||||
/// check | **FastAPI** neden tavsiye ediyor?
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
**FastAPI** uygulamalarını çalıştırmak için ana web sunucusu Uvicorn!
|
||||
Harika performans elde etmenin yollarını bulmak.
|
||||
|
||||
Gunicorn ile birleştirdiğinizde asenkron ve çoklu işlem destekleyen bir sunucu elde ediyorsunuz!
|
||||
|
||||
Daha fazla detay için [Deployment](deployment/index.md){.internal-link target=_blank} bölümünü inceleyebilirsiniz.
|
||||
Hug ile birlikte (Hug, Falcon’a dayanır) **FastAPI**’da fonksiyonlarda opsiyonel bir `response` parametresi ilan edilmesi fikrine ilham vermek. FastAPI’da bu parametre çoğunlukla header, cookie ve alternatif durum kodlarını ayarlamak için kullanılır.
|
||||
|
||||
///
|
||||
|
||||
## Karşılaştırma ve Hız
|
||||
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a> { #molten }
|
||||
|
||||
Uvicorn, Starlette ve FastAPI arasındakı farkı daha iyi anlamak ve karşılaştırma yapmak için [Kıyaslamalar](benchmarks.md){.internal-link target=_blank} bölümüne bakın!
|
||||
**FastAPI**’ı geliştirmenin ilk aşamalarında Molten’ı keşfettim. Oldukça benzer fikirleri vardı:
|
||||
|
||||
* Python tip belirteçlerine dayanır.
|
||||
* Bu tiplere bağlı doğrulama ve dökümantasyon sağlar.
|
||||
* Bağımlılık enjeksiyonu sistemi vardır.
|
||||
|
||||
Pydantic gibi doğrulama, dönüşüm ve dökümantasyon için üçüncü parti bir kütüphane kullanmaz; kendi içinde sağlar. Bu yüzden bu veri tipi tanımlarını tekrar kullanmak o kadar kolay olmaz.
|
||||
|
||||
Biraz daha ayrıntılı yapılandırma ister. Ve ASGI yerine WSGI tabanlı olduğundan, Uvicorn, Starlette ve Sanic gibi araçların yüksek performansından faydalanmaya yönelik tasarlanmamıştır.
|
||||
|
||||
Bağımlılık enjeksiyonu sistemi, bağımlılıkların önceden kaydedilmesini ve tiplerine göre çözülmesini gerektirir. Yani belirli bir tipi sağlayan birden fazla “bileşen” tanımlanamaz.
|
||||
|
||||
Route’lar, endpoint’i işleyen fonksiyonun üstüne konan dekoratörlerle değil, tek bir yerde, farklı yerlerde tanımlanmış fonksiyonlar kullanılarak ilan edilir. Bu yaklaşım, Flask (ve Starlette) yerine Django’ya daha yakındır; kodda aslında birbirine sıkı bağlı olan şeyleri ayırır.
|
||||
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Model özelliklerinin “varsayılan” değerlerini kullanarak veri tiplerine ekstra doğrulamalar tanımlamak. Bu, editör desteğini iyileştirir ve Pydantic’te daha önce yoktu.
|
||||
|
||||
Bu yaklaşım, Pydantic’te de aynı doğrulama beyan stilinin desteklenmesine ilham verdi (bu işlevselliklerin tamamı artık Pydantic’te mevcut).
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a> { #hug }
|
||||
|
||||
Hug, Python tip belirteçlerini kullanarak API parametre tiplerini ilan etmeyi uygulayan ilk framework’lerden biriydi. Diğer araçlara da ilham veren harika bir fikirdi.
|
||||
|
||||
Standart Python tipleri yerine kendi özel tiplerini kullansa da büyük bir adımdı.
|
||||
|
||||
JSON ile tüm API’ı beyan eden özel bir şema üreten ilk framework’lerden biriydi.
|
||||
|
||||
OpenAPI veya JSON Schema gibi bir standarda dayanmadığı için Swagger UI gibi diğer araçlarla doğrudan entegre edilemezdi. Yine de oldukça yenilikçiydi.
|
||||
|
||||
Nadir bir özelliği daha vardı: aynı framework ile hem API’lar hem de CLI’lar oluşturmak mümkündü.
|
||||
|
||||
Senkron Python web framework’leri için önceki standart olan WSGI’ye dayandığından, WebSocket vb. şeyleri işleyemez, ancak yine de yüksek performansa sahiptir.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Hug, Python dosyalarındaki import’ları otomatik sıralayan harika bir araç olan <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a>’un geliştiricisi Timothy Crosley tarafından geliştirildi.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a ilham olan fikirler
|
||||
|
||||
Hug, APIStar’ın bazı kısımlarına ilham verdi ve APIStar ile birlikte en umut verici bulduğum araçlardandı.
|
||||
|
||||
**FastAPI**, parametreleri ilan etmek ve API’ı otomatik tanımlayan bir şema üretmek için Python tip belirteçlerini kullanma fikrini Hug’dan ilhamla benimsedi.
|
||||
|
||||
Ayrıca header ve cookie ayarlamak için fonksiyonlarda `response` parametresi ilan etme fikrine de Hug ilham verdi.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5) { #apistar-0-5 }
|
||||
|
||||
**FastAPI**’yi inşa etmeye karar vermeden hemen önce **APIStar** sunucusunu buldum. Aradığım şeylerin neredeyse hepsine sahipti ve harika bir tasarımı vardı.
|
||||
|
||||
Python tip belirteçleriyle parametreleri ve istekleri ilan eden bir framework’ün gördüğüm ilk örneklerindendi (NestJS ve Molten’dan önce). Aşağı yukarı Hug ile aynı zamanlarda buldum; ancak APIStar, OpenAPI standardını kullanıyordu.
|
||||
|
||||
Farklı yerlerdeki aynı tip belirteçlerine dayanarak otomatik veri doğrulama, veri dönüşümü ve OpenAPI şeması üretimi vardı.
|
||||
|
||||
Gövde şema tanımları Pydantic’tekiyle aynı Python tip belirteçlerini kullanmıyordu; biraz daha Marshmallow’a benziyordu. Bu yüzden editör desteği o kadar iyi olmazdı; yine de APIStar mevcut en iyi seçenekti.
|
||||
|
||||
O dönem kıyaslamalarda en iyi performansa sahipti (sadece Starlette tarafından geçiliyordu).
|
||||
|
||||
Başta otomatik API dökümantasyonu sunan bir web arayüzü yoktu ama Swagger UI ekleyebileceğimi biliyordum.
|
||||
|
||||
Bağımlılık enjeksiyonu sistemi vardı. Diğer araçlarda olduğu gibi bileşenlerin önceden kaydedilmesini gerektiriyordu. Yine de harika bir özellikti.
|
||||
|
||||
Güvenlik entegrasyonu olmadığından tam bir projede kullanamadım; bu yüzden Flask-apispec tabanlı full‑stack üreticilerle sahip olduğum özelliklerin tamamını ikame edemedim. Bu işlevi ekleyen bir pull request’i yapılacaklar listeme almıştım.
|
||||
|
||||
Sonra projenin odağı değişti.
|
||||
|
||||
Artık bir API web framework’ü değildi; geliştirici Starlette’e odaklanmak zorundaydı.
|
||||
|
||||
Şimdi APIStar, bir web framework’ü değil, OpenAPI spesifikasyonlarını doğrulamak için araçlar takımından ibaret.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
APIStar, aşağıdakilerin de yaratıcısı olan Tom Christie tarafından geliştirildi:
|
||||
|
||||
* Django REST Framework
|
||||
* **FastAPI**’ın üzerine kurulu Starlette
|
||||
* Starlette ve **FastAPI** tarafından kullanılan Uvicorn
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI**'a ilham olan
|
||||
|
||||
Var olmak.
|
||||
|
||||
Aynı Python tipleriyle (hem veri doğrulama, dönüşüm ve dökümantasyon) birden çok şeyi ilan etmek ve aynı anda harika editör desteği sağlamak, bence dahiyane bir fikirdi.
|
||||
|
||||
Uzun süre benzer bir framework arayıp birçok alternatifi denedikten sonra, APIStar mevcut en iyi seçenekti.
|
||||
|
||||
Sonra APIStar bir sunucu olarak var olmaktan çıktı ve Starlette oluşturuldu; böyle bir sistem için daha iyi bir temel oldu. Bu, **FastAPI**’yi inşa etmek için son ilhamdı.
|
||||
|
||||
Önceki bu araçlardan edinilen deneyimler üzerine özellikleri, tip sistemi ve diğer kısımları geliştirip artırırken, **FastAPI**’yi APIStar’ın “ruhani varisi” olarak görüyorum.
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI** Tarafından Kullanılanlar { #used-by-fastapi }
|
||||
|
||||
### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> { #pydantic }
|
||||
|
||||
Pydantic, Python tip belirteçlerine dayalı olarak veri doğrulama, dönüşüm ve dökümantasyon (JSON Schema kullanarak) tanımlamak için bir kütüphanedir.
|
||||
|
||||
Bu onu aşırı sezgisel kılar.
|
||||
|
||||
Marshmallow ile karşılaştırılabilir. Kıyaslamalarda Marshmallow’dan daha hızlıdır. Aynı Python tip belirteçlerine dayandığı için editör desteği harikadır.
|
||||
|
||||
/// check | **FastAPI** bunu şurada kullanır
|
||||
|
||||
Tüm veri doğrulama, veri dönüşümü ve JSON Schema tabanlı otomatik model dökümantasyonunu halletmekte.
|
||||
|
||||
**FastAPI** daha sonra bu JSON Schema verisini alır ve (yaptığı diğer şeylerin yanı sıra) OpenAPI içine yerleştirir.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
|
||||
|
||||
Starlette, yüksek performanslı asyncio servisleri oluşturmak için ideal, hafif bir <abbr title="Asenkron Python web uygulamaları geliştirmek için yeni standart">ASGI</abbr> framework’ü/araç takımıdır.
|
||||
|
||||
Çok basit ve sezgiseldir. Kolayca genişletilebilir ve modüler bileşenlere sahip olacak şekilde tasarlanmıştır.
|
||||
|
||||
Şunlara sahiptir:
|
||||
|
||||
* Cidden etkileyici performans.
|
||||
* WebSocket desteği.
|
||||
* Süreç içi arka plan görevleri.
|
||||
* Başlatma ve kapatma olayları.
|
||||
* HTTPX üzerinde geliştirilmiş test istemcisi.
|
||||
* CORS, GZip, Statik Dosyalar, Streaming cevaplar.
|
||||
* Oturum (Session) ve Cookie desteği.
|
||||
* %100 test kapsamı.
|
||||
* %100 tip anotasyonlu kod tabanı.
|
||||
* Az sayıda zorunlu bağımlılık.
|
||||
|
||||
Starlette, şu anda test edilen en hızlı Python framework’üdür. Yalnızca bir framework değil, bir sunucu olan Uvicorn tarafından geçilir.
|
||||
|
||||
Starlette, temel web mikroframework işlevselliğinin tamamını sağlar.
|
||||
|
||||
Ancak otomatik veri doğrulama, dönüşüm veya dökümantasyon sağlamaz.
|
||||
|
||||
**FastAPI**’nin bunun üzerine eklediği ana şeylerden biri, Pydantic kullanarak, bütünüyle Python tip belirteçlerine dayalı bu özelliklerdir. Buna ek olarak bağımlılık enjeksiyonu sistemi, güvenlik yardımcıları, OpenAPI şema üretimi vb. gelir.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
ASGI, Django çekirdek ekip üyeleri tarafından geliştirilen yeni bir “standart”tır. Hâlâ resmi bir “Python standardı” (PEP) değildir, ancak bu süreç üzerindedirler.
|
||||
|
||||
Buna rağmen, şimdiden birçok araç tarafından bir “standart” olarak kullanılmaktadır. Bu, birlikte çalışabilirliği büyük ölçüde artırır; örneğin Uvicorn’u başka bir ASGI sunucusuyla (Daphne veya Hypercorn gibi) değiştirebilir ya da `python-socketio` gibi ASGI uyumlu araçlar ekleyebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
/// check | **FastAPI** bunu şurada kullanır
|
||||
|
||||
Tüm temel web kısımlarını ele almak; üzerine özellikler eklemek.
|
||||
|
||||
`FastAPI` sınıfı, doğrudan `Starlette` sınıfından miras alır.
|
||||
|
||||
Dolayısıyla Starlette ile yapabildiğiniz her şeyi, adeta “turbo şarjlı Starlette” olan **FastAPI** ile de doğrudan yapabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a> { #uvicorn }
|
||||
|
||||
Uvicorn, uvloop ve httptools üzerinde inşa edilmiş, ışık hızında bir ASGI sunucusudur.
|
||||
|
||||
Bir web framework’ü değil, bir sunucudur. Örneğin path’lere göre yönlendirme araçları sağlamaz; bunu Starlette (veya **FastAPI**) gibi bir framework üstte sağlar.
|
||||
|
||||
Starlette ve **FastAPI** için önerilen sunucudur.
|
||||
|
||||
/// check | **FastAPI** bunu şöyle önerir
|
||||
|
||||
**FastAPI** uygulamalarını çalıştırmak için ana web sunucusu.
|
||||
|
||||
Komut satırında `--workers` seçeneğini kullanarak asenkron çok süreçli (multi‑process) bir sunucu da elde edebilirsiniz.
|
||||
|
||||
Daha fazla detay için [Dağıtım](deployment/index.md){.internal-link target=_blank} bölümüne bakın.
|
||||
|
||||
///
|
||||
|
||||
## Kıyaslamalar ve Hız { #benchmarks-and-speed }
|
||||
|
||||
Uvicorn, Starlette ve FastAPI arasındaki farkı anlamak ve karşılaştırmak için [Kıyaslamalar](benchmarks.md){.internal-link target=_blank} bölümüne göz atın.
|
||||
|
||||
@@ -145,8 +145,6 @@ Paket bağımlılıklarını tanımlamak ve yüklemek için başka formatlar ve
|
||||
* Aşağıdakilerle bir `main.py` dosyası oluşturun:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -158,7 +156,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -260,7 +258,7 @@ FastAPI'nin düzgün şekilde kapanabilmesi ve [lifespan event](../advanced/even
|
||||
|
||||
Detaylar için <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">shell ve exec form için Docker dokümanlarına</a> bakabilirsiniz.
|
||||
|
||||
Bu durum `docker compose` kullanırken oldukça belirgin olabilir. Daha teknik detaylar için şu Docker Compose FAQ bölümüne bakın: <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Why do my services take 10 seconds to recreate or stop?</a>.
|
||||
Bu durum `docker compose` kullanırken oldukça belirgin olabilir. Daha teknik detaylar için şu Docker Compose FAQ bölümüne bakın: <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Hizmetlerimin yeniden oluşturulması veya durması neden 10 saniye sürüyor?</a>.
|
||||
|
||||
#### Dizin Yapısı { #directory-structure }
|
||||
|
||||
@@ -456,7 +454,7 @@ Container kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekan
|
||||
|
||||
## Replication - Process Sayısı { #replication-number-of-processes }
|
||||
|
||||
Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>'ınız varsa, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **cluster seviyesinde** ele almak istersiniz.
|
||||
Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir <abbr title="Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makineler grubu.">cluster</abbr>'ınız varsa, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **cluster seviyesinde** ele almak istersiniz.
|
||||
|
||||
Kubernetes gibi dağıtık container yönetim sistemleri, gelen request'ler için **load balancing** desteği sunarken aynı zamanda **container replication**'ını yönetmek için entegre mekanizmalara sahiptir. Hepsi **cluster seviyesinde**.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Geçmişi, Tasarımı ve Geleceği
|
||||
# Geçmişi, Tasarımı ve Geleceği { #history-design-and-future }
|
||||
|
||||
Bir süre önce, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">bir **FastAPI** kullanıcısı sordu</a>:
|
||||
|
||||
@@ -6,7 +6,7 @@ Bir süre önce, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomme
|
||||
|
||||
İşte o geçmişin bir kısmı.
|
||||
|
||||
## Alternatifler
|
||||
## Alternatifler { #alternatives }
|
||||
|
||||
Bir süredir karmaşık gereksinimlere sahip API'lar oluşturuyor (Makine Öğrenimi, dağıtık sistemler, asenkron işler, NoSQL veritabanları vb.) ve farklı geliştirici ekiplerini yönetiyorum.
|
||||
|
||||
@@ -28,7 +28,7 @@ Ancak bir noktada, geçmişteki diğer araçlardan en iyi fikirleri alarak büt
|
||||
|
||||
</blockquote>
|
||||
|
||||
## Araştırma
|
||||
## Araştırma { #investigation }
|
||||
|
||||
Önceki alternatifleri kullanarak hepsinden bir şeyler öğrenip, fikirler alıp, bunları kendim ve çalıştığım geliştirici ekipler için en iyi şekilde birleştirebilme şansım oldu.
|
||||
|
||||
@@ -38,7 +38,7 @@ Ayrıca, en iyi yaklaşım zaten mevcut olan standartları kullanmaktı.
|
||||
|
||||
Sonuç olarak, **FastAPI**'ı kodlamaya başlamadan önce, birkaç ay boyunca OpenAPI, JSON Schema, OAuth2 ve benzerlerinin tanımlamalarını inceledim. İlişkilerini, örtüştükleri noktaları ve farklılıklarını anlamaya çalıştım.
|
||||
|
||||
## Tasarım
|
||||
## Tasarım { #design }
|
||||
|
||||
Sonrasında, (**FastAPI** kullanan bir geliştirici olarak) sahip olmak istediğim "API"ı tasarlamak için biraz zaman harcadım.
|
||||
|
||||
@@ -52,7 +52,7 @@ Bu şekilde, kod tekrarını mümkün olduğunca azaltmak, her yerde <abbr title
|
||||
|
||||
Hepsi, tüm geliştiriciler için en iyi geliştirme deneyimini sağlayacak şekilde.
|
||||
|
||||
## Gereksinimler
|
||||
## Gereksinimler { #requirements }
|
||||
|
||||
Çeşitli alternatifleri test ettikten sonra, avantajlarından dolayı <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a>'i kullanmaya karar verdim.
|
||||
|
||||
@@ -60,11 +60,11 @@ Sonra, JSON Schema ile tamamen uyumlu olmasını sağlamak, kısıtlama bildirim
|
||||
|
||||
Geliştirme sırasında, diğer ana gereksinim olan <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>'e de katkıda bulundum.
|
||||
|
||||
## Geliştirme
|
||||
## Geliştirme { #development }
|
||||
|
||||
**FastAPI**'ı oluşturmaya başladığımda, parçaların çoğu zaten yerindeydi, tasarım tanımlanmıştı, gereksinimler ve araçlar hazırdı, standartlar ve tanımlamalar hakkındaki bilgi net ve tazeydi.
|
||||
|
||||
## Gelecek
|
||||
## Gelecek { #future }
|
||||
|
||||
Şimdiye kadar, **FastAPI**'ın fikirleriyle birçok kişiye faydalı olduğu apaçık ortada.
|
||||
|
||||
|
||||
11
docs/tr/docs/translation-banner.md
Normal file
11
docs/tr/docs/translation-banner.md
Normal file
@@ -0,0 +1,11 @@
|
||||
/// details | 🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri
|
||||
|
||||
Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝
|
||||
|
||||
Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖
|
||||
|
||||
[Yapay zekâyı daha iyi yönlendirmemize yardımcı olarak](https://fastapi.tiangolo.com/tr/contributing/#translations) bu çeviriyi iyileştirebilirsiniz.
|
||||
|
||||
[İngilizce sürüm](ENGLISH_VERSION_URL)
|
||||
|
||||
///
|
||||
@@ -103,13 +103,13 @@ Elbette ihtiyaç duyduğunuzda, body parametrelerine ek olarak query parametrele
|
||||
Varsayılan olarak tekil değerler query parametresi olarak yorumlandığı için, ayrıca `Query` eklemeniz gerekmez; şöyle yazmanız yeterlidir:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Ya da Python 3.10 ve üzeri için:
|
||||
Ya da Python 3.9'da:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Örneğin:
|
||||
|
||||
@@ -52,11 +52,11 @@ Bu durumlarda tag’leri bir `Enum` içinde tutmak mantıklı olabilir.
|
||||
|
||||
Bir `summary` ve `description` ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## Docstring’den Description { #description-from-docstring }
|
||||
|
||||
Açıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation - dokümantasyon için, fonksiyon içinde ilk ifade olarak yazılan (herhangi bir değişkene atanmayan) çok satırlı string">docstring</abbr> olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur.
|
||||
Açıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde <abbr title="dokümantasyon için, fonksiyon içinde ilk ifade olarak yazılan (herhangi bir değişkene atanmayan) çok satırlı string">docstring</abbr> olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur.
|
||||
|
||||
Docstring içinde <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> yazabilirsiniz; doğru şekilde yorumlanır ve gösterilir (docstring girintisi dikkate alınarak).
|
||||
|
||||
@@ -70,7 +70,7 @@ Interactive docs’ta şöyle kullanılacaktır:
|
||||
|
||||
`response_description` parametresi ile response açıklamasını belirtebilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
@@ -90,7 +90,7 @@ Bu yüzden siz sağlamazsanız, **FastAPI** otomatik olarak "Successful response
|
||||
|
||||
## Bir *path operation*’ı Deprecate Etmek { #deprecate-a-path-operation }
|
||||
|
||||
Bir *path operation*’ı kaldırmadan, <abbr title="obsolete, recommended not to use it - kullanım dışı, kullanılması önerilmez">deprecated</abbr> olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:
|
||||
Bir *path operation*’ı kaldırmadan, <abbr title="kullanım dışı, kullanılması önerilmez">deprecated</abbr> olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.128.3"
|
||||
__version__ = "0.128.1"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ from fastapi.logger import logger
|
||||
from fastapi.security.oauth2 import SecurityScopes
|
||||
from fastapi.types import DependencyCacheKey
|
||||
from fastapi.utils import create_model_field, get_path_param_names
|
||||
from pydantic import BaseModel, Json
|
||||
from pydantic import BaseModel
|
||||
from pydantic.fields import FieldInfo
|
||||
from starlette.background import BackgroundTasks as StarletteBackgroundTasks
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
@@ -66,7 +66,6 @@ from starlette.requests import HTTPConnection, Request
|
||||
from starlette.responses import Response
|
||||
from starlette.websockets import WebSocket
|
||||
from typing_extensions import Literal, get_args, get_origin
|
||||
from typing_inspection.typing_objects import is_typealiastype
|
||||
|
||||
multipart_not_installed_error = (
|
||||
'Form data requires "python-multipart" to be installed. \n'
|
||||
@@ -371,9 +370,6 @@ def analyze_param(
|
||||
depends = None
|
||||
type_annotation: Any = Any
|
||||
use_annotation: Any = Any
|
||||
if is_typealiastype(annotation):
|
||||
# unpack in case PEP 695 type syntax is used
|
||||
annotation = annotation.__value__
|
||||
if annotation is not inspect.Signature.empty:
|
||||
use_annotation = annotation
|
||||
type_annotation = annotation
|
||||
@@ -453,9 +449,7 @@ def analyze_param(
|
||||
depends = dataclasses.replace(depends, dependency=type_annotation)
|
||||
|
||||
# Handle non-param type annotations like Request
|
||||
# Only apply special handling when there's no explicit Depends - if there's a Depends,
|
||||
# the dependency will be called and its return value used instead of the special injection
|
||||
if depends is None and lenient_issubclass(
|
||||
if lenient_issubclass(
|
||||
type_annotation,
|
||||
(
|
||||
Request,
|
||||
@@ -466,6 +460,7 @@ def analyze_param(
|
||||
SecurityScopes,
|
||||
),
|
||||
):
|
||||
assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
|
||||
assert field_info is None, (
|
||||
f"Cannot specify FastAPI annotation for type {type_annotation!r}"
|
||||
)
|
||||
@@ -726,19 +721,11 @@ def _validate_value_with_model_field(
|
||||
return v_, []
|
||||
|
||||
|
||||
def _is_json_field(field: ModelField) -> bool:
|
||||
return any(type(item) is Json for item in field.field_info.metadata)
|
||||
|
||||
|
||||
def _get_multidict_value(
|
||||
field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None
|
||||
) -> Any:
|
||||
alias = alias or get_validation_alias(field)
|
||||
if (
|
||||
(not _is_json_field(field))
|
||||
and is_sequence_field(field)
|
||||
and isinstance(values, (ImmutableMultiDict, Headers))
|
||||
):
|
||||
if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
|
||||
value = values.getlist(alias)
|
||||
else:
|
||||
value = values.get(alias, None)
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
import contextlib
|
||||
import email.message
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import types
|
||||
from collections.abc import (
|
||||
AsyncIterator,
|
||||
Awaitable,
|
||||
Collection,
|
||||
Coroutine,
|
||||
Generator,
|
||||
Mapping,
|
||||
Sequence,
|
||||
)
|
||||
from contextlib import (
|
||||
AbstractAsyncContextManager,
|
||||
AbstractContextManager,
|
||||
AsyncExitStack,
|
||||
asynccontextmanager,
|
||||
)
|
||||
from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from enum import Enum, IntEnum
|
||||
from typing import (
|
||||
Annotated,
|
||||
Any,
|
||||
Callable,
|
||||
Optional,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
@@ -152,50 +143,6 @@ def websocket_session(
|
||||
return app
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
# Vendored from starlette.routing to avoid importing private symbols
|
||||
class _AsyncLiftContextManager(AbstractAsyncContextManager[_T]):
|
||||
"""
|
||||
Wraps a synchronous context manager to make it async.
|
||||
|
||||
This is vendored from Starlette to avoid importing private symbols.
|
||||
"""
|
||||
|
||||
def __init__(self, cm: AbstractContextManager[_T]) -> None:
|
||||
self._cm = cm
|
||||
|
||||
async def __aenter__(self) -> _T:
|
||||
return self._cm.__enter__()
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[type[BaseException]],
|
||||
exc_value: Optional[BaseException],
|
||||
traceback: Optional[types.TracebackType],
|
||||
) -> Optional[bool]:
|
||||
return self._cm.__exit__(exc_type, exc_value, traceback)
|
||||
|
||||
|
||||
# Vendored from starlette.routing to avoid importing private symbols
|
||||
def _wrap_gen_lifespan_context(
|
||||
lifespan_context: Callable[[Any], Generator[Any, Any, Any]],
|
||||
) -> Callable[[Any], AbstractAsyncContextManager[Any]]:
|
||||
"""
|
||||
Wrap a generator-based lifespan context into an async context manager.
|
||||
|
||||
This is vendored from Starlette to avoid importing private symbols.
|
||||
"""
|
||||
cmgr = contextlib.contextmanager(lifespan_context)
|
||||
|
||||
@functools.wraps(cmgr)
|
||||
def wrapper(app: Any) -> _AsyncLiftContextManager[Any]:
|
||||
return _AsyncLiftContextManager(cmgr(app))
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def _merge_lifespan_context(
|
||||
original_context: Lifespan[Any], nested_context: Lifespan[Any]
|
||||
) -> Lifespan[Any]:
|
||||
@@ -213,30 +160,6 @@ def _merge_lifespan_context(
|
||||
return merged_lifespan # type: ignore[return-value]
|
||||
|
||||
|
||||
class _DefaultLifespan:
|
||||
"""
|
||||
Default lifespan context manager that runs on_startup and on_shutdown handlers.
|
||||
|
||||
This is a copy of the Starlette _DefaultLifespan class that was removed
|
||||
in Starlette. FastAPI keeps it to maintain backward compatibility with
|
||||
on_startup and on_shutdown event handlers.
|
||||
|
||||
Ref: https://github.com/Kludex/starlette/pull/3117
|
||||
"""
|
||||
|
||||
def __init__(self, router: "APIRouter") -> None:
|
||||
self._router = router
|
||||
|
||||
async def __aenter__(self) -> None:
|
||||
await self._router._startup()
|
||||
|
||||
async def __aexit__(self, *exc_info: object) -> None:
|
||||
await self._router._shutdown()
|
||||
|
||||
def __call__(self: _T, app: object) -> _T:
|
||||
return self
|
||||
|
||||
|
||||
# Cache for endpoint context to avoid re-extracting on every request
|
||||
_endpoint_context_cache: dict[int, EndpointContext] = {}
|
||||
|
||||
@@ -980,33 +903,13 @@ class APIRouter(routing.Router):
|
||||
),
|
||||
] = Default(generate_unique_id),
|
||||
) -> None:
|
||||
# Handle on_startup/on_shutdown locally since Starlette removed support
|
||||
# Ref: https://github.com/Kludex/starlette/pull/3117
|
||||
# TODO: deprecate this once the lifespan (or alternative) interface is improved
|
||||
self.on_startup: list[Callable[[], Any]] = (
|
||||
[] if on_startup is None else list(on_startup)
|
||||
)
|
||||
self.on_shutdown: list[Callable[[], Any]] = (
|
||||
[] if on_shutdown is None else list(on_shutdown)
|
||||
)
|
||||
|
||||
# Determine the lifespan context to use
|
||||
if lifespan is None:
|
||||
# Use the default lifespan that runs on_startup/on_shutdown handlers
|
||||
lifespan_context: Lifespan[Any] = _DefaultLifespan(self)
|
||||
elif inspect.isasyncgenfunction(lifespan):
|
||||
lifespan_context = asynccontextmanager(lifespan)
|
||||
elif inspect.isgeneratorfunction(lifespan):
|
||||
lifespan_context = _wrap_gen_lifespan_context(lifespan)
|
||||
else:
|
||||
lifespan_context = lifespan
|
||||
self.lifespan_context = lifespan_context
|
||||
|
||||
super().__init__(
|
||||
routes=routes,
|
||||
redirect_slashes=redirect_slashes,
|
||||
default=default,
|
||||
lifespan=lifespan_context,
|
||||
on_startup=on_startup,
|
||||
on_shutdown=on_shutdown,
|
||||
lifespan=lifespan,
|
||||
)
|
||||
if prefix:
|
||||
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
||||
@@ -4570,58 +4473,6 @@ class APIRouter(routing.Router):
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
)
|
||||
|
||||
# TODO: remove this once the lifespan (or alternative) interface is improved
|
||||
async def _startup(self) -> None:
|
||||
"""
|
||||
Run any `.on_startup` event handlers.
|
||||
|
||||
This method is kept for backward compatibility after Starlette removed
|
||||
support for on_startup/on_shutdown handlers.
|
||||
|
||||
Ref: https://github.com/Kludex/starlette/pull/3117
|
||||
"""
|
||||
for handler in self.on_startup:
|
||||
if is_async_callable(handler):
|
||||
await handler()
|
||||
else:
|
||||
handler()
|
||||
|
||||
# TODO: remove this once the lifespan (or alternative) interface is improved
|
||||
async def _shutdown(self) -> None:
|
||||
"""
|
||||
Run any `.on_shutdown` event handlers.
|
||||
|
||||
This method is kept for backward compatibility after Starlette removed
|
||||
support for on_startup/on_shutdown handlers.
|
||||
|
||||
Ref: https://github.com/Kludex/starlette/pull/3117
|
||||
"""
|
||||
for handler in self.on_shutdown:
|
||||
if is_async_callable(handler):
|
||||
await handler()
|
||||
else:
|
||||
handler()
|
||||
|
||||
# TODO: remove this once the lifespan (or alternative) interface is improved
|
||||
def add_event_handler(
|
||||
self,
|
||||
event_type: str,
|
||||
func: Callable[[], Any],
|
||||
) -> None:
|
||||
"""
|
||||
Add an event handler function for startup or shutdown.
|
||||
|
||||
This method is kept for backward compatibility after Starlette removed
|
||||
support for on_startup/on_shutdown handlers.
|
||||
|
||||
Ref: https://github.com/Kludex/starlette/pull/3117
|
||||
"""
|
||||
assert event_type in ("startup", "shutdown")
|
||||
if event_type == "startup":
|
||||
self.on_startup.append(func)
|
||||
else:
|
||||
self.on_shutdown.append(func)
|
||||
|
||||
@deprecated(
|
||||
"""
|
||||
on_event is deprecated, use lifespan event handlers instead.
|
||||
|
||||
@@ -43,10 +43,9 @@ classifiers = [
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
]
|
||||
dependencies = [
|
||||
"starlette>=0.40.0,<1.0.0",
|
||||
"starlette>=0.40.0,<0.51.0",
|
||||
"pydantic>=2.7.0",
|
||||
"typing-extensions>=4.8.0",
|
||||
"typing-inspection>=0.4.2",
|
||||
"annotated-doc>=0.0.2",
|
||||
]
|
||||
|
||||
@@ -108,9 +107,9 @@ all = [
|
||||
# For Starlette's schema generation, would not be used with FastAPI
|
||||
"pyyaml >=5.3.1",
|
||||
# For UJSONResponse
|
||||
"ujson >=5.8.0",
|
||||
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
|
||||
# For ORJSONResponse
|
||||
"orjson >=3.9.3",
|
||||
"orjson >=3.2.1",
|
||||
# To validate email fields
|
||||
"email-validator >=2.0.0",
|
||||
# Uvicorn with uvloop
|
||||
@@ -129,62 +128,62 @@ dev = [
|
||||
{ include-group = "tests" },
|
||||
{ include-group = "docs" },
|
||||
{ include-group = "translations" },
|
||||
"playwright >=1.57.0",
|
||||
"prek >=0.2.22",
|
||||
"playwright>=1.57.0",
|
||||
"prek==0.2.22",
|
||||
]
|
||||
docs = [
|
||||
{ include-group = "docs-tests" },
|
||||
"black >=25.1.0",
|
||||
"cairosvg >=2.8.2",
|
||||
"griffe-typingdoc >=0.3.0",
|
||||
"griffe-warnings-deprecated >=1.1.0",
|
||||
"jieba >=0.42.1",
|
||||
"markdown-include-variants >=0.0.8",
|
||||
"mdx-include >=1.4.1,<2.0.0",
|
||||
"mkdocs-macros-plugin >=1.5.0",
|
||||
"mkdocs-material >=9.7.0",
|
||||
"mkdocs-redirects >=1.2.1,<1.3.0",
|
||||
"mkdocstrings[python] >=0.30.1",
|
||||
"pillow >=11.3.0",
|
||||
"python-slugify >=8.0.4",
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
"typer >=0.21.1",
|
||||
"black==25.1.0",
|
||||
"cairosvg==2.8.2",
|
||||
"griffe-typingdoc==0.3.0",
|
||||
"griffe-warnings-deprecated==1.1.0",
|
||||
"jieba==0.42.1",
|
||||
"markdown-include-variants==0.0.8",
|
||||
"mdx-include>=1.4.1,<2.0.0",
|
||||
"mkdocs-macros-plugin==1.5.0",
|
||||
"mkdocs-material==9.7.0",
|
||||
"mkdocs-redirects>=1.2.1,<1.3.0",
|
||||
"mkdocstrings[python]==0.30.1",
|
||||
"pillow==11.3.0",
|
||||
"python-slugify==8.0.4",
|
||||
"pyyaml>=5.3.1,<7.0.0",
|
||||
"typer==0.21.1",
|
||||
]
|
||||
docs-tests = [
|
||||
"httpx >=0.23.0,<1.0.0",
|
||||
"ruff >=0.14.14",
|
||||
"httpx>=0.23.0,<1.0.0",
|
||||
"ruff==0.14.14",
|
||||
]
|
||||
github-actions = [
|
||||
"httpx >=0.27.0,<1.0.0",
|
||||
"pydantic >=2.5.3,<3.0.0",
|
||||
"pydantic-settings >=2.1.0,<3.0.0",
|
||||
"pygithub >=2.3.0,<3.0.0",
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
"smokeshow >=0.5.0",
|
||||
"httpx>=0.27.0,<1.0.0",
|
||||
"pydantic>=2.5.3,<3.0.0",
|
||||
"pydantic-settings>=2.1.0,<3.0.0",
|
||||
"pygithub>=2.3.0,<3.0.0",
|
||||
"pyyaml>=5.3.1,<7.0.0",
|
||||
"smokeshow>=0.5.0",
|
||||
]
|
||||
tests = [
|
||||
{ include-group = "docs-tests" },
|
||||
"anyio[trio] >=3.2.1,<5.0.0",
|
||||
"coverage[toml] >=6.5.0,<8.0",
|
||||
"dirty-equals >=0.9.0",
|
||||
"flask >=3.0.0,<4.0.0",
|
||||
"inline-snapshot >=0.21.1",
|
||||
"mypy >=1.14.1",
|
||||
"pwdlib[argon2] >=0.2.1",
|
||||
"pyjwt >=2.9.0",
|
||||
"pytest >=7.1.3,<9.0.0",
|
||||
"pytest-codspeed >=4.2.0",
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
"sqlmodel >=0.0.31",
|
||||
"strawberry-graphql >=0.200.0,<1.0.0",
|
||||
"types-orjson >=3.6.2",
|
||||
"types-ujson >=5.10.0.20240515",
|
||||
"a2wsgi >=1.9.0,<=2.0.0",
|
||||
"anyio[trio]>=3.2.1,<5.0.0",
|
||||
"coverage[toml]>=6.5.0,<8.0",
|
||||
"dirty-equals==0.9.0",
|
||||
"flask>=1.1.2,<4.0.0",
|
||||
"inline-snapshot>=0.21.1",
|
||||
"mypy==1.14.1",
|
||||
"pwdlib[argon2]>=0.2.1",
|
||||
"pyjwt==2.9.0",
|
||||
"pytest>=7.1.3,<9.0.0",
|
||||
"pytest-codspeed==4.2.0",
|
||||
"pyyaml>=5.3.1,<7.0.0",
|
||||
"sqlmodel==0.0.31",
|
||||
"strawberry-graphql>=0.200.0,<1.0.0",
|
||||
"types-orjson==3.6.2",
|
||||
"types-ujson==5.10.0.20240515",
|
||||
"a2wsgi>=1.9.0,<=2.0.0",
|
||||
]
|
||||
translations = [
|
||||
"gitpython >=3.1.46",
|
||||
"pydantic-ai >=0.4.10",
|
||||
"pygithub >=2.8.1",
|
||||
"gitpython==3.1.46",
|
||||
"pydantic-ai==0.4.10",
|
||||
"pygithub==2.8.1",
|
||||
]
|
||||
|
||||
[tool.pdm]
|
||||
|
||||
@@ -23,7 +23,7 @@ SUPPORTED_LANGS = {
|
||||
"de",
|
||||
"en",
|
||||
"es",
|
||||
"fr",
|
||||
# "fr",
|
||||
"ja",
|
||||
"ko",
|
||||
"pt",
|
||||
@@ -31,7 +31,7 @@ SUPPORTED_LANGS = {
|
||||
"tr",
|
||||
"uk",
|
||||
# "zh",
|
||||
"zh-hant",
|
||||
# "zh-hant",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -347,12 +347,9 @@ def list_outdated(language: str) -> list[Path]:
|
||||
|
||||
|
||||
@app.command()
|
||||
def update_outdated(
|
||||
language: Annotated[str, typer.Option(envvar="LANGUAGE")],
|
||||
max: Annotated[int, typer.Option(envvar="MAX")] = 10,
|
||||
) -> None:
|
||||
def update_outdated(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
|
||||
outdated_paths = list_outdated(language)
|
||||
for path in outdated_paths[:max]:
|
||||
for path in outdated_paths:
|
||||
print(f"Updating lang: {language} path: {path}")
|
||||
translate_page(language=language, en_path=path)
|
||||
print(f"Done updating: {path}")
|
||||
@@ -360,12 +357,9 @@ def update_outdated(
|
||||
|
||||
|
||||
@app.command()
|
||||
def add_missing(
|
||||
language: Annotated[str, typer.Option(envvar="LANGUAGE")],
|
||||
max: Annotated[int, typer.Option(envvar="MAX")] = 10,
|
||||
) -> None:
|
||||
def add_missing(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
|
||||
missing_paths = list_missing(language)
|
||||
for path in missing_paths[:max]:
|
||||
for path in missing_paths:
|
||||
print(f"Adding lang: {language} path: {path}")
|
||||
translate_page(language=language, en_path=path)
|
||||
print(f"Done adding: {path}")
|
||||
@@ -373,14 +367,11 @@ def add_missing(
|
||||
|
||||
|
||||
@app.command()
|
||||
def update_and_add(
|
||||
language: Annotated[str, typer.Option(envvar="LANGUAGE")],
|
||||
max: Annotated[int, typer.Option(envvar="MAX")] = 10,
|
||||
) -> None:
|
||||
def update_and_add(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
|
||||
print(f"Updating outdated translations for {language}")
|
||||
update_outdated(language=language, max=max)
|
||||
update_outdated(language=language)
|
||||
print(f"Adding missing translations for {language}")
|
||||
add_missing(language=language, max=max)
|
||||
add_missing(language=language)
|
||||
print(f"Done updating and adding for {language}")
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from typing_extensions import TypeAliasType
|
||||
|
||||
|
||||
async def some_value() -> int:
|
||||
return 123
|
||||
|
||||
|
||||
DependedValue = TypeAliasType(
|
||||
"DependedValue", Annotated[int, Depends(some_value)], type_params=()
|
||||
)
|
||||
|
||||
|
||||
def test_pep695_type_dependencies():
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
async def get_with_dep(value: DependedValue) -> str: # noqa
|
||||
return f"value: {value}"
|
||||
|
||||
client = TestClient(app)
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
assert response.text == '"value: 123"'
|
||||
@@ -1,63 +0,0 @@
|
||||
import json
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Cookie, FastAPI, Form, Header, Query
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import Json
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.post("/form-json-list")
|
||||
def form_json_list(items: Annotated[Json[list[str]], Form()]) -> list[str]:
|
||||
return items
|
||||
|
||||
|
||||
@app.get("/query-json-list")
|
||||
def query_json_list(items: Annotated[Json[list[str]], Query()]) -> list[str]:
|
||||
return items
|
||||
|
||||
|
||||
@app.get("/header-json-list")
|
||||
def header_json_list(x_items: Annotated[Json[list[str]], Header()]) -> list[str]:
|
||||
return x_items
|
||||
|
||||
|
||||
@app.get("/cookie-json-list")
|
||||
def cookie_json_list(items: Annotated[Json[list[str]], Cookie()]) -> list[str]:
|
||||
return items
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_form_json_list():
|
||||
response = client.post(
|
||||
"/form-json-list", data={"items": json.dumps(["abc", "def"])}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == ["abc", "def"]
|
||||
|
||||
|
||||
def test_query_json_list():
|
||||
response = client.get(
|
||||
"/query-json-list", params={"items": json.dumps(["abc", "def"])}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == ["abc", "def"]
|
||||
|
||||
|
||||
def test_header_json_list():
|
||||
response = client.get(
|
||||
"/header-json-list", headers={"x-items": json.dumps(["abc", "def"])}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == ["abc", "def"]
|
||||
|
||||
|
||||
def test_cookie_json_list():
|
||||
client.cookies.set("items", json.dumps(["abc", "def"]))
|
||||
response = client.get("/cookie-json-list")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == ["abc", "def"]
|
||||
client.cookies.clear()
|
||||
@@ -1,173 +0,0 @@
|
||||
"""Test using special types (Response, Request, BackgroundTasks) as dependency annotations.
|
||||
|
||||
These tests verify that special FastAPI types can be used with Depends() annotations
|
||||
and that the dependency injection system properly handles them.
|
||||
"""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import BackgroundTasks, Depends, FastAPI, Request, Response
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
def test_response_with_depends_annotated():
|
||||
"""Response type hint should work with Annotated[Response, Depends(...)]."""
|
||||
app = FastAPI()
|
||||
|
||||
def modify_response(response: Response) -> Response:
|
||||
response.headers["X-Custom"] = "modified"
|
||||
return response
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(response: Annotated[Response, Depends(modify_response)]):
|
||||
return {"status": "ok"}
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"status": "ok"}
|
||||
assert resp.headers.get("X-Custom") == "modified"
|
||||
|
||||
|
||||
def test_response_with_depends_default():
|
||||
"""Response type hint should work with Response = Depends(...)."""
|
||||
app = FastAPI()
|
||||
|
||||
def modify_response(response: Response) -> Response:
|
||||
response.headers["X-Custom"] = "modified"
|
||||
return response
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(response: Response = Depends(modify_response)):
|
||||
return {"status": "ok"}
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"status": "ok"}
|
||||
assert resp.headers.get("X-Custom") == "modified"
|
||||
|
||||
|
||||
def test_response_without_depends():
|
||||
"""Regular Response injection should still work."""
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(response: Response):
|
||||
response.headers["X-Direct"] = "set"
|
||||
return {"status": "ok"}
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"status": "ok"}
|
||||
assert resp.headers.get("X-Direct") == "set"
|
||||
|
||||
|
||||
def test_response_dependency_chain():
|
||||
"""Response dependency should work in a chain of dependencies."""
|
||||
app = FastAPI()
|
||||
|
||||
def first_modifier(response: Response) -> Response:
|
||||
response.headers["X-First"] = "1"
|
||||
return response
|
||||
|
||||
def second_modifier(
|
||||
response: Annotated[Response, Depends(first_modifier)],
|
||||
) -> Response:
|
||||
response.headers["X-Second"] = "2"
|
||||
return response
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(response: Annotated[Response, Depends(second_modifier)]):
|
||||
return {"status": "ok"}
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.headers.get("X-First") == "1"
|
||||
assert resp.headers.get("X-Second") == "2"
|
||||
|
||||
|
||||
def test_response_dependency_returns_different_response_instance():
|
||||
"""Dependency that returns a different Response instance should work.
|
||||
|
||||
When a dependency returns a new Response object (e.g., JSONResponse) instead
|
||||
of modifying the injected one, the returned response should be used and any
|
||||
modifications to it in the endpoint should be preserved.
|
||||
"""
|
||||
app = FastAPI()
|
||||
|
||||
def default_response() -> Response:
|
||||
response = JSONResponse(content={"status": "ok"})
|
||||
response.headers["X-Custom"] = "initial"
|
||||
return response
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(response: Annotated[Response, Depends(default_response)]):
|
||||
response.headers["X-Custom"] = "modified"
|
||||
return response
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"status": "ok"}
|
||||
assert resp.headers.get("X-Custom") == "modified"
|
||||
|
||||
|
||||
# Tests for Request type hint with Depends
|
||||
def test_request_with_depends_annotated():
|
||||
"""Request type hint should work in dependency chain."""
|
||||
app = FastAPI()
|
||||
|
||||
def extract_request_info(request: Request) -> dict:
|
||||
return {
|
||||
"path": request.url.path,
|
||||
"user_agent": request.headers.get("user-agent", "unknown"),
|
||||
}
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(
|
||||
info: Annotated[dict, Depends(extract_request_info)],
|
||||
):
|
||||
return info
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/", headers={"user-agent": "test-agent"})
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {"path": "/", "user_agent": "test-agent"}
|
||||
|
||||
|
||||
# Tests for BackgroundTasks type hint with Depends
|
||||
def test_background_tasks_with_depends_annotated():
|
||||
"""BackgroundTasks type hint should work with Annotated[BackgroundTasks, Depends(...)]."""
|
||||
app = FastAPI()
|
||||
task_results = []
|
||||
|
||||
def background_task(message: str):
|
||||
task_results.append(message)
|
||||
|
||||
def add_background_task(background_tasks: BackgroundTasks) -> BackgroundTasks:
|
||||
background_tasks.add_task(background_task, "from dependency")
|
||||
return background_tasks
|
||||
|
||||
@app.get("/")
|
||||
def endpoint(
|
||||
background_tasks: Annotated[BackgroundTasks, Depends(add_background_task)],
|
||||
):
|
||||
background_tasks.add_task(background_task, "from endpoint")
|
||||
return {"status": "ok"}
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert "from dependency" in task_results
|
||||
assert "from endpoint" in task_results
|
||||
@@ -241,79 +241,3 @@ def test_merged_mixed_state_lifespans() -> None:
|
||||
|
||||
with TestClient(app) as client:
|
||||
assert client.app_state == {"router": True}
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings(
|
||||
r"ignore:\s*on_event is deprecated, use lifespan event handlers instead.*:DeprecationWarning"
|
||||
)
|
||||
def test_router_async_shutdown_handler(state: State) -> None:
|
||||
"""Test that async on_shutdown event handlers are called correctly, for coverage."""
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
def main() -> dict[str, str]:
|
||||
return {"message": "Hello World"}
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def app_shutdown() -> None:
|
||||
state.app_shutdown = True
|
||||
|
||||
assert state.app_shutdown is False
|
||||
with TestClient(app) as client:
|
||||
assert state.app_shutdown is False
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200, response.text
|
||||
assert state.app_shutdown is True
|
||||
|
||||
|
||||
def test_router_sync_generator_lifespan(state: State) -> None:
|
||||
"""Test that a sync generator lifespan works via _wrap_gen_lifespan_context."""
|
||||
from collections.abc import Generator
|
||||
|
||||
def lifespan(app: FastAPI) -> Generator[None, None, None]:
|
||||
state.app_startup = True
|
||||
yield
|
||||
state.app_shutdown = True
|
||||
|
||||
app = FastAPI(lifespan=lifespan) # type: ignore[arg-type]
|
||||
|
||||
@app.get("/")
|
||||
def main() -> dict[str, str]:
|
||||
return {"message": "Hello World"}
|
||||
|
||||
assert state.app_startup is False
|
||||
assert state.app_shutdown is False
|
||||
with TestClient(app) as client:
|
||||
assert state.app_startup is True
|
||||
assert state.app_shutdown is False
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Hello World"}
|
||||
assert state.app_startup is True
|
||||
assert state.app_shutdown is True
|
||||
|
||||
|
||||
def test_router_async_generator_lifespan(state: State) -> None:
|
||||
"""Test that an async generator lifespan (not wrapped) works."""
|
||||
|
||||
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
state.app_startup = True
|
||||
yield
|
||||
state.app_shutdown = True
|
||||
|
||||
app = FastAPI(lifespan=lifespan) # type: ignore[arg-type]
|
||||
|
||||
@app.get("/")
|
||||
def main() -> dict[str, str]:
|
||||
return {"message": "Hello World"}
|
||||
|
||||
assert state.app_startup is False
|
||||
assert state.app_shutdown is False
|
||||
with TestClient(app) as client:
|
||||
assert state.app_startup is True
|
||||
assert state.app_shutdown is False
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Hello World"}
|
||||
assert state.app_startup is True
|
||||
assert state.app_shutdown is True
|
||||
|
||||
Reference in New Issue
Block a user