Sync fastapi docs from 11614be9 on 2026-03-11
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
# LLM test dosyası { #llm-test-file }
|
||||
|
||||
Bu doküman, dokümantasyonu çeviren <abbr title="Large Language Model - Büyük Dil Modeli">LLM</abbr>'nin `scripts/translate.py` içindeki `general_prompt`'u ve `docs/{language code}/llm-prompt.md` içindeki dile özel prompt'u anlayıp anlamadığını test eder. Dile özel prompt, `general_prompt`'a eklenir.
|
||||
|
||||
Buraya eklenen testler, dile özel prompt'ları tasarlayan herkes tarafından görülecektir.
|
||||
|
||||
Şu şekilde kullanın:
|
||||
|
||||
* Dile özel bir prompt bulundurun: `docs/{language code}/llm-prompt.md`.
|
||||
* Bu dokümanın hedeflediğiniz dile sıfırdan yeni bir çevirisini yapın (örneğin `translate.py` içindeki `translate-page` komutu). Bu, çeviriyi `docs/{language code}/docs/_llm-test.md` altında oluşturur.
|
||||
* Çeviride her şeyin yolunda olup olmadığını kontrol edin.
|
||||
* Gerekirse dile özel prompt'u, genel prompt'u veya İngilizce dokümanı iyileştirin.
|
||||
* Ardından çeviride kalan sorunları elle düzeltin; böylece iyi bir çeviri elde edin.
|
||||
* İyi çeviri yerindeyken yeniden çeviri yapın. İdeal sonuç, LLM'nin artık çeviride hiçbir değişiklik yapmamasıdır. Bu da genel prompt'un ve dile özel prompt'un olabilecek en iyi hâle geldiği anlamına gelir (bazen rastgele gibi görünen birkaç değişiklik yapabilir; çünkü <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM'ler deterministik algoritmalar değildir</a>).
|
||||
|
||||
Testler:
|
||||
|
||||
## Code snippets { #code-snippets }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Bu bir code snippet: `foo`. Bu da başka bir code snippet: `bar`. Bir tane daha: `baz quux`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Code snippet'lerin içeriği olduğu gibi bırakılmalıdır.
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Alıntılar { #quotes }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Dün bir arkadaşım şunu yazdı: "If you spell incorrectly correctly, you have spelled it incorrectly". Ben de şunu yanıtladım: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'".
|
||||
|
||||
/// note | Not
|
||||
|
||||
LLM muhtemelen bunu yanlış çevirecektir. Yeniden çeviri yapıldığında düzeltilmiş çeviriyi koruyup korumadığı önemlidir.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Prompt tasarlayan kişi, düz tırnakları tipografik tırnaklara dönüştürüp dönüştürmemeyi seçebilir. Olduğu gibi bırakmak da uygundur.
|
||||
|
||||
Örneğin `docs/de/llm-prompt.md` içindeki `### Quotes` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Code snippet'lerde alıntılar { #quotes-in-code-snippets }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
`pip install "foo[bar]"`
|
||||
|
||||
Code snippet'lerde string literal örnekleri: `"this"`, `'that'`.
|
||||
|
||||
Code snippet'lerde string literal için zor bir örnek: `f"I like {'oranges' if orange else "apples"}"`
|
||||
|
||||
Hardcore: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
... Ancak code snippet'lerin içindeki tırnaklar olduğu gibi kalmalıdır.
|
||||
|
||||
////
|
||||
|
||||
## Code block'lar { #code-blocks }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Bir Bash code örneği...
|
||||
|
||||
```bash
|
||||
# Evrene bir selam yazdır
|
||||
echo "Hello universe"
|
||||
```
|
||||
|
||||
...ve bir console code örneği...
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting server
|
||||
Searching for package file structure
|
||||
```
|
||||
|
||||
...ve bir başka console code örneği...
|
||||
|
||||
```console
|
||||
// "Code" adında bir dizin oluştur
|
||||
$ mkdir code
|
||||
// O dizine geç
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...ve bir Python code örneği...
|
||||
|
||||
```Python
|
||||
wont_work() # This won't work 😱
|
||||
works(foo="bar") # This works 🎉
|
||||
```
|
||||
|
||||
...ve hepsi bu.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Code block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır (comments).
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Sekmeler ve renkli kutular { #tabs-and-colored-boxes }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
/// info | Bilgi
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// note | Not
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// check | Ek bilgi
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
/// danger | Tehlike
|
||||
Bazı metin
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Sekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir.
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın.
|
||||
|
||||
////
|
||||
|
||||
## Web ve internal link'ler { #web-and-internal-links }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Link metni çevrilmelidir, link adresi değişmeden kalmalıdır:
|
||||
|
||||
* [Yukarıdaki başlığa link](#code-snippets)
|
||||
* [Internal link](index.md#installation){.internal-link target=_blank}
|
||||
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">Harici link</a>
|
||||
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">Bir stile bağlantı</a>
|
||||
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">Bir betiğe bağlantı</a>
|
||||
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">Bir görsele bağlantı</a>
|
||||
|
||||
Link metni çevrilmelidir, link adresi çeviriye işaret etmelidir:
|
||||
|
||||
* <a href="https://fastapi.tiangolo.com/tr/" class="external-link" target="_blank">FastAPI link</a>
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Link'ler çevrilmelidir, ancak adresleri değişmeden kalmalıdır. Bir istisna, FastAPI dokümantasyonunun sayfalarına verilen mutlak link'lerdir. Bu durumda link, çeviriye işaret etmelidir.
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## HTML "abbr" öğeleri { #html-abbr-elements }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
Burada HTML "abbr" öğeleriyle sarılmış bazı şeyler var (bazıları uydurma):
|
||||
|
||||
### abbr tam bir ifade verir { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done - İşleri Bitirme">GTD</abbr>
|
||||
* <abbr title="less than - küçüktür"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Paralel Sunucu Gateway Interface">PSGI</abbr>
|
||||
|
||||
### abbr tam bir ifade ve bir açıklama verir { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Mozilla Geliştirici Ağı: Firefox ekibi tarafından yazılmış, geliştiricilere yönelik dokümantasyon">MDN</abbr>
|
||||
* <abbr title="Input/Output - Girdi/Çıktı: disk okuma ya da yazma, ağ iletişimi.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
"abbr" öğelerinin "title" attribute'ları belirli talimatlara göre çevrilir.
|
||||
|
||||
Çeviriler, LLM'nin kaldırmaması gereken kendi "abbr" öğelerini ekleyebilir. Örneğin İngilizce kelimeleri açıklamak için.
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## HTML "dfn" öğeleri { #html-dfn-elements }
|
||||
|
||||
* <dfn title="Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makinelerden oluşan bir grup.">küme</dfn>
|
||||
* <dfn title="Girdi ve çıktı katmanları arasında çok sayıda gizli katman içeren yapay sinir ağlarını kullanan; böylece kapsamlı bir iç yapı geliştiren bir makine öğrenmesi yöntemi">Derin Öğrenme</dfn>
|
||||
|
||||
## Başlıklar { #headings }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
### Bir web uygulaması geliştirin - bir öğretici { #develop-a-webapp-a-tutorial }
|
||||
|
||||
Merhaba.
|
||||
|
||||
### Type hint'ler ve -annotation'lar { #type-hints-and-annotations }
|
||||
|
||||
Tekrar merhaba.
|
||||
|
||||
### Super- ve subclass'lar { #super-and-subclasses }
|
||||
|
||||
Tekrar merhaba.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Başlıklarla ilgili tek katı kural, LLM'nin süslü parantezler içindeki hash kısmını değiştirmemesidir; böylece link'ler bozulmaz.
|
||||
|
||||
`scripts/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın.
|
||||
|
||||
Dile özel bazı talimatlar için örneğin `docs/de/llm-prompt.md` içindeki `### Headings` bölümüne bakın.
|
||||
|
||||
////
|
||||
|
||||
## Dokümanlarda kullanılan terimler { #terms-used-in-the-docs }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
* siz
|
||||
* sizin
|
||||
|
||||
* örn.
|
||||
* vb.
|
||||
|
||||
* `foo` bir `int` olarak
|
||||
* `bar` bir `str` olarak
|
||||
* `baz` bir `list` olarak
|
||||
|
||||
* Tutorial - Kullanıcı kılavuzu
|
||||
* İleri Düzey Kullanıcı Kılavuzu
|
||||
* SQLModel dokümanları
|
||||
* API dokümanları
|
||||
* otomatik dokümanlar
|
||||
|
||||
* Veri Bilimi
|
||||
* Deep Learning
|
||||
* Machine Learning
|
||||
* Dependency Injection
|
||||
* HTTP Basic authentication
|
||||
* HTTP Digest
|
||||
* ISO formatı
|
||||
* JSON Schema standardı
|
||||
* JSON schema
|
||||
* schema tanımı
|
||||
* Password Flow
|
||||
* Mobil
|
||||
|
||||
* deprecated
|
||||
* designed
|
||||
* invalid
|
||||
* on the fly
|
||||
* standard
|
||||
* default
|
||||
* case-sensitive
|
||||
* case-insensitive
|
||||
|
||||
* uygulamayı serve etmek
|
||||
* sayfayı serve etmek
|
||||
|
||||
* app
|
||||
* application
|
||||
|
||||
* request
|
||||
* response
|
||||
* error response
|
||||
|
||||
* path operation
|
||||
* path operation decorator
|
||||
* path operation function
|
||||
|
||||
* body
|
||||
* request body
|
||||
* response body
|
||||
* JSON body
|
||||
* form body
|
||||
* file body
|
||||
* function body
|
||||
|
||||
* parameter
|
||||
* body parameter
|
||||
* path parameter
|
||||
* query parameter
|
||||
* cookie parameter
|
||||
* header parameter
|
||||
* form parameter
|
||||
* function parameter
|
||||
|
||||
* event
|
||||
* startup event
|
||||
* server'ın startup'ı
|
||||
* shutdown event
|
||||
* lifespan event
|
||||
|
||||
* handler
|
||||
* event handler
|
||||
* exception handler
|
||||
* handle etmek
|
||||
|
||||
* model
|
||||
* Pydantic model
|
||||
* data model
|
||||
* database model
|
||||
* form model
|
||||
* model object
|
||||
|
||||
* class
|
||||
* base class
|
||||
* parent class
|
||||
* subclass
|
||||
* child class
|
||||
* sibling class
|
||||
* class method
|
||||
|
||||
* header
|
||||
* headers
|
||||
* authorization header
|
||||
* `Authorization` header
|
||||
* forwarded header
|
||||
|
||||
* dependency injection system
|
||||
* dependency
|
||||
* dependable
|
||||
* dependant
|
||||
|
||||
* I/O bound
|
||||
* CPU bound
|
||||
* concurrency
|
||||
* parallelism
|
||||
* multiprocessing
|
||||
|
||||
* env var
|
||||
* environment variable
|
||||
* `PATH`
|
||||
* `PATH` variable
|
||||
|
||||
* authentication
|
||||
* authentication provider
|
||||
* authorization
|
||||
* authorization form
|
||||
* authorization provider
|
||||
* kullanıcı authenticate olur
|
||||
* sistem kullanıcıyı authenticate eder
|
||||
|
||||
* CLI
|
||||
* command line interface
|
||||
|
||||
* server
|
||||
* client
|
||||
|
||||
* cloud provider
|
||||
* cloud service
|
||||
|
||||
* geliştirme
|
||||
* geliştirme aşamaları
|
||||
|
||||
* dict
|
||||
* dictionary
|
||||
* enumeration
|
||||
* enum
|
||||
* enum member
|
||||
|
||||
* encoder
|
||||
* decoder
|
||||
* encode etmek
|
||||
* decode etmek
|
||||
|
||||
* exception
|
||||
* raise etmek
|
||||
|
||||
* expression
|
||||
* statement
|
||||
|
||||
* frontend
|
||||
* backend
|
||||
|
||||
* GitHub discussion
|
||||
* GitHub issue
|
||||
|
||||
* performance
|
||||
* performance optimization
|
||||
|
||||
* return type
|
||||
* return value
|
||||
|
||||
* security
|
||||
* security scheme
|
||||
|
||||
* task
|
||||
* background task
|
||||
* task function
|
||||
|
||||
* template
|
||||
* template engine
|
||||
|
||||
* type annotation
|
||||
* type hint
|
||||
|
||||
* server worker
|
||||
* Uvicorn worker
|
||||
* Gunicorn Worker
|
||||
* worker process
|
||||
* worker class
|
||||
* workload
|
||||
|
||||
* deployment
|
||||
* deploy etmek
|
||||
|
||||
* SDK
|
||||
* software development kit
|
||||
|
||||
* `APIRouter`
|
||||
* `requirements.txt`
|
||||
* Bearer Token
|
||||
* breaking change
|
||||
* bug
|
||||
* button
|
||||
* callable
|
||||
* code
|
||||
* commit
|
||||
* context manager
|
||||
* coroutine
|
||||
* database session
|
||||
* disk
|
||||
* domain
|
||||
* engine
|
||||
* fake X
|
||||
* HTTP GET method
|
||||
* item
|
||||
* library
|
||||
* lifespan
|
||||
* lock
|
||||
* middleware
|
||||
* mobile application
|
||||
* module
|
||||
* mounting
|
||||
* network
|
||||
* origin
|
||||
* override
|
||||
* payload
|
||||
* processor
|
||||
* property
|
||||
* proxy
|
||||
* pull request
|
||||
* query
|
||||
* RAM
|
||||
* remote machine
|
||||
* status code
|
||||
* string
|
||||
* tag
|
||||
* web framework
|
||||
* wildcard
|
||||
* return etmek
|
||||
* validate etmek
|
||||
|
||||
////
|
||||
|
||||
//// tab | Bilgi
|
||||
|
||||
Bu, dokümanlarda görülen (çoğunlukla) teknik terimlerin eksiksiz ve normatif olmayan bir listesidir. Prompt tasarlayan kişi için, LLM'nin hangi terimlerde desteğe ihtiyaç duyduğunu anlamada yardımcı olabilir. Örneğin iyi bir çeviriyi sürekli daha zayıf bir çeviriye geri alıyorsa. Ya da sizin dilinizde bir terimi çekimlemekte (conjugating/declinating) zorlanıyorsa.
|
||||
|
||||
Örneğin `docs/de/llm-prompt.md` içindeki `### List of English terms and their preferred German translations` bölümüne bakın.
|
||||
|
||||
////
|
||||
@@ -1,3 +1,3 @@
|
||||
# Hakkında
|
||||
# Hakkında { #about }
|
||||
|
||||
FastAPI, tasarımı, ilham kaynağı ve daha fazlası hakkında. 🤓
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
# OpenAPI'de Ek Response'lar { #additional-responses-in-openapi }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu konu oldukça ileri seviye bir konudur.
|
||||
|
||||
**FastAPI**'ye yeni başlıyorsanız buna ihtiyaç duymayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Ek status code'lar, media type'lar, açıklamalar vb. ile ek response'lar tanımlayabilirsiniz.
|
||||
|
||||
Bu ek response'lar OpenAPI şemasına dahil edilir; dolayısıyla API dokümanlarında da görünürler.
|
||||
|
||||
Ancak bu ek response'lar için, status code'unuzu ve içeriğinizi vererek `JSONResponse` gibi bir `Response`'u doğrudan döndürdüğünüzden emin olmanız gerekir.
|
||||
|
||||
## `model` ile Ek Response { #additional-response-with-model }
|
||||
|
||||
*Path operation decorator*'larınıza `responses` adlı bir parametre geçebilirsiniz.
|
||||
|
||||
Bu parametre bir `dict` alır: anahtarlar her response için status code'lardır (`200` gibi), değerler ise her birine ait bilgileri içeren başka `dict`'lerdir.
|
||||
|
||||
Bu response `dict`'lerinin her birinde, `response_model`'e benzer şekilde bir Pydantic model içeren `model` anahtarı olabilir.
|
||||
|
||||
**FastAPI** bu modeli alır, JSON Schema'sını üretir ve OpenAPI'de doğru yere ekler.
|
||||
|
||||
Örneğin, `404` status code'u ve `Message` Pydantic model'i ile başka bir response tanımlamak için şunu yazabilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
`JSONResponse`'u doğrudan döndürmeniz gerektiğini unutmayın.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`model` anahtarı OpenAPI'nin bir parçası değildir.
|
||||
|
||||
**FastAPI** buradaki Pydantic model'i alır, JSON Schema'yı üretir ve doğru yere yerleştirir.
|
||||
|
||||
Doğru yer şurasıdır:
|
||||
|
||||
* Değeri başka bir JSON nesnesi (`dict`) olan `content` anahtarının içinde:
|
||||
* Media type anahtarı (örn. `application/json`) bulunur; bunun değeri başka bir JSON nesnesidir ve onun içinde:
|
||||
* Değeri model'den gelen JSON Schema olan `schema` anahtarı vardır; doğru yer burasıdır.
|
||||
* **FastAPI** bunu doğrudan gömmek yerine OpenAPI'deki başka bir yerde bulunan global JSON Schema'lara bir referans ekler. Böylece diğer uygulamalar ve client'lar bu JSON Schema'ları doğrudan kullanabilir, daha iyi code generation araçları sağlayabilir, vb.
|
||||
|
||||
///
|
||||
|
||||
Bu *path operation* için OpenAPI'de üretilen response'lar şöyle olur:
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Additional Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Schema'lar OpenAPI şemasının içinde başka bir yere referanslanır:
|
||||
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Message": {
|
||||
"title": "Message",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": [
|
||||
"id",
|
||||
"value"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"title": "Id",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"title": "Value",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"msg": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"title": "Error Type",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Ana Response İçin Ek Media Type'lar { #additional-media-types-for-the-main-response }
|
||||
|
||||
Aynı `responses` parametresini, aynı ana response için farklı media type'lar eklemek amacıyla da kullanabilirsiniz.
|
||||
|
||||
Örneğin, `image/png` için ek bir media type ekleyerek, *path operation*'ınızın bir JSON nesnesi (media type `application/json`) ya da bir PNG görseli döndürebildiğini belirtebilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Görseli `FileResponse` kullanarak doğrudan döndürmeniz gerektiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`responses` parametrenizde açıkça farklı bir media type belirtmediğiniz sürece FastAPI, response'un ana response class'ı ile aynı media type'a sahip olduğunu varsayar (varsayılan `application/json`).
|
||||
|
||||
Ancak media type'ı `None` olan özel bir response class belirttiyseniz, FastAPI ilişkili bir model'i olan tüm ek response'lar için `application/json` kullanır.
|
||||
|
||||
///
|
||||
|
||||
## Bilgileri Birleştirme { #combining-information }
|
||||
|
||||
`response_model`, `status_code` ve `responses` parametreleri dahil olmak üzere, response bilgilerini birden fazla yerden birleştirebilirsiniz.
|
||||
|
||||
Varsayılan `200` status code'unu (ya da gerekiyorsa özel bir tane) kullanarak bir `response_model` tanımlayabilir, ardından aynı response için ek bilgileri `responses` içinde, doğrudan OpenAPI şemasına ekleyebilirsiniz.
|
||||
|
||||
**FastAPI**, `responses` içindeki ek bilgileri korur ve model'inizin JSON Schema'sı ile birleştirir.
|
||||
|
||||
Örneğin, Pydantic model kullanan ve özel bir `description` içeren `404` status code'lu bir response tanımlayabilirsiniz.
|
||||
|
||||
Ayrıca `response_model`'inizi kullanan, ancak özel bir `example` içeren `200` status code'lu bir response da tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
|
||||
|
||||
Bunların hepsi OpenAPI'nize birleştirilerek dahil edilir ve API dokümanlarında gösterilir:
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
## Ön Tanımlı Response'ları Özel Olanlarla Birleştirme { #combine-predefined-responses-and-custom-ones }
|
||||
|
||||
Birçok *path operation* için geçerli olacak bazı ön tanımlı response'larınız olabilir; ancak bunları her *path operation*'ın ihtiyaç duyduğu özel response'larla birleştirmek isteyebilirsiniz.
|
||||
|
||||
Bu durumlarda, Python'daki bir `dict`'i `**dict_to_unpack` ile "unpacking" tekniğini kullanabilirsiniz:
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
}
|
||||
new_dict = {**old_dict, "new key": "new value"}
|
||||
```
|
||||
|
||||
Burada `new_dict`, `old_dict` içindeki tüm key-value çiftlerini ve buna ek olarak yeni key-value çiftini içerir:
|
||||
|
||||
```Python
|
||||
{
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
"new key": "new value",
|
||||
}
|
||||
```
|
||||
|
||||
Bu tekniği, *path operation*'larınızda bazı ön tanımlı response'ları yeniden kullanmak ve bunları ek özel response'larla birleştirmek için kullanabilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
|
||||
## OpenAPI Response'ları Hakkında Daha Fazla Bilgi { #more-information-about-openapi-responses }
|
||||
|
||||
Response'ların içine tam olarak neleri dahil edebileceğinizi görmek için OpenAPI spesifikasyonundaki şu bölümlere bakabilirsiniz:
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">OpenAPI Responses Object</a>, `Response Object`'i içerir.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">OpenAPI Response Object</a>, buradaki her şeyi `responses` parametreniz içinde, her bir response'un içine doğrudan ekleyebilirsiniz. Buna `description`, `headers`, `content` (bunun içinde farklı media type'lar ve JSON Schema'lar tanımlarsınız) ve `links` dahildir.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Ek Status Code'ları { #additional-status-codes }
|
||||
|
||||
Varsayılan olarak **FastAPI**, response'ları bir `JSONResponse` kullanarak döndürür; *path operation*'ınızdan döndürdüğünüz içeriği bu `JSONResponse`'un içine yerleştirir.
|
||||
|
||||
Varsayılan status code'u veya *path operation* içinde sizin belirlediğiniz status code'u kullanır.
|
||||
|
||||
## Ek status code'ları { #additional-status-codes_1 }
|
||||
|
||||
Ana status code'a ek olarak başka status code'lar da döndürmek istiyorsanız, `JSONResponse` gibi bir `Response`'u doğrudan döndürerek bunu yapabilirsiniz ve ek status code'u doğrudan orada ayarlarsınız.
|
||||
|
||||
Örneğin, item'ları güncellemeye izin veren bir *path operation*'ınız olduğunu düşünelim; başarılı olduğunda 200 "OK" HTTP status code'unu döndürüyor olsun.
|
||||
|
||||
Ancak yeni item'ları da kabul etmesini istiyorsunuz. Ve item daha önce yoksa, onu oluşturup 201 "Created" HTTP status code'unu döndürsün.
|
||||
|
||||
Bunu yapmak için `JSONResponse` import edin ve içeriğinizi doğrudan onunla döndürün; istediğiniz `status_code`'u da ayarlayın:
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Yukarıdaki örnekte olduğu gibi bir `Response`'u doğrudan döndürdüğünüzde, response aynen olduğu gibi döndürülür.
|
||||
|
||||
Bir model ile serialize edilmez, vb.
|
||||
|
||||
İçinde olmasını istediğiniz veriyi taşıdığından emin olun ve değerlerin geçerli JSON olduğundan emin olun (eğer `JSONResponse` kullanıyorsanız).
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` altında da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `status` için de aynı durum geçerlidir.
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI ve API docs { #openapi-and-api-docs }
|
||||
|
||||
Ek status code'ları ve response'ları doğrudan döndürürseniz, FastAPI sizin ne döndüreceğinizi önceden bilemeyeceği için bunlar OpenAPI şemasına (API docs) dahil edilmez.
|
||||
|
||||
Ancak bunu kodunuzda şu şekilde dokümante edebilirsiniz: [Ek Response'lar](additional-responses.md){.internal-link target=_blank}.
|
||||
@@ -0,0 +1,163 @@
|
||||
# Gelişmiş Dependency'ler { #advanced-dependencies }
|
||||
|
||||
## Parametreli dependency'ler { #parameterized-dependencies }
|
||||
|
||||
Şimdiye kadar gördüğümüz tüm dependency'ler sabit bir function ya da class idi.
|
||||
|
||||
Ancak, birçok farklı function veya class tanımlamak zorunda kalmadan, dependency üzerinde bazı parametreler ayarlamak isteyebileceğiniz durumlar olabilir.
|
||||
|
||||
Örneğin, query parametresi `q`'nun belirli bir sabit içeriği barındırıp barındırmadığını kontrol eden bir dependency istediğimizi düşünelim.
|
||||
|
||||
Ama bu sabit içeriği parametreleştirebilmek istiyoruz.
|
||||
|
||||
## "Callable" bir instance { #a-callable-instance }
|
||||
|
||||
Python'da bir class'ın instance'ını "callable" yapmanın bir yolu vardır.
|
||||
|
||||
Class'ın kendisini değil (zaten callable'dır), o class'ın bir instance'ını.
|
||||
|
||||
Bunu yapmak için `__call__` adında bir method tanımlarız:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
|
||||
|
||||
Bu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAPI**'nin kullanacağı şey bu `__call__` olacaktır; ayrıca daha sonra *path operation function* içindeki parametreye bir değer geçmek için çağrılacak olan da budur.
|
||||
|
||||
## Instance'ı parametreleştirme { #parameterize-the-instance }
|
||||
|
||||
Ve şimdi, dependency'yi "parametreleştirmek" için kullanacağımız instance parametrelerini tanımlamak üzere `__init__` kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
Bu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu doğrudan kendi kodumuzda kullanırız.
|
||||
|
||||
## Bir instance oluşturma { #create-an-instance }
|
||||
|
||||
Bu class'tan bir instance'ı şöyle oluşturabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
Böylece dependency'mizi "parametreleştirmiş" oluruz; artık içinde `"bar"` vardır ve bu değer `checker.fixed_content` attribute'u olarak durur.
|
||||
|
||||
## Instance'ı dependency olarak kullanma { #use-the-instance-as-a-dependency }
|
||||
|
||||
Sonra `Depends(FixedContentQueryChecker)` yerine `Depends(checker)` içinde bu `checker`'ı kullanabiliriz. Çünkü dependency, class'ın kendisi değil, `checker` instance'ıdır.
|
||||
|
||||
Ve dependency çözülürken **FastAPI** bu `checker`'ı şöyle çağırır:
|
||||
|
||||
```Python
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
...ve bunun döndürdüğü her şeyi, *path operation function* içinde `fixed_content_included` parametresine dependency değeri olarak geçirir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bunların tamamı biraz yapay görünebilir. Ayrıca bunun nasıl faydalı olduğu da henüz çok net olmayabilir.
|
||||
|
||||
Bu örnekler bilerek basit tutuldu; ama mekanizmanın nasıl çalıştığını gösteriyor.
|
||||
|
||||
Security bölümlerinde, aynı şekilde implement edilmiş yardımcı function'lar bulunuyor.
|
||||
|
||||
Buradaki her şeyi anladıysanız, security için kullanılan bu yardımcı araçların arka planda nasıl çalıştığını da zaten biliyorsunuz demektir.
|
||||
|
||||
///
|
||||
|
||||
## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Büyük ihtimalle bu teknik detaylara ihtiyacınız yok.
|
||||
|
||||
Bu detaylar, özellikle 0.121.0'dan eski bir FastAPI uygulamanız varsa ve `yield` kullanan dependency'lerle ilgili sorunlar yaşıyorsanız faydalıdır.
|
||||
|
||||
///
|
||||
|
||||
`yield` kullanan dependency'ler; farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için zaman içinde evrildi. Aşağıda nelerin değiştiğinin bir özeti var.
|
||||
|
||||
### `yield` ve `scope` ile dependency'ler { #dependencies-with-yield-and-scope }
|
||||
|
||||
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ı [`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 }
|
||||
|
||||
FastAPI 0.118.0 öncesinde, `yield` kullanan bir dependency kullanırsanız, *path operation function* döndükten sonra ama response gönderilmeden hemen önce `yield` sonrasındaki çıkış kodu çalıştırılırdı.
|
||||
|
||||
Amaç, response'un ağ üzerinden taşınmasını beklerken gereğinden uzun süre resource tutmaktan kaçınmaktı.
|
||||
|
||||
Bu değişiklik aynı zamanda şunu da ifade ediyordu: `StreamingResponse` döndürürseniz, `yield` kullanan dependency'nin çıkış kodu zaten çalışmış olurdu.
|
||||
|
||||
Örneğin, `yield` kullanan bir dependency içinde bir veritabanı session'ınız varsa, `StreamingResponse` veri stream ederken bu session'ı kullanamazdı; çünkü `yield` sonrasındaki çıkış kodunda session zaten kapatılmış olurdu.
|
||||
|
||||
Bu davranış 0.118.0'da geri alındı ve `yield` sonrasındaki çıkış kodunun, response gönderildikten sonra çalıştırılması sağlandı.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Aşağıda göreceğiniz gibi, bu davranış 0.106.0 sürümünden önceki davranışa oldukça benzer; ancak köşe durumlar için çeşitli iyileştirmeler ve bug fix'ler içerir.
|
||||
|
||||
///
|
||||
|
||||
#### Erken Çıkış Kodu için Kullanım Senaryoları { #use-cases-with-early-exit-code }
|
||||
|
||||
Bazı özel koşullardaki kullanım senaryoları, response gönderilmeden önce `yield` kullanan dependency'lerin çıkış kodunun çalıştırıldığı eski davranıştan fayda görebilir.
|
||||
|
||||
Örneğin, `yield` kullanan bir dependency içinde yalnızca bir kullanıcıyı doğrulamak için veritabanı session'ı kullanan bir kodunuz olduğunu düşünün; ama bu session *path operation function* içinde bir daha hiç kullanılmıyor, yalnızca dependency içinde kullanılıyor **ve** response'un gönderilmesi uzun sürüyor. Mesela veriyi yavaş gönderen bir `StreamingResponse` var, ama herhangi bir nedenle veritabanını kullanmıyor.
|
||||
|
||||
Bu durumda veritabanı session'ı, response tamamen gönderilene kadar elde tutulur. Ancak session kullanılmıyorsa, bunu elde tutmak gerekli değildir.
|
||||
|
||||
Şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
|
||||
|
||||
`Session`'ın otomatik kapatılması olan çıkış kodu şurada:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...yavaş veri gönderen response'un gönderimi bittikten sonra çalıştırılır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
Ama `generate_stream()` veritabanı session'ını kullanmadığı için, response gönderilirken session'ı açık tutmak aslında gerekli değildir.
|
||||
|
||||
SQLModel (veya SQLAlchemy) kullanarak bu spesifik senaryoya sahipseniz, session'a artık ihtiyacınız kalmadıktan sonra session'ı açıkça kapatabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
|
||||
|
||||
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 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.
|
||||
|
||||
### `yield` ve `except` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-except-technical-details }
|
||||
|
||||
FastAPI 0.110.0 öncesinde, `yield` kullanan bir dependency kullanır, sonra o dependency içinde `except` ile bir exception yakalar ve exception'ı tekrar raise etmezseniz; exception otomatik olarak herhangi bir exception handler'a veya internal server error handler'a raise/forward edilirdi.
|
||||
|
||||
Bu davranış 0.110.0 sürümünde değiştirildi. Amaç, handler olmayan (internal server errors) forward edilmiş exception'ların yönetilmemesinden kaynaklanan bellek tüketimini düzeltmek ve bunu normal Python kodunun davranışıyla tutarlı hale getirmekti.
|
||||
|
||||
### 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 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.
|
||||
|
||||
Bu davranış FastAPI 0.106.0'da, response'un ağ üzerinde taşınmasını beklerken resource tutmamak amacıyla değiştirildi.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Ek olarak, bir background task normalde ayrı ele alınması gereken bağımsız bir mantık setidir ve kendi resource'larına sahip olmalıdır (ör. kendi veritabanı bağlantısı).
|
||||
|
||||
Bu şekilde muhtemelen daha temiz bir kod elde edersiniz.
|
||||
|
||||
///
|
||||
|
||||
Bu davranışa güvenerek kod yazdıysanız, artık background task'ler için resource'ları background task'in içinde oluşturmalı ve içeride yalnızca `yield` kullanan dependency'lerin resource'larına bağlı olmayan verileri kullanmalısınız.
|
||||
|
||||
Örneğin, aynı veritabanı session'ını kullanmak yerine background task içinde yeni bir veritabanı session'ı oluşturur ve veritabanındaki objeleri bu yeni session ile alırsınız. Ardından, background task function'ına veritabanından gelen objeyi parametre olarak geçirmek yerine, o objenin ID'sini geçirir ve objeyi background task function'ı içinde yeniden elde edersiniz.
|
||||
@@ -0,0 +1,61 @@
|
||||
# Gelişmiş Python Tipleri { #advanced-python-types }
|
||||
|
||||
Python tipleriyle çalışırken işinize yarayabilecek bazı ek fikirler.
|
||||
|
||||
## `Union` veya `Optional` Kullanımı { #using-union-or-optional }
|
||||
|
||||
Kodunuz herhangi bir nedenle `|` kullanamıyorsa — örneğin bir tip açıklamasında (type annotation) değil de `response_model=` gibi bir yerdeyse — dikey çizgi (`|`) yerine `typing` içindeki `Union`'ı kullanabilirsiniz.
|
||||
|
||||
Örneğin, bir şeyin `str` ya da `None` olabileceğini şöyle belirtebilirsiniz:
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
|
||||
def say_hi(name: Union[str, None]):
|
||||
print(f"Hi {name}!")
|
||||
```
|
||||
|
||||
`typing`, bir şeyin `None` olabileceğini belirtmek için `Optional` ile bir kısayol da sunar.
|
||||
|
||||
Benim oldukça öznel bakış açıma göre küçük bir ipucu:
|
||||
|
||||
- 🚨 `Optional[SomeType]` kullanmaktan kaçının
|
||||
- Bunun yerine ✨ **`Union[SomeType, None]` kullanın** ✨.
|
||||
|
||||
İkisi de eşdeğer ve temelde aynıdır; ancak "**optional**" kelimesi değerin isteğe bağlı olduğunu ima eder. Oysa aslında " `None` olabilir" demektir; değer isteğe bağlı olmasa ve hâlâ zorunlu olsa bile.
|
||||
|
||||
Bence `Union[SomeType, None]` ne demek istediğini daha açık anlatır.
|
||||
|
||||
Burada mesele sadece kelimeler ve isimler. Ancak bu kelimeler sizin ve ekip arkadaşlarınızın koda bakışını etkileyebilir.
|
||||
|
||||
Örnek olarak şu fonksiyona bakalım:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def say_hi(name: Optional[str]):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
`name` parametresi `Optional[str]` olarak tanımlıdır; ancak isteğe bağlı değildir, parametre olmadan fonksiyonu çağıramazsınız:
|
||||
|
||||
```Python
|
||||
say_hi() # Ah hayır, bu hata fırlatır! 😱
|
||||
```
|
||||
|
||||
`name` parametresi varsayılan bir değeri olmadığı için hâlâ zorunludur (yani *optional* değildir). Yine de `name`, değer olarak `None` kabul eder:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # Bu çalışır, None geçerlidir 🎉
|
||||
```
|
||||
|
||||
İyi haber şu ki, çoğu durumda tip birliklerini (union) tanımlamak için doğrudan `|` kullanabilirsiniz:
|
||||
|
||||
```python
|
||||
def say_hi(name: str | None):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
Dolayısıyla, normalde `Optional` ve `Union` gibi isimler için endişelenmenize gerek yok. 😎
|
||||
@@ -0,0 +1,99 @@
|
||||
# Async Testler { #async-tests }
|
||||
|
||||
Sağlanan `TestClient` ile **FastAPI** uygulamalarınızı nasıl test edeceğinizi zaten gördünüz. Şimdiye kadar yalnızca senkron testler yazdık, yani `async` fonksiyonlar kullanmadan.
|
||||
|
||||
Testlerinizde asenkron fonksiyonlar kullanabilmek faydalı olabilir; örneğin veritabanınızı asenkron olarak sorguluyorsanız. Diyelim ki FastAPI uygulamanıza request gönderilmesini test etmek ve ardından async bir veritabanı kütüphanesi kullanırken backend'in doğru veriyi veritabanına başarıyla yazdığını doğrulamak istiyorsunuz.
|
||||
|
||||
Bunu nasıl çalıştırabileceğimize bir bakalım.
|
||||
|
||||
## pytest.mark.anyio { #pytest-mark-anyio }
|
||||
|
||||
Testlerimizde asenkron fonksiyonlar çağırmak istiyorsak, test fonksiyonlarımızın da asenkron olması gerekir. AnyIO bunun için güzel bir plugin sağlar; böylece bazı test fonksiyonlarının asenkron olarak çağrılacağını belirtebiliriz.
|
||||
|
||||
## HTTPX { #httpx }
|
||||
|
||||
**FastAPI** uygulamanız `async def` yerine normal `def` fonksiyonları kullanıyor olsa bile, altta yatan yapı hâlâ bir `async` uygulamadır.
|
||||
|
||||
`TestClient`, standart pytest kullanarak normal `def` test fonksiyonlarınızın içinden asenkron FastAPI uygulamasını çağırmak için içeride bazı “sihirli” işlemler yapar. Ancak bu sihir, onu asenkron fonksiyonların içinde kullandığımızda artık çalışmaz. Testlerimizi asenkron çalıştırdığımızda, test fonksiyonlarımızın içinde `TestClient` kullanamayız.
|
||||
|
||||
`TestClient`, <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> tabanlıdır ve neyse ki API'yi test etmek için HTTPX'i doğrudan kullanabiliriz.
|
||||
|
||||
## Örnek { #example }
|
||||
|
||||
Basit bir örnek için, [Bigger Applications](../tutorial/bigger-applications.md){.internal-link target=_blank} ve [Testing](../tutorial/testing.md){.internal-link target=_blank} bölümlerinde anlatılana benzer bir dosya yapısı düşünelim:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
`main.py` dosyası şöyle olur:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/main.py *}
|
||||
|
||||
`test_main.py` dosyasında `main.py` için testler yer alır, artık şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
|
||||
|
||||
## Çalıştırma { #run-it }
|
||||
|
||||
Testlerinizi her zamanki gibi şu şekilde çalıştırabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Detaylı Anlatım { #in-detail }
|
||||
|
||||
`@pytest.mark.anyio` marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Test fonksiyonu artık `TestClient` kullanırken eskiden olduğu gibi sadece `def` değil, `async def`.
|
||||
|
||||
///
|
||||
|
||||
Ardından app ile bir `AsyncClient` oluşturup `await` kullanarak ona async request'ler gönderebiliriz.
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
|
||||
|
||||
Bu, şu kullanıma denktir:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
...ki daha önce request'leri `TestClient` ile bu şekilde gönderiyorduk.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Yeni `AsyncClient` ile async/await kullandığımızı unutmayın; request asenkron çalışır.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Uygulamanız lifespan event'lerine dayanıyorsa, `AsyncClient` bu event'leri tetiklemez. Tetiklendiklerinden emin olmak için <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a> paketindeki `LifespanManager`'ı kullanın.
|
||||
|
||||
///
|
||||
|
||||
## Diğer Asenkron Fonksiyon Çağrıları { #other-asynchronous-function-calls }
|
||||
|
||||
Test fonksiyonu artık asenkron olduğundan, testlerinizde FastAPI uygulamanıza request göndermenin yanında başka `async` fonksiyonları da (çağırıp `await` ederek) kodunuzun başka yerlerinde yaptığınız gibi aynı şekilde kullanabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Testlerinize asenkron fonksiyon çağrıları entegre ederken `RuntimeError: Task attached to a different loop` hatasıyla karşılaşırsanız (ör. <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB'nin MotorClient</a> kullanımı), event loop gerektiren nesneleri yalnızca async fonksiyonların içinde oluşturmanız gerektiğini unutmayın; örneğin bir `@app.on_event("startup")` callback'i içinde.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,466 @@
|
||||
# Proxy Arkasında Çalıştırma { #behind-a-proxy }
|
||||
|
||||
Birçok durumda, FastAPI uygulamanızın önünde Traefik veya Nginx gibi bir **proxy** kullanırsınız.
|
||||
|
||||
Bu proxy'ler HTTPS sertifikalarını ve diğer bazı işleri üstlenebilir.
|
||||
|
||||
## Proxy Forwarded Header'ları { #proxy-forwarded-headers }
|
||||
|
||||
Uygulamanızın önündeki bir **proxy**, request'leri **server**'ınıza göndermeden önce genelde bazı header'ları dinamik olarak ayarlar. Böylece server, request'in proxy tarafından **forward** edildiğini; domain dahil orijinal (public) URL'yi, HTTPS kullanıldığını vb. bilgileri anlayabilir.
|
||||
|
||||
**Server** programı (örneğin **FastAPI CLI** üzerinden **Uvicorn**) bu header'ları yorumlayabilir ve ardından bu bilgiyi uygulamanıza aktarabilir.
|
||||
|
||||
Ancak güvenlik nedeniyle, server güvenilir bir proxy arkasında olduğunu bilmediği için bu header'ları yorumlamaz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Proxy header'ları şunlardır:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
### Proxy Forwarded Header'larını Etkinleştirme { #enable-proxy-forwarded-headers }
|
||||
|
||||
FastAPI CLI'yi `--forwarded-allow-ips` *CLI Option*'ı ile başlatıp, bu forwarded header'ları okumada güvenilecek IP adreslerini verebilirsiniz.
|
||||
|
||||
Bunu `--forwarded-allow-ips="*"` olarak ayarlarsanız, gelen tüm IP'lere güvenir.
|
||||
|
||||
**Server**'ınız güvenilir bir **proxy** arkasındaysa ve onunla sadece proxy konuşuyorsa, bu ayar server'ın o **proxy**'nin IP'si her neyse onu kabul etmesini sağlar.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run --forwarded-allow-ips="*"
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### HTTPS ile Redirect'ler { #redirects-with-https }
|
||||
|
||||
Örneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
|
||||
|
||||
Client `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir.
|
||||
|
||||
Ancak *CLI Option* `--forwarded-allow-ips` ayarlanmadan önce, `http://localhost:8000/items/`'a redirect edebilir.
|
||||
|
||||
Oysa uygulamanız `https://mysuperapp.com` üzerinde host ediliyor olabilir ve redirect'in `https://mysuperapp.com/items/` olması gerekir.
|
||||
|
||||
Artık `--proxy-headers` ayarını yaparak FastAPI'nin doğru adrese redirect edebilmesini sağlarsınız. 😎
|
||||
|
||||
```
|
||||
https://mysuperapp.com/items/
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
HTTPS hakkında daha fazla bilgi için [HTTPS Hakkında](../deployment/https.md){.internal-link target=_blank} rehberine bakın.
|
||||
|
||||
///
|
||||
|
||||
### Proxy Forwarded Header'ları Nasıl Çalışır { #how-proxy-forwarded-headers-work }
|
||||
|
||||
**Proxy**'nin, client ile **application server** arasında forwarded header'ları nasıl eklediğini gösteren görsel bir temsil:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Proxy as Proxy/Load Balancer
|
||||
participant Server as FastAPI Server
|
||||
|
||||
Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Proxy: Proxy adds forwarded headers
|
||||
|
||||
Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)
|
||||
|
||||
Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs
|
||||
|
||||
Proxy->>Client: HTTPS Response
|
||||
```
|
||||
|
||||
**Proxy**, orijinal client request'ini araya girerek (intercept) alır ve request'i **application server**'a iletmeden önce özel *forwarded* header'ları (`X-Forwarded-*`) ekler.
|
||||
|
||||
Bu header'lar, aksi halde kaybolacak olan orijinal request bilgilerini korur:
|
||||
|
||||
* **X-Forwarded-For**: Orijinal client'ın IP adresi
|
||||
* **X-Forwarded-Proto**: Orijinal protokol (`https`)
|
||||
* **X-Forwarded-Host**: Orijinal host (`mysuperapp.com`)
|
||||
|
||||
**FastAPI CLI** `--forwarded-allow-ips` ile yapılandırıldığında bu header'lara güvenir ve örneğin redirect'lerde doğru URL'leri üretmek için bunları kullanır.
|
||||
|
||||
## Path Prefix'i Kırpılan (Stripped) Bir Proxy { #proxy-with-a-stripped-path-prefix }
|
||||
|
||||
Uygulamanıza bir path prefix ekleyen bir proxy'niz olabilir.
|
||||
|
||||
Bu durumlarda uygulamanızı yapılandırmak için `root_path` kullanabilirsiniz.
|
||||
|
||||
`root_path`, FastAPI'nin (Starlette üzerinden) üzerine kurulduğu ASGI spesifikasyonunun sağladığı bir mekanizmadır.
|
||||
|
||||
`root_path` bu özel senaryoları yönetmek için kullanılır.
|
||||
|
||||
Ayrıca sub-application mount ederken de içeride kullanılır.
|
||||
|
||||
Path prefix'i kırpılan bir proxy kullanmak, şu anlama gelir: Kodunuzda `/app` altında bir path tanımlarsınız; ancak üstte bir katman (proxy) ekleyip **FastAPI** uygulamanızı `/api/v1` gibi bir path'in altına koyarsınız.
|
||||
|
||||
Bu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir.
|
||||
|
||||
Kodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
|
||||
|
||||
Proxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **"kırpar"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez.
|
||||
|
||||
Buraya kadar her şey normal çalışır.
|
||||
|
||||
Ancak entegre doküman arayüzünü (frontend) açtığınızda, OpenAPI şemasını `/api/v1/openapi.json` yerine `/openapi.json` üzerinden almayı bekler.
|
||||
|
||||
Dolayısıyla tarayıcıda çalışan frontend `/openapi.json`'a erişmeye çalışır ve OpenAPI şemasını alamaz.
|
||||
|
||||
Çünkü uygulamamız proxy arkasında `/api/v1` path prefix'i ile çalışmaktadır; frontend'in OpenAPI şemasını `/api/v1/openapi.json` üzerinden çekmesi gerekir.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
||||
browser("Browser")
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
|
||||
server["Server on http://127.0.0.1:8000/app"]
|
||||
|
||||
browser --> proxy
|
||||
proxy --> server
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`0.0.0.0` IP'si, genelde programın ilgili makine/server üzerindeki tüm kullanılabilir IP'lerde dinlediği anlamına gelir.
|
||||
|
||||
///
|
||||
|
||||
Docs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulunduğunu belirtmek için OpenAPI şemasına da ihtiyacı olur. Örneğin:
|
||||
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// Burada daha fazla şey var
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// Burada daha fazla şey var
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bu örnekte "Proxy", **Traefik** gibi bir şey olabilir. Server da FastAPI uygulamanızı çalıştıran (Uvicorn'lu) FastAPI CLI olabilir.
|
||||
|
||||
### `root_path` Sağlama { #providing-the-root-path }
|
||||
|
||||
Bunu yapmak için `--root-path` komut satırı seçeneğini şöyle kullanabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hypercorn kullanıyorsanız, onda da `--root-path` seçeneği vardır.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
ASGI spesifikasyonu bu kullanım senaryosu için bir `root_path` tanımlar.
|
||||
|
||||
`--root-path` komut satırı seçeneği de bu `root_path`'i sağlar.
|
||||
|
||||
///
|
||||
|
||||
### Mevcut `root_path`'i Kontrol Etme { #checking-the-current-root-path }
|
||||
|
||||
Uygulamanızın her request için kullandığı mevcut `root_path` değerini alabilirsiniz; bu değer ASGI spesifikasyonunun bir parçası olan `scope` dict'inin içindedir.
|
||||
|
||||
Burada sadece göstermek için bunu mesaja dahil ediyoruz.
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
|
||||
|
||||
Ardından Uvicorn'u şu şekilde başlatırsanız:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Response şöyle bir şey olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
### FastAPI Uygulamasında `root_path` Ayarlama { #setting-the-root-path-in-the-fastapi-app }
|
||||
|
||||
Alternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
|
||||
|
||||
`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir.
|
||||
|
||||
### `root_path` Hakkında { #about-root-path }
|
||||
|
||||
Şunu unutmayın: Server (Uvicorn) bu `root_path`'i, uygulamaya iletmek dışında başka bir amaçla kullanmaz.
|
||||
|
||||
Ancak tarayıcınızla <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> adresine giderseniz normal response'u görürsünüz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
Yani `http://127.0.0.1:8000/api/v1/app` üzerinden erişilmeyi beklemez.
|
||||
|
||||
Uvicorn, proxy'nin Uvicorn'a `http://127.0.0.1:8000/app` üzerinden erişmesini bekler; bunun üstüne ekstra `/api/v1` prefix'ini eklemek proxy'nin sorumluluğudur.
|
||||
|
||||
## Stripped Path Prefix Kullanan Proxy'ler Hakkında { #about-proxies-with-a-stripped-path-prefix }
|
||||
|
||||
Stripped path prefix kullanan bir proxy, yapılandırma yöntemlerinden yalnızca biridir.
|
||||
|
||||
Birçok durumda varsayılan davranış, proxy'nin stripped path prefix kullanmaması olacaktır.
|
||||
|
||||
Böyle bir durumda (stripped path prefix olmadan), proxy `https://myawesomeapp.com` gibi bir yerde dinler; tarayıcı `https://myawesomeapp.com/api/v1/app`'e giderse ve sizin server'ınız (ör. Uvicorn) `http://127.0.0.1:8000` üzerinde dinliyorsa, proxy (stripped path prefix olmadan) Uvicorn'a aynı path ile erişir: `http://127.0.0.1:8000/api/v1/app`.
|
||||
|
||||
## Traefik ile Local Olarak Test Etme { #testing-locally-with-traefik }
|
||||
|
||||
<a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a> kullanarak, stripped path prefix'li deneyi local'de kolayca çalıştırabilirsiniz.
|
||||
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Traefik'i indirin</a>; tek bir binary'dir, sıkıştırılmış dosyayı çıkarıp doğrudan terminalden çalıştırabilirsiniz.
|
||||
|
||||
Ardından `traefik.toml` adında bir dosya oluşturup şunu yazın:
|
||||
|
||||
```TOML hl_lines="3"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":9999"
|
||||
|
||||
[providers]
|
||||
[providers.file]
|
||||
filename = "routes.toml"
|
||||
```
|
||||
|
||||
Bu, Traefik'e 9999 portunda dinlemesini ve `routes.toml` adlı başka bir dosyayı kullanmasını söyler.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Standart HTTP portu 80 yerine 9999 portunu kullanıyoruz; böylece admin (`sudo`) yetkileriyle çalıştırmanız gerekmez.
|
||||
|
||||
///
|
||||
|
||||
Şimdi diğer dosyayı, `routes.toml`'u oluşturun:
|
||||
|
||||
```TOML hl_lines="5 12 20"
|
||||
[http]
|
||||
[http.middlewares]
|
||||
|
||||
[http.middlewares.api-stripprefix.stripPrefix]
|
||||
prefixes = ["/api/v1"]
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.app-http]
|
||||
entryPoints = ["http"]
|
||||
service = "app"
|
||||
rule = "PathPrefix(`/api/v1`)"
|
||||
middlewares = ["api-stripprefix"]
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.app]
|
||||
[http.services.app.loadBalancer]
|
||||
[[http.services.app.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:8000"
|
||||
```
|
||||
|
||||
Bu dosya, Traefik'i `/api/v1` path prefix'ini kullanacak şekilde yapılandırır.
|
||||
|
||||
Ardından Traefik, request'leri `http://127.0.0.1:8000` üzerinde çalışan Uvicorn'unuza yönlendirir.
|
||||
|
||||
Şimdi Traefik'i başlatın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ./traefik --configFile=traefik.toml
|
||||
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ve şimdi uygulamanızı `--root-path` seçeneğiyle başlatın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Response'ları Kontrol Edin { #check-the-responses }
|
||||
|
||||
Şimdi Uvicorn'un portundaki URL'ye giderseniz: <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>, normal response'u görürsünüz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`http://127.0.0.1:8000/app` üzerinden erişiyor olsanız bile, `root_path` değerinin `--root-path` seçeneğinden alınıp `/api/v1` olarak gösterildiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
Şimdi de Traefik'in portundaki URL'yi, path prefix ile birlikte açın: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
|
||||
|
||||
Aynı response'u alırız:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
ama bu sefer proxy'nin sağladığı prefix path olan `/api/v1` ile gelen URL'de.
|
||||
|
||||
Elbette buradaki fikir, herkesin uygulamaya proxy üzerinden erişmesidir; dolayısıyla `/api/v1` path prefix'li sürüm "doğru" olandır.
|
||||
|
||||
Uvicorn'un doğrudan sunduğu, path prefix olmayan sürüm (`http://127.0.0.1:8000/app`) ise sadece _proxy_'nin (Traefik) erişmesi için kullanılmalıdır.
|
||||
|
||||
Bu da Proxy'nin (Traefik) path prefix'i nasıl kullandığını ve server'ın (Uvicorn) `--root-path` seçeneğinden gelen `root_path`'i nasıl kullandığını gösterir.
|
||||
|
||||
### Docs UI'yi Kontrol Edin { #check-the-docs-ui }
|
||||
|
||||
Şimdi işin eğlenceli kısmı. ✨
|
||||
|
||||
Uygulamaya erişmenin "resmi" yolu, tanımladığımız path prefix ile proxy üzerinden erişmektir. Bu yüzden beklendiği gibi, Uvicorn'un doğrudan servis ettiği docs UI'yi URL'de path prefix olmadan açarsanız çalışmaz; çünkü proxy üzerinden erişileceğini varsayar.
|
||||
|
||||
Şuradan kontrol edebilirsiniz: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
Ancak docs UI'yi proxy üzerinden, `9999` portuyla, `/api/v1/docs` altında "resmi" URL'den açarsak doğru çalışır! 🎉
|
||||
|
||||
Şuradan kontrol edebilirsiniz: <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
Tam istediğimiz gibi. ✔️
|
||||
|
||||
Bunun nedeni, FastAPI'nin OpenAPI içinde varsayılan `server`'ı, `root_path` tarafından verilen URL ile oluşturmak için bu `root_path`'i kullanmasıdır.
|
||||
|
||||
## Ek `server`'lar { #additional-servers }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu daha ileri seviye bir kullanım senaryosudur. İsterseniz atlayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Varsayılan olarak **FastAPI**, OpenAPI şemasında `root_path` için bir `server` oluşturur.
|
||||
|
||||
Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs UI'nin hem staging hem de production ortamıyla etkileşime girmesini istiyorsanız.
|
||||
|
||||
Özel bir `servers` listesi verirseniz ve bir `root_path` varsa (çünkü API'niz proxy arkasındadır), **FastAPI** bu `root_path` ile bir "server"ı listenin başına ekler.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
|
||||
|
||||
Şöyle bir OpenAPI şeması üretir:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// Burada daha fazla şey var
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// Burada daha fazla şey var
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`url` değeri `/api/v1` olan, `root_path`'ten alınmış otomatik üretilen server'a dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
Docs UI'de, <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> adresinde şöyle görünür:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Docs UI, seçtiğiniz server ile etkileşime girer.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
OpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir.
|
||||
|
||||
`servers` parametresini belirtmezseniz ve `root_path` `/` ile aynıysa, üretilen OpenAPI şemasında `servers` özelliği varsayılan olarak tamamen çıkarılır; bu da `url` değeri `/` olan tek bir server ile eşdeğerdir.
|
||||
|
||||
///
|
||||
|
||||
### `root_path`'ten Otomatik `server` Eklenmesini Kapatma { #disable-automatic-server-from-root-path }
|
||||
|
||||
**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
|
||||
|
||||
Böylece OpenAPI şemasına dahil etmez.
|
||||
|
||||
## Bir Sub-Application Mount Etme { #mounting-a-sub-application }
|
||||
|
||||
Bir sub-application'ı ( [Sub Applications - Mounts](sub-applications.md){.internal-link target=_blank} bölümünde anlatıldığı gibi) mount etmeniz gerekiyorsa ve aynı zamanda `root_path` ile bir proxy kullanıyorsanız, bunu beklendiği gibi normal şekilde yapabilirsiniz.
|
||||
|
||||
FastAPI içeride `root_path`'i akıllıca kullanır; dolayısıyla doğrudan çalışır. ✨
|
||||
@@ -0,0 +1,312 @@
|
||||
# Özel Response - HTML, Stream, File ve Diğerleri { #custom-response-html-stream-file-others }
|
||||
|
||||
Varsayılan olarak **FastAPI**, response'ları `JSONResponse` kullanarak döndürür.
|
||||
|
||||
Bunu, [Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde gördüğünüz gibi doğrudan bir `Response` döndürerek geçersiz kılabilirsiniz.
|
||||
|
||||
Ancak doğrudan bir `Response` döndürürseniz (veya `JSONResponse` gibi herhangi bir alt sınıfını), veri otomatik olarak dönüştürülmez (bir `response_model` tanımlamış olsanız bile) ve dokümantasyon da otomatik üretilmez (örneğin, üretilen OpenAPI’nin parçası olarak HTTP header `Content-Type` içindeki ilgili "media type" dahil edilmez).
|
||||
|
||||
Bununla birlikte, *path operation decorator* içinde `response_class` parametresini kullanarak hangi `Response`’un (örn. herhangi bir `Response` alt sınıfı) kullanılacağını da ilan edebilirsiniz.
|
||||
|
||||
*path operation function*’ınızdan döndürdüğünüz içerik, o `Response`’un içine yerleştirilir.
|
||||
|
||||
Ve eğer bu `Response` ( `JSONResponse` ve `UJSONResponse`’ta olduğu gibi) bir JSON media type’a (`application/json`) sahipse, döndürdüğünüz veri; *path operation decorator* içinde tanımladığınız herhangi bir Pydantic `response_model` ile otomatik olarak dönüştürülür (ve filtrelenir).
|
||||
|
||||
/// note | Not
|
||||
|
||||
Media type’ı olmayan bir response class kullanırsanız, FastAPI response’unuzun content içermediğini varsayar; bu yüzden ürettiği OpenAPI dokümanında response formatını dokümante etmez.
|
||||
|
||||
///
|
||||
|
||||
## `ORJSONResponse` Kullan { #use-orjsonresponse }
|
||||
|
||||
Örneğin performansı sıkıştırmaya çalışıyorsanız, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kurup kullanabilir ve response’u `ORJSONResponse` olarak ayarlayabilirsiniz.
|
||||
|
||||
Kullanmak istediğiniz `Response` class’ını (alt sınıfını) import edin ve *path operation decorator* içinde tanımlayın.
|
||||
|
||||
Büyük response'larda, doğrudan bir `Response` döndürmek bir dictionary döndürmekten çok daha hızlıdır.
|
||||
|
||||
Çünkü varsayılan olarak FastAPI, içindeki her item’ı inceleyip JSON olarak serialize edilebilir olduğundan emin olur; tutorial’da anlatılan aynı [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} mekanizmasını kullanır. Bu da örneğin veritabanı modelleri gibi **keyfi objeleri** döndürebilmenizi sağlar.
|
||||
|
||||
Ancak döndürdüğünüz içeriğin **JSON ile serialize edilebilir** olduğundan eminseniz, onu doğrudan response class’ına verebilir ve FastAPI’nin response class’ına vermeden önce dönüş içeriğinizi `jsonable_encoder` içinden geçirirken oluşturacağı ek yükten kaçınabilirsiniz.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır.
|
||||
|
||||
Bu durumda HTTP header `Content-Type`, `application/json` olarak ayarlanır.
|
||||
|
||||
Ve OpenAPI’de de bu şekilde dokümante edilir.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`ORJSONResponse` yalnızca FastAPI’de vardır, Starlette’te yoktur.
|
||||
|
||||
///
|
||||
|
||||
## HTML Response { #html-response }
|
||||
|
||||
**FastAPI**’den doğrudan HTML içeren bir response döndürmek için `HTMLResponse` kullanın.
|
||||
|
||||
* `HTMLResponse` import edin.
|
||||
* *path operation decorator*’ınızın `response_class` parametresi olarak `HTMLResponse` verin.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır.
|
||||
|
||||
Bu durumda HTTP header `Content-Type`, `text/html` olarak ayarlanır.
|
||||
|
||||
Ve OpenAPI’de de bu şekilde dokümante edilir.
|
||||
|
||||
///
|
||||
|
||||
### Bir `Response` Döndür { #return-a-response }
|
||||
|
||||
[Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde görüldüğü gibi, *path operation* içinde doğrudan bir response döndürerek response’u override edebilirsiniz.
|
||||
|
||||
Yukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
*path operation function*’ınızın doğrudan döndürdüğü bir `Response`, OpenAPI’de dokümante edilmez (örneğin `Content-Type` dokümante edilmez) ve otomatik interaktif dokümanlarda görünmez.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Elbette gerçek `Content-Type` header’ı, status code vb. değerler, döndürdüğünüz `Response` objesinden gelir.
|
||||
|
||||
///
|
||||
|
||||
### OpenAPI’de Dokümante Et ve `Response`’u Override Et { #document-in-openapi-and-override-response }
|
||||
|
||||
Response’u fonksiyonun içinden override etmek ama aynı zamanda OpenAPI’de "media type"’ı dokümante etmek istiyorsanız, `response_class` parametresini kullanıp ayrıca bir `Response` objesi döndürebilirsiniz.
|
||||
|
||||
Bu durumda `response_class` sadece OpenAPI *path operation*’ını dokümante etmek için kullanılır; sizin `Response`’unuz ise olduğu gibi kullanılır.
|
||||
|
||||
#### Doğrudan bir `HTMLResponse` Döndür { #return-an-htmlresponse-directly }
|
||||
|
||||
Örneğin şöyle bir şey olabilir:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
|
||||
|
||||
Bu örnekte `generate_html_response()` fonksiyonu, HTML’i bir `str` olarak döndürmek yerine zaten bir `Response` üretip döndürmektedir.
|
||||
|
||||
`generate_html_response()` çağrısının sonucunu döndürerek, varsayılan **FastAPI** davranışını override edecek bir `Response` döndürmüş olursunuz.
|
||||
|
||||
Ama `response_class` içinde `HTMLResponse` da verdiğiniz için **FastAPI**, bunu OpenAPI’de ve interaktif dokümanlarda `text/html` ile HTML olarak nasıl dokümante edeceğini bilir:
|
||||
|
||||
<img src="/img/tutorial/custom-response/image01.png">
|
||||
|
||||
## Mevcut Response'lar { #available-responses }
|
||||
|
||||
Mevcut response'lardan bazıları aşağıdadır.
|
||||
|
||||
Unutmayın: `Response` ile başka herhangi bir şeyi döndürebilir, hatta özel bir alt sınıf da oluşturabilirsiniz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import HTMLResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici için kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` olarak da sağlar. Ancak mevcut response'ların çoğu doğrudan Starlette’ten gelir.
|
||||
|
||||
///
|
||||
|
||||
### `Response` { #response }
|
||||
|
||||
Ana `Response` class’ıdır; diğer tüm response'lar bundan türetilir.
|
||||
|
||||
Bunu doğrudan döndürebilirsiniz.
|
||||
|
||||
Şu parametreleri kabul eder:
|
||||
|
||||
* `content` - Bir `str` veya `bytes`.
|
||||
* `status_code` - Bir `int` HTTP status code.
|
||||
* `headers` - String’lerden oluşan bir `dict`.
|
||||
* `media_type` - Media type’ı veren bir `str`. Örn. `"text/html"`.
|
||||
|
||||
FastAPI (aslında Starlette) otomatik olarak bir Content-Length header’ı ekler. Ayrıca `media_type`’a göre bir Content-Type header’ı ekler ve text türleri için sona bir charset ekler.
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
|
||||
Yukarıda okuduğunuz gibi, bir miktar text veya bytes alır ve HTML response döndürür.
|
||||
|
||||
### `PlainTextResponse` { #plaintextresponse }
|
||||
|
||||
Bir miktar text veya bytes alır ve düz metin response döndürür.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
|
||||
Bir miktar veri alır ve `application/json` olarak encode edilmiş bir response döndürür.
|
||||
|
||||
Yukarıda okuduğunuz gibi, **FastAPI**’de varsayılan response budur.
|
||||
|
||||
### `ORJSONResponse` { #orjsonresponse }
|
||||
|
||||
Yukarıda okuduğunuz gibi <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kullanan hızlı bir alternatif JSON response.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bunun için `orjson` kurulmalıdır; örneğin `pip install orjson`.
|
||||
|
||||
///
|
||||
|
||||
### `UJSONResponse` { #ujsonresponse }
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a> kullanan alternatif bir JSON response.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bunun için `ujson` kurulmalıdır; örneğin `pip install ujson`.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`ujson`, bazı edge-case’leri ele alma konusunda Python’un built-in implementasyonu kadar dikkatli değildir.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`ORJSONResponse` daha hızlı bir alternatif olabilir.
|
||||
|
||||
///
|
||||
|
||||
### `RedirectResponse` { #redirectresponse }
|
||||
|
||||
HTTP redirect döndürür. Varsayılan olarak 307 status code (Temporary Redirect) kullanır.
|
||||
|
||||
`RedirectResponse`’u doğrudan döndürebilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
|
||||
|
||||
---
|
||||
|
||||
Veya `response_class` parametresi içinde kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
|
||||
|
||||
Bunu yaparsanız, *path operation* function’ınızdan doğrudan URL döndürebilirsiniz.
|
||||
|
||||
Bu durumda kullanılan `status_code`, `RedirectResponse` için varsayılan olan `307` olur.
|
||||
|
||||
---
|
||||
|
||||
Ayrıca `status_code` parametresini `response_class` parametresiyle birlikte kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
Bir async generator veya normal generator/iterator alır ve response body’yi stream eder.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
|
||||
|
||||
#### `StreamingResponse`’u file-like objelerle kullanma { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
Bir <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> objeniz varsa (örn. `open()`’ın döndürdüğü obje), o file-like obje üzerinde iterate eden bir generator function oluşturabilirsiniz.
|
||||
|
||||
Böylece önce hepsini memory’ye okumak zorunda kalmazsınız; bu generator function’ı `StreamingResponse`’a verip döndürebilirsiniz.
|
||||
|
||||
Buna cloud storage ile etkileşime giren, video işleyen ve benzeri birçok kütüphane dahildir.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
|
||||
|
||||
1. Bu generator function’dır. İçinde `yield` ifadeleri olduğu için "generator function" denir.
|
||||
2. Bir `with` bloğu kullanarak, generator function bittiğinde file-like objenin kapandığından emin oluruz. Yani response göndermeyi bitirdikten sonra kapanır.
|
||||
3. Bu `yield from`, fonksiyona `file_like` isimli şeyi iterate etmesini söyler. Ardından iterate edilen her parça için, o parçayı bu generator function’dan (`iterfile`) geliyormuş gibi yield eder.
|
||||
|
||||
Yani, içerdeki "üretme" (generating) işini başka bir şeye devreden bir generator function’dır.
|
||||
|
||||
Bunu bu şekilde yaptığımızda `with` bloğu içinde tutabilir ve böylece iş bitince file-like objenin kapanmasını garanti edebiliriz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Burada `async` ve `await` desteklemeyen standart `open()` kullandığımız için path operation’ı normal `def` ile tanımlarız.
|
||||
|
||||
///
|
||||
|
||||
### `FileResponse` { #fileresponse }
|
||||
|
||||
Asenkron olarak bir dosyayı response olarak stream eder.
|
||||
|
||||
Diğer response türlerine göre instantiate ederken farklı argümanlar alır:
|
||||
|
||||
* `path` - Stream edilecek dosyanın dosya path'i.
|
||||
* `headers` - Eklenecek özel header’lar; dictionary olarak.
|
||||
* `media_type` - Media type’ı veren string. Ayarlanmazsa, dosya adı veya path kullanılarak media type tahmin edilir.
|
||||
* `filename` - Ayarlanırsa response içindeki `Content-Disposition`’a dahil edilir.
|
||||
|
||||
File response'ları uygun `Content-Length`, `Last-Modified` ve `ETag` header’larını içerir.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
|
||||
|
||||
`response_class` parametresini de kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
|
||||
|
||||
Bu durumda *path operation* function’ınızdan doğrudan dosya path'ini döndürebilirsiniz.
|
||||
|
||||
## Özel response class { #custom-response-class }
|
||||
|
||||
`Response`’dan türeterek kendi özel response class’ınızı oluşturabilir ve kullanabilirsiniz.
|
||||
|
||||
Örneğin, dahil gelen `ORJSONResponse` class’ında kullanılmayan bazı özel ayarlarla <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> kullanmak istediğinizi varsayalım.
|
||||
|
||||
Diyelim ki girintili ve biçimlendirilmiş JSON döndürmek istiyorsunuz; bunun için `orjson.OPT_INDENT_2` seçeneğini kullanmak istiyorsunuz.
|
||||
|
||||
Bir `CustomORJSONResponse` oluşturabilirsiniz. Burada yapmanız gereken temel şey, content’i `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
|
||||
|
||||
Artık şunu döndürmek yerine:
|
||||
|
||||
```json
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
...bu response şunu döndürür:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
|
||||
Elbette JSON’u formatlamaktan çok daha iyi şekillerde bundan faydalanabilirsiniz. 😉
|
||||
|
||||
## Varsayılan response class { #default-response-class }
|
||||
|
||||
Bir **FastAPI** class instance’ı veya bir `APIRouter` oluştururken, varsayılan olarak hangi response class’ının kullanılacağını belirtebilirsiniz.
|
||||
|
||||
Bunu tanımlayan parametre `default_response_class`’tır.
|
||||
|
||||
Aşağıdaki örnekte **FastAPI**, tüm *path operations* için varsayılan olarak `JSONResponse` yerine `ORJSONResponse` kullanır.
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Daha önce olduğu gibi, *path operations* içinde `response_class`’ı yine override edebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Ek dokümantasyon { #additional-documentation }
|
||||
|
||||
OpenAPI’de media type’ı ve daha birçok detayı `responses` kullanarak da tanımlayabilirsiniz: [OpenAPI’de Ek Response'lar](additional-responses.md){.internal-link target=_blank}.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Dataclass Kullanımı { #using-dataclasses }
|
||||
|
||||
FastAPI, **Pydantic** üzerine inşa edilmiştir ve request/response tanımlamak için Pydantic model'lerini nasıl kullanacağınızı gösteriyordum.
|
||||
|
||||
Ancak FastAPI, <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> kullanmayı da aynı şekilde destekler:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
|
||||
|
||||
Bu destek hâlâ **Pydantic** sayesinde vardır; çünkü Pydantic, <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses` için dahili destek</a> sunar.
|
||||
|
||||
Yani yukarıdaki kod Pydantic'i doğrudan kullanmasa bile, FastAPI bu standart dataclass'ları Pydantic'in kendi dataclass biçimine dönüştürmek için Pydantic'i kullanmaktadır.
|
||||
|
||||
Ve elbette aynı özellikleri destekler:
|
||||
|
||||
* veri doğrulama (data validation)
|
||||
* veri serileştirme (data serialization)
|
||||
* veri dokümantasyonu (data documentation), vb.
|
||||
|
||||
Bu, Pydantic model'lerinde olduğu gibi çalışır. Aslında arka planda da aynı şekilde, Pydantic kullanılarak yapılır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Dataclass'ların, Pydantic model'lerinin yapabildiği her şeyi yapamadığını unutmayın.
|
||||
|
||||
Bu yüzden yine de Pydantic model'lerini kullanmanız gerekebilir.
|
||||
|
||||
Ancak elinizde zaten bir sürü dataclass varsa, bunları FastAPI ile bir web API'yi beslemek için kullanmak güzel bir numaradır. 🤓
|
||||
|
||||
///
|
||||
|
||||
## `response_model` İçinde Dataclass'lar { #dataclasses-in-response-model }
|
||||
|
||||
`response_model` parametresinde `dataclasses` da kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
|
||||
|
||||
Dataclass otomatik olarak bir Pydantic dataclass'ına dönüştürülür.
|
||||
|
||||
Bu sayede şeması API docs kullanıcı arayüzünde görünür:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## İç İçe Veri Yapılarında Dataclass'lar { #dataclasses-in-nested-data-structures }
|
||||
|
||||
İç içe veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları da birleştirebilirsiniz.
|
||||
|
||||
Bazı durumlarda yine de Pydantic'in `dataclasses` sürümünü kullanmanız gerekebilir. Örneğin, otomatik oluşturulan API dokümantasyonunda hata alıyorsanız.
|
||||
|
||||
Bu durumda standart `dataclasses` yerine, drop-in replacement olan `pydantic.dataclasses` kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
|
||||
|
||||
1. `field` hâlâ standart `dataclasses` içinden import edilir.
|
||||
|
||||
2. `pydantic.dataclasses`, `dataclasses` için bir drop-in replacement'tır.
|
||||
|
||||
3. `Author` dataclass'ı, `Item` dataclass'larından oluşan bir liste içerir.
|
||||
|
||||
4. `Author` dataclass'ı, `response_model` parametresi olarak kullanılır.
|
||||
|
||||
5. Request body olarak dataclass'larla birlikte diğer standart type annotation'ları da kullanabilirsiniz.
|
||||
|
||||
Bu örnekte, `Item` dataclass'larından oluşan bir listedir.
|
||||
|
||||
6. Burada `items` içeren bir dictionary döndürüyoruz; `items` bir dataclass listesi.
|
||||
|
||||
FastAPI, veriyi JSON'a <dfn title="veriyi aktarılabilir bir formata dönüştürme">serileştirme</dfn>yi yine başarır.
|
||||
|
||||
7. Burada `response_model`, `Author` dataclass'larından oluşan bir listenin type annotation'ını kullanıyor.
|
||||
|
||||
Yine `dataclasses` ile standart type annotation'ları birleştirebilirsiniz.
|
||||
|
||||
8. Bu *path operation function*, `async def` yerine normal `def` kullanıyor.
|
||||
|
||||
Her zaman olduğu gibi, FastAPI'de ihtiyaca göre `def` ve `async def`’i birlikte kullanabilirsiniz.
|
||||
|
||||
Hangisini ne zaman kullanmanız gerektiğine dair hızlı bir hatırlatma isterseniz, [`async` ve `await`](../async.md#in-a-hurry){.internal-link target=_blank} dokümanındaki _"In a hurry?"_ bölümüne bakın.
|
||||
|
||||
9. Bu *path operation function* dataclass döndürmüyor (isterse döndürebilir), onun yerine dahili verilerle bir dictionary listesi döndürüyor.
|
||||
|
||||
FastAPI, response'u dönüştürmek için (dataclass'ları içeren) `response_model` parametresini kullanacaktır.
|
||||
|
||||
Karmaşık veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları pek çok farklı kombinasyonda birleştirebilirsiniz.
|
||||
|
||||
Daha spesifik ayrıntılar için yukarıdaki kod içi annotation ipuçlarına bakın.
|
||||
|
||||
## Daha Fazla Öğrenin { #learn-more }
|
||||
|
||||
`dataclasses`'ı diğer Pydantic model'leriyle de birleştirebilir, onlardan kalıtım alabilir, kendi model'lerinize dahil edebilirsiniz, vb.
|
||||
|
||||
Daha fazlası için <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">Pydantic'in dataclasses dokümantasyonuna</a> bakın.
|
||||
|
||||
## Sürüm { #version }
|
||||
|
||||
Bu özellik FastAPI `0.67.0` sürümünden beri mevcuttur. 🔖
|
||||
@@ -0,0 +1,165 @@
|
||||
# Lifespan Olayları { #lifespan-events }
|
||||
|
||||
Uygulama **başlamadan** önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodun **bir kez**, uygulama **request almaya başlamadan önce** çalıştırılacağı anlamına gelir.
|
||||
|
||||
Benzer şekilde, uygulama **kapanırken** çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelen **çok sayıda request** işlendi **sonra**, **bir kez** çalıştırılır.
|
||||
|
||||
Bu kod, uygulama request almaya **başlamadan** önce ve request’leri işlemeyi **bitirdikten** hemen sonra çalıştığı için, uygulamanın tüm **lifespan**’ını (birazdan "lifespan" kelimesi önemli olacak 😉) kapsar.
|
||||
|
||||
Bu yaklaşım, tüm uygulama boyunca kullanacağınız ve request’ler arasında **paylaşılan** **resource**’ları kurmak ve/veya sonrasında bunları **temizlemek** için çok faydalıdır. Örneğin bir veritabanı connection pool’u ya da paylaşılan bir machine learning modelini yüklemek gibi.
|
||||
|
||||
## Kullanım Senaryosu { #use-case }
|
||||
|
||||
Önce bir **kullanım senaryosu** örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım.
|
||||
|
||||
Request’leri işlemek için kullanmak istediğiniz bazı **machine learning modelleriniz** olduğunu hayal edelim. 🤖
|
||||
|
||||
Aynı modeller request’ler arasında paylaşılır; yani request başına bir model, kullanıcı başına bir model vb. gibi değil.
|
||||
|
||||
Modeli yüklemenin, diskten çok fazla **data** okunması gerektiği için **oldukça uzun sürebildiğini** düşünelim. Dolayısıyla bunu her request için yapmak istemezsiniz.
|
||||
|
||||
Modeli modülün/dosyanın en üst seviyesinde yükleyebilirdiniz; ancak bu, basit bir otomatik test çalıştırdığınızda bile **modelin yükleneceği** anlamına gelir. Böyle olunca test, kodun bağımsız bir kısmını çalıştırabilmek için önce modelin yüklenmesini beklemek zorunda kalır ve **yavaş** olur.
|
||||
|
||||
Burada çözeceğimiz şey bu: modeli request’ler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce.
|
||||
|
||||
## Lifespan { #lifespan }
|
||||
|
||||
Bu *startup* ve *shutdown* mantığını, `FastAPI` uygulamasının `lifespan` parametresi ve bir "context manager" kullanarak tanımlayabilirsiniz (bunun ne olduğunu birazdan göstereceğim).
|
||||
|
||||
Önce bir örnekle başlayıp sonra ayrıntılarına bakalım.
|
||||
|
||||
Aşağıdaki gibi `yield` kullanan async bir `lifespan()` fonksiyonu oluşturuyoruz:
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
|
||||
|
||||
Burada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli bir *startup* işlemini simüle ediyoruz. Bu kod, *startup* sırasında, uygulama **request almaya başlamadan önce** çalıştırılır.
|
||||
|
||||
Ardından `yield`’den hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulama **request’leri işlemeyi bitirdikten sonra**, *shutdown*’dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resource’ları serbest bırakabilir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`shutdown`, uygulamayı **durdurduğunuzda** gerçekleşir.
|
||||
|
||||
Belki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sıkılmışsınızdır. 🤷
|
||||
|
||||
///
|
||||
|
||||
### Lifespan fonksiyonu { #lifespan-function }
|
||||
|
||||
Dikkat edilmesi gereken ilk şey, `yield` içeren async bir fonksiyon tanımlıyor olmamız. Bu, `yield` kullanan Dependencies’e oldukça benzer.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
|
||||
|
||||
Fonksiyonun `yield`’den önceki kısmı, uygulama başlamadan **önce** çalışır.
|
||||
|
||||
`yield`’den sonraki kısım ise, uygulama işini bitirdikten **sonra** çalışır.
|
||||
|
||||
### Async Context Manager { #async-context-manager }
|
||||
|
||||
Bakarsanız, fonksiyon `@asynccontextmanager` ile dekore edilmiş.
|
||||
|
||||
Bu da fonksiyonu "**async context manager**" denen şeye dönüştürür.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
|
||||
|
||||
Python’da **context manager**, `with` ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin `open()` bir context manager olarak kullanılabilir:
|
||||
|
||||
```Python
|
||||
with open("file.txt") as file:
|
||||
file.read()
|
||||
```
|
||||
|
||||
Python’ın güncel sürümlerinde bir de **async context manager** vardır. Bunu `async with` ile kullanırsınız:
|
||||
|
||||
```Python
|
||||
async with lifespan(app):
|
||||
await do_stuff()
|
||||
```
|
||||
|
||||
Yukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur: `with` bloğuna girmeden önce `yield`’den önceki kodu çalıştırır, `with` bloğundan çıktıktan sonra da `yield`’den sonraki kodu çalıştırır.
|
||||
|
||||
Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPI’ye veriyoruz ki o kullansın.
|
||||
|
||||
`FastAPI` uygulamasının `lifespan` parametresi bir **async context manager** alır; dolayısıyla oluşturduğumuz yeni `lifespan` async context manager’ını buraya geçebiliriz.
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
|
||||
|
||||
## Alternatif Events (kullanımdan kaldırıldı) { #alternative-events-deprecated }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
*startup* ve *shutdown* işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibi `FastAPI` uygulamasının `lifespan` parametresini kullanmaktır. Bir `lifespan` parametresi sağlarsanız, `startup` ve `shutdown` event handler’ları artık çağrılmaz. Ya tamamen `lifespan` ya da tamamen events; ikisi birden değil.
|
||||
|
||||
Muhtemelen bu bölümü atlayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
*startup* ve *shutdown* sırasında çalıştırılacak bu mantığı tanımlamanın alternatif bir yolu daha vardır.
|
||||
|
||||
Uygulama başlamadan önce veya uygulama kapanırken çalıştırılması gereken event handler’ları (fonksiyonları) tanımlayabilirsiniz.
|
||||
|
||||
Bu fonksiyonlar `async def` ile veya normal `def` ile tanımlanabilir.
|
||||
|
||||
### `startup` eventi { #startup-event }
|
||||
|
||||
Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, `"startup"` event’i ile tanımlayın:
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
|
||||
|
||||
Bu durumda `startup` event handler fonksiyonu, "database" öğesini (sadece bir `dict`) bazı değerlerle başlatır.
|
||||
|
||||
Birden fazla event handler fonksiyonu ekleyebilirsiniz.
|
||||
|
||||
Ve tüm `startup` event handler’ları tamamlanmadan uygulamanız request almaya başlamaz.
|
||||
|
||||
### `shutdown` eventi { #shutdown-event }
|
||||
|
||||
Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `"shutdown"` event’i ile tanımlayın:
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
|
||||
|
||||
Burada `shutdown` event handler fonksiyonu, `log.txt` dosyasına `"Application shutdown"` satırını yazar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`open()` fonksiyonunda `mode="a"` "append" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Dikkat edin, bu örnekte bir dosyayla etkileşen standart Python `open()` fonksiyonunu kullanıyoruz.
|
||||
|
||||
Dolayısıyla disk’e yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu.
|
||||
|
||||
Ancak `open()` `async` ve `await` kullanmaz.
|
||||
|
||||
Bu yüzden event handler fonksiyonunu `async def` yerine standart `def` ile tanımlarız.
|
||||
|
||||
///
|
||||
|
||||
### `startup` ve `shutdown` birlikte { #startup-and-shutdown-together }
|
||||
|
||||
*startup* ve *shutdown* mantığınızın birbiriyle bağlantılı olma ihtimali yüksektir; bir şeyi başlatıp sonra bitirmek, bir resource edinip sonra serbest bırakmak vb. isteyebilirsiniz.
|
||||
|
||||
Bunu, ortak mantık veya değişken paylaşmayan ayrı fonksiyonlarda yapmak daha zordur; çünkü değerleri global değişkenlerde tutmanız veya benzer numaralar yapmanız gerekir.
|
||||
|
||||
Bu nedenle artık bunun yerine, yukarıda açıklandığı gibi `lifespan` kullanmanız önerilmektedir.
|
||||
|
||||
## Teknik Detaylar { #technical-details }
|
||||
|
||||
Meraklı nerd’ler için küçük bir teknik detay. 🤓
|
||||
|
||||
Altta, ASGI teknik spesifikasyonunda bu, <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protokolü</a>’nün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Starlette `lifespan` handler’ları hakkında daha fazlasını <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette Lifespan dokümanları</a> içinde okuyabilirsiniz.
|
||||
|
||||
Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar.
|
||||
|
||||
///
|
||||
|
||||
## Alt Uygulamalar { #sub-applications }
|
||||
|
||||
🚨 Unutmayın: Bu lifespan event’leri (`startup` ve `shutdown`) yalnızca ana uygulama için çalıştırılır; [Alt Uygulamalar - Mounts](sub-applications.md){.internal-link target=_blank} için çalıştırılmaz.
|
||||
@@ -0,0 +1,208 @@
|
||||
# SDK Üretme { #generating-sdks }
|
||||
|
||||
**FastAPI**, **OpenAPI** spesifikasyonunu temel aldığı için API'leri birçok aracın anlayabildiği standart bir formatta tanımlanabilir.
|
||||
|
||||
Bu sayede güncel **dokümantasyon**, birden fazla dilde istemci kütüphaneleri (<abbr title="Software Development Kits - Yazılım Geliştirme Kitleri">**SDKs**</abbr>) ve kodunuzla senkron kalan **test** veya **otomasyon iş akışları** üretmek kolaylaşır.
|
||||
|
||||
Bu rehberde, FastAPI backend'iniz için bir **TypeScript SDK** üretmeyi öğreneceksiniz.
|
||||
|
||||
## Açık Kaynak SDK Üreteçleri { #open-source-sdk-generators }
|
||||
|
||||
Esnek bir seçenek olan <a href="https://openapi-generator.tech/" class="external-link" target="_blank">OpenAPI Generator</a>, **birçok programlama dilini** destekler ve OpenAPI spesifikasyonunuzdan SDK üretebilir.
|
||||
|
||||
**TypeScript client**'lar için <a href="https://heyapi.dev/" class="external-link" target="_blank">Hey API</a>, TypeScript ekosistemi için özel olarak tasarlanmış, optimize bir deneyim sunan bir çözümdür.
|
||||
|
||||
Daha fazla SDK üretecini <a href="https://openapi.tools/#sdk" class="external-link" target="_blank">OpenAPI.Tools</a> üzerinde keşfedebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
FastAPI otomatik olarak **OpenAPI 3.1** spesifikasyonları üretir; bu yüzden kullanacağınız aracın bu sürümü desteklemesi gerekir.
|
||||
|
||||
///
|
||||
|
||||
## FastAPI Sponsorlarından SDK Üreteçleri { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
Bu bölüm, FastAPI'yi sponsorlayan şirketlerin sunduğu **yatırım destekli** ve **şirket destekli** çözümleri öne çıkarır. Bu ürünler, yüksek kaliteli üretilen SDK'ların üzerine **ek özellikler** ve **entegrasyonlar** sağlar.
|
||||
|
||||
✨ [**FastAPI'ye sponsor olarak**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ bu şirketler, framework'ün ve **ekosisteminin** sağlıklı ve **sürdürülebilir** kalmasına yardımcı olur.
|
||||
|
||||
Sponsor olmaları aynı zamanda FastAPI **topluluğuna** (size) güçlü bir bağlılığı da gösterir; yalnızca **iyi bir hizmet** sunmayı değil, aynı zamanda **güçlü ve gelişen bir framework** olan FastAPI'yi desteklemeyi de önemsediklerini gösterir. 🙇
|
||||
|
||||
Örneğin şunları deneyebilirsiniz:
|
||||
|
||||
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
|
||||
* <a href="https://www.stainless.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
|
||||
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>
|
||||
|
||||
Bu çözümlerin bazıları açık kaynak olabilir veya ücretsiz katman sunabilir; yani finansal bir taahhüt olmadan deneyebilirsiniz. Başka ticari SDK üreteçleri de vardır ve internette bulunabilir. 🤓
|
||||
|
||||
## TypeScript SDK Oluşturma { #create-a-typescript-sdk }
|
||||
|
||||
Basit bir FastAPI uygulamasıyla başlayalım:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
|
||||
|
||||
*Path operation*'ların, request payload ve response payload için kullandıkları modelleri `Item` ve `ResponseMessage` modelleriyle tanımladıklarına dikkat edin.
|
||||
|
||||
### API Dokümanları { #api-docs }
|
||||
|
||||
`/docs` adresine giderseniz, request'lerde gönderilecek ve response'larda alınacak veriler için **schema**'ları içerdiğini görürsünüz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image01.png">
|
||||
|
||||
Bu schema'ları görebilirsiniz, çünkü uygulamada modellerle birlikte tanımlandılar.
|
||||
|
||||
Bu bilgi uygulamanın **OpenAPI schema**'sında bulunur ve sonrasında API dokümanlarında gösterilir.
|
||||
|
||||
OpenAPI'ye dahil edilen, modellerden gelen bu bilginin aynısı **client code üretmek** için kullanılabilir.
|
||||
|
||||
### Hey API { #hey-api }
|
||||
|
||||
Modelleri olan bir FastAPI uygulamamız olduğunda, Hey API ile bir TypeScript client üretebiliriz. Bunu yapmanın en hızlı yolu npx kullanmaktır.
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
|
||||
```
|
||||
|
||||
Bu komut `./src/client` içine bir TypeScript SDK üretecektir.
|
||||
|
||||
Web sitelerinde <a href="https://heyapi.dev/openapi-ts/get-started" class="external-link" target="_blank">`@hey-api/openapi-ts` kurulumunu</a> öğrenebilir ve <a href="https://heyapi.dev/openapi-ts/output" class="external-link" target="_blank">üretilen çıktıyı</a> inceleyebilirsiniz.
|
||||
|
||||
### SDK'yı Kullanma { #using-the-sdk }
|
||||
|
||||
Artık client code'u import edip kullanabilirsiniz. Şuna benzer görünebilir; method'lar için otomatik tamamlama aldığınıza dikkat edin:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image02.png">
|
||||
|
||||
Ayrıca gönderilecek payload için de otomatik tamamlama alırsınız:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image03.png">
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`name` ve `price` için otomatik tamamlamaya dikkat edin; bunlar FastAPI uygulamasında, `Item` modelinde tanımlanmıştı.
|
||||
|
||||
///
|
||||
|
||||
Gönderdiğiniz veriler için satır içi hatalar (inline errors) da alırsınız:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image04.png">
|
||||
|
||||
Response objesi de otomatik tamamlama sunacaktır:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image05.png">
|
||||
|
||||
## Tag'lerle FastAPI Uygulaması { #fastapi-app-with-tags }
|
||||
|
||||
Birçok durumda FastAPI uygulamanız daha büyük olacaktır ve farklı *path operation* gruplarını ayırmak için muhtemelen tag'leri kullanacaksınız.
|
||||
|
||||
Örneğin **items** için bir bölüm, **users** için başka bir bölüm olabilir ve bunları tag'lerle ayırabilirsiniz:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
|
||||
|
||||
### Tag'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-tags }
|
||||
|
||||
Tag'leri kullanan bir FastAPI uygulaması için client ürettiğinizde, genelde client code da tag'lere göre ayrılır.
|
||||
|
||||
Bu sayede client code tarafında her şey doğru şekilde sıralanır ve gruplandırılır:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image06.png">
|
||||
|
||||
Bu örnekte şunlar var:
|
||||
|
||||
* `ItemsService`
|
||||
* `UsersService`
|
||||
|
||||
### Client Method İsimleri { #client-method-names }
|
||||
|
||||
Şu an üretilen `createItemItemsPost` gibi method isimleri çok temiz görünmüyor:
|
||||
|
||||
```TypeScript
|
||||
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
|
||||
```
|
||||
|
||||
...çünkü client üreteci, her *path operation* için OpenAPI'nin dahili **operation ID** değerini kullanır.
|
||||
|
||||
OpenAPI, her operation ID'nin tüm *path operation*'lar arasında benzersiz olmasını ister. Bu yüzden FastAPI; operation ID'yi benzersiz tutabilmek için **function adı**, **path** ve **HTTP method/operation** bilgilerini birleştirerek üretir.
|
||||
|
||||
Ancak bunu bir sonraki adımda nasıl iyileştirebileceğinizi göstereceğim. 🤓
|
||||
|
||||
## Özel Operation ID'ler ve Daha İyi Method İsimleri { #custom-operation-ids-and-better-method-names }
|
||||
|
||||
Bu operation ID'lerin **üretilme** şeklini **değiştirerek**, client'larda daha basit **method isimleri** elde edebilirsiniz.
|
||||
|
||||
Bu durumda, her operation ID'nin **benzersiz** olduğundan başka bir şekilde emin olmanız gerekir.
|
||||
|
||||
Örneğin, her *path operation*'ın bir tag'i olmasını sağlayabilir ve operation ID'yi **tag** ve *path operation* **adı**na (function adı) göre üretebilirsiniz.
|
||||
|
||||
### Benzersiz ID Üreten Özel Fonksiyon { #custom-generate-unique-id-function }
|
||||
|
||||
FastAPI, her *path operation* için bir **unique ID** kullanır. Bu ID, **operation ID** için ve ayrıca request/response'lar için gerekebilecek özel model isimleri için de kullanılır.
|
||||
|
||||
Bu fonksiyonu özelleştirebilirsiniz. Bir `APIRoute` alır ve string döndürür.
|
||||
|
||||
Örneğin burada ilk tag'i (muhtemelen tek tag'iniz olur) ve *path operation* adını (function adı) kullanıyor.
|
||||
|
||||
Sonrasında bu özel fonksiyonu `generate_unique_id_function` parametresiyle **FastAPI**'ye geçebilirsiniz:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
|
||||
|
||||
### Özel Operation ID'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-custom-operation-ids }
|
||||
|
||||
Artık client'ı tekrar üretirseniz, geliştirilmiş method isimlerini göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image07.png">
|
||||
|
||||
Gördüğünüz gibi method isimleri artık önce tag'i, sonra function adını içeriyor; URL path'i ve HTTP operation bilgisini artık taşımıyor.
|
||||
|
||||
### Client Üretecine Vermeden Önce OpenAPI Spesifikasyonunu Ön İşlemek { #preprocess-the-openapi-specification-for-the-client-generator }
|
||||
|
||||
Üretilen kodda hâlâ bazı **tekrarlanan bilgiler** var.
|
||||
|
||||
Bu method'un **items** ile ilişkili olduğunu zaten biliyoruz; çünkü bu kelime `ItemsService` içinde var (tag'den geliyor). Ama method adında da tag adı önek olarak duruyor. 😕
|
||||
|
||||
OpenAPI genelinde muhtemelen bunu korumak isteriz; çünkü operation ID'lerin **benzersiz** olmasını sağlar.
|
||||
|
||||
Ancak üretilen client için, client'ları üretmeden hemen önce OpenAPI operation ID'lerini **değiştirip**, method isimlerini daha hoş ve **temiz** hale getirebiliriz.
|
||||
|
||||
OpenAPI JSON'u `openapi.json` diye bir dosyaya indirip, şu tarz bir script ile **öndeki tag'i kaldırabiliriz**:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial004_py310.py *}
|
||||
|
||||
//// tab | Node.js
|
||||
|
||||
```Javascript
|
||||
{!> ../../docs_src/generate_clients/tutorial004.js!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Bununla operation ID'ler `items-get_items` gibi değerlerden sadece `get_items` olacak şekilde yeniden adlandırılır; böylece client üreteci daha basit method isimleri üretebilir.
|
||||
|
||||
### Ön İşlenmiş OpenAPI ile TypeScript Client Üretme { #generate-a-typescript-client-with-the-preprocessed-openapi }
|
||||
|
||||
Sonuç artık bir `openapi.json` dosyasında olduğuna göre, input konumunu güncellemeniz gerekir:
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i ./openapi.json -o src/client
|
||||
```
|
||||
|
||||
Yeni client'ı ürettikten sonra, tüm **otomatik tamamlama**, **satır içi hatalar**, vb. ile birlikte **temiz method isimleri** elde edersiniz:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image08.png">
|
||||
|
||||
## Faydalar { #benefits }
|
||||
|
||||
Otomatik üretilen client'ları kullanınca şu alanlarda **otomatik tamamlama** elde edersiniz:
|
||||
|
||||
* Method'lar.
|
||||
* Body'deki request payload'ları, query parametreleri, vb.
|
||||
* Response payload'ları.
|
||||
|
||||
Ayrıca her şey için **satır içi hatalar** (inline errors) da olur.
|
||||
|
||||
Backend kodunu her güncellediğinizde ve frontend'i **yeniden ürettiğinizde**, yeni *path operation*'lar method olarak eklenir, eskileri kaldırılır ve diğer değişiklikler de üretilen koda yansır. 🤓
|
||||
|
||||
Bu, bir şey değiştiğinde client code'a otomatik olarak **yansıyacağı** anlamına gelir. Ayrıca client'ı **build** ettiğinizde, kullanılan verilerde bir **uyuşmazlık** (mismatch) varsa hata alırsınız.
|
||||
|
||||
Böylece üretimde son kullanıcılara hata yansımasını beklemek ve sonra sorunun nerede olduğunu debug etmeye çalışmak yerine, geliştirme sürecinin çok erken aşamalarında **birçok hatayı tespit edersiniz**. ✨
|
||||
@@ -1,36 +1,21 @@
|
||||
# Gelişmiş Kullanıcı Rehberi
|
||||
# Gelişmiş Kullanıcı Rehberi { #advanced-user-guide }
|
||||
|
||||
## Ek Özellikler
|
||||
## Ek Özellikler { #additional-features }
|
||||
|
||||
[Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası **FastAPI**'ın tüm ana özelliklerini tanıtmaya yetecektir.
|
||||
Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası, **FastAPI**'nin tüm temel özelliklerini tanımanız için yeterli olmalıdır.
|
||||
|
||||
İlerleyen bölümlerde diğer seçenekler, konfigürasyonlar ve ek özellikleri göreceğiz.
|
||||
Sonraki bölümlerde diğer seçenekleri, konfigürasyonları ve ek özellikleri göreceksiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Sonraki bölümler **mutlaka "gelişmiş" olmak zorunda değildir**.
|
||||
|
||||
Kullanım şeklinize bağlı olarak, çözümünüz bu bölümlerden birinde olabilir.
|
||||
Ve kullanım amacınıza bağlı olarak, çözüm bunlardan birinde olabilir.
|
||||
|
||||
///
|
||||
|
||||
## Önce Öğreticiyi Okuyun
|
||||
## Önce Tutorial'ı Okuyun { #read-the-tutorial-first }
|
||||
|
||||
[Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nın çoğu özelliğini kullanabilirsiniz.
|
||||
Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nin çoğu özelliğini yine de kullanabilirsiniz.
|
||||
|
||||
Sonraki bölümler bu sayfayı okuduğunuzu ve bu ana fikirleri bildiğinizi varsayarak hazırlanmıştır.
|
||||
|
||||
## Diğer Kurslar
|
||||
|
||||
[Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası ve bu **Gelişmiş Kullanıcı Rehberi**, öğretici bir kılavuz (bir kitap gibi) şeklinde yazılmıştır ve **FastAPI'ı öğrenmek** için yeterli olsa da, ek kurslarla desteklemek isteyebilirsiniz.
|
||||
|
||||
Belki de öğrenme tarzınıza daha iyi uyduğu için başka kursları tercih edebilirsiniz.
|
||||
|
||||
Bazı kurs sağlayıcıları ✨ [**FastAPI destekçileridir**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, bu FastAPI ve **ekosisteminin** sürekli ve sağlıklı bir şekilde **gelişmesini** sağlar.
|
||||
|
||||
Ayrıca, size **iyi bir öğrenme deneyimi** sağlamakla kalmayıp, **iyi ve sağlıklı bir framework** olan FastAPI'a ve ve **topluluğuna** (yani size) olan gerçek bağlılıklarını gösterir.
|
||||
|
||||
Onların kurslarını denemek isteyebilirsiniz:
|
||||
|
||||
* <a href="https://training.talkpython.fm/fastapi-courses" class="external-link" target="_blank">Talk Python Training</a>
|
||||
* <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development</a>
|
||||
Ve sonraki bölümler, onu zaten okuduğunuzu ve bu temel fikirleri bildiğinizi varsayar.
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# İleri Seviye Middleware { #advanced-middleware }
|
||||
|
||||
Ana tutorial'da uygulamanıza [Özel Middleware](../tutorial/middleware.md){.internal-link target=_blank} eklemeyi gördünüz.
|
||||
|
||||
Ardından [`CORSMiddleware` ile CORS'u yönetmeyi](../tutorial/cors.md){.internal-link target=_blank} de okudunuz.
|
||||
|
||||
Bu bölümde diğer middleware'leri nasıl kullanacağımıza bakacağız.
|
||||
|
||||
## ASGI middleware'leri ekleme { #adding-asgi-middlewares }
|
||||
|
||||
**FastAPI**, Starlette üzerine kurulu olduğu ve <abbr title="Asynchronous Server Gateway Interface - Asenkron Sunucu Ağ Geçidi Arayüzü">ASGI</abbr> spesifikasyonunu uyguladığı için, herhangi bir ASGI middleware'ini kullanabilirsiniz.
|
||||
|
||||
Bir middleware'in çalışması için özellikle FastAPI ya da Starlette için yazılmış olması gerekmez; ASGI spec'ine uyduğu sürece yeterlidir.
|
||||
|
||||
Genel olarak ASGI middleware'leri, ilk argüman olarak bir ASGI app almayı bekleyen class'lar olur.
|
||||
|
||||
Dolayısıyla üçüncü taraf ASGI middleware'lerinin dokümantasyonunda muhtemelen şöyle bir şey yapmanızı söylerler:
|
||||
|
||||
```Python
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = SomeASGIApp()
|
||||
|
||||
new_app = UnicornMiddleware(app, some_config="rainbow")
|
||||
```
|
||||
|
||||
Ancak FastAPI (aslında Starlette) bunu yapmanın daha basit bir yolunu sunar; böylece dahili middleware'ler server hatalarını doğru şekilde ele alır ve özel exception handler'lar düzgün çalışır.
|
||||
|
||||
Bunun için `app.add_middleware()` kullanırsınız (CORS örneğindeki gibi).
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.add_middleware(UnicornMiddleware, some_config="rainbow")
|
||||
```
|
||||
|
||||
`app.add_middleware()` ilk argüman olarak bir middleware class'ı alır ve middleware'e aktarılacak ek argümanları da kabul eder.
|
||||
|
||||
## Entegre middleware'ler { #integrated-middlewares }
|
||||
|
||||
**FastAPI**, yaygın kullanım senaryoları için birkaç middleware içerir; şimdi bunları nasıl kullanacağımıza bakacağız.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Bir sonraki örneklerde `from starlette.middleware.something import SomethingMiddleware` kullanmanız da mümkündür.
|
||||
|
||||
**FastAPI**, size (geliştirici olarak) kolaylık olsun diye `fastapi.middleware` içinde bazı middleware'leri sağlar. Ancak mevcut middleware'lerin çoğu doğrudan Starlette'ten gelir.
|
||||
|
||||
///
|
||||
|
||||
## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
|
||||
|
||||
Gelen tüm request'lerin `https` veya `wss` olmasını zorunlu kılar.
|
||||
|
||||
`http` veya `ws` olarak gelen herhangi bir request, bunun yerine güvenli şemaya redirect edilir.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
|
||||
|
||||
## `TrustedHostMiddleware` { #trustedhostmiddleware }
|
||||
|
||||
HTTP Host Header saldırılarına karşı korunmak için, gelen tüm request'lerde `Host` header'ının doğru ayarlanmış olmasını zorunlu kılar.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
|
||||
|
||||
Aşağıdaki argümanlar desteklenir:
|
||||
|
||||
* `allowed_hosts` - Hostname olarak izin verilmesi gereken domain adlarının listesi. `*.example.com` gibi wildcard domain'ler subdomain eşleştirmesi için desteklenir. Herhangi bir hostname'e izin vermek için `allowed_hosts=["*"]` kullanın veya middleware'i hiç eklemeyin.
|
||||
* `www_redirect` - True olarak ayarlanırsa, izin verilen host'ların www olmayan sürümlerine gelen request'ler www sürümlerine redirect edilir. Varsayılanı `True`'dur.
|
||||
|
||||
Gelen bir request doğru şekilde doğrulanmazsa `400` response gönderilir.
|
||||
|
||||
## `GZipMiddleware` { #gzipmiddleware }
|
||||
|
||||
`Accept-Encoding` header'ında `"gzip"` içeren herhangi bir request için GZip response'larını yönetir.
|
||||
|
||||
Middleware hem standart hem de streaming response'ları ele alır.
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
|
||||
|
||||
Aşağıdaki argümanlar desteklenir:
|
||||
|
||||
* `minimum_size` - Bayt cinsinden bu minimum boyuttan küçük response'lara GZip uygulama. Varsayılanı `500`'dür.
|
||||
* `compresslevel` - GZip sıkıştırması sırasında kullanılır. 1 ile 9 arasında bir tamsayıdır. Varsayılanı `9`'dur. Daha düşük değer daha hızlı sıkıştırma ama daha büyük dosya boyutları üretir; daha yüksek değer daha yavaş sıkıştırma ama daha küçük dosya boyutları üretir.
|
||||
|
||||
## Diğer middleware'ler { #other-middlewares }
|
||||
|
||||
Başka birçok ASGI middleware'i vardır.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn'un `ProxyHeadersMiddleware`'i</a>
|
||||
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
|
||||
|
||||
Diğer mevcut middleware'leri görmek için <a href="https://www.starlette.dev/middleware/" class="external-link" target="_blank">Starlette'in Middleware dokümanlarına</a> ve <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">ASGI Awesome List</a> listesine bakın.
|
||||
@@ -0,0 +1,186 @@
|
||||
# OpenAPI Callback'leri { #openapi-callbacks }
|
||||
|
||||
Başka biri tarafından (muhtemelen API'nizi *kullanacak* olan aynı geliştirici tarafından) oluşturulmuş bir *external API*'ye request tetikleyebilen bir *path operation* ile bir API oluşturabilirsiniz.
|
||||
|
||||
API uygulamanızın *external API*'yi çağırdığı sırada gerçekleşen sürece "callback" denir. Çünkü dış geliştiricinin yazdığı yazılım API'nize bir request gönderir ve ardından API'niz *geri çağrı* yaparak (*call back*), bir *external API*'ye request gönderir (muhtemelen aynı geliştiricinin oluşturduğu).
|
||||
|
||||
Bu durumda, o external API'nin nasıl görünmesi *gerektiğini* dokümante etmek isteyebilirsiniz. Hangi *path operation*'a sahip olmalı, hangi body'yi beklemeli, hangi response'u döndürmeli, vb.
|
||||
|
||||
## Callback'leri olan bir uygulama { #an-app-with-callbacks }
|
||||
|
||||
Bunların hepsine bir örnekle bakalım.
|
||||
|
||||
Fatura oluşturmayı sağlayan bir uygulama geliştirdiğinizi düşünün.
|
||||
|
||||
Bu faturaların `id`, `title` (opsiyonel), `customer` ve `total` alanları olacak.
|
||||
|
||||
API'nizin kullanıcısı (external bir geliştirici) API'nizde bir POST request ile fatura oluşturacak.
|
||||
|
||||
Sonra API'niz (varsayalım ki):
|
||||
|
||||
* Faturayı external geliştiricinin bir müşterisine gönderir.
|
||||
* Parayı tahsil eder.
|
||||
* API kullanıcısına (external geliştiriciye) tekrar bir bildirim gönderir.
|
||||
* Bu, external geliştiricinin sağladığı bir *external API*'ye (*sizin API'nizden*) bir POST request gönderilerek yapılır (işte bu "callback"tir).
|
||||
|
||||
## Normal **FastAPI** uygulaması { #the-normal-fastapi-app }
|
||||
|
||||
Önce callback eklemeden önce normal API uygulamasının nasıl görüneceğine bakalım.
|
||||
|
||||
Bir `Invoice` body alacak bir *path operation*'ı ve callback için URL'yi taşıyacak `callback_url` adlı bir query parametresi olacak.
|
||||
|
||||
Bu kısım oldukça standart; kodun çoğu muhtemelen size zaten tanıdık gelecektir:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`callback_url` query parametresi, Pydantic'in <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a> tipini kullanır.
|
||||
|
||||
///
|
||||
|
||||
Tek yeni şey, *path operation decorator*'ına argüman olarak verilen `callbacks=invoices_callback_router.routes`. Bunun ne olduğuna şimdi bakacağız.
|
||||
|
||||
## Callback'i dokümante etmek { #documenting-the-callback }
|
||||
|
||||
Callback'in gerçek kodu, büyük ölçüde sizin API uygulamanıza bağlıdır.
|
||||
|
||||
Ve bir uygulamadan diğerine oldukça değişebilir.
|
||||
|
||||
Sadece bir-iki satır kod bile olabilir, örneğin:
|
||||
|
||||
```Python
|
||||
callback_url = "https://example.com/api/v1/invoices/events/"
|
||||
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
```
|
||||
|
||||
Ancak callback'in belki de en önemli kısmı, API'nizin kullanıcısının (external geliştiricinin) *external API*'yi doğru şekilde uyguladığından emin olmaktır; çünkü *sizin API'niz* callback'in request body'sinde belirli veriler gönderecektir, vb.
|
||||
|
||||
Dolayısıyla sıradaki adım olarak, *sizin API'nizden* callback almak için o *external API*'nin nasıl görünmesi gerektiğini dokümante eden kodu ekleyeceğiz.
|
||||
|
||||
Bu dokümantasyon, API'nizde `/docs` altındaki Swagger UI'da görünecek ve external geliştiricilere *external API*'yi nasıl inşa edeceklerini gösterecek.
|
||||
|
||||
Bu örnek callback'in kendisini implemente etmiyor (o zaten tek satır kod olabilir), sadece dokümantasyon kısmını ekliyor.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Gerçek callback, sadece bir HTTP request'tir.
|
||||
|
||||
Callback'i kendiniz implemente ederken <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> veya <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a> gibi bir şey kullanabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Callback dokümantasyon kodunu yazın { #write-the-callback-documentation-code }
|
||||
|
||||
Bu kod uygulamanızda çalıştırılmayacak; sadece o *external API*'nin nasıl görünmesi gerektiğini *dokümante etmek* için gerekiyor.
|
||||
|
||||
Ancak **FastAPI** ile bir API için otomatik dokümantasyonu kolayca nasıl üreteceğinizi zaten biliyorsunuz.
|
||||
|
||||
O halde aynı bilgiyi kullanarak, *external API*'nin nasıl görünmesi gerektiğini dokümante edeceğiz... external API'nin implemente etmesi gereken *path operation*'ları oluşturarak (API'nizin çağıracağı olanlar).
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bir callback'i dokümante eden kodu yazarken, kendinizi *external geliştirici* olarak hayal etmek faydalı olabilir. Ve şu anda *sizin API'nizi* değil, *external API*'yi implemente ettiğinizi düşünün.
|
||||
|
||||
Bu bakış açısını (external geliştiricinin bakış açısını) geçici olarak benimsemek; parametreleri nereye koyacağınızı, body için Pydantic modelini, response için modelini vb. external API tarafında nasıl tasarlayacağınızı daha net hale getirebilir.
|
||||
|
||||
///
|
||||
|
||||
### Bir callback `APIRouter` oluşturun { #create-a-callback-apirouter }
|
||||
|
||||
Önce bir veya daha fazla callback içerecek yeni bir `APIRouter` oluşturun.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
|
||||
|
||||
### Callback *path operation*'ını oluşturun { #create-the-callback-path-operation }
|
||||
|
||||
Callback *path operation*'ını oluşturmak için, yukarıda oluşturduğunuz aynı `APIRouter`'ı kullanın.
|
||||
|
||||
Normal bir FastAPI *path operation*'ı gibi görünmelidir:
|
||||
|
||||
* Muhtemelen alması gereken body'nin bir deklarasyonu olmalı, örn. `body: InvoiceEvent`.
|
||||
* Ayrıca döndürmesi gereken response'un deklarasyonu da olabilir, örn. `response_model=InvoiceEventReceived`.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
|
||||
|
||||
Normal bir *path operation*'dan 2 temel farkı vardır:
|
||||
|
||||
* Gerçek bir koda ihtiyaç duymaz; çünkü uygulamanız bu kodu asla çağırmayacak. Bu yalnızca *external API*'yi dokümante etmek için kullanılır. Yani fonksiyon sadece `pass` içerebilir.
|
||||
* *path*, bir <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (aşağıda daha fazlası) içerebilir; böylece parametreler ve *sizin API'nize* gönderilen orijinal request'in bazı parçalarıyla değişkenler kullanılabilir.
|
||||
|
||||
### Callback path ifadesi { #the-callback-path-expression }
|
||||
|
||||
Callback *path*'i, *sizin API'nize* gönderilen orijinal request'in bazı parçalarını içerebilen bir <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> barındırabilir.
|
||||
|
||||
Bu örnekte, bu bir `str`:
|
||||
|
||||
```Python
|
||||
"{$callback_url}/invoices/{$request.body.id}"
|
||||
```
|
||||
|
||||
Yani API'nizin kullanıcısı (external geliştirici) *sizin API'nize* şu adrese bir request gönderirse:
|
||||
|
||||
```
|
||||
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
```
|
||||
|
||||
ve JSON body şu şekilde olursa:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"id": "2expen51ve",
|
||||
"customer": "Mr. Richie Rich",
|
||||
"total": "9999"
|
||||
}
|
||||
```
|
||||
|
||||
o zaman *sizin API'niz* faturayı işleyecek ve daha sonra bir noktada `callback_url`'ye (yani *external API*'ye) bir callback request gönderecek:
|
||||
|
||||
```
|
||||
https://www.external.org/events/invoices/2expen51ve
|
||||
```
|
||||
|
||||
ve JSON body yaklaşık şöyle bir şey içerecek:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"description": "Payment celebration",
|
||||
"paid": true
|
||||
}
|
||||
```
|
||||
|
||||
ve o *external API*'den şu gibi bir JSON body içeren response bekleyecek:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Callback URL'sinin, `callback_url` içindeki query parametresi olarak alınan URL'yi (`https://www.external.org/events`) ve ayrıca JSON body'nin içindeki fatura `id`'sini (`2expen51ve`) birlikte kullandığına dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
### Callback router'ını ekleyin { #add-the-callback-router }
|
||||
|
||||
Bu noktada, yukarıda oluşturduğunuz callback router'ında gerekli callback *path operation*'ları (external geliştiricinin *external API*'de implemente etmesi gerekenler) hazır.
|
||||
|
||||
Şimdi *sizin API'nizin path operation decorator*'ında `callbacks` parametresini kullanarak, callback router'ının `.routes` attribute'unu (bu aslında route/*path operation*'lardan oluşan bir `list`) geçin:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`callback=` içine router'ın kendisini (`invoices_callback_router`) değil, `invoices_callback_router.routes` şeklinde `.routes` attribute'unu verdiğinize dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
### Dokümanları kontrol edin { #check-the-docs }
|
||||
|
||||
Artık uygulamanızı başlatıp <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidebilirsiniz.
|
||||
|
||||
*Path operation*'ınız için, *external API*'nin nasıl görünmesi gerektiğini gösteren bir "Callbacks" bölümünü içeren dokümanları göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/openapi-callbacks/image01.png">
|
||||
@@ -0,0 +1,55 @@
|
||||
# OpenAPI Webhook'lar { #openapi-webhooks }
|
||||
|
||||
Bazı durumlarda, API'nizi kullanan **kullanıcılara** uygulamanızın *onların* uygulamasını (request göndererek) bazı verilerle çağırabileceğini; genellikle bir tür **event** hakkında **bildirim** yapmak için kullanacağını söylemek istersiniz.
|
||||
|
||||
Bu da şunu ifade eder: Kullanıcılarınızın API'nize request göndermesi şeklindeki normal akış yerine, request'i **sizin API'niz** (veya uygulamanız) **onların sistemine** (onların API'sine, onların uygulamasına) **gönderebilir**.
|
||||
|
||||
Buna genellikle **webhook** denir.
|
||||
|
||||
## Webhook adımları { #webhooks-steps }
|
||||
|
||||
Süreç genellikle şöyledir: Kodunuzda göndereceğiniz mesajın ne olduğunu, yani request'in **body**'sini **siz tanımlarsınız**.
|
||||
|
||||
Ayrıca uygulamanızın bu request'leri veya event'leri hangi **anlarda** göndereceğini de bir şekilde tanımlarsınız.
|
||||
|
||||
Ve **kullanıcılarınız** da bir şekilde (örneğin bir web dashboard üzerinden) uygulamanızın bu request'leri göndermesi gereken **URL**'yi tanımlar.
|
||||
|
||||
Webhook'lar için URL'lerin nasıl kaydedileceğine dair tüm **mantık** ve bu request'leri gerçekten gönderen kod tamamen size bağlıdır. Bunu **kendi kodunuzda** istediğiniz gibi yazarsınız.
|
||||
|
||||
## **FastAPI** ve OpenAPI ile webhook'ları dokümante etmek { #documenting-webhooks-with-fastapi-and-openapi }
|
||||
|
||||
**FastAPI** ile OpenAPI kullanarak bu webhook'ların adlarını, uygulamanızın gönderebileceği HTTP operation türlerini (örn. `POST`, `PUT`, vb.) ve uygulamanızın göndereceği request **body**'lerini tanımlayabilirsiniz.
|
||||
|
||||
Bu, kullanıcılarınızın **webhook** request'lerinizi alacak şekilde **API'lerini implement etmesini** çok daha kolaylaştırabilir; hatta kendi API kodlarının bir kısmını otomatik üretebilirler.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Webhook'lar OpenAPI 3.1.0 ve üzeri sürümlerde mevcuttur; FastAPI `0.99.0` ve üzeri tarafından desteklenir.
|
||||
|
||||
///
|
||||
|
||||
## Webhook'ları olan bir uygulama { #an-app-with-webhooks }
|
||||
|
||||
Bir **FastAPI** uygulaması oluşturduğunuzda, *webhook*'ları tanımlamak için kullanabileceğiniz bir `webhooks` attribute'u vardır; *path operation* tanımlar gibi, örneğin `@app.webhooks.post()` ile.
|
||||
|
||||
{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
|
||||
|
||||
Tanımladığınız webhook'lar **OpenAPI** şemasında ve otomatik **docs UI**'da yer alır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`app.webhooks` nesnesi aslında sadece bir `APIRouter`'dır; uygulamanızı birden fazla dosya ile yapılandırırken kullanacağınız türün aynısıdır.
|
||||
|
||||
///
|
||||
|
||||
Dikkat edin: Webhook'larda aslında bir *path* (ör. `/items/`) deklare etmiyorsunuz; oraya verdiğiniz metin sadece webhook'un bir **identifier**'ıdır (event'in adı). Örneğin `@app.webhooks.post("new-subscription")` içinde webhook adı `new-subscription`'dır.
|
||||
|
||||
Bunun nedeni, webhook request'ini almak istedikleri gerçek **URL path**'i **kullanıcılarınızın** başka bir şekilde (örn. bir web dashboard üzerinden) tanımlamasının beklenmesidir.
|
||||
|
||||
### Dokümanları kontrol edin { #check-the-docs }
|
||||
|
||||
Şimdi uygulamanızı başlatıp <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
|
||||
|
||||
Dokümanlarınızda normal *path operation*'ları ve artık bazı **webhook**'ları da göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/openapi-webhooks/image01.png">
|
||||
@@ -0,0 +1,172 @@
|
||||
# Path Operation İleri Düzey Yapılandırma { #path-operation-advanced-configuration }
|
||||
|
||||
## OpenAPI operationId { #openapi-operationid }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
OpenAPI konusunda "uzman" değilseniz, muhtemelen buna ihtiyacınız yok.
|
||||
|
||||
///
|
||||
|
||||
*path operation*’ınızda kullanılacak OpenAPI `operationId` değerini `operation_id` parametresiyle ayarlayabilirsiniz.
|
||||
|
||||
Bunun her operation için benzersiz olduğundan emin olmanız gerekir.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
|
||||
|
||||
### operationId olarak *path operation function* adını kullanma { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
API’lerinizin function adlarını `operationId` olarak kullanmak istiyorsanız, hepsini dolaşıp her *path operation*’ın `operation_id` değerini `APIRoute.name` ile override edebilirsiniz.
|
||||
|
||||
Bunu, tüm *path operation*’ları ekledikten sonra yapmalısınız.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`app.openapi()` fonksiyonunu manuel olarak çağırıyorsanız, bunu yapmadan önce `operationId`’leri güncellemelisiniz.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bunu yaparsanız, her bir *path operation function*’ın adının benzersiz olduğundan emin olmanız gerekir.
|
||||
|
||||
Farklı modüllerde (Python dosyalarında) olsalar bile.
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI’den Hariç Tutma { #exclude-from-openapi }
|
||||
|
||||
Bir *path operation*’ı üretilen OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) hariç tutmak için `include_in_schema` parametresini kullanın ve `False` yapın:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
|
||||
|
||||
## Docstring’den İleri Düzey Açıklama { #advanced-description-from-docstring }
|
||||
|
||||
OpenAPI için, bir *path operation function*’ın docstring’inden kullanılacak satırları sınırlandırabilirsiniz.
|
||||
|
||||
Bir `\f` (escape edilmiş "form feed" karakteri) eklerseniz, **FastAPI** OpenAPI için kullanılan çıktıyı bu noktada **keser**.
|
||||
|
||||
Dokümantasyonda görünmez, ancak diğer araçlar (Sphinx gibi) geri kalan kısmı kullanabilir.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
## Ek Responses { #additional-responses }
|
||||
|
||||
Muhtemelen bir *path operation* için `response_model` ve `status_code` tanımlamayı görmüşsünüzdür.
|
||||
|
||||
Bu, bir *path operation*’ın ana response’u ile ilgili metadata’yı tanımlar.
|
||||
|
||||
Ek response’ları; modelleri, status code’ları vb. ile birlikte ayrıca da tanımlayabilirsiniz.
|
||||
|
||||
Dokümantasyonda bununla ilgili ayrı bir bölüm var; [OpenAPI’de Ek Responses](additional-responses.md){.internal-link target=_blank} sayfasından okuyabilirsiniz.
|
||||
|
||||
## OpenAPI Extra { #openapi-extra }
|
||||
|
||||
Uygulamanızda bir *path operation* tanımladığınızda, **FastAPI** OpenAPI şemasına dahil edilmek üzere o *path operation* ile ilgili metadata’yı otomatik olarak üretir.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
OpenAPI spesifikasyonunda buna <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Nesnesi</a> denir.
|
||||
|
||||
///
|
||||
|
||||
Bu, *path operation* hakkında tüm bilgileri içerir ve otomatik dokümantasyonu üretmek için kullanılır.
|
||||
|
||||
`tags`, `parameters`, `requestBody`, `responses` vb. alanları içerir.
|
||||
|
||||
Bu *path operation*’a özel OpenAPI şeması normalde **FastAPI** tarafından otomatik üretilir; ancak siz bunu genişletebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu, düşük seviyeli bir genişletme noktasıdır.
|
||||
|
||||
Yalnızca ek response’lar tanımlamanız gerekiyorsa, bunu yapmanın daha pratik yolu [OpenAPI’de Ek Responses](additional-responses.md){.internal-link target=_blank} kullanmaktır.
|
||||
|
||||
///
|
||||
|
||||
Bir *path operation* için OpenAPI şemasını `openapi_extra` parametresiyle genişletebilirsiniz.
|
||||
|
||||
### OpenAPI Extensions { #openapi-extensions }
|
||||
|
||||
Örneğin bu `openapi_extra`, [OpenAPI Uzantıları](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) tanımlamak için faydalı olabilir:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
|
||||
|
||||
Otomatik API dokümanlarını açtığınızda, extension’ınız ilgili *path operation*’ın en altında görünür.
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
Ayrıca ortaya çıkan OpenAPI’yi (API’nizde `/openapi.json`) görüntülerseniz, extension’ınızı ilgili *path operation*’ın bir parçası olarak orada da görürsünüz:
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-aperture-labs-portal": "blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Özel OpenAPI *path operation* şeması { #custom-openapi-path-operation-schema }
|
||||
|
||||
`openapi_extra` içindeki dictionary, *path operation* için otomatik üretilen OpenAPI şemasıyla derinlemesine (deep) birleştirilir.
|
||||
|
||||
Böylece otomatik üretilen şemaya ek veri ekleyebilirsiniz.
|
||||
|
||||
Örneğin, Pydantic ile FastAPI’nin otomatik özelliklerini kullanmadan request’i kendi kodunuzla okuyup doğrulamaya karar verebilirsiniz; ancak yine de OpenAPI şemasında request’i tanımlamak isteyebilirsiniz.
|
||||
|
||||
Bunu `openapi_extra` ile yapabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
|
||||
|
||||
Bu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak <dfn title="bytes gibi düz bir formattan, ör. bytes, Python nesnelerine dönüştürme">ayrıştırılmıyor</dfn>; doğrudan `bytes` olarak okunuyor ve `magic_data_reader()` fonksiyonu bunu bir şekilde parse etmekten sorumlu oluyor.
|
||||
|
||||
Buna rağmen, request body için beklenen şemayı tanımlayabiliriz.
|
||||
|
||||
### Özel OpenAPI content type { #custom-openapi-content-type }
|
||||
|
||||
Aynı yöntemi kullanarak, Pydantic model ile JSON Schema’yı tanımlayıp bunu *path operation* için özel OpenAPI şeması bölümüne dahil edebilirsiniz.
|
||||
|
||||
Ve bunu, request içindeki veri tipi JSON olmasa bile yapabilirsiniz.
|
||||
|
||||
Örneğin bu uygulamada, FastAPI’nin Pydantic modellerinden JSON Schema çıkarmaya yönelik entegre işlevselliğini ve JSON için otomatik doğrulamayı kullanmıyoruz. Hatta request content type’ını JSON değil, YAML olarak tanımlıyoruz:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
|
||||
|
||||
Buna rağmen, varsayılan entegre işlevselliği kullanmasak da, YAML olarak almak istediğimiz veri için JSON Schema’yı manuel üretmek üzere bir Pydantic model kullanmaya devam ediyoruz.
|
||||
|
||||
Ardından request’i doğrudan kullanıp body’yi `bytes` olarak çıkarıyoruz. Bu da FastAPI’nin request payload’ını JSON olarak parse etmeye çalışmayacağı anlamına gelir.
|
||||
|
||||
Sonrasında kodumuzda bu YAML içeriğini doğrudan parse ediyor, ardından YAML içeriğini doğrulamak için yine aynı Pydantic modeli kullanıyoruz:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Burada aynı Pydantic modeli tekrar kullanıyoruz.
|
||||
|
||||
Aynı şekilde, başka bir yöntemle de doğrulama yapabilirdik.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,31 @@
|
||||
# Response - Status Code Değiştirme { #response-change-status-code }
|
||||
|
||||
Muhtemelen daha önce varsayılan bir [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank} ayarlayabileceğinizi okumuşsunuzdur.
|
||||
|
||||
Ancak bazı durumlarda, varsayılandan farklı bir status code döndürmeniz gerekir.
|
||||
|
||||
## Kullanım senaryosu { #use-case }
|
||||
|
||||
Örneğin, varsayılan olarak "OK" `200` HTTP status code'u döndürmek istediğinizi düşünün.
|
||||
|
||||
Ama veri mevcut değilse onu oluşturmak ve "CREATED" `201` HTTP status code'u döndürmek istiyorsunuz.
|
||||
|
||||
Aynı zamanda, döndürdüğünüz veriyi bir `response_model` ile filtreleyip dönüştürebilmeyi de sürdürmek istiyorsunuz.
|
||||
|
||||
Bu tür durumlarda bir `Response` parametresi kullanabilirsiniz.
|
||||
|
||||
## Bir `Response` parametresi kullanın { #use-a-response-parameter }
|
||||
|
||||
*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz (cookie ve header'lar için yapabildiğiniz gibi).
|
||||
|
||||
Ardından bu *geçici (temporal)* `Response` nesnesi üzerinde `status_code` değerini ayarlayabilirsiniz.
|
||||
|
||||
{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
|
||||
|
||||
Sonrasında, normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (`dict`, bir veritabanı modeli, vb.).
|
||||
|
||||
Ve eğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.
|
||||
|
||||
**FastAPI**, status code'u (ayrıca cookie ve header'ları) bu *geçici (temporal)* response'tan alır ve `response_model` ile filtrelenmiş, sizin döndürdüğünüz değeri içeren nihai response'a yerleştirir.
|
||||
|
||||
Ayrıca `Response` parametresini dependency'lerde de tanımlayıp status code'u orada ayarlayabilirsiniz. Ancak unutmayın, en son ayarlanan değer geçerli olur.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Response Cookie'leri { #response-cookies }
|
||||
|
||||
## Bir `Response` parametresi kullanın { #use-a-response-parameter }
|
||||
|
||||
*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz.
|
||||
|
||||
Ardından bu *geçici* response nesnesi üzerinde cookie'leri set edebilirsiniz.
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
|
||||
|
||||
Sonrasında normalde yaptığınız gibi ihtiyaç duyduğunuz herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.).
|
||||
|
||||
Ayrıca bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.
|
||||
|
||||
**FastAPI**, bu *geçici* response'u cookie'leri (ayrıca header'ları ve status code'u) çıkarmak için kullanır ve bunları, döndürdüğünüz değeri içeren nihai response'a ekler. Döndürdüğünüz değer, varsa `response_model` ile filtrelenmiş olur.
|
||||
|
||||
`Response` parametresini dependency'lerde de tanımlayıp, onların içinde cookie (ve header) set edebilirsiniz.
|
||||
|
||||
## Doğrudan bir `Response` döndürün { #return-a-response-directly }
|
||||
|
||||
Kodunuzda doğrudan bir `Response` döndürürken de cookie oluşturabilirsiniz.
|
||||
|
||||
Bunu yapmak için, [Doğrudan Response Döndürme](response-directly.md){.internal-link target=_blank} bölümünde anlatıldığı gibi bir response oluşturabilirsiniz.
|
||||
|
||||
Sonra bunun içinde Cookie'leri set edin ve response'u döndürün:
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// tip
|
||||
|
||||
`Response` parametresini kullanmak yerine doğrudan bir response döndürürseniz, FastAPI onu olduğu gibi (doğrudan) döndürür.
|
||||
|
||||
Bu yüzden, verinizin doğru tipte olduğundan emin olmanız gerekir. Örneğin `JSONResponse` döndürüyorsanız, verinin JSON ile uyumlu olması gerekir.
|
||||
|
||||
Ayrıca `response_model` tarafından filtrelenmesi gereken bir veriyi göndermediğinizden de emin olun.
|
||||
|
||||
///
|
||||
|
||||
### Daha fazla bilgi { #more-info }
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.responses` içinde `starlette.responses` ile aynı response sınıflarını sunar. Ancak mevcut response'ların büyük kısmı doğrudan Starlette'ten gelir.
|
||||
|
||||
Ve `Response`, header ve cookie set etmek için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` olarak da sağlar.
|
||||
|
||||
///
|
||||
|
||||
Mevcut tüm parametreleri ve seçenekleri görmek için <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette dokümantasyonuna</a> bakın.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Doğrudan Bir Response Döndürme { #return-a-response-directly }
|
||||
|
||||
**FastAPI** ile bir *path operation* oluşturduğunuzda, normalde ondan herhangi bir veri döndürebilirsiniz: bir `dict`, bir `list`, bir Pydantic model, bir veritabanı modeli vb.
|
||||
|
||||
Varsayılan olarak **FastAPI**, döndürdüğünüz bu değeri [JSON Uyumlu Encoder](../tutorial/encoder.md){.internal-link target=_blank} bölümünde anlatılan `jsonable_encoder` ile otomatik olarak JSON'a çevirir.
|
||||
|
||||
Ardından perde arkasında, JSON-uyumlu bu veriyi (ör. bir `dict`) client'a response göndermek için kullanılacak bir `JSONResponse` içine yerleştirir.
|
||||
|
||||
Ancak *path operation*'larınızdan doğrudan bir `JSONResponse` döndürebilirsiniz.
|
||||
|
||||
Bu, örneğin özel header'lar veya cookie'ler döndürmek istediğinizde faydalı olabilir.
|
||||
|
||||
## Bir `Response` Döndürme { #return-a-response }
|
||||
|
||||
Aslında herhangi bir `Response` veya onun herhangi bir alt sınıfını döndürebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`JSONResponse` zaten `Response`'un bir alt sınıfıdır.
|
||||
|
||||
///
|
||||
|
||||
Bir `Response` döndürdüğünüzde, **FastAPI** bunu olduğu gibi doğrudan iletir.
|
||||
|
||||
Pydantic model'leriyle herhangi bir veri dönüşümü yapmaz, içeriği başka bir tipe çevirmez vb.
|
||||
|
||||
Bu size ciddi bir esneklik sağlar. Herhangi bir veri türü döndürebilir, herhangi bir veri deklarasyonunu veya validasyonunu override edebilirsiniz.
|
||||
|
||||
## Bir `Response` İçinde `jsonable_encoder` Kullanma { #using-the-jsonable-encoder-in-a-response }
|
||||
|
||||
**FastAPI**, sizin döndürdüğünüz `Response` üzerinde hiçbir değişiklik yapmadığı için, içeriğinin gönderilmeye hazır olduğundan emin olmanız gerekir.
|
||||
|
||||
Örneğin, bir Pydantic model'i, önce JSON-uyumlu tiplere çevrilmeden (`datetime`, `UUID` vb.) doğrudan bir `JSONResponse` içine koyamazsınız. Önce tüm veri tipleri JSON-uyumlu hale gelecek şekilde `dict`'e çevrilmesi gerekir.
|
||||
|
||||
Bu gibi durumlarda, response'a vermeden önce verinizi dönüştürmek için `jsonable_encoder` kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olması için `starlette.responses` içeriğini `fastapi.responses` üzerinden de sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'tan gelir.
|
||||
|
||||
///
|
||||
|
||||
## Özel Bir `Response` Döndürme { #returning-a-custom-response }
|
||||
|
||||
Yukarıdaki örnek ihtiyaç duyduğunuz tüm parçaları gösteriyor, ancak henüz çok kullanışlı değil. Çünkü `item`'ı zaten doğrudan döndürebilirdiniz ve **FastAPI** varsayılan olarak onu sizin için bir `JSONResponse` içine koyup `dict`'e çevirirdi vb.
|
||||
|
||||
Şimdi bunu kullanarak nasıl özel bir response döndürebileceğinize bakalım.
|
||||
|
||||
Diyelim ki <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> response döndürmek istiyorsunuz.
|
||||
|
||||
XML içeriğinizi bir string içine koyabilir, onu bir `Response` içine yerleştirip döndürebilirsiniz:
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
## Notlar { #notes }
|
||||
|
||||
Bir `Response`'u doğrudan döndürdüğünüzde, verisi otomatik olarak validate edilmez, dönüştürülmez (serialize edilmez) veya dokümante edilmez.
|
||||
|
||||
Ancak yine de [OpenAPI'de Ek Response'lar](additional-responses.md){.internal-link target=_blank} bölümünde anlatıldığı şekilde dokümante edebilirsiniz.
|
||||
|
||||
İlerleyen bölümlerde, otomatik veri dönüşümü, dokümantasyon vb. özellikleri korurken bu özel `Response`'ları nasıl kullanıp declare edebileceğinizi göreceksiniz.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Response Header'ları { #response-headers }
|
||||
|
||||
## Bir `Response` parametresi kullanın { #use-a-response-parameter }
|
||||
|
||||
*Path operation function* içinde (cookie'lerde yapabildiğiniz gibi) tipi `Response` olan bir parametre tanımlayabilirsiniz.
|
||||
|
||||
Sonra da bu *geçici* response nesnesi üzerinde header'ları ayarlayabilirsiniz.
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
|
||||
|
||||
Ardından normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.).
|
||||
|
||||
Eğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.
|
||||
|
||||
**FastAPI**, header'ları (aynı şekilde cookie'leri ve status code'u) bu *geçici* response'dan alır ve döndürdüğünüz değeri (varsa bir `response_model` ile filtrelenmiş hâliyle) içeren nihai response'a ekler.
|
||||
|
||||
`Response` parametresini dependency'lerde de tanımlayıp, onların içinde header (ve cookie) ayarlayabilirsiniz.
|
||||
|
||||
## Doğrudan bir `Response` döndürün { #return-a-response-directly }
|
||||
|
||||
Doğrudan bir `Response` döndürdüğünüzde de header ekleyebilirsiniz.
|
||||
|
||||
[Bir Response'u Doğrudan Döndürün](response-directly.md){.internal-link target=_blank} bölümünde anlatıldığı gibi bir response oluşturun ve header'ları ek bir parametre olarak geçin:
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir.
|
||||
|
||||
Ayrıca `Response` header ve cookie ayarlamak için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` altında da sağlar.
|
||||
|
||||
///
|
||||
|
||||
## Özel Header'lar { #custom-headers }
|
||||
|
||||
Özel/proprietary header'ların <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` prefix'i kullanılarak</a> eklenebileceğini unutmayın.
|
||||
|
||||
Ancak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS ayarlarınıza eklemeniz gerekir ([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank} bölümünde daha fazla bilgi), bunun için <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette'in CORS dokümanında</a> açıklanan `expose_headers` parametresini kullanın.
|
||||
@@ -0,0 +1,107 @@
|
||||
# HTTP Basic Auth { #http-basic-auth }
|
||||
|
||||
En basit senaryolarda HTTP Basic Auth kullanabilirsiniz.
|
||||
|
||||
HTTP Basic Auth’ta uygulama, içinde kullanıcı adı ve şifre bulunan bir header bekler.
|
||||
|
||||
Eğer bunu almazsa HTTP 401 "Unauthorized" hatası döndürür.
|
||||
|
||||
Ayrıca değeri `Basic` olan ve isteğe bağlı `realm` parametresi içerebilen `WWW-Authenticate` header’ını da döndürür.
|
||||
|
||||
Bu da tarayıcıya, kullanıcı adı ve şifre için entegre giriş penceresini göstermesini söyler.
|
||||
|
||||
Ardından kullanıcı adı ve şifreyi yazdığınızda tarayıcı bunları otomatik olarak header içinde gönderir.
|
||||
|
||||
## Basit HTTP Basic Auth { #simple-http-basic-auth }
|
||||
|
||||
* `HTTPBasic` ve `HTTPBasicCredentials` import edin.
|
||||
* `HTTPBasic` kullanarak bir "`security` scheme" oluşturun.
|
||||
* *path operation*’ınızda bir dependency ile bu `security`’yi kullanın.
|
||||
* Bu, `HTTPBasicCredentials` tipinde bir nesne döndürür:
|
||||
* İçinde gönderilen `username` ve `password` bulunur.
|
||||
|
||||
{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
|
||||
|
||||
URL’yi ilk kez açmaya çalıştığınızda (veya dokümanlardaki "Execute" butonuna tıkladığınızda) tarayıcı sizden kullanıcı adınızı ve şifrenizi ister:
|
||||
|
||||
<img src="/img/tutorial/security/image12.png">
|
||||
|
||||
## Kullanıcı adını kontrol edin { #check-the-username }
|
||||
|
||||
Daha kapsamlı bir örneğe bakalım.
|
||||
|
||||
Kullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek için bir dependency kullanın.
|
||||
|
||||
Bunun için kullanıcı adı ve şifreyi kontrol ederken Python standart modülü olan <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a>’i kullanın.
|
||||
|
||||
`secrets.compare_digest()`; `bytes` ya da yalnızca ASCII karakterleri (İngilizce’deki karakterler) içeren bir `str` almalıdır. Bu da `Sebastián` içindeki `á` gibi karakterlerle çalışmayacağı anlamına gelir.
|
||||
|
||||
Bunu yönetmek için önce `username` ve `password` değerlerini UTF-8 ile encode ederek `bytes`’a dönüştürürüz.
|
||||
|
||||
Sonra `secrets.compare_digest()` kullanarak `credentials.username`’in `"stanleyjobson"` ve `credentials.password`’ün `"swordfish"` olduğundan emin olabiliriz.
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
|
||||
|
||||
Bu, kabaca şuna benzer olurdu:
|
||||
|
||||
```Python
|
||||
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
|
||||
# Bir hata döndür
|
||||
...
|
||||
```
|
||||
|
||||
Ancak `secrets.compare_digest()` kullanarak, "timing attacks" denilen bir saldırı türüne karşı güvenli olursunuz.
|
||||
|
||||
### Timing Attacks { #timing-attacks }
|
||||
|
||||
Peki "timing attack" nedir?
|
||||
|
||||
Bazı saldırganların kullanıcı adı ve şifreyi tahmin etmeye çalıştığını düşünelim.
|
||||
|
||||
Ve `johndoe` kullanıcı adı ve `love123` şifresi ile bir request gönderiyorlar.
|
||||
|
||||
Uygulamanızdaki Python kodu o zaman kabaca şuna denk olur:
|
||||
|
||||
```Python
|
||||
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
|
||||
...
|
||||
```
|
||||
|
||||
Ancak Python, `johndoe` içindeki ilk `j` ile `stanleyjobson` içindeki ilk `s`’i karşılaştırdığı anda `False` döndürür; çünkü iki string’in aynı olmadığını zaten anlar ve "kalan harfleri karşılaştırmak için daha fazla hesaplama yapmaya gerek yok" diye düşünür. Uygulamanız da "Incorrect username or password" der.
|
||||
|
||||
Sonra saldırganlar bu sefer `stanleyjobsox` kullanıcı adı ve `love123` şifresi ile dener.
|
||||
|
||||
Uygulama kodunuz da şuna benzer bir şey yapar:
|
||||
|
||||
```Python
|
||||
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
|
||||
...
|
||||
```
|
||||
|
||||
Bu kez Python, iki string’in aynı olmadığını fark etmeden önce hem `stanleyjobsox` hem de `stanleyjobson` içinde `stanleyjobso` kısmının tamamını karşılaştırmak zorunda kalır. Bu nedenle "Incorrect username or password" yanıtını vermesi birkaç mikro saniye daha uzun sürer.
|
||||
|
||||
#### Yanıt süresi saldırganlara yardımcı olur { #the-time-to-answer-helps-the-attackers }
|
||||
|
||||
Bu noktada saldırganlar, server’ın "Incorrect username or password" response’unu göndermesinin birkaç mikro saniye daha uzun sürdüğünü fark ederek _bir şeyleri_ doğru yaptıklarını anlar; yani başlangıçtaki bazı harfler doğrudur.
|
||||
|
||||
Sonra tekrar denerken, bunun `johndoe`’dan ziyade `stanleyjobsox`’a daha yakın bir şey olması gerektiğini bilerek devam edebilirler.
|
||||
|
||||
#### "Profesyonel" bir saldırı { #a-professional-attack }
|
||||
|
||||
Elbette saldırganlar bunu elle tek tek denemez; bunu yapan bir program yazarlar. Muhtemelen saniyede binlerce ya da milyonlarca test yaparlar ve her seferinde yalnızca bir doğru harf daha elde ederler.
|
||||
|
||||
Böylece birkaç dakika ya da birkaç saat içinde doğru kullanıcı adı ve şifreyi, yanıt süresini kullanarak ve uygulamamızın "yardımıyla" tahmin etmiş olurlar.
|
||||
|
||||
#### `secrets.compare_digest()` ile düzeltin { #fix-it-with-secrets-compare-digest }
|
||||
|
||||
Ancak bizim kodumuzda `secrets.compare_digest()` kullanıyoruz.
|
||||
|
||||
Kısacası, `stanleyjobsox` ile `stanleyjobson`’u karşılaştırmak için geçen süre, `johndoe` ile `stanleyjobson`’u karşılaştırmak için geçen süreyle aynı olur. Şifre için de aynı şekilde.
|
||||
|
||||
Bu sayede uygulama kodunuzda `secrets.compare_digest()` kullanarak bu güvenlik saldırıları ailesine karşı güvenli olursunuz.
|
||||
|
||||
### Hatayı döndürün { #return-the-error }
|
||||
|
||||
Credential’ların hatalı olduğunu tespit ettikten sonra, 401 status code ile (credential verilmediğinde dönenle aynı) bir `HTTPException` döndürün ve tarayıcının giriş penceresini yeniden göstermesi için `WWW-Authenticate` header’ını ekleyin:
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
|
||||
@@ -1,19 +1,19 @@
|
||||
# Gelişmiş Güvenlik
|
||||
# Gelişmiş Güvenlik { #advanced-security }
|
||||
|
||||
## Ek Özellikler
|
||||
## Ek Özellikler { #additional-features }
|
||||
|
||||
[Tutorial - User Guide: Security](../../tutorial/security/index.md){.internal-link target=_blank} sayfasında ele alınanların dışında güvenlikle ilgili bazı ek özellikler vardır.
|
||||
[Öğretici - Kullanıcı Kılavuzu: Güvenlik](../../tutorial/security/index.md){.internal-link target=_blank} sayfasında ele alınanların dışında güvenlikle ilgili bazı ek özellikler vardır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Sonraki bölümler **mutlaka "gelişmiş" olmak zorunda değildir**.
|
||||
|
||||
Kullanım şeklinize bağlı olarak, çözümünüz bu bölümlerden birinde olabilir.
|
||||
Ve kullanım durumunuza göre, çözüm bu bölümlerden birinde olabilir.
|
||||
|
||||
///
|
||||
|
||||
## Önce Öğreticiyi Okuyun
|
||||
## Önce Öğreticiyi Okuyun { #read-the-tutorial-first }
|
||||
|
||||
Sonraki bölümler [Tutorial - User Guide: Security](../../tutorial/security/index.md){.internal-link target=_blank} sayfasını okuduğunuzu varsayarak hazırlanmıştır.
|
||||
Sonraki bölümler, ana [Öğretici - Kullanıcı Kılavuzu: Güvenlik](../../tutorial/security/index.md){.internal-link target=_blank} sayfasını zaten okuduğunuzu varsayar.
|
||||
|
||||
Bu bölümler aynı kavramlara dayanır, ancak bazı ek işlevsellikler sağlar.
|
||||
Hepsi aynı kavramlara dayanır, ancak bazı ek işlevselliklere izin verir.
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
# OAuth2 scope'ları { #oauth2-scopes }
|
||||
|
||||
OAuth2 scope'larını **FastAPI** ile doğrudan kullanabilirsiniz; sorunsuz çalışacak şekilde entegre edilmiştir.
|
||||
|
||||
Bu sayede OAuth2 standardını takip eden, daha ince taneli bir izin sistemini OpenAPI uygulamanıza (ve API dokümanlarınıza) entegre edebilirsiniz.
|
||||
|
||||
Scope'lu OAuth2; Facebook, Google, GitHub, Microsoft, X (Twitter) vb. birçok büyük kimlik doğrulama sağlayıcısının kullandığı mekanizmadır. Kullanıcı ve uygulamalara belirli izinler vermek için bunu kullanırlar.
|
||||
|
||||
Facebook, Google, GitHub, Microsoft, X (Twitter) ile "giriş yaptığınızda", o uygulama scope'lu OAuth2 kullanıyor demektir.
|
||||
|
||||
Bu bölümde, **FastAPI** uygulamanızda aynı scope'lu OAuth2 ile authentication ve authorization'ı nasıl yöneteceğinizi göreceksiniz.
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu bölüm az çok ileri seviye sayılır. Yeni başlıyorsanız atlayabilirsiniz.
|
||||
|
||||
OAuth2 scope'larına mutlaka ihtiyacınız yok; authentication ve authorization'ı istediğiniz şekilde ele alabilirsiniz.
|
||||
|
||||
Namun scope'lu OAuth2, API'nize (OpenAPI ile) ve API dokümanlarınıza güzel biçimde entegre edilebilir.
|
||||
|
||||
Buna rağmen, bu scope'ları (veya başka herhangi bir security/authorization gereksinimini) kodunuzda ihtiyaç duyduğunuz şekilde yine siz zorunlu kılarsınız.
|
||||
|
||||
Birçok durumda scope'lu OAuth2 gereğinden fazla (overkill) olabilir.
|
||||
|
||||
Ama ihtiyacınız olduğunu biliyorsanız ya da merak ediyorsanız okumaya devam edin.
|
||||
|
||||
///
|
||||
|
||||
## OAuth2 scope'ları ve OpenAPI { #oauth2-scopes-and-openapi }
|
||||
|
||||
OAuth2 spesifikasyonu, "scope"ları boşluklarla ayrılmış string'lerden oluşan bir liste olarak tanımlar.
|
||||
|
||||
Bu string'lerin her birinin içeriği herhangi bir formatta olabilir, ancak boşluk içermemelidir.
|
||||
|
||||
Bu scope'lar "izinleri" temsil eder.
|
||||
|
||||
OpenAPI'de (ör. API dokümanlarında) "security scheme" tanımlayabilirsiniz.
|
||||
|
||||
Bu security scheme'lerden biri OAuth2 kullanıyorsa, scope'ları da tanımlayıp kullanabilirsiniz.
|
||||
|
||||
Her bir "scope" sadece bir string'dir (boşluksuz).
|
||||
|
||||
Genellikle belirli güvenlik izinlerini tanımlamak için kullanılır, örneğin:
|
||||
|
||||
* `users:read` veya `users:write` sık görülen örneklerdir.
|
||||
* `instagram_basic` Facebook / Instagram tarafından kullanılır.
|
||||
* `https://www.googleapis.com/auth/drive` Google tarafından kullanılır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
OAuth2'de "scope", gereken belirli bir izni bildiren bir string'den ibarettir.
|
||||
|
||||
`:` gibi başka karakterler içermesi ya da bir URL olması önemli değildir.
|
||||
|
||||
Bu detaylar implementasyon'a bağlıdır.
|
||||
|
||||
OAuth2 için bunlar sadece string'dir.
|
||||
|
||||
///
|
||||
|
||||
## Genel görünüm { #global-view }
|
||||
|
||||
Önce, ana **Tutorial - User Guide** içindeki [Password (ve hashing) ile OAuth2, JWT token'lı Bearer](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank} örneklerinden, OAuth2 scope'larına geçince hangi kısımların değiştiğine hızlıca bakalım:
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
|
||||
|
||||
Şimdi bu değişiklikleri adım adım inceleyelim.
|
||||
|
||||
## OAuth2 Security scheme { #oauth2-security-scheme }
|
||||
|
||||
İlk değişiklik, artık OAuth2 security scheme'ini iki adet kullanılabilir scope ile tanımlamamız: `me` ve `items`.
|
||||
|
||||
`scopes` parametresi; her scope'un key, açıklamasının ise value olduğu bir `dict` alır:
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
|
||||
|
||||
Bu scope'ları tanımladığımız için, login/authorize yaptığınızda API dokümanlarında görünecekler.
|
||||
|
||||
Ve hangi scope'lara erişim vermek istediğinizi seçebileceksiniz: `me` ve `items`.
|
||||
|
||||
Bu, Facebook/Google/GitHub vb. ile giriş yaparken izin verdiğinizde kullanılan mekanizmanın aynısıdır:
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
## Scope'lu JWT token { #jwt-token-with-scopes }
|
||||
|
||||
Şimdi token *path operation*'ını, istenen scope'ları döndürecek şekilde değiştirin.
|
||||
|
||||
Hâlâ aynı `OAuth2PasswordRequestForm` kullanılıyor. Bu form, request'te aldığı her scope için `str`'lerden oluşan bir `list` içeren `scopes` özelliğine sahiptir.
|
||||
|
||||
Ve scope'ları JWT token'ın bir parçası olarak döndürüyoruz.
|
||||
|
||||
/// danger | Uyarı
|
||||
|
||||
Basitlik için burada, gelen scope'ları doğrudan token'a ekliyoruz.
|
||||
|
||||
Ama uygulamanızda güvenlik açısından, yalnızca kullanıcının gerçekten sahip olabileceği scope'ları (veya sizin önceden tanımladıklarınızı) eklediğinizden emin olmalısınız.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
|
||||
|
||||
## *Path operation*'larda ve dependency'lerde scope tanımlama { #declare-scopes-in-path-operations-and-dependencies }
|
||||
|
||||
Artık `/users/me/items/` için olan *path operation*'ın `items` scope'unu gerektirdiğini tanımlıyoruz.
|
||||
|
||||
Bunun için `fastapi` içinden `Security` import edip kullanıyoruz.
|
||||
|
||||
Dependency'leri (`Depends` gibi) tanımlamak için `Security` kullanabilirsiniz; fakat `Security`, ayrıca string'lerden oluşan bir scope listesi alan `scopes` parametresini de alır.
|
||||
|
||||
Bu durumda `Security`'ye dependency fonksiyonu olarak `get_current_active_user` veriyoruz (`Depends` ile yaptığımız gibi).
|
||||
|
||||
Ama ayrıca bir `list` olarak scope'ları da veriyoruz; burada tek bir scope var: `items` (daha fazla da olabilir).
|
||||
|
||||
Ve `get_current_active_user` dependency fonksiyonu, sadece `Depends` ile değil `Security` ile de alt-dependency'ler tanımlayabilir. Kendi alt-dependency fonksiyonunu (`get_current_user`) ve daha fazla scope gereksinimini tanımlar.
|
||||
|
||||
Bu örnekte `me` scope'unu gerektiriyor (birden fazla scope da isteyebilirdi).
|
||||
|
||||
/// note | Not
|
||||
|
||||
Farklı yerlerde farklı scope'lar eklemek zorunda değilsiniz.
|
||||
|
||||
Burada, **FastAPI**'nin farklı seviyelerde tanımlanan scope'ları nasıl ele aldığını göstermek için böyle yapıyoruz.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
|
||||
|
||||
/// info | Teknik Detaylar
|
||||
|
||||
`Security` aslında `Depends`'in bir alt sınıfıdır ve sadece birazdan göreceğimiz bir ek parametreye sahiptir.
|
||||
|
||||
Ancak `Depends` yerine `Security` kullanınca **FastAPI**, security scope'larının tanımlanabileceğini bilir, bunları içeride kullanır ve API'yi OpenAPI ile dokümante eder.
|
||||
|
||||
Fakat `fastapi` içinden `Query`, `Path`, `Depends`, `Security` vb. import ettiğiniz şeyler, aslında özel sınıflar döndüren fonksiyonlardır.
|
||||
|
||||
///
|
||||
|
||||
## `SecurityScopes` kullanımı { #use-securityscopes }
|
||||
|
||||
Şimdi `get_current_user` dependency'sini güncelleyelim.
|
||||
|
||||
Bu fonksiyon, yukarıdaki dependency'ler tarafından kullanılıyor.
|
||||
|
||||
Burada, daha önce oluşturduğumuz aynı OAuth2 scheme'i dependency olarak tanımlıyoruz: `oauth2_scheme`.
|
||||
|
||||
Bu dependency fonksiyonunun kendi içinde bir scope gereksinimi olmadığı için, `oauth2_scheme` ile `Depends` kullanabiliriz; security scope'larını belirtmemiz gerekmiyorsa `Security` kullanmak zorunda değiliz.
|
||||
|
||||
Ayrıca `fastapi.security` içinden import edilen, `SecurityScopes` tipinde özel bir parametre tanımlıyoruz.
|
||||
|
||||
Bu `SecurityScopes` sınıfı, `Request`'e benzer (`Request`, request nesnesini doğrudan almak için kullanılmıştı).
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
|
||||
|
||||
## `scopes`'ları kullanma { #use-the-scopes }
|
||||
|
||||
`security_scopes` parametresi `SecurityScopes` tipinde olacaktır.
|
||||
|
||||
Bu nesnenin `scopes` adlı bir özelliği vardır; bu liste, kendisinin ve bunu alt-dependency olarak kullanan tüm dependency'lerin gerektirdiği tüm scope'ları içerir. Yani tüm "dependant"lar... kafa karıştırıcı gelebilir; aşağıda tekrar açıklanıyor.
|
||||
|
||||
`security_scopes` nesnesi (`SecurityScopes` sınıfından) ayrıca, bu scope'ları boşluklarla ayrılmış tek bir string olarak veren `scope_str` attribute'una sahiptir (bunu kullanacağız).
|
||||
|
||||
Sonrasında birkaç farklı noktada tekrar kullanabileceğimiz (`raise` edebileceğimiz) bir `HTTPException` oluşturuyoruz.
|
||||
|
||||
Bu exception içinde, gerekiyorsa, gerekli scope'ları boşlukla ayrılmış bir string olarak (`scope_str` ile) ekliyoruz. Bu scope'ları içeren string'i `WWW-Authenticate` header'ına koyuyoruz (spesifikasyonun bir parçası).
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
|
||||
|
||||
## `username` ve veri şeklinin doğrulanması { #verify-the-username-and-data-shape }
|
||||
|
||||
Bir `username` aldığımızı doğruluyoruz ve scope'ları çıkarıyoruz.
|
||||
|
||||
Ardından bu veriyi Pydantic model'i ile doğruluyoruz (`ValidationError` exception'ını yakalayarak). JWT token'ı okurken veya Pydantic ile veriyi doğrularken bir hata olursa, daha önce oluşturduğumuz `HTTPException`'ı fırlatıyoruz.
|
||||
|
||||
Bunun için Pydantic model'i `TokenData`'yı, `scopes` adlı yeni bir özellik ekleyerek güncelliyoruz.
|
||||
|
||||
Veriyi Pydantic ile doğrulayarak örneğin scope'ların tam olarak `str`'lerden oluşan bir `list` olduğunu ve `username`'in bir `str` olduğunu garanti edebiliriz.
|
||||
|
||||
Aksi halde, örneğin bir `dict` veya başka bir şey gelebilir; bu da daha sonra uygulamanın bir yerinde kırılmaya yol açıp güvenlik riski oluşturabilir.
|
||||
|
||||
Ayrıca bu `username` ile bir kullanıcı olduğunu doğruluyoruz; yoksa yine aynı exception'ı fırlatıyoruz.
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}
|
||||
|
||||
## `scopes`'ların doğrulanması { #verify-the-scopes }
|
||||
|
||||
Şimdi bu dependency'nin ve tüm dependant'ların ( *path operation*'lar dahil) gerektirdiği tüm scope'ların, alınan token'da sağlanan scope'lar içinde olup olmadığını doğruluyoruz; değilse `HTTPException` fırlatıyoruz.
|
||||
|
||||
Bunun için, tüm bu scope'ları `str` olarak içeren bir `list` olan `security_scopes.scopes` kullanılır.
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}
|
||||
|
||||
## Dependency ağacı ve scope'lar { #dependency-tree-and-scopes }
|
||||
|
||||
Bu dependency ağacını ve scope'ları tekrar gözden geçirelim.
|
||||
|
||||
`get_current_active_user` dependency'si, alt-dependency olarak `get_current_user`'ı kullandığı için, `get_current_active_user` üzerinde tanımlanan `"me"` scope'u, `get_current_user`'a geçirilen `security_scopes.scopes` içindeki gerekli scope listesine dahil edilir.
|
||||
|
||||
*Path operation*'ın kendisi de `"items"` scope'unu tanımlar; bu da `get_current_user`'a geçirilen `security_scopes.scopes` listesinde yer alır.
|
||||
|
||||
Dependency'lerin ve scope'ların hiyerarşisi şöyle görünür:
|
||||
|
||||
* *Path operation* `read_own_items` şunlara sahiptir:
|
||||
* Dependency ile gerekli scope'lar `["items"]`:
|
||||
* `get_current_active_user`:
|
||||
* `get_current_active_user` dependency fonksiyonu şunlara sahiptir:
|
||||
* Dependency ile gerekli scope'lar `["me"]`:
|
||||
* `get_current_user`:
|
||||
* `get_current_user` dependency fonksiyonu şunlara sahiptir:
|
||||
* Kendisinin gerektirdiği scope yok.
|
||||
* `oauth2_scheme` kullanan bir dependency.
|
||||
* `SecurityScopes` tipinde bir `security_scopes` parametresi:
|
||||
* Bu `security_scopes` parametresinin `scopes` adlı bir özelliği vardır ve yukarıda tanımlanan tüm scope'ları içeren bir `list` taşır, yani:
|
||||
* *Path operation* `read_own_items` için `security_scopes.scopes` `["me", "items"]` içerir.
|
||||
* *Path operation* `read_users_me` için `security_scopes.scopes` `["me"]` içerir; çünkü bu scope `get_current_active_user` dependency'sinde tanımlanmıştır.
|
||||
* *Path operation* `read_system_status` için `security_scopes.scopes` `[]` (boş) olur; çünkü herhangi bir `Security` ile `scopes` tanımlamamıştır ve dependency'si olan `get_current_user` da `scopes` tanımlamaz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Buradaki önemli ve "sihirli" nokta şu: `get_current_user`, her *path operation* için kontrol etmesi gereken farklı bir `scopes` listesi alır.
|
||||
|
||||
Bu, belirli bir *path operation* için dependency ağacındaki her *path operation* ve her dependency üzerinde tanımlanan `scopes`'lara bağlıdır.
|
||||
|
||||
///
|
||||
|
||||
## `SecurityScopes` hakkında daha fazla detay { #more-details-about-securityscopes }
|
||||
|
||||
`SecurityScopes`'u herhangi bir noktada ve birden fazla yerde kullanabilirsiniz; mutlaka "kök" dependency'de olmak zorunda değildir.
|
||||
|
||||
Her zaman, **o spesifik** *path operation* ve **o spesifik** dependency ağacı için, mevcut `Security` dependency'lerinde ve tüm dependant'larda tanımlanan security scope'larını içerir.
|
||||
|
||||
`SecurityScopes`, dependant'ların tanımladığı tüm scope'ları barındırdığı için, gereken scope'ların token'da olup olmadığını merkezi bir dependency fonksiyonunda doğrulayıp, farklı *path operation*'larda farklı scope gereksinimleri tanımlayabilirsiniz.
|
||||
|
||||
Bu kontroller her *path operation* için bağımsız yapılır.
|
||||
|
||||
## Deneyin { #check-it }
|
||||
|
||||
API dokümanlarını açarsanız, authenticate olup hangi scope'ları authorize etmek istediğinizi seçebilirsiniz.
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
Hiç scope seçmezseniz "authenticated" olursunuz; ancak `/users/me/` veya `/users/me/items/`'e erişmeye çalıştığınızda, yeterli izniniz olmadığını söyleyen bir hata alırsınız. Yine de `/status/`'a erişebilirsiniz.
|
||||
|
||||
`me` scope'unu seçip `items` scope'unu seçmezseniz `/users/me/`'a erişebilirsiniz ama `/users/me/items/`'e erişemezsiniz.
|
||||
|
||||
Bu, bir üçüncü taraf uygulamanın, bir kullanıcı tarafından sağlanan token ile bu *path operation*'lardan birine erişmeye çalıştığında; kullanıcının uygulamaya kaç izin verdiğine bağlı olarak yaşayacağı durumdur.
|
||||
|
||||
## Üçüncü taraf entegrasyonları hakkında { #about-third-party-integrations }
|
||||
|
||||
Bu örnekte OAuth2 "password" flow'unu kullanıyoruz.
|
||||
|
||||
Bu, kendi uygulamamıza giriş yaptığımız durumlar için uygundur; muhtemelen kendi frontend'imiz vardır.
|
||||
|
||||
Çünkü `username` ve `password` alacağını bildiğimiz frontend'i biz kontrol ediyoruz, dolayısıyla güvenebiliriz.
|
||||
|
||||
Ancak başkalarının bağlanacağı bir OAuth2 uygulaması geliştiriyorsanız (yani Facebook, Google, GitHub vb. gibi bir authentication provider muadili geliştiriyorsanız) diğer flow'lardan birini kullanmalısınız.
|
||||
|
||||
En yaygını implicit flow'dur.
|
||||
|
||||
En güvenlisi code flow'dur; ancak daha fazla adım gerektirdiği için implementasyonu daha karmaşıktır. Daha karmaşıktır olduğundan, birçok sağlayıcı implicit flow'yu önermeye yönelir.
|
||||
|
||||
/// note | Not
|
||||
|
||||
Her authentication provider'ın flow'ları markasının bir parçası yapmak için farklı şekilde adlandırması yaygındır.
|
||||
|
||||
Ama sonuçta aynı OAuth2 standardını implement ediyorlar.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI**, bu OAuth2 authentication flow'larının tamamı için `fastapi.security.oauth2` içinde yardımcı araçlar sunar.
|
||||
|
||||
## Decorator `dependencies` içinde `Security` { #security-in-decorator-dependencies }
|
||||
|
||||
Decorator'ın `dependencies` parametresinde bir `list` `Depends` tanımlayabildiğiniz gibi ( [Path operation decorator'larında Dependencies](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} bölümünde açıklandığı üzere), burada `scopes` ile birlikte `Security` de kullanabilirsiniz.
|
||||
@@ -0,0 +1,302 @@
|
||||
# Ayarlar ve Ortam Değişkenleri { #settings-and-environment-variables }
|
||||
|
||||
Birçok durumda uygulamanızın bazı harici ayarlara veya konfigürasyonlara ihtiyacı olabilir; örneğin secret key'ler, veritabanı kimlik bilgileri, e-posta servisleri için kimlik bilgileri vb.
|
||||
|
||||
Bu ayarların çoğu değişkendir (değişebilir); örneğin veritabanı URL'leri. Ayrıca birçoğu hassas olabilir; örneğin secret'lar.
|
||||
|
||||
Bu nedenle bunları, uygulama tarafından okunan environment variable'lar ile sağlamak yaygındır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Environment variable'ları anlamak için [Environment Variables](../environment-variables.md){.internal-link target=_blank} dokümanını okuyabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Tipler ve doğrulama { #types-and-validation }
|
||||
|
||||
Bu environment variable'lar yalnızca metin (string) taşıyabilir; çünkü Python'ın dışındadırlar ve diğer programlarla ve sistemin geri kalanıyla uyumlu olmaları gerekir (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle de).
|
||||
|
||||
Bu da, Python içinde bir environment variable'dan okunan herhangi bir değerin `str` olacağı anlamına gelir; farklı bir tipe dönüştürme veya herhangi bir doğrulama işlemi kod içinde yapılmalıdır.
|
||||
|
||||
## Pydantic `Settings` { #pydantic-settings }
|
||||
|
||||
Neyse ki Pydantic, environment variable'lardan gelen bu ayarları yönetmek için <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/" class="external-link" target="_blank">Pydantic: Settings management</a> ile çok iyi bir yardımcı araç sunar.
|
||||
|
||||
### `pydantic-settings`'i kurun { #install-pydantic-settings }
|
||||
|
||||
Önce, [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, aktive ettiğinizden emin olun ve ardından `pydantic-settings` paketini kurun:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install pydantic-settings
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ayrıca `all` extras'ını şu şekilde kurduğunuzda da dahil gelir:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[all]"
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### `Settings` nesnesini oluşturun { #create-the-settings-object }
|
||||
|
||||
Pydantic'ten `BaseSettings` import edin ve bir alt sınıf (sub-class) oluşturun; tıpkı bir Pydantic model'inde olduğu gibi.
|
||||
|
||||
Pydantic model'lerinde olduğu gibi, type annotation'larla (ve gerekirse default değerlerle) class attribute'ları tanımlarsınız.
|
||||
|
||||
Pydantic model'lerinde kullandığınız aynı doğrulama özelliklerini ve araçlarını burada da kullanabilirsiniz; örneğin farklı veri tipleri ve `Field()` ile ek doğrulamalar.
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Hızlıca kopyalayıp yapıştırmak istiyorsanız bu örneği kullanmayın; aşağıdaki son örneği kullanın.
|
||||
|
||||
///
|
||||
|
||||
Ardından, bu `Settings` sınıfının bir instance'ını oluşturduğunuzda (bu örnekte `settings` nesnesi), Pydantic environment variable'ları büyük/küçük harfe duyarsız şekilde okur; yani büyük harfli `APP_NAME` değişkeni, yine de `app_name` attribute'u için okunur.
|
||||
|
||||
Sonrasında veriyi dönüştürür ve doğrular. Böylece `settings` nesnesini kullandığınızda, tanımladığınız tiplerde verilere sahip olursunuz (örn. `items_per_user` bir `int` olur).
|
||||
|
||||
### `settings`'i kullanın { #use-the-settings }
|
||||
|
||||
Daha sonra uygulamanızda yeni `settings` nesnesini kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
|
||||
|
||||
### Server'ı çalıştırın { #run-the-server }
|
||||
|
||||
Sonraki adımda server'ı çalıştırırken konfigürasyonları environment variable olarak geçersiniz; örneğin `ADMIN_EMAIL` ve `APP_NAME` şu şekilde ayarlanabilir:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Tek bir komut için birden fazla env var ayarlamak istiyorsanız aralarına boşluk koyun ve hepsini komuttan önce yazın.
|
||||
|
||||
///
|
||||
|
||||
Böylece `admin_email` ayarı `"deadpool@example.com"` olur.
|
||||
|
||||
`app_name` `"ChimichangApp"` olur.
|
||||
|
||||
`items_per_user` ise default değeri olan `50` olarak kalır.
|
||||
|
||||
## Ayarları başka bir module'de tutma { #settings-in-another-module }
|
||||
|
||||
[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, bu ayarları başka bir module dosyasına koyabilirsiniz.
|
||||
|
||||
Örneğin `config.py` adında bir dosyanız şu şekilde olabilir:
|
||||
|
||||
{* ../../docs_src/settings/app01_py310/config.py *}
|
||||
|
||||
Ve ardından bunu `main.py` dosyasında kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, ayrıca bir `__init__.py` dosyasına da ihtiyacınız olacak.
|
||||
|
||||
///
|
||||
|
||||
## Dependency içinde ayarlar { #settings-in-a-dependency }
|
||||
|
||||
Bazı durumlarda, her yerde kullanılan global bir `settings` nesnesi yerine ayarları bir dependency üzerinden sağlamak faydalı olabilir.
|
||||
|
||||
Bu özellikle test sırasında çok işe yarar; çünkü bir dependency'yi kendi özel ayarlarınızla override etmek çok kolaydır.
|
||||
|
||||
### Config dosyası { #the-config-file }
|
||||
|
||||
Bir önceki örnekten devam edersek, `config.py` dosyanız şöyle görünebilir:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
|
||||
|
||||
Dikkat edin, artık default bir instance `settings = Settings()` oluşturmuyoruz.
|
||||
|
||||
### Ana uygulama dosyası { #the-main-app-file }
|
||||
|
||||
Şimdi, yeni bir `config.Settings()` döndüren bir dependency oluşturuyoruz.
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`@lru_cache` konusunu birazdan ele alacağız.
|
||||
|
||||
Şimdilik `get_settings()`'in normal bir fonksiyon olduğunu varsayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Sonra bunu dependency olarak *path operation function*'dan talep edebilir ve ihtiyaç duyduğumuz her yerde kullanabiliriz.
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
|
||||
|
||||
### Ayarlar ve test { #settings-and-testing }
|
||||
|
||||
Ardından, `get_settings` için bir dependency override oluşturarak test sırasında farklı bir settings nesnesi sağlamak çok kolay olur:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
|
||||
|
||||
Dependency override içinde, yeni `Settings` nesnesini oluştururken `admin_email` için yeni bir değer ayarlarız ve sonra bu yeni nesneyi döndürürüz.
|
||||
|
||||
Sonrasında bunun kullanıldığını test edebiliriz.
|
||||
|
||||
## `.env` dosyası okuma { #reading-a-env-file }
|
||||
|
||||
Çok sayıda ayarınız varsa ve bunlar farklı ortamlarda sık sık değişiyorsa, bunları bir dosyaya koyup, sanki environment variable'mış gibi o dosyadan okumak faydalı olabilir.
|
||||
|
||||
Bu yaklaşım oldukça yaygındır ve bir adı vardır: Bu environment variable'lar genellikle `.env` adlı bir dosyaya konur ve bu dosyaya "dotenv" denir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Nokta (`.`) ile başlayan dosyalar, Linux ve macOS gibi Unix-benzeri sistemlerde gizli dosyadır.
|
||||
|
||||
Ancak dotenv dosyasının mutlaka bu dosya adına sahip olması gerekmez.
|
||||
|
||||
///
|
||||
|
||||
Pydantic, harici bir kütüphane kullanarak bu tür dosyalardan okuma desteğine sahiptir. Daha fazlası için: <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic Settings: Dotenv (.env) support</a>.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bunun çalışması için `pip install python-dotenv` yapmanız gerekir.
|
||||
|
||||
///
|
||||
|
||||
### `.env` dosyası { #the-env-file }
|
||||
|
||||
Şöyle bir `.env` dosyanız olabilir:
|
||||
|
||||
```bash
|
||||
ADMIN_EMAIL="deadpool@example.com"
|
||||
APP_NAME="ChimichangApp"
|
||||
```
|
||||
|
||||
### Ayarları `.env`'den okuyun { #read-settings-from-env }
|
||||
|
||||
Ardından `config.py` dosyanızı şöyle güncelleyin:
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`model_config` attribute'u yalnızca Pydantic konfigürasyonu içindir. Daha fazlası için <a href="https://docs.pydantic.dev/latest/concepts/config/" class="external-link" target="_blank">Pydantic: Concepts: Configuration</a>.
|
||||
|
||||
///
|
||||
|
||||
Burada, Pydantic `Settings` sınıfınızın içinde `env_file` konfigürasyonunu tanımlar ve değer olarak kullanmak istediğimiz dotenv dosyasının dosya adını veririz.
|
||||
|
||||
### `lru_cache` ile `Settings`'i yalnızca bir kez oluşturma { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
Diskten dosya okumak normalde maliyetli (yavaş) bir işlemdir; bu yüzden muhtemelen bunu yalnızca bir kez yapıp aynı settings nesnesini tekrar kullanmak istersiniz. Her request için yeniden okumak istemezsiniz.
|
||||
|
||||
Ancak her seferinde şunu yaptığımızda:
|
||||
|
||||
```Python
|
||||
Settings()
|
||||
```
|
||||
|
||||
yeni bir `Settings` nesnesi oluşturulur ve oluşturulurken `.env` dosyasını yeniden okur.
|
||||
|
||||
Dependency fonksiyonu sadece şöyle olsaydı:
|
||||
|
||||
```Python
|
||||
def get_settings():
|
||||
return Settings()
|
||||
```
|
||||
|
||||
bu nesneyi her request için oluştururduk ve `.env` dosyasını her request'te okurduk. ⚠️
|
||||
|
||||
Fakat en üstte `@lru_cache` decorator'ünü kullandığımız için `Settings` nesnesi yalnızca bir kez, ilk çağrıldığı anda oluşturulur. ✔️
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
|
||||
|
||||
Sonraki request'lerde dependency'ler içinden `get_settings()` çağrıldığında, `get_settings()`'in iç kodu tekrar çalıştırılıp yeni bir `Settings` nesnesi yaratılmak yerine, ilk çağrıda döndürülen aynı nesne tekrar tekrar döndürülür.
|
||||
|
||||
#### `lru_cache` Teknik Detayları { #lru-cache-technical-details }
|
||||
|
||||
`@lru_cache`, decorator olarak uygulandığı fonksiyonu, her seferinde tekrar hesaplamak yerine ilk seferde döndürdüğü değeri döndürecek şekilde değiştirir; yani fonksiyon kodunu her çağrıda yeniden çalıştırmaz.
|
||||
|
||||
Bu nedenle altındaki fonksiyon, argüman kombinasyonlarının her biri için bir kez çalıştırılır. Sonra bu argüman kombinasyonlarının her biri için döndürülmüş değerler, fonksiyon aynı argüman kombinasyonuyla çağrıldıkça tekrar tekrar kullanılır.
|
||||
|
||||
Örneğin, şöyle bir fonksiyonunuz varsa:
|
||||
|
||||
```Python
|
||||
@lru_cache
|
||||
def say_hi(name: str, salutation: str = "Ms."):
|
||||
return f"Hello {salutation} {name}"
|
||||
```
|
||||
|
||||
programınız şu şekilde çalışabilir:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant code as Code
|
||||
participant function as say_hi()
|
||||
participant execute as Execute function
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Rick")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Rick", salutation="Mr.")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Rick")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
```
|
||||
|
||||
Bizim `get_settings()` dependency'miz özelinde ise fonksiyon hiç argüman almaz; dolayısıyla her zaman aynı değeri döndürür.
|
||||
|
||||
Bu şekilde, neredeyse global bir değişken gibi davranır. Ancak bir dependency fonksiyonu kullandığı için testte kolayca override edebiliriz.
|
||||
|
||||
`@lru_cache`, Python standart kütüphanesinin bir parçası olan `functools` içindedir. Daha fazla bilgi için: <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python docs for `@lru_cache`</a>.
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Uygulamanızın ayarlarını veya konfigürasyonlarını yönetmek için, Pydantic model'lerinin tüm gücüyle birlikte Pydantic Settings'i kullanabilirsiniz.
|
||||
|
||||
* Dependency kullanarak test etmeyi basitleştirebilirsiniz.
|
||||
* Bununla `.env` dosyalarını kullanabilirsiniz.
|
||||
* `@lru_cache` kullanmak, dotenv dosyasını her request için tekrar tekrar okumayı engellerken, test sırasında override etmenize de izin verir.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Alt Uygulamalar - Mount İşlemi { #sub-applications-mounts }
|
||||
|
||||
Kendi bağımsız OpenAPI şemaları ve kendi dokümantasyon arayüzleri olan iki bağımsız FastAPI uygulamasına ihtiyacınız varsa, bir ana uygulama oluşturup bir (veya daha fazla) alt uygulamayı "mount" edebilirsiniz.
|
||||
|
||||
## Bir **FastAPI** uygulamasını mount etmek { #mounting-a-fastapi-application }
|
||||
|
||||
"Mount" etmek, belirli bir path altında tamamen "bağımsız" bir uygulamayı eklemek anlamına gelir. Ardından o path’in altındaki her şeyi, alt uygulamada tanımlanan _path operation_’lar ile o alt uygulama yönetir.
|
||||
|
||||
### Üst seviye uygulama { #top-level-application }
|
||||
|
||||
Önce ana, üst seviye **FastAPI** uygulamasını ve onun *path operation*’larını oluşturun:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
|
||||
|
||||
### Alt uygulama { #sub-application }
|
||||
|
||||
Sonra alt uygulamanızı ve onun *path operation*’larını oluşturun.
|
||||
|
||||
Bu alt uygulama da standart bir FastAPI uygulamasıdır; ancak "mount" edilecek olan budur:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
|
||||
|
||||
### Alt uygulamayı mount edin { #mount-the-sub-application }
|
||||
|
||||
Üst seviye uygulamanızda (`app`), alt uygulama `subapi`’yi mount edin.
|
||||
|
||||
Bu örnekte `/subapi` path’ine mount edilecektir:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
|
||||
|
||||
### Otomatik API dokümanlarını kontrol edin { #check-the-automatic-api-docs }
|
||||
|
||||
Şimdi dosyanızla birlikte `fastapi` komutunu çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ardından <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresinden dokümanları açın.
|
||||
|
||||
Ana uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image01.png">
|
||||
|
||||
Sonra alt uygulamanın dokümanlarını <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a> adresinden açın.
|
||||
|
||||
Alt uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir ve hepsi doğru alt-path öneki `/subapi` altında yer alır:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image02.png">
|
||||
|
||||
İki arayüzden herhangi biriyle etkileşime girmeyi denerseniz doğru şekilde çalıştıklarını görürsünüz; çünkü tarayıcı her bir uygulama ya da alt uygulama ile ayrı ayrı iletişim kurabilir.
|
||||
|
||||
### Teknik Detaylar: `root_path` { #technical-details-root-path }
|
||||
|
||||
Yukarıda anlatıldığı gibi bir alt uygulamayı mount ettiğinizde FastAPI, ASGI spesifikasyonundaki `root_path` adlı bir mekanizmayı kullanarak alt uygulamaya mount path’ini iletmeyi otomatik olarak yönetir.
|
||||
|
||||
Bu sayede alt uygulama, dokümantasyon arayüzü için o path önekini kullanması gerektiğini bilir.
|
||||
|
||||
Ayrıca alt uygulamanın kendi mount edilmiş alt uygulamaları da olabilir; FastAPI tüm bu `root_path`’leri otomatik olarak yönettiği için her şey doğru şekilde çalışır.
|
||||
|
||||
`root_path` hakkında daha fazlasını ve bunu açıkça nasıl kullanacağınızı [Proxy Arkasında](behind-a-proxy.md){.internal-link target=_blank} bölümünde öğreneceksiniz.
|
||||
@@ -0,0 +1,126 @@
|
||||
# Şablonlar { #templates }
|
||||
|
||||
**FastAPI** ile istediğiniz herhangi bir template engine'i kullanabilirsiniz.
|
||||
|
||||
Yaygın bir tercih, Flask ve diğer araçların da kullandığı Jinja2'dir.
|
||||
|
||||
Bunu kolayca yapılandırmak için, doğrudan **FastAPI** uygulamanızda kullanabileceğiniz yardımcı araçlar vardır (Starlette tarafından sağlanır).
|
||||
|
||||
## Bağımlılıkları Yükleme { #install-dependencies }
|
||||
|
||||
Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden ve `jinja2`'yi yüklediğinizden emin olun:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install jinja2
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## `Jinja2Templates` Kullanımı { #using-jinja2templates }
|
||||
|
||||
* `Jinja2Templates`'ı içe aktarın.
|
||||
* Daha sonra tekrar kullanabileceğiniz bir `templates` nesnesi oluşturun.
|
||||
* Template döndürecek *path operation* içinde bir `Request` parametresi tanımlayın.
|
||||
* Oluşturduğunuz `templates` nesnesini kullanarak bir `TemplateResponse` render edip döndürün; template'in adını, request nesnesini ve Jinja2 template'i içinde kullanılacak anahtar-değer çiftlerini içeren bir "context" sözlüğünü (dict) iletin.
|
||||
|
||||
{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
|
||||
|
||||
/// note
|
||||
|
||||
FastAPI 0.108.0 ve Starlette 0.29.0 öncesinde, ilk parametre `name` idi.
|
||||
|
||||
Ayrıca, daha önceki sürümlerde `request` nesnesi, Jinja2 için context içindeki anahtar-değer çiftlerinin bir parçası olarak geçirilirdi.
|
||||
|
||||
///
|
||||
|
||||
/// tip
|
||||
|
||||
`response_class=HTMLResponse` olarak tanımlarsanız doküman arayüzü (docs UI) response'un HTML olacağını anlayabilir.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.templating import Jinja2Templates` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici için kolaylık olması adına `starlette.templating` içeriğini `fastapi.templating` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `Request` ve `StaticFiles` için de aynı durum geçerlidir.
|
||||
|
||||
///
|
||||
|
||||
## Template Yazma { #writing-templates }
|
||||
|
||||
Ardından örneğin `templates/item.html` konumunda bir template yazabilirsiniz:
|
||||
|
||||
```jinja hl_lines="7"
|
||||
{!../../docs_src/templates/templates/item.html!}
|
||||
```
|
||||
|
||||
### Template Context Değerleri { #template-context-values }
|
||||
|
||||
Şu HTML içeriğinde:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja
|
||||
Item ID: {{ id }}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
...gösterilecek olan `id`, sizin "context" olarak ilettiğiniz `dict` içinden alınır:
|
||||
|
||||
```Python
|
||||
{"id": id}
|
||||
```
|
||||
|
||||
Örneğin ID değeri `42` ise, şu şekilde render edilir:
|
||||
|
||||
```html
|
||||
Item ID: 42
|
||||
```
|
||||
|
||||
### Template `url_for` Argümanları { #template-url-for-arguments }
|
||||
|
||||
Template içinde `url_for()` da kullanabilirsiniz; argüman olarak, *path operation function*'ınızın kullandığı argümanların aynısını alır.
|
||||
|
||||
Dolayısıyla şu bölüm:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja
|
||||
<a href="{{ url_for('read_item', id=id) }}">
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
...*path operation function* olan `read_item(id=id)` tarafından handle edilecek URL'nin aynısına bir link üretir.
|
||||
|
||||
Örneğin ID değeri `42` ise, şu şekilde render edilir:
|
||||
|
||||
```html
|
||||
<a href="/items/42">
|
||||
```
|
||||
|
||||
## Template'ler ve statik dosyalar { #templates-and-static-files }
|
||||
|
||||
Template içinde `url_for()` kullanabilir ve örneğin `name="static"` ile mount ettiğiniz `StaticFiles` ile birlikte kullanabilirsiniz.
|
||||
|
||||
```jinja hl_lines="4"
|
||||
{!../../docs_src/templates/templates/item.html!}
|
||||
```
|
||||
|
||||
Bu örnekte, şu şekilde `static/styles.css` konumundaki bir CSS dosyasına link verir:
|
||||
|
||||
```CSS hl_lines="4"
|
||||
{!../../docs_src/templates/static/styles.css!}
|
||||
```
|
||||
|
||||
Ve `StaticFiles` kullandığınız için, bu CSS dosyası **FastAPI** uygulamanız tarafından `/static/styles.css` URL'sinde otomatik olarak servis edilir.
|
||||
|
||||
## Daha fazla detay { #more-details }
|
||||
|
||||
Template'leri nasıl test edeceğiniz dahil daha fazla detay için <a href="https://www.starlette.dev/templates/" class="external-link" target="_blank">Starlette'in template dokümantasyonuna</a> bakın.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Override Kullanarak Dependency'leri Test Etme { #testing-dependencies-with-overrides }
|
||||
|
||||
## Test Sırasında Dependency Override Etme { #overriding-dependencies-during-testing }
|
||||
|
||||
Test yazarken bazı durumlarda bir dependency'yi override etmek isteyebilirsiniz.
|
||||
|
||||
Orijinal dependency'nin (ve varsa tüm alt dependency'lerinin) çalışmasını istemezsiniz.
|
||||
|
||||
Bunun yerine, yalnızca testler sırasında (hatta belki sadece belirli bazı testlerde) kullanılacak farklı bir dependency sağlarsınız; böylece orijinal dependency'nin ürettiği değerin kullanıldığı yerde, test için üretilen değeri kullanabilirsiniz.
|
||||
|
||||
### Kullanım Senaryoları: Harici Servis { #use-cases-external-service }
|
||||
|
||||
Örneğin, çağırmanız gereken harici bir authentication provider'ınız olabilir.
|
||||
|
||||
Ona bir token gönderirsiniz ve o da authenticated bir user döndürür.
|
||||
|
||||
Bu provider request başına ücret alıyor olabilir ve onu çağırmak, testlerde sabit bir mock user kullanmaya kıyasla daha fazla zaman alabilir.
|
||||
|
||||
Muhtemelen harici provider'ı bir kez test etmek istersiniz; ancak çalışan her testte onu çağırmanız şart değildir.
|
||||
|
||||
Bu durumda, o provider'ı çağıran dependency'yi override edebilir ve yalnızca testleriniz için mock user döndüren özel bir dependency kullanabilirsiniz.
|
||||
|
||||
### `app.dependency_overrides` Attribute'ünü Kullanın { #use-the-app-dependency-overrides-attribute }
|
||||
|
||||
Bu tür durumlar için **FastAPI** uygulamanızda `app.dependency_overrides` adında bir attribute bulunur; bu basit bir `dict`'tir.
|
||||
|
||||
Test için bir dependency'yi override etmek istediğinizde, key olarak orijinal dependency'yi (bir function), value olarak da override edecek dependency'nizi (başka bir function) verirsiniz.
|
||||
|
||||
Böylece **FastAPI**, orijinal dependency yerine bu override'ı çağırır.
|
||||
|
||||
{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
**FastAPI** uygulamanızın herhangi bir yerinde kullanılan bir dependency için override tanımlayabilirsiniz.
|
||||
|
||||
Orijinal dependency bir *path operation function* içinde, bir *path operation decorator* içinde (return value kullanmadığınız durumlarda), bir `.include_router()` çağrısında, vb. kullanılıyor olabilir.
|
||||
|
||||
FastAPI yine de onu override edebilir.
|
||||
|
||||
///
|
||||
|
||||
Sonrasında override'larınızı (yani kaldırıp sıfırlamayı) `app.dependency_overrides` değerini boş bir `dict` yaparak gerçekleştirebilirsiniz:
|
||||
|
||||
```Python
|
||||
app.dependency_overrides = {}
|
||||
```
|
||||
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bir dependency'yi yalnızca bazı testler sırasında override etmek istiyorsanız, override'ı testin başında (test function'ının içinde) ayarlayıp testin sonunda (yine test function'ının sonunda) sıfırlayabilirsiniz.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,12 @@
|
||||
# Event'leri Test Etme: lifespan ve startup - shutdown { #testing-events-lifespan-and-startup-shutdown }
|
||||
|
||||
Test'lerinizde `lifespan`'ın çalışması gerektiğinde, `TestClient`'ı bir `with` ifadesiyle kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
|
||||
|
||||
|
||||
Bu konuda daha fazla ayrıntıyı resmi Starlette dokümantasyon sitesindeki ["Testlerde lifespan'ı çalıştırma"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) bölümünde okuyabilirsiniz.
|
||||
|
||||
Kullanımdan kaldırılmış `startup` ve `shutdown` event'leri için ise `TestClient`'ı aşağıdaki gibi kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
|
||||
@@ -1,13 +1,13 @@
|
||||
# WebSockets'i Test Etmek
|
||||
# WebSockets'i Test Etmek { #testing-websockets }
|
||||
|
||||
WebSockets testi yapmak için `TestClient`'ı kullanabilirsiniz.
|
||||
WebSockets'i test etmek için aynı `TestClient`'ı kullanabilirsiniz.
|
||||
|
||||
Bu işlem için, `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanabilirsiniz:
|
||||
Bunun için `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanırsınız:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
|
||||
{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Daha fazla detay için Starlette'in <a href="https://www.starlette.dev/staticfiles/" class="external-link" target="_blank">Websockets'i Test Etmek</a> dokümantasyonunu inceleyin.
|
||||
Daha fazla detay için Starlette'in <a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank">WebSockets'i test etme</a> dokümantasyonuna bakın.
|
||||
|
||||
///
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# Request'i Doğrudan Kullanmak { #using-the-request-directly }
|
||||
|
||||
Şu ana kadar, ihtiyacınız olan request parçalarını tipleriyle birlikte tanımlıyordunuz.
|
||||
|
||||
Verileri şuradan alarak:
|
||||
|
||||
* path'ten parameter olarak.
|
||||
* Header'lardan.
|
||||
* Cookie'lerden.
|
||||
* vb.
|
||||
|
||||
Bunu yaptığınızda **FastAPI**, bu verileri doğrular (validate eder), dönüştürür ve API'niz için dokümantasyonu otomatik olarak üretir.
|
||||
|
||||
Ancak bazı durumlarda `Request` nesnesine doğrudan erişmeniz gerekebilir.
|
||||
|
||||
## `Request` nesnesi hakkında detaylar { #details-about-the-request-object }
|
||||
|
||||
**FastAPI** aslında altta **Starlette** çalıştırır ve üstüne çeşitli araçlardan oluşan bir katman ekler. Bu yüzden gerektiğinde Starlette'in <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">`Request`</a> nesnesini doğrudan kullanabilirsiniz.
|
||||
|
||||
Bu ayrıca şu anlama gelir: `Request` nesnesinden veriyi doğrudan alırsanız (örneğin body'yi okursanız) FastAPI bu veriyi doğrulamaz, dönüştürmez veya dokümante etmez (otomatik API arayüzü için OpenAPI ile).
|
||||
|
||||
Buna rağmen normal şekilde tanımladığınız diğer herhangi bir parameter (örneğin Pydantic model ile body) yine doğrulanır, dönüştürülür, annotate edilir, vb.
|
||||
|
||||
Ama bazı özel durumlarda `Request` nesnesini almak faydalıdır.
|
||||
|
||||
## `Request` nesnesini doğrudan kullanın { #use-the-request-object-directly }
|
||||
|
||||
*Path operation function* içinde client'ın IP adresini/host'unu almak istediğinizi düşünelim.
|
||||
|
||||
Bunun için request'e doğrudan erişmeniz gerekir.
|
||||
|
||||
{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
|
||||
|
||||
Tipi `Request` olan bir *path operation function* parameter'ı tanımladığınızda **FastAPI**, o parameter'a `Request` nesnesini geçmesi gerektiğini anlar.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu örnekte, request parameter'ının yanında bir path parameter'ı da tanımladığımıza dikkat edin.
|
||||
|
||||
Dolayısıyla path parameter'ı çıkarılır, doğrulanır, belirtilen tipe dönüştürülür ve OpenAPI ile annotate edilir.
|
||||
|
||||
Aynı şekilde, diğer parameter'ları normal biçimde tanımlamaya devam edip buna ek olarak `Request` de alabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## `Request` dokümantasyonu { #request-documentation }
|
||||
|
||||
<a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">Resmi Starlette dokümantasyon sitesinde `Request` nesnesiyle ilgili daha fazla detayı</a> okuyabilirsiniz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.requests import Request` de kullanabilirsiniz.
|
||||
|
||||
**FastAPI** bunu size (geliştiriciye) kolaylık olsun diye doğrudan sunar. Ancak kendisi doğrudan Starlette'ten gelir.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,186 @@
|
||||
# WebSockets { #websockets }
|
||||
|
||||
**FastAPI** ile <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a> kullanabilirsiniz.
|
||||
|
||||
## `websockets` Kurulumu { #install-websockets }
|
||||
|
||||
Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktive ettiğinizden ve `websockets`'i ("WebSocket" protokolünü kullanmayı kolaylaştıran bir Python kütüphanesi) kurduğunuzdan emin olun:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install websockets
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## WebSockets client { #websockets-client }
|
||||
|
||||
### Production'da { #in-production }
|
||||
|
||||
Production sisteminizde muhtemelen React, Vue.js veya Angular gibi modern bir framework ile oluşturulmuş bir frontend vardır.
|
||||
|
||||
WebSockets kullanarak backend'inizle iletişim kurmak için de büyük ihtimalle frontend'inizin sağladığı yardımcı araçları kullanırsınız.
|
||||
|
||||
Ya da native kod ile doğrudan WebSocket backend'inizle iletişim kuran native bir mobil uygulamanız olabilir.
|
||||
|
||||
Veya WebSocket endpoint'i ile iletişim kurmak için başka herhangi bir yönteminizi de kullanıyor olabilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
Ancak bu örnek için, tamamı uzun bir string içinde olacak şekilde biraz JavaScript içeren çok basit bir HTML dokümanı kullanacağız.
|
||||
|
||||
Elbette bu optimal değil ve production için kullanmazsınız.
|
||||
|
||||
Production'da yukarıdaki seçeneklerden birini kullanırsınız.
|
||||
|
||||
Ama WebSockets'in server tarafına odaklanmak ve çalışan bir örnek görmek için en basit yol bu:
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}
|
||||
|
||||
## Bir `websocket` Oluşturun { #create-a-websocket }
|
||||
|
||||
**FastAPI** uygulamanızda bir `websocket` oluşturun:
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.websockets import WebSocket` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için aynı `WebSocket`'i doğrudan sağlar. Ancak aslında doğrudan Starlette'ten gelir.
|
||||
|
||||
///
|
||||
|
||||
## Mesajları `await` Edin ve Mesaj Gönderin { #await-for-messages-and-send-messages }
|
||||
|
||||
WebSocket route'unuzda mesajları `await` edebilir ve mesaj gönderebilirsiniz.
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}
|
||||
|
||||
Binary, text ve JSON verisi alıp gönderebilirsiniz.
|
||||
|
||||
## Deneyin { #try-it }
|
||||
|
||||
Dosyanızın adı `main.py` ise uygulamanızı şu şekilde çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Tarayıcınızda <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresini açın.
|
||||
|
||||
Şuna benzer basit bir sayfa göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/websockets/image01.png">
|
||||
|
||||
Input kutusuna mesaj yazıp gönderebilirsiniz:
|
||||
|
||||
<img src="/img/tutorial/websockets/image02.png">
|
||||
|
||||
Ve WebSockets kullanan **FastAPI** uygulamanız yanıt döndürecektir:
|
||||
|
||||
<img src="/img/tutorial/websockets/image03.png">
|
||||
|
||||
Birçok mesaj gönderebilir (ve alabilirsiniz):
|
||||
|
||||
<img src="/img/tutorial/websockets/image04.png">
|
||||
|
||||
Ve hepsinde aynı WebSocket bağlantısı kullanılacaktır.
|
||||
|
||||
## `Depends` ve Diğerlerini Kullanma { #using-depends-and-others }
|
||||
|
||||
WebSocket endpoint'lerinde `fastapi` içinden import edip şunları kullanabilirsiniz:
|
||||
|
||||
* `Depends`
|
||||
* `Security`
|
||||
* `Cookie`
|
||||
* `Header`
|
||||
* `Path`
|
||||
* `Query`
|
||||
|
||||
Diğer FastAPI endpoint'leri/*path operations* ile aynı şekilde çalışırlar:
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bu bir WebSocket olduğu için `HTTPException` raise etmek pek anlamlı değildir; bunun yerine `WebSocketException` raise ederiz.
|
||||
|
||||
<a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">Spesifikasyonda tanımlanan geçerli kodlar</a> arasından bir kapatma kodu kullanabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
### Dependency'lerle WebSockets'i Deneyin { #try-the-websockets-with-dependencies }
|
||||
|
||||
Dosyanızın adı `main.py` ise uygulamanızı şu şekilde çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Tarayıcınızda <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresini açın.
|
||||
|
||||
Burada şunları ayarlayabilirsiniz:
|
||||
|
||||
* path'te kullanılan "Item ID".
|
||||
* query parametresi olarak kullanılan "Token".
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
query'deki `token` değerinin bir dependency tarafından ele alınacağına dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
Bununla WebSocket'e bağlanabilir, ardından mesaj gönderip alabilirsiniz:
|
||||
|
||||
<img src="/img/tutorial/websockets/image05.png">
|
||||
|
||||
## Bağlantı Kopmalarını ve Birden Fazla Client'ı Yönetme { #handling-disconnections-and-multiple-clients }
|
||||
|
||||
Bir WebSocket bağlantısı kapandığında, `await websocket.receive_text()` bir `WebSocketDisconnect` exception'ı raise eder; ardından bunu bu örnekteki gibi yakalayıp (catch) yönetebilirsiniz.
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}
|
||||
|
||||
Denemek için:
|
||||
|
||||
* Uygulamayı birden fazla tarayıcı sekmesiyle açın.
|
||||
* Bu sekmelerden mesaj yazın.
|
||||
* Sonra sekmelerden birini kapatın.
|
||||
|
||||
Bu, `WebSocketDisconnect` exception'ını raise eder ve diğer tüm client'lar şuna benzer bir mesaj alır:
|
||||
|
||||
```
|
||||
Client #1596980209979 left the chat
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Yukarıdaki uygulama, birden fazla WebSocket bağlantısına mesajları nasıl yönetip broadcast edeceğinizi göstermek için minimal ve basit bir örnektir.
|
||||
|
||||
Ancak her şey memory'de, tek bir list içinde yönetildiği için yalnızca process çalıştığı sürece ve yalnızca tek bir process ile çalışacaktır.
|
||||
|
||||
FastAPI ile kolay entegre olan ama Redis, PostgreSQL vb. tarafından desteklenen daha sağlam bir şeye ihtiyacınız varsa <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>'a göz atın.
|
||||
|
||||
///
|
||||
|
||||
## Daha Fazla Bilgi { #more-info }
|
||||
|
||||
Seçenekler hakkında daha fazlasını öğrenmek için Starlette dokümantasyonunda şunlara bakın:
|
||||
|
||||
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">`WebSocket` class'ı</a>.
|
||||
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">Class tabanlı WebSocket yönetimi</a>.
|
||||
@@ -1,32 +1,48 @@
|
||||
# WSGI - Flask, Django ve Daha Fazlasını FastAPI ile Kullanma
|
||||
# WSGI'yi Dahil Etme - Flask, Django ve Diğerleri { #including-wsgi-flask-django-others }
|
||||
|
||||
WSGI uygulamalarını [Sub Applications - Mounts](sub-applications.md){.internal-link target=_blank}, [Behind a Proxy](behind-a-proxy.md){.internal-link target=_blank} bölümlerinde gördüğünüz gibi bağlayabilirsiniz.
|
||||
WSGI uygulamalarını [Alt Uygulamalar - Mount Etme](sub-applications.md){.internal-link target=_blank}, [Bir Proxy Arkasında](behind-a-proxy.md){.internal-link target=_blank} bölümlerinde gördüğünüz gibi mount edebilirsiniz.
|
||||
|
||||
Bunun için `WSGIMiddleware` ile Flask, Django vb. WSGI uygulamanızı sarmalayabilir ve FastAPI'ya bağlayabilirsiniz.
|
||||
Bunun için `WSGIMiddleware`'ı kullanabilir ve bunu WSGI uygulamanızı (örneğin Flask, Django vb.) sarmalamak için kullanabilirsiniz.
|
||||
|
||||
## `WSGIMiddleware` Kullanımı
|
||||
## `WSGIMiddleware` Kullanımı { #using-wsgimiddleware }
|
||||
|
||||
`WSGIMiddleware`'ı projenize dahil edin.
|
||||
/// info | Bilgi
|
||||
|
||||
Ardından WSGI (örneğin Flask) uygulamanızı middleware ile sarmalayın.
|
||||
Bunun için `a2wsgi` kurulmalıdır; örneğin `pip install a2wsgi` ile.
|
||||
|
||||
Son olarak da bir yol altında bağlama işlemini gerçekleştirin.
|
||||
///
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
|
||||
`WSGIMiddleware`'ı `a2wsgi` paketinden import etmeniz gerekir.
|
||||
|
||||
## Kontrol Edelim
|
||||
Ardından WSGI (örn. Flask) uygulamasını middleware ile sarmalayın.
|
||||
|
||||
Artık `/v1/` yolunun altındaki her istek Flask uygulaması tarafından işlenecektir.
|
||||
Ve sonra bunu bir path'in altına mount edin.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Önceden, `fastapi.middleware.wsgi` içindeki `WSGIMiddleware`'ın kullanılması öneriliyordu, ancak artık kullanımdan kaldırıldı.
|
||||
|
||||
Bunun yerine `a2wsgi` paketini kullanmanız önerilir. Kullanım aynıdır.
|
||||
|
||||
Sadece `a2wsgi` paketinin kurulu olduğundan emin olun ve `WSGIMiddleware`'ı `a2wsgi` içinden doğru şekilde import edin.
|
||||
|
||||
///
|
||||
|
||||
## Kontrol Edelim { #check-it }
|
||||
|
||||
Artık `/v1/` path'i altındaki her request Flask uygulaması tarafından işlenecektir.
|
||||
|
||||
Geri kalanı ise **FastAPI** tarafından işlenecektir.
|
||||
|
||||
Eğer uygulamanızı çalıştırıp <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a> adresine giderseniz, Flask'tan gelen yanıtı göreceksiniz:
|
||||
Eğer uygulamanızı çalıştırıp <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a> adresine giderseniz, Flask'tan gelen response'u göreceksiniz:
|
||||
|
||||
```txt
|
||||
Hello, World from Flask!
|
||||
```
|
||||
|
||||
Eğer <a href="http://localhost:8000/v2/" class="external-link" target="_blank">http://localhost:8000/v2/</a> adresine giderseniz, FastAPI'dan gelen yanıtı göreceksiniz:
|
||||
Ve eğer <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> adresine giderseniz, FastAPI'dan gelen response'u göreceksiniz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
|
||||
+305
-305
@@ -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 “<dfn title="marshalling, conversion olarak da adlandırılır">dönüşüm</dfn>”ü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 <dfn title="verinin nasıl oluşturulması gerektiğinin tanımı">şemayı</dfn> 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 <dfn title="okuyup Python verisine dönüştürme">ayrıştırma</dfn>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 <dfn title="Asenkron Python web uygulamaları geliştirmek için yeni standart">ASGI</dfn> 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.
|
||||
|
||||
+208
-171
@@ -1,18 +1,18 @@
|
||||
# Concurrency ve async / await
|
||||
# Eşzamanlılık ve async / await { #concurrency-and-async-await }
|
||||
|
||||
*path operasyon fonksiyonu* için `async def `sözdizimi, asenkron kod, eşzamanlılık ve paralellik hakkında bazı ayrıntılar.
|
||||
*path operasyon fonksiyonları* için `async def` sözdizimi hakkında detaylar ve asenkron kod, eşzamanlılık (concurrency) ve paralellik üzerine arka plan bilgisi.
|
||||
|
||||
## Aceleniz mi var?
|
||||
## Aceleniz mi var? { #in-a-hurry }
|
||||
|
||||
<abbr title="too long; didn't read"><strong>TL;DR:</strong></abbr>
|
||||
<abbr title="too long; didn't read - çok uzun; okumadım"><strong>TL;DR:</strong></abbr>
|
||||
|
||||
Eğer `await` ile çağrılması gerektiğini belirten üçüncü taraf kütüphaneleri kullanıyorsanız, örneğin:
|
||||
Eğer `await` ile çağırmanız gerektiğini söyleyen üçüncü taraf kütüphaneler kullanıyorsanız, örneğin:
|
||||
|
||||
```Python
|
||||
results = await some_library()
|
||||
```
|
||||
|
||||
O zaman *path operasyon fonksiyonunu* `async def` ile tanımlayın örneğin:
|
||||
O zaman *path operasyon fonksiyonlarınızı* aşağıdaki gibi `async def` ile tanımlayın:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -23,13 +23,13 @@ async def read_results():
|
||||
|
||||
/// note | Not
|
||||
|
||||
Sadece `async def` ile tanımlanan fonksiyonlar içinde `await` kullanabilirsiniz.
|
||||
`await` yalnızca `async def` ile oluşturulan fonksiyonların içinde kullanılabilir.
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
Eğer bir veritabanı, bir API, dosya sistemi vb. ile iletişim kuran bir üçüncü taraf bir kütüphane kullanıyorsanız ve `await` kullanımını desteklemiyorsa, (bu şu anda çoğu veritabanı kütüphanesi için geçerli bir durumdur), o zaman *path operasyon fonksiyonunuzu* `def` kullanarak normal bir şekilde tanımlayın, örneğin:
|
||||
Eğer bir veritabanı, bir API, dosya sistemi vb. ile iletişim kuran ve `await` desteği olmayan bir üçüncü taraf kütüphane kullanıyorsanız (bu şu anda çoğu veritabanı kütüphanesi için geçerlidir), o zaman *path operasyon fonksiyonlarınızı* normal olarak `def` ile tanımlayın:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -40,279 +40,307 @@ def results():
|
||||
|
||||
---
|
||||
|
||||
Eğer uygulamanız (bir şekilde) başka bir şeyle iletişim kurmak ve onun cevap vermesini beklemek zorunda değilse, `async def` kullanın.
|
||||
Uygulamanız (bir şekilde) başka bir şeyle iletişim kurmak ve onun yanıtını beklemek zorunda değilse, içinde `await` kullanmanız gerekmese bile `async def` kullanın.
|
||||
|
||||
---
|
||||
|
||||
Sadece bilmiyorsanız, normal `def` kullanın.
|
||||
Emin değilseniz, normal `def` kullanın.
|
||||
|
||||
---
|
||||
|
||||
**Not**: *path operasyon fonksiyonlarınızda* `def` ve `async def`'i ihtiyaç duyduğunuz gibi karıştırabilir ve her birini sizin için en iyi seçeneği kullanarak tanımlayabilirsiniz. FastAPI onlarla doğru olanı yapacaktır.
|
||||
Not: *path operasyon fonksiyonlarınızda* `def` ve `async def`'i ihtiyacınız kadar karıştırabilirsiniz, her birini sizin için en iyi seçenekle tanımlayın. FastAPI onlar için doğru olanı yapacaktır.
|
||||
|
||||
Her neyse, yukarıdaki durumlardan herhangi birinde, FastAPI yine de asenkron olarak çalışacak ve son derece hızlı olacaktır.
|
||||
Yukarıdaki durumların herhangi birinde FastAPI yine de asenkron olarak çalışır ve son derece hızlıdır.
|
||||
|
||||
Ancak yukarıdaki adımları takip ederek, bazı performans optimizasyonları yapılabilecektir.
|
||||
Ancak yukarıdaki adımları izleyerek bazı performans optimizasyonları mümkün olur.
|
||||
|
||||
## Teknik Detaylar
|
||||
## Teknik Detaylar { #technical-details }
|
||||
|
||||
Python'un modern versiyonlarında **`async` ve `await`** sözdizimi ile **"coroutines"** kullanan **"asenkron kod"** desteğine sahiptir.
|
||||
Python’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **"coroutines"** denilen bir yapıyı kullanarak **"asenkron kod"** desteğine sahiptir.
|
||||
|
||||
Bu ifadeyi aşağıdaki bölümlerde daha da ayrıntılı açıklayalım:
|
||||
Aşağıdaki bölümlerde bu ifadeyi parça parça ele alalım:
|
||||
|
||||
* **Asenkron kod**
|
||||
* **Asenkron Kod**
|
||||
* **`async` ve `await`**
|
||||
* **Coroutines**
|
||||
* **Coroutine'ler**
|
||||
|
||||
## Asenkron kod
|
||||
## Asenkron Kod { #asynchronous-code }
|
||||
|
||||
Asenkron kod programlama dilinin 💬 bilgisayara / programa 🤖 kodun bir noktasında, *başka bir kodun* bir yerde bitmesini 🤖 beklemesi gerektiğini söylemenin bir yoludur. Bu *başka koda* "slow-file" denir 📝.
|
||||
Asenkron kod, dilin 💬 bilgisayara / programa 🤖 kodun bir noktasında, bir yerde *başka bir şeyin* bitmesini beklemesi gerektiğini söylemesinin bir yoludur. Diyelim ki bu *başka şeye* "slow-file" 📝 diyoruz.
|
||||
|
||||
Böylece, bu süreçte bilgisayar "slow-file" 📝 tamamlanırken gidip başka işler yapabilir.
|
||||
Bu sırada bilgisayar, "slow-file" 📝 biterken gidip başka işler yapabilir.
|
||||
|
||||
Sonra bilgisayar / program 🤖 her fırsatı olduğunda o noktada yaptığı tüm işleri 🤖 bitirene kadar geri dönücek. Ve 🤖 yapması gerekeni yaparak, beklediği görevlerden herhangi birinin bitip bitmediğini görecek.
|
||||
Sonra bilgisayar / program 🤖, ya tekrar beklediği için ya da o anda elindeki tüm işleri bitirdiğinde fırsat buldukça geri gelir. Ve beklediği görevlerden herhangi biri bittiyse, yapılması gerekenleri yapar.
|
||||
|
||||
Ardından, 🤖 bitirmek için ilk görevi alır ("slow-file" 📝) ve onunla ne yapması gerekiyorsa onu devam ettirir.
|
||||
Ardından, 🤖 ilk biten görevi alır (örneğin bizim "slow-file" 📝) ve onunla yapması gerekenlere devam eder.
|
||||
|
||||
Bu "başka bir şey için bekle" normalde, aşağıdakileri beklemek gibi (işlemcinin ve RAM belleğinin hızına kıyasla) nispeten "yavaş" olan <abbr title="Input ve Output (Giriş ve Çıkış)">I/O</abbr> işlemlerine atıfta bulunur:
|
||||
Bu "başka bir şeyi beklemek" genelde işlemci ve RAM hızına kıyasla nispeten "yavaş" olan <abbr title="Input and Output - Giriş ve Çıkış">I/O</abbr> işlemlerine atıfta bulunur, örneğin şunları beklemek gibi:
|
||||
|
||||
* istemci tarafından ağ üzerinden veri göndermek
|
||||
* ağ üzerinden istemciye gönderilen veriler
|
||||
* sistem tarafından okunacak ve programınıza verilecek bir dosya içeriği
|
||||
* programınızın diske yazılmak üzere sisteme verdiği dosya içerikleri
|
||||
* istemciden verinin ağ üzerinden gelmesi
|
||||
* programınızın gönderdiği verinin ağ üzerinden istemciye ulaşması
|
||||
* diskteki bir dosyanın içeriğinin sistem tarafından okunup programınıza verilmesi
|
||||
* programınızın sisteme verdiği içeriğin diske yazılması
|
||||
* uzak bir API işlemi
|
||||
* bir veritabanı bitirme işlemi
|
||||
* sonuçları döndürmek için bir veritabanı sorgusu
|
||||
* bir veritabanı işleminin bitmesi
|
||||
* bir veritabanı sorgusunun sonuç döndürmesi
|
||||
* vb.
|
||||
|
||||
Yürütme süresi çoğunlukla <abbr title="Input ve Output (Giriş ve Çıkış)">I/O</abbr> işlemleri beklenerek tüketildiğinden bunlara "I/O bağlantılı" işlemler denir.
|
||||
Çalışma süresi çoğunlukla <abbr title="Input and Output - Giriş ve Çıkış">I/O</abbr> işlemlerini beklemekle geçtiğinden, bunlara "I/O bound" işlemler denir.
|
||||
|
||||
Buna "asenkron" denir, çünkü bilgisayar/program yavaş görevle "senkronize" olmak zorunda değildir, görevin tam olarak biteceği anı bekler, hiçbir şey yapmadan, görev sonucunu alabilmek ve çalışmaya devam edebilmek için .
|
||||
"Bunun" asenkron" denmesinin sebebi, bilgisayarın / programın yavaş görevle "senkronize" olmak, görev tam bittiği anda orada olup görev sonucunu almak ve işe devam etmek için hiçbir şey yapmadan beklemek zorunda olmamasıdır.
|
||||
|
||||
Bunun yerine, "asenkron" bir sistem olarak, bir kez bittiğinde, bilgisayarın / programın yapması gerekeni bitirmesi için biraz (birkaç mikrosaniye) sırada bekleyebilir ve ardından sonuçları almak için geri gelebilir ve onlarla çalışmaya devam edebilir.
|
||||
Bunun yerine "asenkron" bir sistem olarak, görev bittiğinde, bilgisayarın / programın o sırada yaptığı işi bitirmesi için biraz (birkaç mikrosaniye) sırada bekleyebilir ve sonra sonuçları almak üzere geri dönüp onlarla çalışmaya devam edebilir.
|
||||
|
||||
"Senkron" ("asenkron"un aksine) için genellikle "sıralı" terimini de kullanırlar, çünkü bilgisayar/program, bu adımlar beklemeyi içerse bile, farklı bir göreve geçmeden önce tüm adımları sırayla izler.
|
||||
"Senkron" (asenkronun tersi) için genelde "sıralı" terimi de kullanılır; çünkü bilgisayar / program, farklı bir göreve geçmeden önce tüm adımları sırayla izler, bu adımlar beklemeyi içerse bile.
|
||||
|
||||
### Eşzamanlılık ve Burgerler { #concurrency-and-burgers }
|
||||
|
||||
### Eşzamanlılık (Concurrency) ve Burgerler
|
||||
Yukarıda anlatılan **asenkron** kod fikrine bazen **"eşzamanlılık"** (concurrency) da denir. **"Paralellik"**ten (parallelism) farklıdır.
|
||||
|
||||
**Eşzamanlılık** ve **paralellik**, "aynı anda az çok birden fazla şeyin olması" ile ilgilidir.
|
||||
|
||||
Yukarıda açıklanan bu **asenkron** kod fikrine bazen **"eşzamanlılık"** da denir. **"Paralellikten"** farklıdır.
|
||||
Ama *eşzamanlılık* ve *paralellik* arasındaki ayrıntılar oldukça farklıdır.
|
||||
|
||||
**Eşzamanlılık** ve **paralellik**, "aynı anda az ya da çok olan farklı işler" ile ilgilidir.
|
||||
Farkı görmek için burgerlerle ilgili şu hikayeyi hayal edin:
|
||||
|
||||
Ancak *eşzamanlılık* ve *paralellik* arasındaki ayrıntılar oldukça farklıdır.
|
||||
### Eşzamanlı Burgerler { #concurrent-burgers }
|
||||
|
||||
Aşkınla fast food almaya gidiyorsun, kasiyer senden önceki insanların siparişlerini alırken sıraya giriyorsun. 😍
|
||||
|
||||
Farkı görmek için burgerlerle ilgili aşağıdaki hikayeyi hayal edin:
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
||||
|
||||
### Eşzamanlı Burgerler
|
||||
Sonra sıra size geliyor, sen ve aşkın için 2 çok havalı burger sipariş ediyorsun. 🍔🍔
|
||||
|
||||
<!-- Cinsiyetten bağımsız olan aşçı emojisi "🧑🍳" tarayıcılarda yeterince iyi görüntülenmiyor. Bu yüzden erken "👨🍳" ve kadın "👩🍳" aşçıları karışık bir şekilde kullanıcağım. -->
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
||||
|
||||
Aşkınla beraber 😍 dışarı hamburger yemeye çıktınız 🍔, kasiyer 💁 öndeki insanlardan sipariş alırken siz sıraya girdiniz.
|
||||
Kasiyer, mutfaktaki aşçıya burgerlerini hazırlamaları gerektiğini söylüyor (o an önceki müşterilerin burgerlerini hazırlıyor olsalar bile).
|
||||
|
||||
Sıra sizde ve sen aşkın 😍 ve kendin için 2 çılgın hamburger 🍔 söylüyorsun.
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
|
||||
|
||||
Ödemeyi yaptın 💸.
|
||||
Ödeme yapıyorsun. 💸
|
||||
|
||||
Kasiyer 💁 mutfakdaki aşçıya 👨🍳 hamburgerleri 🍔 hazırlaması gerektiğini söyler ve aşçı bunu bilir (o an önceki müşterilerin siparişlerini hazırlıyor olsa bile).
|
||||
Kasiyer sana sıra numaranı veriyor.
|
||||
|
||||
Kasiyer 💁 size bir sıra numarası verir.
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
|
||||
|
||||
Beklerken askınla 😍 bir masaya oturur ve uzun bir süre konuşursunuz(Burgerleriniz çok çılgın olduğundan ve hazırlanması biraz zaman alıyor ✨🍔✨).
|
||||
Beklerken aşkınla bir masa seçip oturuyorsunuz, uzun uzun sohbet ediyorsunuz (burgerler baya havalı ve hazırlanması biraz zaman alıyor).
|
||||
|
||||
Hamburgeri beklerkenki zamanı 🍔, aşkının ne kadar zeki ve tatlı olduğuna hayran kalarak harcayabilirsin ✨😍✨.
|
||||
Masada aşkınla otururken, burgerleri beklerken, o zamanı aşkının ne kadar harika, tatlı ve zeki olduğuna hayran kalarak geçirebilirsin ✨😍✨.
|
||||
|
||||
Aşkınla 😍 konuşurken arada sıranın size gelip gelmediğini kontrol ediyorsun.
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
|
||||
|
||||
Nihayet sıra size geldi. Tezgaha gidip hamburgerleri 🍔kapıp masaya geri dönüyorsun.
|
||||
Bekler ve sohbet ederken, ara ara tezgâhtaki numaraya bakıp sıranın size gelip gelmediğini kontrol ediyorsun.
|
||||
|
||||
Aşkınla hamburgerlerinizi yiyor 🍔 ve iyi vakit geçiriyorsunuz ✨.
|
||||
Bir noktada, nihayet sıra size geliyor. Tezgâha gidiyor, burgerleri alıp masaya dönüyorsun.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
|
||||
|
||||
Aşkınla burgerleri yiyip güzel vakit geçiriyorsunuz. ✨
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Harika çizimler: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
Bu hikayedeki bilgisayar / program 🤖 olduğunuzu hayal edin.
|
||||
Bu hikâyede bilgisayar / program 🤖 olduğunu hayal et.
|
||||
|
||||
Sırada beklerken boştasın 😴, sıranı beklerken herhangi bir "üretim" yapmıyorsun. Ama bu sıra hızlı çünkü kasiyer sadece siparişleri alıyor (onları hazırlamıyor), burada bir sıknıtı yok.
|
||||
Sıradayken sadece boştasın 😴, sıranı bekliyorsun, çok "üretken" bir şey yapmıyorsun. Ama sorun yok, çünkü kasiyer sadece sipariş alıyor (hazırlamıyor), bu yüzden sıra hızlı ilerliyor.
|
||||
|
||||
Sonra sıra size geldiğinde gerçekten "üretken" işler yapabilirsiniz 🤓, menüyü oku, ne istediğine larar ver, aşkının seçimini al 😍, öde 💸, doğru kartı çıkart, ödemeyi kontrol et, faturayı kontrol et, siparişin doğru olup olmadığını kontrol et, vb.
|
||||
Sıra sana geldiğinde gerçekten "üretken" işler yapıyorsun: menüyü işliyorsun, ne istediğine karar veriyorsun, aşkının seçimini alıyorsun, ödüyorsun, doğru para ya da kartı verdiğini kontrol ediyorsun, doğru ücretlendirildiğini kontrol ediyorsun, sipariş kalemlerinin doğru olduğunu kontrol ediyorsun, vb.
|
||||
|
||||
Ama hamburgerler 🍔 hazır olmamasına rağmen Kasiyer 💁 ile işiniz "duraklıyor" ⏸, çünkü hamburgerlerin hazır olmasını bekliyoruz 🕙.
|
||||
Ama sonra, burgerlerin hâlâ gelmemiş olsa da, kasiyerle olan işin "duraklatılıyor" ⏸, çünkü burgerlerin hazır olmasını 🕙 beklemen gerekiyor.
|
||||
|
||||
Ama tezgahtan uzaklaşıp sıranız gelene kadarmasanıza dönebilir 🔀 ve dikkatinizi aşkınıza 😍 verebilirsiniz vr bunun üzerine "çalışabilirsiniz" ⏯ 🤓. Artık "üretken" birşey yapıyorsunuz 🤓, sevgilinle 😍 flört eder gibi.
|
||||
Fakat tezgâhtan uzaklaşıp masada sıra numaranla oturduğun için, dikkatinizi 🔀 aşkına çevirebilir, onunla "çalışmaya" ⏯ 🤓 odaklanabilirsin. Yani yine çok "üretken" bir şey yapıyorsun, aşkınla flört etmek gibi 😍.
|
||||
|
||||
Kasiyer 💁 "Hamburgerler hazır !" 🍔 dediğinde ve görüntülenen numara sizin numaranız olduğunda hemen koşup hamburgerlerinizi almaya çalışmıyorsunuz. Biliyorsunuzki kimse sizin hamburgerlerinizi 🍔 çalmayacak çünkü sıra sizin.
|
||||
Ardından kasiyer 💁, tezgâh ekranına numaranı koyarak "burgerleri bitirdim" diyor; ama numara seninki olduğunda çılgınca sıçramıyorsun. Sıra numaran sende, herkesin kendi numarası var; kimse burgerlerini çalamaz.
|
||||
|
||||
Yani Aşkınızın😍 hikayeyi bitirmesini bekliyorsunuz (çalışmayı bitir ⏯ / görev işleniyor.. 🤓), nazikçe gülümseyin ve hamburger yemeye gittiğinizi söyleyin ⏸.
|
||||
Bu yüzden aşkının hikâyeyi bitirmesini (mevcut işi ⏯ / işlenen görevi 🤓 bitirmesini) bekliyor, nazikçe gülümsüyor ve burgerleri almaya gittiğini söylüyorsun ⏸.
|
||||
|
||||
Ardından tezgaha 🔀, şimdi biten ilk göreve ⏯ gidin, Hamburgerleri 🍔 alın, teşekkür edin ve masaya götürün. sayacın bu adımı tamamlanır ⏹. Bu da yeni bir görev olan "hamburgerleri ye" 🔀 ⏯ görevini başlatırken "hamburgerleri al" ⏹ görevini bitirir.
|
||||
Sonra tezgâha 🔀 gidip artık bitmiş olan ilk göreve ⏯ dönüyor, burgerleri alıyor, teşekkür ediyor ve masaya getiriyorsun. Tezgâhla etkileşimin bu adımı / görevi böylece bitiyor ⏹. Bu da yeni bir görev olan "burgerleri yemek" 🔀 ⏯ görevini oluşturuyor, ama "burgerleri almak" görevi tamamlandı ⏹.
|
||||
|
||||
### Parallel Hamburgerler
|
||||
### Paralel Burgerler { #parallel-burgers }
|
||||
|
||||
Şimdi bunların "Eşzamanlı Hamburger" değil, "Paralel Hamburger" olduğunu düşünelim.
|
||||
Şimdi bunların "Eşzamanlı Burgerler" değil, "Paralel Burgerler" olduğunu hayal edelim.
|
||||
|
||||
Hamburger 🍔 almak için 😍 aşkınla Paralel fast food'a gidiyorsun.
|
||||
Aşkınla paralel fast food almaya gidiyorsun.
|
||||
|
||||
Birden fazla kasiyer varken (varsayalım 8) sıraya girdiniz👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 ve sıranız gelene kadar bekliyorsunuz.
|
||||
Aynı anda aşçı da olan birden fazla (8 diyelim) kasiyerin, senden önceki insanların siparişlerini aldığı bir sırada bekliyorsun.
|
||||
|
||||
Sizden önceki herkez ayrılmadan önce hamburgerlerinin 🍔 hazır olmasını bekliyor 🕙. Çünkü kasiyerlerin her biri bir hamburger hazırlanmadan önce bir sonraki siparişe geçmiiyor.
|
||||
Senden önceki herkes, tezgâhtan ayrılmadan önce burgerlerinin hazırlanmasını bekliyor; çünkü 8 kasiyerin her biri bir sonraki siparişe geçmeden önce burgeri hemen gidip hazırlıyor.
|
||||
|
||||
Sonunda senin sıran, aşkın 😍 ve kendin için 2 hamburger 🍔 siparişi verdiniz.
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
|
||||
|
||||
Ödemeyi yaptınız 💸.
|
||||
Sonunda sıra size geliyor, sen ve aşkın için 2 çok havalı burger siparişi veriyorsun.
|
||||
|
||||
Kasiyer mutfağa gider 👨🍳.
|
||||
Ödüyorsun 💸.
|
||||
|
||||
Sırada bekliyorsunuz 🕙, kimse sizin burgerinizi 🍔 almaya çalışmıyor çünkü sıra sizin.
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
|
||||
|
||||
Sen ve aşkın 😍 sıranızı korumak ve hamburgerleri almakla o kadar meşgulsünüz ki birbirinize vakit 🕙 ayıramıyorsunuz 😞.
|
||||
Kasiyer mutfağa gidiyor.
|
||||
|
||||
İşte bu "senkron" çalışmadır. Kasiyer/aşçı 👨🍳ile senkron hareket ediyorsunuz. Bu yüzden beklemek 🕙 ve kasiyer/aşçı burgeri 🍔bitirip size getirdiğinde orda olmak zorundasınız yoksa başka biri alabilir.
|
||||
Tezgâhın önünde ayakta 🕙 bekliyorsun; sıra numarası olmadığından, burgerlerini senden önce kimsenin almaması için orada durman gerekiyor.
|
||||
|
||||
Sonra kasiyeri/aşçı 👨🍳 nihayet hamburgerlerinizle 🍔, uzun bir süre sonra 🕙 tezgaha geri geliyor.
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
|
||||
|
||||
Burgerlerinizi 🍔 al ve aşkınla masanıza doğru ilerle 😍.
|
||||
Sen ve aşkın, kimsenin önünüze geçip burgerler gelince almaması için meşgul olduğunuzdan, aşkına dikkatini veremiyorsun. 😞
|
||||
|
||||
Sadece burgerini yiyorsun 🍔 ve bitti ⏹.
|
||||
Bu "senkron" bir iştir; kasiyer/aşçı 👨🍳 ile "senkronize"sin. 🕙 Beklemen ve kasiyer/aşçı 👨🍳 burgerleri bitirip sana verdiği anda tam orada olman gerekir; yoksa bir başkası alabilir.
|
||||
|
||||
Bekleyerek çok fazla zaman geçtiğinden 🕙 konuşmaya çok fazla vakit kalmadı 😞.
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
||||
|
||||
Sonra kasiyer/aşçı 👨🍳, uzun süre tezgâhın önünde 🕙 bekledikten sonra nihayet burgerlerinle geri geliyor.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
||||
|
||||
Burgerleri alıyor ve aşkınla masaya gidiyorsun.
|
||||
|
||||
Sadece yiyorsunuz ve iş bitiyor. ⏹
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
||||
|
||||
Vaktin çoğu tezgâhın önünde 🕙 beklemekle geçtiğinden, pek konuşma ya da flört olmadı. 😞
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Harika çizimler: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
Paralel burger senaryosunda ise, siz iki işlemcili birer robotsunuz 🤖 (sen ve sevgilin 😍), Beklıyorsunuz 🕙 hem konuşarak güzel vakit geçirirken ⏯ hem de sıranızı bekliyorsunuz 🕙.
|
||||
Bu paralel burger senaryosunda, ikiniz (sen ve aşkın) iki işlemcili bir bilgisayar / programsınız 🤖; ikiniz de uzun süre tezgâhta "bekleme" işine 🕙 dikkat ⏯ ayırıyorsunuz.
|
||||
|
||||
Mağazada ise 8 işlemci bulunuyor (Kasiyer/aşçı) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳. Eşzamanlı burgerde yalnızca 2 kişi olabiliyordu (bir kasiyer ve bir aşçı) 💁 👨🍳.
|
||||
Fast food dükkânında 8 işlemci var (kasiyer/aşçılar). Eşzamanlı burger dükkânında yalnızca 2 kişi olabilir (bir kasiyer ve bir aşçı).
|
||||
|
||||
Ama yine de bu en iyisi değil 😞.
|
||||
Ama yine de nihai deneyim pek iyi değil. 😞
|
||||
|
||||
---
|
||||
|
||||
Bu hikaye burgerler 🍔 için paralel.
|
||||
Bu, burgerler için paralel karşılık gelen hikâye olurdu. 🍔
|
||||
|
||||
Bir gerçek hayat örneği verelim. Bir banka hayal edin.
|
||||
Daha "gerçek hayat" bir örnek için, bir banka hayal edin.
|
||||
|
||||
Bankaların çoğunda birkaç kasiyer 👨💼👨💼👨💼👨💼 ve uzun bir sıra var 🕙🕙🕙🕙🕙🕙🕙🕙.
|
||||
Yakın zamana kadar, bankaların çoğunda birden çok gişe memuru 👨💼👨💼👨💼👨💼 ve uzun bir sıra 🕙🕙🕙🕙🕙🕙🕙🕙 vardı.
|
||||
|
||||
Tüm işi sırayla bir müşteri ile yapan tüm kasiyerler 👨💼⏯.
|
||||
Tüm gişe memurları bir müşteriyle tüm işi yapar, sonra sıradakiyle 👨💼⏯.
|
||||
|
||||
Ve uzun süre kuyrukta beklemek 🕙 zorundasın yoksa sıranı kaybedersin.
|
||||
Ve sıranı kaybetmemek için uzun süre 🕙 kuyrukta beklemen gerekir.
|
||||
|
||||
Muhtemelen ayak işlerı yaparken sevgilini 😍 bankaya 🏦 getirmezsin.
|
||||
Muhtemelen, bankada 🏦 işlerini hallederken aşkını 😍 yanında götürmek istemezsin.
|
||||
|
||||
### Burger Sonucu
|
||||
### Burger Sonucu { #burger-conclusion }
|
||||
|
||||
Bu "aşkınla fast food burgerleri" senaryosunda, çok fazla bekleme olduğu için 🕙, eşzamanlı bir sisteme sahip olmak çok daha mantıklı ⏸🔀⏯.
|
||||
"Fast food burgerleri ve aşkın" senaryosunda, çok fazla bekleme 🕙 olduğundan, eşzamanlı bir sistem ⏸🔀⏯ çok daha mantıklıdır.
|
||||
|
||||
Web uygulamalarının çoğu için durum böyledir.
|
||||
Bu, çoğu web uygulaması için de geçerlidir.
|
||||
|
||||
Pek çok kullanıcı var, ama sunucunuz pek de iyi olmayan bir bağlantı ile istek atmalarını bekliyor.
|
||||
Çok fazla kullanıcı vardır; ancak sunucunuz, iyi olmayan bağlantılarından gelen istekleri 🕙 bekler.
|
||||
|
||||
Ve sonra yanıtların geri gelmesi için tekrar 🕙 bekliyor
|
||||
Ve sonra yanıtların geri gelmesini yine 🕙 bekler.
|
||||
|
||||
Bu "bekleme" 🕙 mikrosaniye cinsinden ölçülür, yine de, hepsini toplarsak çok fazla bekleme var.
|
||||
Bu "beklemeler" 🕙 mikrosaniyelerle ölçülür; ama hepsi toplandığında sonuçta oldukça fazla bekleme olur.
|
||||
|
||||
Bu nedenle, web API'leri için asenkron ⏸🔀⏯ kod kullanmak çok daha mantıklı.
|
||||
Bu yüzden web API’leri için asenkron ⏸🔀⏯ kod kullanmak çok mantıklıdır.
|
||||
|
||||
Mevcut popüler Python frameworklerinin çoğu (Flask ve Django gibi), Python'daki yeni asenkron özellikler mevcut olmadan önce yazıldı. Bu nedenle, dağıtılma biçimleri paralel yürütmeyi ve yenisi kadar güçlü olmayan eski bir eşzamansız yürütme biçimini destekler.
|
||||
Bu tür asenkronluk, NodeJS’i popüler yapan şeydir (NodeJS paralel olmasa bile) ve Go dilinin gücüdür.
|
||||
|
||||
Asenkron web (ASGI) özelliği, WebSockets için destek eklemek için Django'ya eklenmiş olsa da.
|
||||
Ve **FastAPI** ile elde ettiğiniz performans seviyesi de budur.
|
||||
|
||||
Asenkron çalışabilme NodeJS in popüler olmasının sebebi (paralel olamasa bile) ve Go dilini güçlü yapan özelliktir.
|
||||
Ayrıca, aynı anda hem paralellik hem de asenkronluk kullanabildiğiniz için, test edilen çoğu NodeJS framework’ünden daha yüksek ve C’ye daha yakın derlenen bir dil olan Go ile başa baş performans elde edersiniz <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(hepsi Starlette sayesinde)</a>.
|
||||
|
||||
Ve bu **FastAPI** ile elde ettiğiniz performans düzeyiyle aynıdır.
|
||||
### Eşzamanlılık paralellikten daha mı iyi? { #is-concurrency-better-than-parallelism }
|
||||
|
||||
Aynı anda paralellik ve asenkronluğa sahip olabildiğiniz için, test edilen NodeJS çerçevelerinin çoğundan daha yüksek performans elde edersiniz ve C'ye daha yakın derlenmiş bir dil olan Go ile eşit bir performans elde edersiniz <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(bütün teşekkürler Starlette'e )</a>.
|
||||
Hayır! Hikâyenin özü bu değil.
|
||||
|
||||
### Eşzamanlılık paralellikten daha mı iyi?
|
||||
Eşzamanlılık paralellikten farklıdır. Ve çok fazla bekleme içeren **belirli** senaryolarda daha iyidir. Bu nedenle, genellikle web uygulaması geliştirme için paralellikten çok daha iyidir. Ama her şey için değil.
|
||||
|
||||
Hayır! Hikayenin ahlakı bu değil.
|
||||
Bunu dengelemek için, şu kısa hikâyeyi hayal edin:
|
||||
|
||||
Eşzamanlılık paralellikten farklıdır. Ve çok fazla bekleme içeren **belirli** senaryolarda daha iyidir. Bu nedenle, genellikle web uygulamaları için paralellikten çok daha iyidir. Ama her şey için değil.
|
||||
> Büyük, kirli bir evi temizlemen gerekiyor.
|
||||
|
||||
Yanı, bunu aklınızda oturtmak için aşağıdaki kısa hikayeyi hayal edin:
|
||||
|
||||
> Büyük, kirli bir evi temizlemelisin.
|
||||
|
||||
*Evet, tüm hikaye bu*.
|
||||
*Evet, tüm hikâye bu kadar*.
|
||||
|
||||
---
|
||||
|
||||
Beklemek yok 🕙. Hiçbir yerde. Sadece evin birden fazla yerinde yapılacak fazlasıyla iş var.
|
||||
Hiçbir yerde 🕙 bekleme yok; sadece evin birden fazla yerinde yapılacak çok iş var.
|
||||
|
||||
You could have turns as in the burgers example, first the living room, then the kitchen, but as you are not waiting 🕙 for anything, just cleaning and cleaning, the turns wouldn't affect anything.
|
||||
Hamburger örneğindeki gibi dönüşleriniz olabilir, önce oturma odası, sonra mutfak, ama hiçbir şey için 🕙 beklemediğinizden, sadece temizlik, temizlik ve temizlik, dönüşler hiçbir şeyi etkilemez.
|
||||
Hamburger örneğindeki gibi dönüşlerle ilerleyebilirsin, önce salon, sonra mutfak; ama hiçbir şey 🕙 beklemediğin için, sadece temizlik yaptığından, dönüşlerin hiçbir etkisi olmaz.
|
||||
|
||||
Sıralı veya sırasız (eşzamanlılık) bitirmek aynı zaman alır ve aynı miktarda işi yaparsınız.
|
||||
Dönüşlerle ya da dönüşsüz (eşzamanlılık) bitirmek aynı zaman alır ve aynı miktarda iş yapmış olursun.
|
||||
|
||||
Ama bu durumda, 8 eski kasiyer/aşçı - yeni temizlikçiyi getirebilseydiniz 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 ve her birini (artı siz) evin bir bölgesini temizlemek için görevlendirseydiniz, ekstra yardımla tüm işleri **paralel** olarak yapabilir ve çok daha erken bitirebilirdiniz.
|
||||
Ama bu durumda, 8 eski kasiyer/aşçı—yeni temizlikçiyi getirip her birine (artı sana) evin bir bölümünü versen, fazladan yardımla tüm işleri **paralel** yaparak çok daha çabuk bitirebilirdin.
|
||||
|
||||
Bu senaryoda, temizlikçilerin her biri (siz dahil) birer işlemci olacak ve üzerine düşeni yapacaktır.
|
||||
Bu senaryoda, her bir temizlikçi (sen dâhil) birer işlemci olur ve kendi iş payını yapar.
|
||||
|
||||
Yürütme süresinin çoğu (beklemek yerine) iş yapıldığından ve bilgisayardaki iş bir <abbr title="Central Processing Unit">CPU</abbr> tarafından yapıldığından, bu sorunlara "CPU bound" diyorlar".
|
||||
Ve yürütme süresinin çoğu gerçek işten (bekleme yerine) oluştuğu ve bilgisayardaki işi bir <abbr title="Central Processing Unit - Merkezi İşlem Birimi">CPU</abbr> yaptığı için, bu sorunlara "CPU bound" denir.
|
||||
|
||||
---
|
||||
|
||||
CPU'ya bağlı işlemlerin yaygın örnekleri, karmaşık matematik işlemleri gerektiren işlerdir.
|
||||
CPU’ya bağlı işlemlerin yaygın örnekleri, karmaşık matematiksel işlem gerektiren iş yükleridir.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* **Ses** veya **görüntü işleme**.
|
||||
* **Bilgisayar görüsü**: bir görüntü milyonlarca pikselden oluşur, her pikselin 3 değeri / rengi vardır, bu pikseller üzerinde aynı anda bir şeyler hesaplamayı gerektiren işleme.
|
||||
* **Makine Öğrenimi**: Çok sayıda "matris" ve "vektör" çarpımı gerektirir. Sayıları olan ve hepsini aynı anda çarpan büyük bir elektronik tablo düşünün.
|
||||
* **Derin Öğrenme**: Bu, Makine Öğreniminin bir alt alanıdır, dolayısıyla aynısı geçerlidir. Sadece çarpılacak tek bir sayı tablosu değil, büyük bir sayı kümesi vardır ve çoğu durumda bu modelleri oluşturmak ve/veya kullanmak için özel işlemciler kullanırsınız.
|
||||
* **Bilgisayar görüsü**: bir görüntü milyonlarca pikselden oluşur, her pikselin 3 değeri / rengi vardır; işleme genellikle bu pikseller üzerinde aynı anda bir şeyler hesaplamayı gerektirir.
|
||||
* **Makine Öğrenimi**: genellikle çok sayıda "matris" ve "vektör" çarpımı gerekir. Sayılar içeren devasa bir elektronik tabloyu ve hepsini aynı anda çarpmayı düşünün.
|
||||
* **Derin Öğrenme**: Makine Öğreniminin bir alt alanıdır, dolayısıyla aynısı geçerlidir. Sadece çarpılacak tek bir sayı tablosu değil, kocaman bir sayı kümesi vardır ve çoğu durumda bu modelleri kurmak ve/veya kullanmak için özel işlemciler kullanırsınız.
|
||||
|
||||
### Eşzamanlılık + Paralellik: Web + Makine Öğrenimi
|
||||
### Eşzamanlılık + Paralellik: Web + Makine Öğrenimi { #concurrency-parallelism-web-machine-learning }
|
||||
|
||||
**FastAPI** ile web geliştirme için çok yaygın olan eşzamanlılıktan yararlanabilirsiniz (NodeJS'in aynı çekiciliği).
|
||||
**FastAPI** ile web geliştirmede çok yaygın olan eşzamanlılıktan (NodeJS’in başlıca cazibesiyle aynı) yararlanabilirsiniz.
|
||||
|
||||
Ancak, Makine Öğrenimi sistemlerindekile gibi **CPU'ya bağlı** iş yükleri için paralellik ve çoklu işlemenin (birden çok işlemin paralel olarak çalışması) avantajlarından da yararlanabilirsiniz.
|
||||
Ama ayrıca **CPU’ya bağlı** iş yükleri (Makine Öğrenimi sistemlerindeki gibi) için paralellik ve çoklu işlemden (paralel çalışan birden çok işlem) de yararlanabilirsiniz.
|
||||
|
||||
Buna ek olarak Python'un **Veri Bilimi**, Makine Öğrenimi ve özellikle Derin Öğrenme için ana dil olduğu gerçeği, FastAPI'yi Veri Bilimi / Makine Öğrenimi web API'leri ve uygulamaları için çok iyi bir seçenek haline getirir.
|
||||
Buna ek olarak Python’un **Veri Bilimi**, Makine Öğrenimi ve özellikle Derin Öğrenme için ana dil olması, FastAPI’yi Veri Bilimi / Makine Öğrenimi web API’leri ve uygulamaları için çok iyi bir seçenek yapar.
|
||||
|
||||
Production'da nasıl oldugunu görmek için şu bölüme bakın [Deployment](deployment/index.md){.internal-link target=_blank}.
|
||||
Production’da bu paralelliği nasıl sağlayacağınızı görmek için [Deployment](deployment/index.md){.internal-link target=_blank} bölümüne bakın.
|
||||
|
||||
## `async` ve `await`
|
||||
## `async` ve `await` { #async-and-await }
|
||||
|
||||
Python'un modern sürümleri, asenkron kodu tanımlamanın çok sezgisel bir yoluna sahiptir. Bu, normal "sequentıal" (sıralı) kod gibi görünmesini ve doğru anlarda sizin için "awaıt" ile bekleme yapmasını sağlar.
|
||||
Python’un modern sürümleri, asenkron kodu tanımlamak için oldukça sezgisel bir yol sunar. Bu sayede kod normal "sıralı" kod gibi görünür ve doğru anlarda sizin yerinize "beklemeyi" yapar.
|
||||
|
||||
Sonuçları vermeden önce beklemeyi gerektirecek ve yeni Python özelliklerini destekleyen bir işlem olduğunda aşağıdaki gibi kodlayabilirsiniz:
|
||||
Sonuçları vermeden önce bekleme gerektiren ve bu yeni Python özelliklerini destekleyen bir işlem olduğunda, şöyle kodlayabilirsiniz:
|
||||
|
||||
```Python
|
||||
burgers = await get_burgers(2)
|
||||
```
|
||||
|
||||
Buradaki `await` anahtari Python'a, sonuçları `burgers` degiskenine atamadan önce `get_burgers(2)` kodunun işini bitirmesini 🕙 beklemesi gerektiğini söyler. Bununla Python, bu ara zamanda başka bir şey 🔀 ⏯ yapabileceğini bilecektir (başka bir istek almak gibi).
|
||||
Buradaki kilit nokta `await`. Python’a, sonuçları `burgers` değişkenine koymadan önce `get_burgers(2)` çalışmasının bitmesini 🕙 beklemesi ⏸ gerektiğini söyler. Böylece Python, bu arada başka bir şey 🔀 ⏯ yapabileceğini bilir (ör. başka bir request almak gibi).
|
||||
|
||||
`await`kodunun çalışması için, eşzamansızlığı destekleyen bir fonksiyonun içinde olması gerekir. Bunu da yapmak için fonksiyonu `async def` ile tanımlamamız yeterlidir:
|
||||
`await`’in çalışabilmesi için, bu asenkronluğu destekleyen bir fonksiyonun içinde olması gerekir. Bunu yapmak için fonksiyonu `async def` ile tanımlayın:
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def get_burgers(number: int):
|
||||
# burgerleri oluşturmak için asenkron birkaç iş
|
||||
# Burgerleri yaratmak için bazı asenkron işler yap
|
||||
return burgers
|
||||
```
|
||||
|
||||
...`def` yerine:
|
||||
|
||||
```Python hl_lines="2"
|
||||
# bu kod asenkron değil
|
||||
# Bu asenkron değildir
|
||||
def get_sequential_burgers(number: int):
|
||||
# burgerleri oluşturmak için senkron bırkaç iş
|
||||
# Burgerleri yaratmak için bazı sıralı işler yap
|
||||
return burgers
|
||||
```
|
||||
|
||||
`async def` ile Python, bu fonksıyonun içinde, `await` ifadelerinin farkında olması gerektiğini ve çalışma zamanı gelmeden önce bu işlevin yürütülmesini "duraklatabileceğini" ve başka bir şey yapabileceğini 🔀 bilir.
|
||||
`async def` ile Python, bu fonksiyonun içinde `await` ifadelerinin olabileceğini bilir ve bu fonksiyonun yürütülmesini "duraklatıp" ⏸ başka bir şey yapabileceğini 🔀, sonra geri dönebileceğini anlar.
|
||||
|
||||
`async def` fonksiyonunu çağırmak istediğinizde, onu "awaıt" ıle kullanmanız gerekir. Yani, bu işe yaramaz:
|
||||
`async def` fonksiyonunu çağırmak istediğinizde, onu "await" etmeniz gerekir. Yani şu çalışmaz:
|
||||
|
||||
```Python
|
||||
# Bu işe yaramaz, çünkü get_burgers, şu şekilde tanımlandı: async def
|
||||
# Bu çalışmaz, çünkü get_burgers şöyle tanımlandı: async def
|
||||
burgers = get_burgers(2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Bu nedenle, size onu `await` ile çağırabileceğinizi söyleyen bir kitaplık kullanıyorsanız, onu `async def` ile tanımlanan *path fonksiyonu* içerisinde kullanmanız gerekir, örneğin:
|
||||
Dolayısıyla, `await` ile çağrılabileceğini söyleyen bir kütüphane kullanıyorsanız, onu kullanan *path operasyon fonksiyonunu* `async def` ile oluşturmanız gerekir, örneğin:
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
@@ -321,87 +349,96 @@ async def read_burgers():
|
||||
return burgers
|
||||
```
|
||||
|
||||
### Daha fazla teknik detay
|
||||
### Daha teknik detaylar { #more-technical-details }
|
||||
|
||||
`await` in yalnızca `async def` ile tanımlanan fonksıyonların içinde kullanılabileceğini fark etmişsinizdir.
|
||||
`await`’in yalnızca `async def` ile tanımlanan fonksiyonların içinde kullanılabildiğini fark etmiş olabilirsiniz.
|
||||
|
||||
Ama aynı zamanda, `async def` ile tanımlanan fonksiyonların "await" ile beklenmesi gerekir. Bu nedenle, "`async def` içeren fonksiyonlar yalnızca "`async def` ile tanımlanan fonksiyonların içinde çağrılabilir.
|
||||
Aynı zamanda, `async def` ile tanımlanan fonksiyonların da "await" edilmesi gerekir. Yani `async def` ile tanımlanan fonksiyonlar yalnızca `async def` ile tanımlanan fonksiyonların içinde çağrılabilir.
|
||||
|
||||
Peki, tavuk-yumurta meselesi: ilk `async` fonksiyon nasıl çağrılır?
|
||||
|
||||
Yani yumurta mı tavukdan, tavuk mu yumurtadan gibi ilk `async` fonksiyonu nasıl çağırılır?
|
||||
**FastAPI** ile çalışıyorsanız bunu dert etmenize gerek yok; çünkü o "ilk" fonksiyon sizin *path operasyon fonksiyonunuz* olacaktır ve FastAPI doğru olanı yapmasını bilir.
|
||||
|
||||
**FastAPI** ile çalışıyorsanız bunun için endişelenmenize gerek yok, çünkü bu "ilk" fonksiyon sizin *path fonksiyonunuz* olacak ve FastAPI doğru olanı nasıl yapacağını bilecek.
|
||||
Ama FastAPI olmadan da `async` / `await` kullanmak isterseniz, bunu da yapabilirsiniz.
|
||||
|
||||
Ancak FastAPI olmadan `async` / `await` kullanmak istiyorsanız, <a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" class="external-link" target="_blank">resmi Python belgelerini kontrol edin</a>.
|
||||
### Kendi async kodunuzu yazın { #write-your-own-async-code }
|
||||
|
||||
### Asenkron kodun diğer biçimleri
|
||||
Starlette (ve **FastAPI**) <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> üzerine kuruludur; bu sayede Python standart kütüphanesindeki <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> ve <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> ile uyumludur.
|
||||
|
||||
Bu `async` ve `await` kullanimi oldukça yenidir.
|
||||
Özellikle, kendi kodunuzda daha gelişmiş desenler gerektiren ileri seviye eşzamanlılık kullanım senaryoları için doğrudan <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> kullanabilirsiniz.
|
||||
|
||||
Ancak asenkron kodla çalışmayı çok daha kolay hale getirir.
|
||||
Hatta FastAPI kullanmıyor olsanız bile, yüksek uyumluluk ve avantajları (ör. *structured concurrency*) için <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> ile kendi async uygulamalarınızı yazabilirsiniz.
|
||||
|
||||
Aynı sözdizimi (hemen hemen aynı) son zamanlarda JavaScript'in modern sürümlerine de dahil edildi (Tarayıcı ve NodeJS'de).
|
||||
AnyIO’nun üzerine, tür açıklamalarını biraz iyileştirmek ve daha iyi **otomatik tamamlama**, **satır içi hatalar** vb. elde etmek için ince bir katman olarak başka bir kütüphane daha oluşturdum. Ayrıca **kendi async kodunuzu** anlamanıza ve yazmanıza yardımcı olacak dostça bir giriş ve eğitim içerir: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. Özellikle **async kodu normal** (bloklayan/senkron) **kodla birleştirmeniz** gerektiğinde faydalı olacaktır.
|
||||
|
||||
Ancak bundan önce, asenkron kodu işlemek oldukça karmaşık ve zordu.
|
||||
### Asenkron kodun diğer biçimleri { #other-forms-of-asynchronous-code }
|
||||
|
||||
Python'un önceki sürümlerinde, threadlerı veya <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a> kullanıyor olabilirdin. Ancak kodu anlamak, hata ayıklamak ve düşünmek çok daha karmaşık olurdu.
|
||||
`async` ve `await` kullanma tarzı, dilde nispeten yenidir.
|
||||
|
||||
NodeJS / Browser JavaScript'in önceki sürümlerinde, "callback" kullanırdınız. Bu da "callbacks cehennemine" yol açar.
|
||||
Ama asenkron kodla çalışmayı çok daha kolaylaştırır.
|
||||
|
||||
## Coroutine'ler
|
||||
Aynı (ya da neredeyse aynı) sözdizimi yakın zamanda modern JavaScript sürümlerine (Tarayıcı ve NodeJS) de eklendi.
|
||||
|
||||
**Coroutine**, bir `async def` fonksiyonu tarafından döndürülen değer için çok süslü bir terimdir. Python bunun bir fonksiyon gibi bir noktada başlayıp biteceğini bilir, ancak içinde bir `await` olduğunda dahili olarak da duraklatılabilir ⏸.
|
||||
Bundan önce, asenkron kodu ele almak oldukça daha karmaşık ve zordu.
|
||||
|
||||
Ancak, `async` ve `await` ile asenkron kod kullanmanın tüm bu işlevselliği, çoğu zaman "Coroutine" kullanmak olarak adlandırılır. Go'nun ana özelliği olan "Goroutines" ile karşılaştırılabilir.
|
||||
Python’un önceki sürümlerinde thread’ler veya <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a> kullanabilirdiniz. Ama kodu anlamak, hata ayıklamak ve üzerine düşünmek çok daha zordu.
|
||||
|
||||
## Sonuç
|
||||
NodeJS / Tarayıcı JavaScript’in önceki sürümlerinde "callback" kullanırdınız. Bu da "callback cehennemi"ne yol açardı.
|
||||
|
||||
Aynı ifadeyi yukarıdan görelim:
|
||||
## Coroutine'ler { #coroutines }
|
||||
|
||||
> Python'ın modern sürümleri, **"async" ve "await"** sözdizimi ile birlikte **"coroutines"** adlı bir özelliği kullanan **"asenkron kod"** desteğine sahiptir.
|
||||
**Coroutine**, bir `async def` fonksiyonunun döndürdüğü şeye verilen süslü isimdir. Python bunun bir fonksiyona benzer bir şey olduğunu, bir noktada başlayıp biteceğini bilir; ama içinde bir `await` olduğunda dahili olarak duraklatılabileceğini ⏸ de bilir.
|
||||
|
||||
Şimdi daha mantıklı gelmeli. ✨
|
||||
`async` ve `await` ile asenkron kod kullanmanın bu işlevselliği çoğu zaman "coroutine" kullanmak olarak özetlenir. Go’nun ana kilit özelliği olan "Goroutines" ile karşılaştırılabilir.
|
||||
|
||||
FastAPI'ye (Starlette aracılığıyla) güç veren ve bu kadar etkileyici bir performansa sahip olmasını sağlayan şey budur.
|
||||
## Sonuç { #conclusion }
|
||||
|
||||
## Çok Teknik Detaylar
|
||||
Yukarıdaki cümleyi tekrar görelim:
|
||||
|
||||
/// warning
|
||||
> Python’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **"coroutines"** denilen bir yapıyı kullanarak **"asenkron kod"** desteğine sahiptir.
|
||||
|
||||
Muhtemelen burayı atlayabilirsiniz.
|
||||
Artık daha anlamlı gelmeli. ✨
|
||||
|
||||
Bunlar, **FastAPI**'nin altta nasıl çalıştığına dair çok teknik ayrıntılardır.
|
||||
Bunların hepsi, FastAPI’ye (Starlette aracılığıyla) güç verir ve böylesine etkileyici bir performansa sahip olmasını sağlar.
|
||||
|
||||
Biraz teknik bilginiz varsa (co-routines, threads, blocking, vb)ve FastAPI'nin "async def" ile normal "def" arasındaki farkı nasıl işlediğini merak ediyorsanız, devam edin.
|
||||
## Çok Teknik Detaylar { #very-technical-details }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Büyük ihtimalle burayı atlayabilirsiniz.
|
||||
|
||||
Bunlar, **FastAPI**’nin altında nasıl çalıştığına dair oldukça teknik ayrıntılardır.
|
||||
|
||||
Coroutine’ler, thread’ler, blocking vb. hakkında teknik bilginiz varsa ve FastAPI’nin `async def` ile normal `def` arasındaki farkı nasıl ele aldığını merak ediyorsanız, devam edin.
|
||||
|
||||
///
|
||||
|
||||
### Path fonksiyonu
|
||||
### Path Operasyon Fonksiyonları { #path-operation-functions }
|
||||
|
||||
"async def" yerine normal "def" ile bir *yol işlem işlevi* bildirdiğinizde, doğrudan çağrılmak yerine (sunucuyu bloke edeceğinden) daha sonra beklenen harici bir iş parçacığı havuzunda çalıştırılır.
|
||||
Bir *path operasyon fonksiyonunu* `async def` yerine normal `def` ile tanımladığınızda, (sunucuyu bloklayacağından) doğrudan çağrılmak yerine, harici bir thread pool’da çalıştırılır ve ardından beklenir.
|
||||
|
||||
Yukarıda açıklanan şekilde çalışmayan başka bir asenkron framework'den geliyorsanız ve küçük bir performans kazancı (yaklaşık 100 nanosaniye) için "def" ile *path fonksiyonu* tanımlamaya alışkınsanız, **FastAPI**'de tam tersi olacağını unutmayın. Bu durumlarda, *path fonksiyonu* <abbr title="Input/Output: disk okuma veya yazma, ağ iletişimleri.">G/Ç</abbr> engelleyen durum oluşturmadıkça "async def" kullanmak daha iyidir.
|
||||
Yukarıda açıklanan şekilde çalışmayan başka bir async framework’ten geliyorsanız ve ufak bir performans kazancı (yaklaşık 100 nanosaniye) için yalnızca hesaplama yapan basit *path operasyon fonksiyonlarını* düz `def` ile tanımlamaya alışkınsanız, **FastAPI**’de etkinin tam tersi olacağını unutmayın. Bu durumlarda, *path operasyon fonksiyonlarınız* bloklayan <abbr title="Input/Output - Giriş/Çıkış: disk okuma veya yazma, ağ iletişimi.">I/O</abbr> yapan kod kullanmadıkça `async def` kullanmak daha iyidir.
|
||||
|
||||
Yine de, her iki durumda da, **FastAPI**'nin önceki frameworkden [hala daha hızlı](index.md#performans){.internal-link target=_blank} (veya en azından karşılaştırılabilir) olma olasılığı vardır.
|
||||
Yine de her iki durumda da, **FastAPI**’nin önceki framework’ünüzden [hala daha hızlı](index.md#performance){.internal-link target=_blank} (ya da en azından karşılaştırılabilir) olması muhtemeldir.
|
||||
|
||||
### Bagımlılıklar
|
||||
### Bağımlılıklar { #dependencies }
|
||||
|
||||
Aynısı bağımlılıklar için de geçerlidir. Bir bağımlılık, "async def" yerine standart bir "def" işleviyse, harici iş parçacığı havuzunda çalıştırılır.
|
||||
Aynısı [bağımlılıklar](tutorial/dependencies/index.md){.internal-link target=_blank} için de geçerlidir. Bir bağımlılık `async def` yerine standart bir `def` fonksiyonuysa, harici thread pool’da çalıştırılır.
|
||||
|
||||
### Alt-bağımlıklar
|
||||
### Alt-bağımlılıklar { #sub-dependencies }
|
||||
|
||||
Birbirini gerektiren (fonksiyonlarin parametreleri olarak) birden fazla bağımlılık ve alt bağımlılıklarınız olabilir, bazıları 'async def' ve bazıları normal 'def' ile oluşturulabilir. Yine de normal 'def' ile oluşturulanlar, "await" kulanilmadan harici bir iş parçacığında (iş parçacığı havuzundan) çağrılır.
|
||||
Birbirini gerektiren birden çok bağımlılık ve [alt-bağımlılık](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} olabilir (fonksiyon tanımlarının parametreleri olarak). Bazıları `async def` ile, bazıları normal `def` ile oluşturulmuş olabilir. Yine de çalışır ve normal `def` ile oluşturulanlar "await" edilmek yerine harici bir thread’de (thread pool’dan) çağrılır.
|
||||
|
||||
### Diğer yardımcı fonksiyonlar
|
||||
### Diğer yardımcı fonksiyonlar { #other-utility-functions }
|
||||
|
||||
Doğrudan çağırdığınız diğer herhangi bir yardımcı fonksiyonu, normal "def" veya "async def" ile tanimlayabilirsiniz. FastAPI onu çağırma şeklinizi etkilemez.
|
||||
Doğrudan çağırdığınız diğer yardımcı fonksiyonları normal `def` veya `async def` ile tanımlayabilirsiniz ve FastAPI onları çağırma biçiminizi etkilemez.
|
||||
|
||||
Bu, FastAPI'nin sizin için çağırdığı fonksiyonlarin tam tersidir: *path fonksiyonu* ve bağımlılıklar.
|
||||
Bu, FastAPI’nin sizin için çağırdığı fonksiyonların tersidir: *path operasyon fonksiyonları* ve bağımlılıklar.
|
||||
|
||||
Yardımcı program fonksiyonunuz 'def' ile normal bir işlevse, bir iş parçacığı havuzunda değil doğrudan (kodunuzda yazdığınız gibi) çağrılır, işlev 'async def' ile oluşturulmuşsa çağırıldığı yerde 'await' ile beklemelisiniz.
|
||||
Yardımcı fonksiyonunuz `def` ile tanımlı normal bir fonksiyonsa, bir thread pool’da değil doğrudan (kodunuzda yazdığınız gibi) çağrılır; fonksiyon `async def` ile tanımlıysa kodunuzda çağırırken onu `await` etmelisiniz.
|
||||
|
||||
---
|
||||
|
||||
Yeniden, bunlar, onları aramaya geldiğinizde muhtemelen işinize yarayacak çok teknik ayrıntılardır.
|
||||
Yine, bunlar muhtemelen özellikle aradığınızda işinize yarayacak çok teknik ayrıntılardır.
|
||||
|
||||
Aksi takdirde, yukarıdaki bölümdeki yönergeleri iyi bilmelisiniz: <a href="#in-a-hurry">Aceleniz mi var?</a>.
|
||||
Aksi hâlde, yukarıdaki bölümdeki yönergeler yeterlidir: <a href="#in-a-hurry">Aceleniz mi var?</a>.
|
||||
|
||||
+18
-18
@@ -1,34 +1,34 @@
|
||||
# Kıyaslamalar
|
||||
# Kıyaslamalar { #benchmarks }
|
||||
|
||||
Bağımsız TechEmpower kıyaslamaları gösteriyor ki <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">en hızlı Python frameworklerinden birisi</a> olan Uvicorn ile çalıştırılan **FastAPI** uygulamaları, sadece Starlette ve Uvicorn'dan daha düşük sıralamada (FastAPI bu frameworklerin üzerine kurulu) yer alıyor. (*)
|
||||
Bağımsız TechEmpower kıyaslamaları, Uvicorn altında çalışan **FastAPI** uygulamalarının <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">mevcut en hızlı Python frameworklerinden biri</a> olduğunu, yalnızca Starlette ve Uvicorn'un kendilerinin altında yer aldığını gösteriyor (FastAPI bunları dahili olarak kullanır).
|
||||
|
||||
Fakat kıyaslamaları ve karşılaştırmaları incelerken şunları aklınızda bulundurmalısınız.
|
||||
|
||||
## Kıyaslamalar ve Hız
|
||||
## Kıyaslamalar ve Hız { #benchmarks-and-speed }
|
||||
|
||||
Kıyaslamaları incelediğinizde, farklı özelliklere sahip araçların eşdeğer olarak karşılaştırıldığını yaygın bir şekilde görebilirsiniz.
|
||||
Kıyaslamalara baktığınızda, farklı türlerdeki birkaç aracın eşdeğermiş gibi karşılaştırıldığını görmek yaygındır.
|
||||
|
||||
Özellikle, (diğer birçok araç arasında) Uvicorn, Starlette ve FastAPI'ın birlikte karşılaştırıldığını görebilirsiniz.
|
||||
|
||||
Aracın çözdüğü problem ne kadar basitse, performansı o kadar iyi olacaktır. Ancak kıyaslamaların çoğu, aracın sağladığı ek özellikleri test etmez.
|
||||
Aracın çözdüğü problem ne kadar basitse, elde edeceği performans o kadar iyi olur. Ayrıca kıyaslamaların çoğu, aracın sağladığı ek özellikleri test etmez.
|
||||
|
||||
Hiyerarşi şöyledir:
|
||||
|
||||
* **Uvicorn**: bir ASGI sunucusu
|
||||
* **Starlette**: (Uvicorn'u kullanır) bir web mikroframeworkü
|
||||
* **FastAPI**: (Starlette'i kullanır) veri doğrulama vb. çeşitli ek özelliklere sahip, API oluşturmak için kullanılan bir API mikroframeworkü
|
||||
* **Starlette**: (Uvicorn'u kullanır) bir web mikroframework'ü
|
||||
* **FastAPI**: (Starlette'i kullanır) veri doğrulama vb. ile API'lar oluşturmak için çeşitli ek özelliklere sahip bir API mikroframework'ü
|
||||
|
||||
* **Uvicorn**:
|
||||
* Sunucunun kendisi dışında ekstra bir kod içermediği için en iyi performansa sahip olacaktır.
|
||||
* Doğrudan Uvicorn ile bir uygulama yazmazsınız. Bu, yazdığınız kodun en azından Starlette tarafından sağlanan tüm kodu (veya **FastAPI**) az çok içermesi gerektiği anlamına gelir. Eğer bunu yaptıysanız, son uygulamanız bir framework kullanmak ve uygulama kodlarını ve hataları en aza indirmekle aynı ek yüke sahip olacaktır.
|
||||
* Eğer Uvicorn'u karşılaştırıyorsanız, Daphne, Hypercorn, uWSGI, vb. uygulama sunucuları ile karşılaştırın.
|
||||
* Sunucunun kendisi dışında çok fazla ekstra kod içermediği için en iyi performansa sahip olacaktır.
|
||||
* Uvicorn ile doğrudan bir uygulama yazmazsınız. Bu, kodunuzun en azından Starlette'in (veya **FastAPI**'ın) sağladığı kodun aşağı yukarı tamamını içermesi gerektiği anlamına gelir. Bunu yaparsanız, nihai uygulamanız; bir framework kullanmış olmanın ve uygulama kodunu ve bug'ları en aza indirmenin getirdiği ek yükle aynı ek yüke sahip olur.
|
||||
* Uvicorn'u karşılaştırıyorsanız, Daphne, Hypercorn, uWSGI vb. application server'larla karşılaştırın.
|
||||
* **Starlette**:
|
||||
* Uvicorn'dan sonraki en iyi performansa sahip olacaktır. İşin aslı, Starlette çalışmak için Uvicorn'u kullanıyor. Dolayısıyla, daha fazla kod çalıştırmaası gerektiğinden muhtemelen Uvicorn'dan sadece "daha yavaş" olabilir.
|
||||
* Ancak yol bazlı yönlendirme vb. basit web uygulamaları oluşturmak için araçlar sağlar.
|
||||
* Eğer Starlette'i karşılaştırıyorsanız, Sanic, Flask, Django, vb. frameworkler (veya mikroframeworkler) ile karşılaştırın.
|
||||
* Uvicorn'dan sonra en iyi performansa sahip olacaktır. Aslında Starlette çalışmak için Uvicorn'u kullanır. Bu yüzden muhtemelen yalnızca daha fazla kod çalıştırmak zorunda kaldığı için Uvicorn'dan "daha yavaş" olabilir.
|
||||
* Ancak path tabanlı routing vb. ile basit web uygulamaları oluşturmanız için araçlar sağlar.
|
||||
* Starlette'i karşılaştırıyorsanız, Sanic, Flask, Django vb. web framework'lerle (veya mikroframework'lerle) karşılaştırın.
|
||||
* **FastAPI**:
|
||||
* Starlette'in Uvicorn'u kullandığı ve ondan daha hızlı olamayacağı gibi, **FastAPI**'da Starlette'i kullanır, dolayısıyla ondan daha hızlı olamaz.
|
||||
* FastAPI, Starlette'e ek olarak daha fazla özellik sunar. Bunlar veri doğrulama ve <abbr title="Dönüşüm: serialization, parsing, marshalling olarak da biliniyor">dönüşümü</abbr> gibi API'lar oluştururken neredeyse ve her zaman ihtiyaç duyduğunuz özelliklerdir. Ve bunu kullanarak, ücretsiz olarak otomatik dokümantasyon elde edersiniz (otomatik dokümantasyon çalışan uygulamalara ek yük getirmez, başlangıçta oluşturulur).
|
||||
* FastAPI'ı kullanmadıysanız ve Starlette'i doğrudan kullandıysanız (veya başka bir araç, Sanic, Flask, Responder, vb.) tüm veri doğrulama ve dönüştürme araçlarını kendiniz geliştirmeniz gerekir. Dolayısıyla, son uygulamanız FastAPI kullanılarak oluşturulmuş gibi hâlâ aynı ek yüke sahip olacaktır. Çoğu durumda, uygulamalarda yazılan kodun büyük bir kısmını veri doğrulama ve dönüştürme kodları oluşturur.
|
||||
* Dolayısıyla, FastAPI'ı kullanarak geliştirme süresinden, hatalardan, kod satırlarından tasarruf edersiniz ve kullanmadığınız durumda (birçok özelliği geliştirmek zorunda kalmakla birlikte) muhtemelen aynı performansı (veya daha iyisini) elde ederdiniz.
|
||||
* Eğer FastAPI'ı karşılaştırıyorsanız, Flask-apispec, NestJS, Molten, vb. gibi veri doğrulama, dönüştürme ve dokümantasyon sağlayan bir web uygulaması frameworkü ile (veya araç setiyle) karşılaştırın.
|
||||
* Starlette'in Uvicorn'u kullanıp ondan daha hızlı olamaması gibi, **FastAPI** da Starlette'i kullanır; dolayısıyla ondan daha hızlı olamaz.
|
||||
* FastAPI, Starlette'in üzerine daha fazla özellik sağlar. API'lar oluştururken neredeyse her zaman ihtiyaç duyduğunuz veri doğrulama ve <abbr title="serialization - serileştirme">serialization</abbr> gibi özellikler. Ayrıca bunu kullanarak ücretsiz olarak otomatik dokümantasyon elde edersiniz (otomatik dokümantasyon, çalışan uygulamalara ek yük bile getirmez; startup'ta üretilir).
|
||||
* FastAPI'ı kullanmayıp Starlette'i doğrudan kullansaydınız (veya Sanic, Flask, Responder vb. başka bir aracı), tüm veri doğrulama ve serialization işlemlerini kendiniz uygulamak zorunda kalırdınız. Dolayısıyla nihai uygulamanız, FastAPI kullanılarak inşa edilmiş olsaydı sahip olacağı ek yükle hâlâ aynı ek yüke sahip olurdu. Ve çoğu durumda, uygulamalarda yazılan en büyük kod miktarı veri doğrulama ve serialization kısmıdır.
|
||||
* Bu nedenle FastAPI kullanarak geliştirme süresinden, bug'lardan, kod satırlarından tasarruf edersiniz; ayrıca muhtemelen, onu kullanmasaydınız (tüm bunları kodunuzda kendiniz uygulamak zorunda kalacağınız için) elde edeceğiniz performansın aynısını (veya daha iyisini) elde edersiniz.
|
||||
* FastAPI'ı karşılaştırıyorsanız, Flask-apispec, NestJS, Molten vb. veri doğrulama, serialization ve dokümantasyon sağlayan bir web uygulaması framework'ü (veya araç seti) ile karşılaştırın. Entegre otomatik veri doğrulama, serialization ve dokümantasyona sahip framework'ler.
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
# FastAPI Uygulamasını Bulut Sağlayıcılar Üzerinde Yayınlama
|
||||
# Bulut Sağlayıcılar Üzerinde FastAPI Yayınlama { #deploy-fastapi-on-cloud-providers }
|
||||
|
||||
FastAPI uygulamasını yayınlamak için hemen hemen **herhangi bir bulut sağlayıcıyı** kullanabilirsiniz.
|
||||
FastAPI uygulamanızı yayınlamak için neredeyse **herhangi bir bulut sağlayıcıyı** kullanabilirsiniz.
|
||||
|
||||
Büyük bulut sağlayıcıların çoğu FastAPI uygulamasını yayınlamak için kılavuzlara sahiptir.
|
||||
Çoğu durumda, ana bulut sağlayıcıların FastAPI'yi onlarla birlikte yayınlamak için kılavuzları vardır.
|
||||
|
||||
## Bulut Sağlayıcılar - Sponsorlar
|
||||
## FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
Bazı bulut sağlayıcılar ✨ [**FastAPI destekçileridir**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, bu FastAPI ve **ekosisteminin** sürekli ve sağlıklı bir şekilde **gelişmesini** sağlar.
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**, **FastAPI**'nin arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.
|
||||
|
||||
Ayrıca, size **iyi servisler** sağlamakla kalmayıp, **iyi ve sağlıklı bir framework** olan FastAPI'a bağlılıklarını gösterir.
|
||||
Bir API'yi minimum çabayla **oluşturma**, **yayınlama** ve **erişme** sürecini kolaylaştırır.
|
||||
|
||||
Bu hizmetleri denemek ve kılavuzlarını incelemek isteyebilirsiniz.
|
||||
FastAPI ile uygulama geliştirirken elde edilen aynı **geliştirici deneyimini**, onları buluta **yayınlamaya** da taşır. 🎉
|
||||
|
||||
FastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨
|
||||
|
||||
## Bulut Sağlayıcılar - Sponsorlar { #cloud-providers-sponsors }
|
||||
|
||||
Diğer bazı bulut sağlayıcılar da ✨ [**FastAPI'ye sponsor olur**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨. 🙇
|
||||
|
||||
Kılavuzlarını takip etmek ve servislerini denemek için onları da değerlendirmek isteyebilirsiniz:
|
||||
|
||||
* <a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" class="external-link" target="_blank">Render</a>
|
||||
* <a href="https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi" class="external-link" target="_blank">Railway</a>
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
# Deployment Kavramları { #deployments-concepts }
|
||||
|
||||
Bir **FastAPI** uygulamasını (hatta genel olarak herhangi bir web API'yi) deploy ederken, muhtemelen önemseyeceğiniz bazı kavramlar vardır. Bu kavramları kullanarak, **uygulamanızı deploy etmek** için **en uygun** yöntemi bulabilirsiniz.
|
||||
|
||||
Önemli kavramlardan bazıları şunlardır:
|
||||
|
||||
* Güvenlik - HTTPS
|
||||
* Startup'ta çalıştırma
|
||||
* Yeniden başlatmalar
|
||||
* Replikasyon (çalışan process sayısı)
|
||||
* Bellek
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
Bunların **deployment**'ları nasıl etkilediğine bakalım.
|
||||
|
||||
Nihai hedef, **API client**'larınıza **güvenli** bir şekilde hizmet verebilmek, **kesintileri** önlemek ve **hesaplama kaynaklarını** (ör. uzak server'lar/sanal makineler) olabildiğince verimli kullanmaktır. 🚀
|
||||
|
||||
Burada bu **kavramlar** hakkında biraz daha bilgi vereceğim. Böylece, çok farklı ortamlarda—hatta bugün var olmayan **gelecekteki** ortamlarda bile—API'nizi nasıl deploy edeceğinize karar verirken ihtiyaç duyacağınız **sezgiyi** kazanmış olursunuz.
|
||||
|
||||
Bu kavramları dikkate alarak, **kendi API**'leriniz için en iyi deployment yaklaşımını **değerlendirebilir ve tasarlayabilirsiniz**.
|
||||
|
||||
Sonraki bölümlerde, FastAPI uygulamalarını deploy etmek için daha **somut tarifler** (recipes) paylaşacağım.
|
||||
|
||||
Ama şimdilik, bu önemli **kavramsal fikirleri** inceleyelim. Bu kavramlar diğer tüm web API türleri için de geçerlidir. 💡
|
||||
|
||||
## Güvenlik - HTTPS { #security-https }
|
||||
|
||||
[HTTPS hakkındaki önceki bölümde](https.md){.internal-link target=_blank} HTTPS'in API'niz için nasıl şifreleme sağladığını öğrenmiştik.
|
||||
|
||||
Ayrıca HTTPS'in genellikle uygulama server'ınızın **dışında** yer alan bir bileşen tarafından sağlandığını, yani bir **TLS Termination Proxy** ile yapıldığını da görmüştük.
|
||||
|
||||
Ve **HTTPS sertifikalarını yenilemekten** sorumlu bir şey olmalıdır; bu aynı bileşen olabileceği gibi farklı bir bileşen de olabilir.
|
||||
|
||||
### HTTPS için Örnek Araçlar { #example-tools-for-https }
|
||||
|
||||
TLS Termination Proxy olarak kullanabileceğiniz bazı araçlar:
|
||||
|
||||
* Traefik
|
||||
* Sertifika yenilemelerini otomatik yönetir ✨
|
||||
* Caddy
|
||||
* Sertifika yenilemelerini otomatik yönetir ✨
|
||||
* Nginx
|
||||
* Sertifika yenilemeleri için Certbot gibi harici bir bileşenle
|
||||
* HAProxy
|
||||
* Sertifika yenilemeleri için Certbot gibi harici bir bileşenle
|
||||
* Nginx gibi bir Ingress Controller ile Kubernetes
|
||||
* Sertifika yenilemeleri için cert-manager gibi harici bir bileşenle
|
||||
* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi (aşağıyı okuyun 👇)
|
||||
|
||||
Bir diğer seçenek de, HTTPS kurulumunu da dahil olmak üzere işin daha büyük kısmını yapan bir **cloud service** kullanmaktır. Bunun bazı kısıtları olabilir veya daha pahalı olabilir vb. Ancak bu durumda TLS Termination Proxy'yi kendiniz kurmak zorunda kalmazsınız.
|
||||
|
||||
Sonraki bölümlerde bazı somut örnekler göstereceğim.
|
||||
|
||||
---
|
||||
|
||||
Sonraki kavramlar, gerçek API'nizi çalıştıran programla (ör. Uvicorn) ilgilidir.
|
||||
|
||||
## Program ve Process { #program-and-process }
|
||||
|
||||
Çalışan "**process**" hakkında çok konuşacağız. Bu yüzden ne anlama geldiğini ve "**program**" kelimesinden farkının ne olduğunu netleştirmek faydalı.
|
||||
|
||||
### Program Nedir { #what-is-a-program }
|
||||
|
||||
**Program** kelimesi günlük kullanımda birçok şeyi anlatmak için kullanılır:
|
||||
|
||||
* Yazdığınız **code**, yani **Python dosyaları**.
|
||||
* İşletim sistemi tarafından **çalıştırılabilen** **dosya**, örn: `python`, `python.exe` veya `uvicorn`.
|
||||
* İşletim sistemi üzerinde **çalışır durumdayken** CPU kullanan ve bellekte veri tutan belirli bir program. Buna **process** de denir.
|
||||
|
||||
### Process Nedir { #what-is-a-process }
|
||||
|
||||
**Process** kelimesi genellikle daha spesifik kullanılır; yalnızca işletim sistemi üzerinde çalışan şeye (yukarıdaki son madde gibi) işaret eder:
|
||||
|
||||
* İşletim sistemi üzerinde **çalışır durumda** olan belirli bir program.
|
||||
* Bu; dosyayı ya da code'u değil, işletim sistemi tarafından **çalıştırılan** ve yönetilen şeyi ifade eder.
|
||||
* Herhangi bir program, herhangi bir code, **yalnızca çalıştırılırken** bir şey yapabilir. Yani bir **process çalışıyorken**.
|
||||
* Process siz tarafından veya işletim sistemi tarafından **sonlandırılabilir** (ya da "killed" edilebilir). O anda çalışması/çalıştırılması durur ve artık **hiçbir şey yapamaz**.
|
||||
* Bilgisayarınızda çalışan her uygulamanın arkasında bir process vardır; çalışan her program, her pencere vb. Bilgisayar açıkken normalde **aynı anda** birçok process çalışır.
|
||||
* Aynı anda **aynı programın birden fazla process**'i çalışabilir.
|
||||
|
||||
İşletim sisteminizdeki "task manager" veya "system monitor" (ya da benzeri araçlar) ile bu process'lerin birçoğunu çalışır halde görebilirsiniz.
|
||||
|
||||
Örneğin muhtemelen aynı browser programını (Firefox, Chrome, Edge vb.) çalıştıran birden fazla process göreceksiniz. Genelde her tab için bir process, üstüne bazı ek process'ler çalıştırırlar.
|
||||
|
||||
<img class="shadow" src="/img/deployment/concepts/image01.png">
|
||||
|
||||
---
|
||||
|
||||
Artık **process** ve **program** arasındaki farkı bildiğimize göre, deployment konusuna devam edelim.
|
||||
|
||||
## Startup'ta Çalıştırma { #running-on-startup }
|
||||
|
||||
Çoğu durumda bir web API oluşturduğunuzda, client'larınızın her zaman erişebilmesi için API'nizin kesintisiz şekilde **sürekli çalışıyor** olmasını istersiniz. Elbette sadece belirli durumlarda çalışmasını istemenizin özel bir sebebi olabilir; ancak çoğunlukla onu sürekli açık ve **kullanılabilir** halde tutarsınız.
|
||||
|
||||
### Uzak Bir Server'da { #in-a-remote-server }
|
||||
|
||||
Uzak bir server (cloud server, sanal makine vb.) kurduğunuzda, yapabileceğiniz en basit şey; local geliştirme sırasında yaptığınız gibi, manuel olarak `fastapi run` (Uvicorn'u kullanır) veya benzeri bir komutla çalıştırmaktır.
|
||||
|
||||
Bu yöntem çalışır ve **geliştirme sırasında** faydalıdır.
|
||||
|
||||
Ancak server'a olan bağlantınız koparsa, **çalışan process** muhtemelen ölür.
|
||||
|
||||
Ve server yeniden başlatılırsa (örneğin update'lerden sonra ya da cloud provider'ın migration'larından sonra) bunu muhtemelen **fark etmezsiniz**. Dolayısıyla process'i manuel yeniden başlatmanız gerektiğini de bilmezsiniz. Sonuçta API'niz ölü kalır. 😱
|
||||
|
||||
### Startup'ta Otomatik Çalıştırma { #run-automatically-on-startup }
|
||||
|
||||
Genellikle server programının (ör. Uvicorn) server açılışında otomatik başlamasını ve herhangi bir **insan müdahalesi** gerektirmeden API'nizi çalıştıran bir process'in sürekli ayakta olmasını istersiniz (ör. FastAPI uygulamanızı çalıştıran Uvicorn).
|
||||
|
||||
### Ayrı Bir Program { #separate-program }
|
||||
|
||||
Bunu sağlamak için genellikle startup'ta uygulamanızın çalıştığından emin olacak **ayrı bir program** kullanırsınız. Pek çok durumda bu program, örneğin bir veritabanı gibi diğer bileşenlerin/uygulamaların da çalıştığından emin olur.
|
||||
|
||||
### Startup'ta Çalıştırmak için Örnek Araçlar { #example-tools-to-run-at-startup }
|
||||
|
||||
Bu işi yapabilen araçlara örnekler:
|
||||
|
||||
* Docker
|
||||
* Kubernetes
|
||||
* Docker Compose
|
||||
* Docker in Swarm Mode
|
||||
* Systemd
|
||||
* Supervisor
|
||||
* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi
|
||||
* Diğerleri...
|
||||
|
||||
Sonraki bölümlerde daha somut örnekler vereceğim.
|
||||
|
||||
## Yeniden Başlatmalar { #restarts }
|
||||
|
||||
Uygulamanızın startup'ta çalıştığından emin olmaya benzer şekilde, hatalardan sonra **yeniden başlatıldığından** da emin olmak istersiniz.
|
||||
|
||||
### Hata Yaparız { #we-make-mistakes }
|
||||
|
||||
Biz insanlar sürekli **hata** yaparız. Yazılımın neredeyse *her zaman* farklı yerlerinde gizli **bug**'lar vardır. 🐛
|
||||
|
||||
Ve biz geliştiriciler bu bug'ları buldukça ve yeni özellikler ekledikçe code'u iyileştiririz (muhtemelen yeni bug'lar da ekleyerek 😅).
|
||||
|
||||
### Küçük Hatalar Otomatik Yönetilir { #small-errors-automatically-handled }
|
||||
|
||||
FastAPI ile web API geliştirirken, code'umuzda bir hata olursa FastAPI genellikle bunu hatayı tetikleyen tek request ile sınırlar. 🛡
|
||||
|
||||
Client o request için **500 Internal Server Error** alır; ancak uygulama tamamen çöküp durmak yerine sonraki request'ler için çalışmaya devam eder.
|
||||
|
||||
### Daha Büyük Hatalar - Çökmeler { #bigger-errors-crashes }
|
||||
|
||||
Yine de bazı durumlarda, yazdığımız bir code **tüm uygulamayı çökertip** Uvicorn ve Python'ın crash olmasına neden olabilir. 💥
|
||||
|
||||
Böyle bir durumda, tek bir noktadaki hata yüzünden uygulamanın ölü kalmasını istemezsiniz; bozuk olmayan *path operations* en azından çalışmaya devam etsin istersiniz.
|
||||
|
||||
### Crash Sonrası Yeniden Başlatma { #restart-after-crash }
|
||||
|
||||
Ancak çalışan **process**'i çökerten gerçekten kötü hatalarda, process'i **yeniden başlatmaktan** sorumlu harici bir bileşen istersiniz; en azından birkaç kez...
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
...Yine de uygulama **hemen crash oluyorsa**, onu sonsuza kadar yeniden başlatmaya çalışmanın pek anlamı yoktur. Böyle durumları büyük ihtimalle geliştirme sırasında ya da en geç deploy'dan hemen sonra fark edersiniz.
|
||||
|
||||
O yüzden ana senaryoya odaklanalım: Gelecekte bazı özel durumlarda tamamen çökebilir ve yine de yeniden başlatmak mantıklıdır.
|
||||
|
||||
///
|
||||
|
||||
Uygulamanızı yeniden başlatmakla görevli bileşenin **harici bir bileşen** olmasını istersiniz. Çünkü o noktada Uvicorn ve Python ile birlikte aynı uygulama zaten crash olmuştur; aynı app'in içindeki aynı code'un bunu düzeltmek için yapabileceği bir şey kalmaz.
|
||||
|
||||
### Otomatik Yeniden Başlatma için Örnek Araçlar { #example-tools-to-restart-automatically }
|
||||
|
||||
Çoğu durumda, **startup'ta programı çalıştırmak** için kullanılan aracın aynısı otomatik **restart**'ları yönetmek için de kullanılır.
|
||||
|
||||
Örneğin bu şunlarla yönetilebilir:
|
||||
|
||||
* Docker
|
||||
* Kubernetes
|
||||
* Docker Compose
|
||||
* Docker in Swarm Mode
|
||||
* Systemd
|
||||
* Supervisor
|
||||
* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi
|
||||
* Diğerleri...
|
||||
|
||||
## Replikasyon - Process'ler ve Bellek { #replication-processes-and-memory }
|
||||
|
||||
FastAPI uygulamasında, Uvicorn'u çalıştıran `fastapi` komutu gibi bir server programı kullanırken, uygulamayı **tek bir process** içinde bir kez çalıştırmak bile aynı anda birden fazla client'a hizmet verebilir.
|
||||
|
||||
Ancak birçok durumda, aynı anda birden fazla worker process çalıştırmak istersiniz.
|
||||
|
||||
### Birden Fazla Process - Worker'lar { #multiple-processes-workers }
|
||||
|
||||
Tek bir process'in karşılayabileceğinden daha fazla client'ınız varsa (örneğin sanal makine çok büyük değilse) ve server CPU'sunda **birden fazla core** varsa, aynı uygulamayla **birden fazla process** çalıştırıp tüm request'leri bunlara dağıtabilirsiniz.
|
||||
|
||||
Aynı API programının **birden fazla process**'ini çalıştırdığınızda, bunlara genellikle **worker** denir.
|
||||
|
||||
### Worker Process'ler ve Port'lar { #worker-processes-and-ports }
|
||||
|
||||
[HTTPS hakkındaki dokümanda](https.md){.internal-link target=_blank} bir server'da aynı port ve IP adresi kombinasyonunu yalnızca tek bir process'in dinleyebileceğini hatırlıyor musunuz?
|
||||
|
||||
Bu hâlâ geçerli.
|
||||
|
||||
Dolayısıyla **aynı anda birden fazla process** çalıştırabilmek için, **port** üzerinde dinleyen **tek bir process** olmalı ve bu process iletişimi bir şekilde worker process'lere aktarmalıdır.
|
||||
|
||||
### Process Başına Bellek { #memory-per-process }
|
||||
|
||||
Program belleğe bir şeyler yüklediğinde—örneğin bir değişkende bir machine learning modelini veya büyük bir dosyanın içeriğini tutmak gibi—bunların hepsi server'ın **belleğini (RAM)** tüketir.
|
||||
|
||||
Ve birden fazla process normalde **belleği paylaşmaz**. Yani her çalışan process'in kendi verileri, değişkenleri ve belleği vardır. Code'unuz çok bellek tüketiyorsa, **her process** buna denk bir miktar bellek tüketir.
|
||||
|
||||
### Server Belleği { #server-memory }
|
||||
|
||||
Örneğin code'unuz **1 GB** boyutunda bir Machine Learning modelini yüklüyorsa, API'niz tek process ile çalışırken en az 1 GB RAM tüketir. **4 process** (4 worker) başlatırsanız her biri 1 GB RAM tüketir. Yani toplamda API'niz **4 GB RAM** tüketir.
|
||||
|
||||
Uzak server'ınız veya sanal makineniz yalnızca 3 GB RAM'e sahipse, 4 GB'tan fazla RAM yüklemeye çalışmak sorun çıkarır. 🚨
|
||||
|
||||
### Birden Fazla Process - Bir Örnek { #multiple-processes-an-example }
|
||||
|
||||
Bu örnekte, iki adet **Worker Process** başlatıp kontrol eden bir **Manager Process** vardır.
|
||||
|
||||
Bu Manager Process büyük ihtimalle IP üzerindeki **port**'u dinleyen süreçtir ve tüm iletişimi worker process'lere aktarır.
|
||||
|
||||
Worker process'ler uygulamanızı çalıştıran process'lerdir; bir **request** alıp bir **response** döndürmek için asıl hesaplamaları yaparlar ve sizin RAM'de değişkenlere koyduğunuz her şeyi yüklerler.
|
||||
|
||||
<img src="/img/deployment/concepts/process-ram.drawio.svg">
|
||||
|
||||
Elbette aynı makinede, uygulamanız dışında da muhtemelen **başka process**'ler çalışır.
|
||||
|
||||
İlginç bir detay: Her process'in kullandığı **CPU** yüzdesi zaman içinde çok **değişken** olabilir; ancak **bellek (RAM)** genellikle az çok **stabil** kalır.
|
||||
|
||||
Eğer API'niz her seferinde benzer miktarda hesaplama yapıyorsa ve çok sayıda client'ınız varsa, **CPU kullanımı** da muhtemelen *stabil olur* (hızlı hızlı sürekli yükselip alçalmak yerine).
|
||||
|
||||
### Replikasyon Araçları ve Stratejileri Örnekleri { #examples-of-replication-tools-and-strategies }
|
||||
|
||||
Bunu başarmak için farklı yaklaşımlar olabilir. Sonraki bölümlerde, örneğin Docker ve container'lar konuşurken, belirli stratejileri daha detaylı anlatacağım.
|
||||
|
||||
Dikkate almanız gereken ana kısıt şudur: **public IP** üzerindeki **port**'u yöneten **tek** bir bileşen olmalı. Sonrasında bu bileşenin, replikasyonla çoğaltılmış **process/worker**'lara iletişimi **aktarmanın** bir yoluna sahip olması gerekir.
|
||||
|
||||
Olası kombinasyonlar ve stratejiler:
|
||||
|
||||
* `--workers` ile **Uvicorn**
|
||||
* Bir Uvicorn **process manager** **IP** ve **port** üzerinde dinler ve **birden fazla Uvicorn worker process** başlatır.
|
||||
* **Kubernetes** ve diğer dağıtık **container sistemleri**
|
||||
* **Kubernetes** katmanında bir şey **IP** ve **port** üzerinde dinler. Replikasyon, her birinde **tek bir Uvicorn process** çalışan **birden fazla container** ile yapılır.
|
||||
* Bunu sizin yerinize yapan **cloud service**'ler
|
||||
* Cloud service muhtemelen **replikasyonu sizin yerinize yönetir**. Size çalıştırılacak **bir process** veya kullanılacak bir **container image** tanımlama imkânı verebilir; her durumda büyük ihtimalle **tek bir Uvicorn process** olur ve bunu çoğaltmaktan cloud service sorumlu olur.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
**Container**, Docker veya Kubernetes ile ilgili bazı maddeler şimdilik çok anlamlı gelmiyorsa dert etmeyin.
|
||||
|
||||
Container image'ları, Docker, Kubernetes vb. konuları ilerideki bir bölümde daha detaylı anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## Başlatmadan Önceki Adımlar { #previous-steps-before-starting }
|
||||
|
||||
Uygulamanızı **başlatmadan önce** bazı adımlar yapmak isteyeceğiniz birçok durum vardır.
|
||||
|
||||
Örneğin **database migrations** çalıştırmak isteyebilirsiniz.
|
||||
|
||||
Ancak çoğu durumda, bu adımları yalnızca **bir kez** çalıştırmak istersiniz.
|
||||
|
||||
Bu yüzden, uygulamayı başlatmadan önce bu **ön adımları** çalıştıracak **tek bir process** olmasını istersiniz.
|
||||
|
||||
Ve daha sonra uygulamanın kendisi için **birden fazla process** (birden fazla worker) başlatsanız bile, bu ön adımları çalıştıranın *yine* tek process olduğundan emin olmalısınız. Bu adımlar **birden fazla process** tarafından çalıştırılsaydı, işi **paralel** şekilde tekrarlarlardı. Adımlar database migration gibi hassas bir şeyse, birbirleriyle çakışıp çatışma çıkarabilirler.
|
||||
|
||||
Elbette bazı durumlarda ön adımları birden fazla kez çalıştırmak sorun değildir; bu durumda yönetmesi çok daha kolay olur.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Ayrıca, kurulumunuza bağlı olarak bazı durumlarda uygulamanızı başlatmadan önce **hiç ön adıma ihtiyaç duymayabilirsiniz**.
|
||||
|
||||
Bu durumda bunların hiçbirini düşünmeniz gerekmez. 🤷
|
||||
|
||||
///
|
||||
|
||||
### Ön Adımlar için Strateji Örnekleri { #examples-of-previous-steps-strategies }
|
||||
|
||||
Bu konu, **sisteminizi nasıl deploy ettiğinize** çok bağlıdır ve muhtemelen programları nasıl başlattığınız, restart'ları nasıl yönettiğiniz vb. ile bağlantılıdır.
|
||||
|
||||
Bazı olası fikirler:
|
||||
|
||||
* Kubernetes'te, app container'ınızdan önce çalışan bir "Init Container"
|
||||
* Ön adımları çalıştırıp sonra uygulamanızı başlatan bir bash script
|
||||
* Yine de o bash script'i başlatmak/restart etmek, hataları tespit etmek vb. için bir mekanizmaya ihtiyacınız olur.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bunu container'larla nasıl yapabileceğinize dair daha somut örnekleri ilerideki bir bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## Kaynak Kullanımı { #resource-utilization }
|
||||
|
||||
Server(lar)ınız bir **kaynaktır**. Programlarınızla CPU'lardaki hesaplama zamanını ve mevcut RAM belleğini tüketebilir veya **kullanabilirsiniz**.
|
||||
|
||||
Sistem kaynaklarının ne kadarını tüketmek/kullanmak istersiniz? "Az" demek kolaydır; ancak pratikte hedef genellikle **çökmeden mümkün olduğunca fazla** kullanmaktır.
|
||||
|
||||
3 server için para ödüyor ama onların RAM ve CPU'sunun yalnızca küçük bir kısmını kullanıyorsanız, muhtemelen **para israf ediyorsunuz** 💸 ve muhtemelen **elektrik tüketimini** de gereksiz yere artırıyorsunuz 🌎 vb.
|
||||
|
||||
Bu durumda 2 server ile devam edip onların kaynaklarını (CPU, bellek, disk, ağ bant genişliği vb.) daha yüksek oranlarda kullanmak daha iyi olabilir.
|
||||
|
||||
Öte yandan, 2 server'ınız var ve CPU ile RAM'in **%100**'ünü kullanıyorsanız, bir noktada bir process daha fazla bellek ister; server diski "bellek" gibi kullanmak zorunda kalır (binlerce kat daha yavaş olabilir) ya da hatta **crash** edebilir. Ya da bir process bir hesaplama yapmak ister ve CPU tekrar boşalana kadar beklemek zorunda kalır.
|
||||
|
||||
Bu senaryoda **bir server daha** eklemek ve bazı process'leri orada çalıştırmak daha iyi olur; böylece hepsinin **yeterli RAM'i ve CPU zamanı** olur.
|
||||
|
||||
Ayrıca, herhangi bir sebeple API'nizde bir kullanım **spike**'ı olma ihtimali de vardır. Belki viral olur, belki başka servisler veya bot'lar kullanmaya başlar. Bu durumlarda güvende olmak için ekstra kaynak isteyebilirsiniz.
|
||||
|
||||
Hedef olarak **keyfi bir sayı** belirleyebilirsiniz; örneğin kaynak kullanımını **%50 ile %90 arasında** tutmak gibi. Önemli olan, bunların muhtemelen ölçmek isteyeceğiniz ve deployment'larınızı ayarlamak için kullanacağınız ana metrikler olmasıdır.
|
||||
|
||||
Server'ınızda CPU ve RAM kullanımını veya her process'in ne kadar kullandığını görmek için `htop` gibi basit araçları kullanabilirsiniz. Ya da server'lar arasında dağıtık çalışan daha karmaşık monitoring araçları kullanabilirsiniz.
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Uygulamanızı nasıl deploy edeceğinize karar verirken aklınızda tutmanız gereken ana kavramların bazılarını okudunuz:
|
||||
|
||||
* Güvenlik - HTTPS
|
||||
* Startup'ta çalıştırma
|
||||
* Yeniden başlatmalar
|
||||
* Replikasyon (çalışan process sayısı)
|
||||
* Bellek
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
Bu fikirleri ve nasıl uygulayacağınızı anlamak, deployment'larınızı yapılandırırken ve ince ayar yaparken ihtiyaç duyacağınız sezgiyi kazanmanızı sağlamalıdır. 🤓
|
||||
|
||||
Sonraki bölümlerde, izleyebileceğiniz stratejilere dair daha somut örnekler paylaşacağım. 🚀
|
||||
@@ -0,0 +1,618 @@
|
||||
# Container'larda FastAPI - Docker { #fastapi-in-containers-docker }
|
||||
|
||||
FastAPI uygulamalarını deploy ederken yaygın bir yaklaşım, bir **Linux container image** oluşturmaktır. Bu genellikle <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> kullanılarak yapılır. Ardından bu container image'ı birkaç farklı yöntemden biriyle deploy edebilirsiniz.
|
||||
|
||||
Linux container'ları kullanmanın **güvenlik**, **tekrarlanabilirlik**, **basitlik** gibi birçok avantajı vardır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Aceleniz var ve bunları zaten biliyor musunuz? Aşağıdaki [`Dockerfile`'a atlayın 👇](#build-a-docker-image-for-fastapi).
|
||||
|
||||
///
|
||||
|
||||
<details>
|
||||
<summary>Dockerfile Önizleme 👀</summary>
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
|
||||
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
||||
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Container Nedir { #what-is-a-container }
|
||||
|
||||
Container'lar (özellikle Linux container'ları), bir uygulamayı tüm bağımlılıkları ve gerekli dosyalarıyla birlikte paketlemenin, aynı sistemdeki diğer container'lardan (diğer uygulama ya da bileşenlerden) izole tutarken yapılan, çok **hafif** bir yoludur.
|
||||
|
||||
Linux container'ları, host'un (makine, sanal makine, cloud server vb.) aynı Linux kernel'ini kullanarak çalışır. Bu da, tüm bir işletim sistemini emüle eden tam sanal makinelere kıyasla çok daha hafif oldukları anlamına gelir.
|
||||
|
||||
Bu sayede container'lar **az kaynak** tüketir; süreçleri doğrudan çalıştırmaya benzer bir seviyede (bir sanal makine çok daha fazla tüketirdi).
|
||||
|
||||
Container'ların ayrıca kendi **izole** çalışan process'leri (çoğunlukla tek bir process), dosya sistemi ve ağı vardır. Bu da deployment, güvenlik, geliştirme vb. süreçleri kolaylaştırır.
|
||||
|
||||
## Container Image Nedir { #what-is-a-container-image }
|
||||
|
||||
Bir **container**, bir **container image**'dan çalıştırılır.
|
||||
|
||||
Container image; bir container içinde bulunması gereken tüm dosyaların, environment variable'ların ve varsayılan komut/programın **statik** bir sürümüdür. Buradaki **statik**, container **image**'ının çalışmadığı, execute edilmediği; sadece paketlenmiş dosyalar ve metadata olduğu anlamına gelir.
|
||||
|
||||
Depolanmış statik içerik olan "**container image**"ın aksine, "**container**" normalde çalışan instance'ı, yani **execute edilen** şeyi ifade eder.
|
||||
|
||||
**Container** başlatılıp çalıştığında (bir **container image**'dan başlatılır), dosyalar oluşturabilir/değiştirebilir, environment variable'ları değiştirebilir vb. Bu değişiklikler sadece o container içinde kalır; alttaki container image'da kalıcı olmaz (diske kaydedilmez).
|
||||
|
||||
Bir container image, **program** dosyası ve içeriklerine benzetilebilir; örn. `python` ve `main.py` gibi bir dosya.
|
||||
|
||||
Ve **container**'ın kendisi (container image'a karşıt olarak) image'ın gerçek çalışan instance'ıdır; bir **process**'e benzer. Hatta bir container, yalnızca içinde **çalışan bir process** varken çalışır (ve genelde tek process olur). İçinde çalışan process kalmayınca container durur.
|
||||
|
||||
## Container Image'lar { #container-images }
|
||||
|
||||
Docker, **container image** ve **container** oluşturup yönetmek için kullanılan başlıca araçlardan biri olmuştur.
|
||||
|
||||
Ayrıca birçok araç, ortam, veritabanı ve uygulama için önceden hazırlanmış **resmi container image**'ların bulunduğu herkese açık bir <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> vardır.
|
||||
|
||||
Örneğin, resmi bir <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Python Image</a> bulunur.
|
||||
|
||||
Ve veritabanları gibi farklı şeyler için de birçok image vardır; örneğin:
|
||||
|
||||
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
|
||||
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
|
||||
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
|
||||
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, vb.
|
||||
|
||||
Hazır bir container image kullanarak farklı araçları **birleştirmek** ve birlikte kullanmak çok kolaydır. Örneğin yeni bir veritabanını denemek için. Çoğu durumda **resmi image**'ları kullanıp sadece environment variable'lar ile yapılandırmanız yeterlidir.
|
||||
|
||||
Bu şekilde, çoğu zaman container'lar ve Docker hakkında öğrendiklerinizi farklı araç ve bileşenlerde tekrar kullanabilirsiniz.
|
||||
|
||||
Dolayısıyla; veritabanı, Python uygulaması, React frontend uygulaması olan bir web server gibi farklı şeyler için **birden fazla container** çalıştırır ve bunları internal network üzerinden birbirine bağlarsınız.
|
||||
|
||||
Docker veya Kubernetes gibi tüm container yönetim sistemlerinde bu ağ özellikleri entegre olarak bulunur.
|
||||
|
||||
## Container'lar ve Process'ler { #containers-and-processes }
|
||||
|
||||
Bir **container image** normalde metadata içinde, **container** başlatıldığında çalıştırılacak varsayılan program/komutu ve o programa geçirilecek parametreleri içerir. Bu, komut satırında yazacağınız şeye çok benzer.
|
||||
|
||||
Bir **container** başlatıldığında bu komutu/programı çalıştırır (ancak isterseniz bunu override edip başka bir komut/program çalıştırabilirsiniz).
|
||||
|
||||
Bir container, **ana process** (komut/program) çalıştığı sürece çalışır.
|
||||
|
||||
Container'larda normalde **tek bir process** olur. Ancak ana process içinden subprocess'ler başlatmak da mümkündür; böylece aynı container içinde **birden fazla process** olur.
|
||||
|
||||
Ama **en az bir çalışan process olmadan** çalışan bir container olamaz. Ana process durursa container da durur.
|
||||
|
||||
## FastAPI için Docker Image Oluşturalım { #build-a-docker-image-for-fastapi }
|
||||
|
||||
Tamam, şimdi bir şeyler inşa edelim! 🚀
|
||||
|
||||
Resmi **Python** image'ını temel alarak, FastAPI için **sıfırdan** bir **Docker image** nasıl oluşturulur göstereceğim.
|
||||
|
||||
Bu, örneğin şu durumlarda **çoğu zaman** yapmak isteyeceğiniz şeydir:
|
||||
|
||||
* **Kubernetes** veya benzeri araçlar kullanırken
|
||||
* **Raspberry Pi** üzerinde çalıştırırken
|
||||
* Container image'ınızı sizin için çalıştıran bir cloud servisi kullanırken, vb.
|
||||
|
||||
### Paket Gereksinimleri { #package-requirements }
|
||||
|
||||
Uygulamanızın **paket gereksinimleri** genelde bir dosyada yer alır.
|
||||
|
||||
Bu, gereksinimleri **yüklemek** için kullandığınız araca göre değişir.
|
||||
|
||||
En yaygın yöntem, paket adları ve versiyonlarının satır satır yazıldığı bir `requirements.txt` dosyasına sahip olmaktır.
|
||||
|
||||
Versiyon aralıklarını belirlemek için elbette [FastAPI sürümleri hakkında](versions.md){.internal-link target=_blank} bölümünde okuduğunuz fikirleri kullanırsınız.
|
||||
|
||||
Örneğin `requirements.txt` şöyle görünebilir:
|
||||
|
||||
```
|
||||
fastapi[standard]>=0.113.0,<0.114.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
```
|
||||
|
||||
Ve bu bağımlılıkları normalde `pip` ile yüklersiniz, örneğin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Paket bağımlılıklarını tanımlamak ve yüklemek için başka formatlar ve araçlar da vardır.
|
||||
|
||||
///
|
||||
|
||||
### **FastAPI** Kodunu Oluşturun { #create-the-fastapi-code }
|
||||
|
||||
* Bir `app` dizini oluşturun ve içine girin.
|
||||
* Boş bir `__init__.py` dosyası oluşturun.
|
||||
* Aşağıdakilerle bir `main.py` dosyası oluşturun:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile { #dockerfile }
|
||||
|
||||
Şimdi aynı proje dizininde `Dockerfile` adlı bir dosya oluşturun ve içine şunları yazın:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)!
|
||||
FROM python:3.14
|
||||
|
||||
# (2)!
|
||||
WORKDIR /code
|
||||
|
||||
# (3)!
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
# (4)!
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (5)!
|
||||
COPY ./app /code/app
|
||||
|
||||
# (6)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Resmi Python base image'ından başlayın.
|
||||
|
||||
2. Geçerli çalışma dizinini `/code` olarak ayarlayın.
|
||||
|
||||
`requirements.txt` dosyasını ve `app` dizinini buraya koyacağız.
|
||||
|
||||
3. Gereksinimleri içeren dosyayı `/code` dizinine kopyalayın.
|
||||
|
||||
Önce kodun tamamını değil, **sadece** gereksinim dosyasını kopyalayın.
|
||||
|
||||
Bu dosya **çok sık değişmediği** için Docker bunu tespit eder ve bu adımda **cache** kullanır; böylece bir sonraki adım için de cache devreye girer.
|
||||
|
||||
4. Gereksinim dosyasındaki paket bağımlılıklarını yükleyin.
|
||||
|
||||
`--no-cache-dir` seçeneği, indirilen paketlerin yerel olarak kaydedilmemesini `pip`'e söyler. Bu kayıt, `pip` aynı paketleri tekrar yüklemek için yeniden çalıştırılacaksa işe yarar; ancak container'larla çalışırken genelde bu durum geçerli değildir.
|
||||
|
||||
/// note | Not
|
||||
|
||||
`--no-cache-dir` yalnızca `pip` ile ilgilidir; Docker veya container'larla ilgili değildir.
|
||||
|
||||
///
|
||||
|
||||
`--upgrade` seçeneği, paketler zaten yüklüyse `pip`'e onları yükseltmesini söyler.
|
||||
|
||||
Bir önceki adım (dosyayı kopyalama) **Docker cache** tarafından tespit edilebildiği için, bu adım da uygun olduğunda **Docker cache'i kullanır**.
|
||||
|
||||
Bu adımda cache kullanmak, geliştirme sırasında image'ı tekrar tekrar build ederken size çok **zaman** kazandırır; her seferinde bağımlılıkları **indirip yüklemek** zorunda kalmazsınız.
|
||||
|
||||
5. `./app` dizinini `/code` dizininin içine kopyalayın.
|
||||
|
||||
Burada en sık değişen şey olan kodun tamamı bulunduğundan, bu adım (ve genelde bundan sonraki adımlar) için Docker **cache**'i kolay kolay kullanılamaz.
|
||||
|
||||
Bu yüzden, container image build sürelerini optimize etmek için bunu `Dockerfile`'ın **sonlarına yakın** koymak önemlidir.
|
||||
|
||||
6. Altta Uvicorn kullanan `fastapi run` komutunu **command** olarak ayarlayın.
|
||||
|
||||
`CMD` bir string listesi alır; bu string'lerin her biri komut satırında boşlukla ayrılmış şekilde yazacağınız parçaları temsil eder.
|
||||
|
||||
Bu komut, yukarıda `WORKDIR /code` ile ayarladığınız `/code` dizininden çalıştırılır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Kod içindeki her numara balonuna tıklayarak her satırın ne yaptığını gözden geçirin. 👆
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Aşağıda açıklandığı gibi `CMD` talimatının **her zaman** **exec form**'unu kullandığınızdan emin olun.
|
||||
|
||||
///
|
||||
|
||||
#### `CMD` Kullanımı - Exec Form { #use-cmd-exec-form }
|
||||
|
||||
<a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> Docker talimatı iki formda yazılabilir:
|
||||
|
||||
✅ **Exec** form:
|
||||
|
||||
```Dockerfile
|
||||
# ✅ Do this
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ **Shell** form:
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ Don't do this
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
FastAPI'nin düzgün şekilde kapanabilmesi ve [lifespan event](../advanced/events.md){.internal-link target=_blank}'lerinin tetiklenmesi için her zaman **exec** formunu kullanın.
|
||||
|
||||
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">Hizmetlerimin yeniden oluşturulması veya durması neden 10 saniye sürüyor?</a>.
|
||||
|
||||
#### Dizin Yapısı { #directory-structure }
|
||||
|
||||
Artık dizin yapınız şöyle olmalı:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
├── Dockerfile
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
#### TLS Termination Proxy Arkasında { #behind-a-tls-termination-proxy }
|
||||
|
||||
Container'ınızı Nginx veya Traefik gibi bir TLS Termination Proxy (load balancer) arkasında çalıştırıyorsanız `--proxy-headers` seçeneğini ekleyin. Bu, Uvicorn'a (FastAPI CLI üzerinden) uygulamanın HTTPS arkasında çalıştığını söyleyen proxy header'larına güvenmesini söyler.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
```
|
||||
|
||||
#### Docker Cache { #docker-cache }
|
||||
|
||||
Bu `Dockerfile` içinde önemli bir numara var: önce kodun geri kalanını değil, **sadece bağımlılık dosyasını** kopyalıyoruz. Nedenini anlatayım.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
```
|
||||
|
||||
Docker ve benzeri araçlar bu container image'larını **artımlı (incremental)** olarak **build** eder; `Dockerfile`'ın en üstünden başlayıp her talimatın oluşturduğu dosyaları ekleyerek **katman katman (layer)** ilerler.
|
||||
|
||||
Docker ve benzeri araçlar image build ederken ayrıca bir **internal cache** kullanır. Son build'den beri bir dosya değişmediyse, dosyayı tekrar kopyalayıp sıfırdan yeni bir layer oluşturmak yerine, daha önce oluşturulan **aynı layer**'ı yeniden kullanır.
|
||||
|
||||
Sadece dosya kopyalamayı azaltmak her zaman büyük fark yaratmaz. Ancak o adımda cache kullanıldığı için, **bir sonraki adımda da cache kullanılabilir**. Örneğin bağımlılıkları yükleyen şu talimat için:
|
||||
|
||||
```Dockerfile
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
```
|
||||
|
||||
Paket gereksinimleri dosyası **sık sık değişmez**. Bu yüzden sadece bu dosyayı kopyalayınca, Docker bu adımda **cache** kullanabilir.
|
||||
|
||||
Sonra Docker, bağımlılıkları indirip yükleyen **bir sonraki adımda** da cache kullanabilir. Asıl **çok zaman kazandığımız** yer de burasıdır. ✨ ...ve beklerken sıkılmayı engeller. 😪😆
|
||||
|
||||
Bağımlılıkları indirip yüklemek **dakikalar sürebilir**, fakat **cache** kullanmak en fazla **saniyeler** alır.
|
||||
|
||||
Geliştirme sırasında kod değişikliklerinizin çalıştığını kontrol etmek için container image'ı tekrar tekrar build edeceğinizden, bu ciddi birikimli zaman kazancı sağlar.
|
||||
|
||||
Sonra `Dockerfile`'ın sonlarına doğru tüm kodu kopyalarız. En sık değişen kısım bu olduğu için sona koyarız; çünkü neredeyse her zaman bu adımdan sonra gelen adımlar cache kullanamaz.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Docker Image'ını Build Edin { #build-the-docker-image }
|
||||
|
||||
Tüm dosyalar hazır olduğuna göre container image'ı build edelim.
|
||||
|
||||
* Proje dizinine gidin (`Dockerfile`'ınızın olduğu ve `app` dizininizi içeren dizin).
|
||||
* FastAPI image'ınızı build edin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Sondaki `.` ifadesine dikkat edin; `./` ile aynı anlama gelir ve Docker'a container image build etmek için hangi dizini kullanacağını söyler.
|
||||
|
||||
Bu örnekte, mevcut dizindir (`.`).
|
||||
|
||||
///
|
||||
|
||||
### Docker Container'ını Başlatın { #start-the-docker-container }
|
||||
|
||||
* Image'ınızdan bir container çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Kontrol Edin { #check-it }
|
||||
|
||||
Docker container'ınızın URL'inden kontrol edebilmelisiniz. Örneğin: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> veya <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ya da Docker host'unuzu kullanarak eşdeğeri).
|
||||
|
||||
Şuna benzer bir şey görürsünüz:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Etkileşimli API Dokümanları { #interactive-api-docs }
|
||||
|
||||
Şimdi <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> veya <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> adresine gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).
|
||||
|
||||
Otomatik etkileşimli API dokümantasyonunu görürsünüz ( <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanır):
|
||||
|
||||

|
||||
|
||||
## Alternatif API Dokümanları { #alternative-api-docs }
|
||||
|
||||
Ayrıca <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> veya <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> adresine de gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).
|
||||
|
||||
Alternatif otomatik dokümantasyonu görürsünüz (<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanır):
|
||||
|
||||

|
||||
|
||||
## Tek Dosyalık FastAPI ile Docker Image Oluşturma { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
|
||||
FastAPI uygulamanız tek bir dosyaysa; örneğin `./app` dizini olmadan sadece `main.py` varsa, dosya yapınız şöyle olabilir:
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
├── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
Bu durumda `Dockerfile` içinde dosyayı kopyaladığınız path'leri buna göre değiştirmeniz yeterlidir:
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (1)!
|
||||
COPY ./main.py /code/
|
||||
|
||||
# (2)!
|
||||
CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. `main.py` dosyasını doğrudan `/code` dizinine kopyalayın (herhangi bir `./app` dizini olmadan).
|
||||
|
||||
2. Tek dosya olan `main.py` içindeki uygulamanızı sunmak için `fastapi run` kullanın.
|
||||
|
||||
Dosyayı `fastapi run`'a verdiğinizde, bunun bir package'ın parçası değil tek bir dosya olduğunu otomatik olarak algılar; nasıl import edip FastAPI uygulamanızı nasıl serve edeceğini bilir. 😎
|
||||
|
||||
## Deployment Kavramları { #deployment-concepts }
|
||||
|
||||
Aynı [Deployment Kavramları](concepts.md){.internal-link target=_blank}nı bu kez container'lar açısından tekrar konuşalım.
|
||||
|
||||
Container'lar, bir uygulamayı **build etme ve deploy etme** sürecini basitleştiren bir araçtır. Ancak bu **deployment kavramları**nı ele almak için belirli bir yaklaşımı zorunlu kılmazlar; birkaç farklı strateji mümkündür.
|
||||
|
||||
**İyi haber** şu: Hangi stratejiyi seçerseniz seçin, deployment kavramlarının tamamını kapsayacak bir yol vardır. 🎉
|
||||
|
||||
Bu **deployment kavramları**nı container'lar açısından gözden geçirelim:
|
||||
|
||||
* HTTPS
|
||||
* Startup'ta çalıştırma
|
||||
* Restart'lar
|
||||
* Replication (çalışan process sayısı)
|
||||
* Memory
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
## HTTPS { #https }
|
||||
|
||||
Bir FastAPI uygulamasının sadece **container image**'ına (ve sonra çalışan **container**'a) odaklanırsak, HTTPS genellikle **haricen** başka bir araçla ele alınır.
|
||||
|
||||
Örneğin <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> kullanan başka bir container olabilir; **HTTPS** ve **sertifika**ların **otomatik** alınmasını o yönetebilir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Traefik; Docker, Kubernetes ve diğerleriyle entegre çalışır. Bu sayede container'larınız için HTTPS'i kurup yapılandırmak oldukça kolaydır.
|
||||
|
||||
///
|
||||
|
||||
Alternatif olarak HTTPS, bir cloud provider'ın sunduğu servislerden biri tarafından da yönetilebilir (uygulama yine container içinde çalışırken).
|
||||
|
||||
## Startup'ta Çalıştırma ve Restart'lar { #running-on-startup-and-restarts }
|
||||
|
||||
Container'ınızı **başlatıp çalıştırmaktan** sorumlu genellikle başka bir araç olur.
|
||||
|
||||
Bu; doğrudan **Docker**, **Docker Compose**, **Kubernetes**, bir **cloud service** vb. olabilir.
|
||||
|
||||
Çoğu (veya tüm) durumda, container'ı startup'ta çalıştırmayı ve hata durumlarında restart'ları etkinleştirmeyi sağlayan basit bir seçenek vardır. Örneğin Docker'da bu, `--restart` komut satırı seçeneğidir.
|
||||
|
||||
Container kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekanizması eklemek zahmetli ve zor olabilir. Ancak **container'larla çalışırken** çoğu zaman bu işlevler varsayılan olarak hazır gelir. ✨
|
||||
|
||||
## Replication - Process Sayısı { #replication-number-of-processes }
|
||||
|
||||
Eğer bir <dfn title="Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makineler grubu.">küme</dfn> (cluster) olarak yapılandırılmış makineler grubunuz varsa ve bunları **Kubernetes**, Docker Swarm Mode, Nomad veya benzeri, birden çok makinede dağıtık container'ları yöneten karmaşık bir sistemle yönetiyorsanız, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **küme seviyesinde (cluster level)** 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**.
|
||||
|
||||
Bu tür durumlarda, yukarıda [anlatıldığı gibi](#dockerfile) bağımlılıkları yükleyip **sıfırdan bir Docker image** build etmek ve birden fazla Uvicorn worker kullanmak yerine **tek bir Uvicorn process** çalıştırmak istersiniz.
|
||||
|
||||
### Load Balancer { #load-balancer }
|
||||
|
||||
Container'lar kullanırken, genellikle ana port'ta dinleyen bir bileşen olur. Bu, **HTTPS**'i ele almak için bir **TLS Termination Proxy** olan başka bir container da olabilir ya da benzeri bir araç olabilir.
|
||||
|
||||
Bu bileşen request'lerin **yükünü** alıp worker'lar arasında (umarım) **dengeli** şekilde dağıttığı için yaygın olarak **Load Balancer** diye de adlandırılır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
HTTPS için kullanılan aynı **TLS Termination Proxy** bileşeni muhtemelen bir **Load Balancer** olarak da çalışır.
|
||||
|
||||
///
|
||||
|
||||
Container'larla çalışırken, onları başlatıp yönettiğiniz sistem; bu **load balancer**'dan (aynı zamanda **TLS Termination Proxy** de olabilir) uygulamanızın bulunduğu container(lar)a **network communication**'ı (ör. HTTP request'leri) iletmek için zaten dahili araçlar sunar.
|
||||
|
||||
### Tek Load Balancer - Çoklu Worker Container { #one-load-balancer-multiple-worker-containers }
|
||||
|
||||
**Kubernetes** veya benzeri dağıtık container yönetim sistemleriyle çalışırken, dahili ağ mekanizmaları sayesinde ana **port**'u dinleyen tek bir **load balancer**, uygulamanızı çalıştıran muhtemelen **birden fazla container**'a request'leri iletebilir.
|
||||
|
||||
Uygulamanızı çalıştıran bu container'ların her birinde normalde **tek bir process** olur (ör. FastAPI uygulamanızı çalıştıran bir Uvicorn process). Hepsi aynı şeyi çalıştıran **özdeş container**'lardır; ancak her birinin kendi process'i, memory'si vb. vardır. Böylece CPU'nun **farklı core**'larında, hatta **farklı makinelerde** paralelleştirmeden yararlanırsınız.
|
||||
|
||||
Load balancer'lı dağıtık sistem, request'leri uygulamanızın bulunduğu container'ların her birine sırayla **dağıtır**. Böylece her request, uygulamanızın birden fazla **replicated container**'ından biri tarafından işlenebilir.
|
||||
|
||||
Ve bu **load balancer** normalde cluster'ınızdaki *diğer* uygulamalara giden request'leri de (ör. farklı bir domain ya da farklı bir URL path prefix altında) yönetebilir ve iletişimi o *diğer* uygulamanın doğru container'larına iletir.
|
||||
|
||||
### Container Başına Tek Process { #one-process-per-container }
|
||||
|
||||
Bu senaryoda, replication'ı zaten cluster seviyesinde yaptığınız için, muhtemelen **container başına tek bir (Uvicorn) process** istersiniz.
|
||||
|
||||
Dolayısıyla bu durumda container içinde `--workers` gibi bir komut satırı seçeneğiyle çoklu worker istemezsiniz. Container başına sadece **tek bir Uvicorn process** istersiniz (ama muhtemelen birden fazla container).
|
||||
|
||||
Container içine ekstra bir process manager koymak (çoklu worker gibi) çoğu zaman zaten cluster sisteminizle çözdüğünüz şeye ek **gereksiz karmaşıklık** katar.
|
||||
|
||||
### Birden Fazla Process'li Container'lar ve Özel Durumlar { #containers-with-multiple-processes-and-special-cases }
|
||||
|
||||
Elbette bazı **özel durumlarda** bir container içinde birden fazla **Uvicorn worker process** çalıştırmak isteyebilirsiniz.
|
||||
|
||||
Bu durumlarda çalıştırmak istediğiniz worker sayısını `--workers` komut satırı seçeneğiyle ayarlayabilirsiniz:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
# (1)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
```
|
||||
|
||||
1. Burada worker sayısını 4 yapmak için `--workers` komut satırı seçeneğini kullanıyoruz.
|
||||
|
||||
Bunun mantıklı olabileceği birkaç örnek:
|
||||
|
||||
#### Basit Bir Uygulama { #a-simple-app }
|
||||
|
||||
Uygulamanız tek bir server üzerinde (cluster değil) çalışacak kadar **basitse**, container içinde bir process manager isteyebilirsiniz.
|
||||
|
||||
#### Docker Compose { #docker-compose }
|
||||
|
||||
**Docker Compose** ile **tek bir server**'a (cluster değil) deploy ediyor olabilirsiniz. Bu durumda, paylaşılan ağı ve **load balancing**'i koruyarak container replication'ını (Docker Compose ile) yönetmenin kolay bir yolu olmayabilir.
|
||||
|
||||
Bu durumda, tek bir container içinde **bir process manager** ile **birden fazla worker process** başlatmak isteyebilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
Ana fikir şu: Bunların **hiçbiri** körü körüne uymanız gereken **değişmez kurallar** değildir. Bu fikirleri, kendi kullanım senaryonuzu **değerlendirmek** ve sisteminiz için en iyi yaklaşımı seçmek için kullanabilirsiniz. Şu kavramları nasıl yöneteceğinize bakarak karar verin:
|
||||
|
||||
* Güvenlik - HTTPS
|
||||
* Startup'ta çalıştırma
|
||||
* Restart'lar
|
||||
* Replication (çalışan process sayısı)
|
||||
* Memory
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
## Memory { #memory }
|
||||
|
||||
**Container başına tek process** çalıştırırsanız, her container'ın tüketeceği memory miktarı aşağı yukarı tanımlı, stabil ve sınırlı olur (replication varsa birden fazla container için).
|
||||
|
||||
Sonra aynı memory limit ve gereksinimlerini container yönetim sisteminizin (ör. **Kubernetes**) konfigürasyonlarında belirleyebilirsiniz. Böylece sistem; ihtiyaç duyulan memory miktarını ve cluster'daki makinelerde mevcut memory'yi dikkate alarak **uygun makinelerde container'ları replicate edebilir**.
|
||||
|
||||
Uygulamanız **basitse**, muhtemelen bu **bir sorun olmaz** ve katı memory limitleri belirlemeniz gerekmeyebilir. Ancak **çok memory kullanıyorsanız** (ör. **machine learning** modelleriyle), ne kadar memory tükettiğinizi kontrol edip **her makinede** çalışacak **container sayısını** ayarlamalısınız (ve gerekirse cluster'a daha fazla makine eklemelisiniz).
|
||||
|
||||
**Container başına birden fazla process** çalıştırırsanız, başlatılan process sayısının mevcut olandan **fazla memory tüketmediğinden** emin olmanız gerekir.
|
||||
|
||||
## Başlatmadan Önceki Adımlar ve Container'lar { #previous-steps-before-starting-and-containers }
|
||||
|
||||
Container kullanıyorsanız (örn. Docker, Kubernetes), temelde iki yaklaşım vardır.
|
||||
|
||||
### Birden Fazla Container { #multiple-containers }
|
||||
|
||||
**Birden fazla container**'ınız varsa ve muhtemelen her biri **tek process** çalıştırıyorsa (ör. bir **Kubernetes** cluster'ında), replication yapılan worker container'lar çalışmadan **önce**, **başlatmadan önceki adımlar**ın işini yapan **ayrı bir container** kullanmak isteyebilirsiniz (tek container, tek process).
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Kubernetes kullanıyorsanız, bu muhtemelen bir <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a> olur.
|
||||
|
||||
///
|
||||
|
||||
Kullanım senaryonuzda bu adımları **paralel olarak birden fazla kez** çalıştırmak sorun değilse (örneğin veritabanı migration çalıştırmıyor, sadece veritabanı hazır mı diye kontrol ediyorsanız), o zaman her container'da ana process başlamadan hemen önce de çalıştırabilirsiniz.
|
||||
|
||||
### Tek Container { #single-container }
|
||||
|
||||
Basit bir kurulumda; **tek bir container** olup onun içinde birden fazla **worker process** (ya da sadece bir process) başlatıyorsanız, bu adımları aynı container içinde, uygulama process'ini başlatmadan hemen önce çalıştırabilirsiniz.
|
||||
|
||||
### Base Docker Image { #base-docker-image }
|
||||
|
||||
Eskiden resmi bir FastAPI Docker image'ı vardı: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Ancak artık kullanımdan kaldırıldı (deprecated). ⛔️
|
||||
|
||||
Muhtemelen bu base Docker image'ını (veya benzeri başka bir image'ı) kullanmamalısınız.
|
||||
|
||||
**Kubernetes** (veya diğerleri) kullanıyor ve cluster seviyesinde birden fazla **container** ile **replication** ayarlıyorsanız, bu durumda yukarıda anlatıldığı gibi **sıfırdan bir image build etmek** daha iyi olur: [FastAPI için Docker Image Oluşturalım](#build-a-docker-image-for-fastapi).
|
||||
|
||||
Ve birden fazla worker gerekiyorsa, sadece `--workers` komut satırı seçeneğini kullanabilirsiniz.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Bu Docker image, Uvicorn dead worker'ları yönetmeyi ve yeniden başlatmayı desteklemediği dönemde oluşturulmuştu. Bu yüzden Uvicorn ile birlikte Gunicorn kullanmak gerekiyordu; sırf Gunicorn, Uvicorn worker process'lerini yönetip yeniden başlatsın diye oldukça fazla karmaşıklık ekleniyordu.
|
||||
|
||||
Ancak artık Uvicorn (ve `fastapi` komutu) `--workers` kullanımını desteklediğine göre, kendi image'ınızı build etmek yerine bir base Docker image kullanmanın bir nedeni kalmadı (kod miktarı da hemen hemen aynı 😅).
|
||||
|
||||
///
|
||||
|
||||
## Container Image'ı Deploy Etme { #deploy-the-container-image }
|
||||
|
||||
Bir Container (Docker) Image'ınız olduktan sonra bunu deploy etmenin birkaç yolu vardır.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* Tek bir server'da **Docker Compose** ile
|
||||
* Bir **Kubernetes** cluster'ı ile
|
||||
* Docker Swarm Mode cluster'ı ile
|
||||
* Nomad gibi başka bir araçla
|
||||
* Container image'ınızı alıp deploy eden bir cloud servisiyle
|
||||
|
||||
## `uv` ile Docker Image { #docker-image-with-uv }
|
||||
|
||||
Projenizi yüklemek ve yönetmek için <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> kullanıyorsanız, onların <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">uv Docker rehberini</a> takip edebilirsiniz.
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Container sistemleri (örn. **Docker** ve **Kubernetes** ile) kullanınca tüm **deployment kavramları**nı ele almak oldukça kolaylaşır:
|
||||
|
||||
* HTTPS
|
||||
* Startup'ta çalıştırma
|
||||
* Restart'lar
|
||||
* Replication (çalışan process sayısı)
|
||||
* Memory
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
Çoğu durumda bir base image kullanmak istemezsiniz; bunun yerine resmi Python Docker image'ını temel alarak **sıfırdan bir container image** build edersiniz.
|
||||
|
||||
`Dockerfile` içindeki talimatların **sırasına** ve **Docker cache**'ine dikkat ederek **build sürelerini minimize edebilir**, üretkenliğinizi artırabilirsiniz (ve beklerken sıkılmayı önlersiniz). 😎
|
||||
@@ -0,0 +1,65 @@
|
||||
# FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
FastAPI uygulamanızı <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>'a **tek bir komutla** deploy edebilirsiniz. Henüz yapmadıysanız gidip bekleme listesine katılın. 🚀
|
||||
|
||||
## Giriş Yapma { #login }
|
||||
|
||||
Önceden bir **FastAPI Cloud** hesabınız olduğundan emin olun (sizi bekleme listesinden davet ettik 😉).
|
||||
|
||||
Ardından giriş yapın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Deploy { #deploy }
|
||||
|
||||
Şimdi uygulamanızı **tek bir komutla** deploy edin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hepsi bu! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨
|
||||
|
||||
## FastAPI Cloud Hakkında { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**, **FastAPI**'nin arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.
|
||||
|
||||
Bir API'yi minimum eforla **geliştirme**, **deploy etme** ve **erişilebilir kılma** sürecini sadeleştirir.
|
||||
|
||||
FastAPI ile uygulama geliştirirken elde ettiğiniz aynı **developer experience**'ı, onları buluta **deploy etmeye** de taşır. 🎉
|
||||
|
||||
Ayrıca bir uygulamayı deploy ederken ihtiyaç duyacağınız pek çok şeyi de sizin için halleder; örneğin:
|
||||
|
||||
* HTTPS
|
||||
* Replication (çoğaltma), request'lere göre autoscaling ile
|
||||
* vb.
|
||||
|
||||
FastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨
|
||||
|
||||
## Diğer cloud sağlayıcılarına deploy etme { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI açık kaynaklıdır ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.
|
||||
|
||||
FastAPI uygulamalarını deploy etmek için cloud sağlayıcınızın kendi kılavuzlarını takip edin. 🤓
|
||||
|
||||
## Kendi server'ınıza deploy etme { #deploy-your-own-server }
|
||||
|
||||
Bu **Deployment** kılavuzunun ilerleyen bölümlerinde tüm detayları da ele alacağız; böylece neler olduğunu, nelerin gerçekleşmesi gerektiğini ve FastAPI uygulamalarını kendi başınıza (kendi server'larınızla da) nasıl deploy edebileceğinizi anlayacaksınız. 🤓
|
||||
@@ -0,0 +1,231 @@
|
||||
# HTTPS Hakkında { #about-https }
|
||||
|
||||
HTTPS’in sadece "açık" ya da "kapalı" olan bir şey olduğunu düşünmek kolaydır.
|
||||
|
||||
Ancak bundan çok daha karmaşıktır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Aceleniz varsa veya çok da önemsemiyorsanız, her şeyi farklı tekniklerle adım adım kurmak için sonraki bölümlere geçin.
|
||||
|
||||
///
|
||||
|
||||
Bir kullanıcı gözüyle **HTTPS’in temellerini öğrenmek** için <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a> adresine bakın.
|
||||
|
||||
Şimdi de **geliştirici perspektifinden**, HTTPS hakkında düşünürken akılda tutulması gereken birkaç nokta:
|
||||
|
||||
* HTTPS için **server**’ın, **üçüncü bir taraf** tarafından verilen **"sertifikalara"** sahip olması gerekir.
|
||||
* Bu sertifikalar aslında üçüncü tarafça "üretilmez", üçüncü taraftan **temin edilir**.
|
||||
* Sertifikaların bir **geçerlilik süresi** vardır.
|
||||
* Süresi **dolar**.
|
||||
* Sonrasında **yenilenmeleri**, üçüncü taraftan **yeniden temin edilmeleri** gerekir.
|
||||
* Bağlantının şifrelenmesi **TCP seviyesinde** gerçekleşir.
|
||||
* Bu, **HTTP’nin bir katman altıdır**.
|
||||
* Dolayısıyla **sertifika ve şifreleme** işlemleri **HTTP’den önce** yapılır.
|
||||
* **TCP "domain"leri bilmez**. Yalnızca IP adreslerini bilir.
|
||||
* İstenen **spesifik domain** bilgisi **HTTP verisinin** içindedir.
|
||||
* **HTTPS sertifikaları** belirli bir **domain**’i "sertifikalandırır"; ancak protokol ve şifreleme TCP seviyesinde, hangi domain ile çalışıldığı **henüz bilinmeden** gerçekleşir.
|
||||
* **Varsayılan olarak** bu, IP adresi başına yalnızca **bir HTTPS sertifikası** olabileceği anlamına gelir.
|
||||
* Server’ınız ne kadar büyük olursa olsun ya da üzerindeki her uygulama ne kadar küçük olursa olsun.
|
||||
* Ancak bunun bir **çözümü** vardır.
|
||||
* **TLS** protokolüne (TCP seviyesinde, HTTP’den önce şifrelemeyi yapan) eklenen **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication - Sunucu Adı Belirtimi">SNI</abbr></a>** adlı bir **extension** vardır.
|
||||
* Bu SNI extension’ı, tek bir server’ın (tek bir **IP adresiyle**) **birden fazla HTTPS sertifikası** kullanmasına ve **birden fazla HTTPS domain/uygulama** sunmasına izin verir.
|
||||
* Bunun çalışması için server üzerinde, **public IP adresini** dinleyen tek bir bileşenin (programın) server’daki **tüm HTTPS sertifikalarına** sahip olması gerekir.
|
||||
* Güvenli bir bağlantı elde edildikten **sonra**, iletişim protokolü **hâlâ HTTP**’dir.
|
||||
* İçerikler, **HTTP protokolü** ile gönderiliyor olsa bile **şifrelenmiştir**.
|
||||
|
||||
Yaygın yaklaşım, server’da (makine, host vb.) çalışan **tek bir program/HTTP server** bulundurup **HTTPS ile ilgili tüm kısımları** yönetmektir: **şifreli HTTPS request**’leri almak, aynı server’da çalışan gerçek HTTP uygulamasına (bu örnekte **FastAPI** uygulaması) **şifresi çözülmüş HTTP request**’leri iletmek, uygulamadan gelen **HTTP response**’u almak, uygun **HTTPS sertifikası** ile **şifrelemek** ve **HTTPS** ile client’a geri göndermek. Bu server’a çoğu zaman **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>** denir.
|
||||
|
||||
TLS Termination Proxy olarak kullanabileceğiniz seçeneklerden bazıları:
|
||||
|
||||
* Traefik (sertifika yenilemelerini de yönetebilir)
|
||||
* Caddy (sertifika yenilemelerini de yönetebilir)
|
||||
* Nginx
|
||||
* HAProxy
|
||||
|
||||
## Let's Encrypt { #lets-encrypt }
|
||||
|
||||
Let's Encrypt’ten önce bu **HTTPS sertifikaları**, güvenilen üçüncü taraflar tarafından satılırdı.
|
||||
|
||||
Bu sertifikalardan birini temin etme süreci zahmetliydi, epey evrak işi gerektirirdi ve sertifikalar oldukça pahalıydı.
|
||||
|
||||
Sonra **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>** ortaya çıktı.
|
||||
|
||||
Linux Foundation’ın bir projesidir. **HTTPS sertifikalarını ücretsiz** ve otomatik bir şekilde sağlar. Bu sertifikalar tüm standart kriptografik güvenliği kullanır ve kısa ömürlüdür (yaklaşık 3 ay). Bu yüzden, ömürleri kısa olduğu için **güvenlik aslında daha iyidir**.
|
||||
|
||||
Domain’ler güvenli şekilde doğrulanır ve sertifikalar otomatik üretilir. Bu sayede sertifikaların yenilenmesini otomatikleştirmek de mümkün olur.
|
||||
|
||||
Amaç, bu sertifikaların temin edilmesi ve yenilenmesini otomatikleştirerek **ücretsiz, kalıcı olarak güvenli HTTPS** sağlamaktır.
|
||||
|
||||
## Geliştiriciler İçin HTTPS { #https-for-developers }
|
||||
|
||||
Burada, bir HTTPS API’nin adım adım nasıl görünebileceğine dair, özellikle geliştiriciler için önemli fikirlere odaklanan bir örnek var.
|
||||
|
||||
### Domain Adı { #domain-name }
|
||||
|
||||
Muhtemelen her şey, bir **domain adı** **temin etmenizle** başlar. Sonra bunu bir DNS server’ında (muhtemelen aynı cloud provider’ınızda) yapılandırırsınız.
|
||||
|
||||
Muhtemelen bir cloud server (virtual machine) ya da benzeri bir şey alırsınız ve bunun <dfn title="Zamanla değişmeyen. Dinamik olmayan.">sabit</dfn> bir **public IP adresi** olur.
|
||||
|
||||
DNS server(lar)ında, bir kaydı ("`A record`") **domain**’inizi server’ınızın **public IP adresine** yönlendirecek şekilde yapılandırırsınız.
|
||||
|
||||
Bunu büyük olasılıkla ilk kurulumda, sadece bir kez yaparsınız.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu Domain Adı kısmı HTTPS’ten çok daha önce gelir. Ancak her şey domain ve IP adresine bağlı olduğu için burada bahsetmeye değer.
|
||||
|
||||
///
|
||||
|
||||
### DNS { #dns }
|
||||
|
||||
Şimdi gerçek HTTPS parçalarına odaklanalım.
|
||||
|
||||
Önce tarayıcı, bu örnekte `someapp.example.com` olan domain için **IP**’nin ne olduğunu **DNS server**’larına sorar.
|
||||
|
||||
DNS server’ları tarayıcıya belirli bir **IP adresini** kullanmasını söyler. Bu, DNS server’larında yapılandırdığınız ve server’ınızın kullandığı public IP adresidir.
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### TLS Handshake Başlangıcı { #tls-handshake-start }
|
||||
|
||||
Tarayıcı daha sonra bu IP adresiyle **443 portu** (HTTPS portu) üzerinden iletişim kurar.
|
||||
|
||||
İletişimin ilk kısmı, client ile server arasında bağlantıyı kurmak ve hangi kriptografik anahtarların kullanılacağına karar vermek vb. içindir.
|
||||
|
||||
<img src="/img/deployment/https/https02.drawio.svg">
|
||||
|
||||
Client ile server arasındaki, TLS bağlantısını kurmaya yönelik bu etkileşime **TLS handshake** denir.
|
||||
|
||||
### SNI Extension’ı ile TLS { #tls-with-sni-extension }
|
||||
|
||||
Server’da, belirli bir **IP adresindeki** belirli bir **portu** dinleyen **yalnızca bir process** olabilir. Aynı IP adresinde başka portları dinleyen başka process’ler olabilir, ancak IP+port kombinasyonu başına yalnızca bir tane olur.
|
||||
|
||||
TLS (HTTPS) varsayılan olarak `443` portunu kullanır. Yani ihtiyaç duyacağımız port budur.
|
||||
|
||||
Bu portu yalnızca bir process dinleyebileceği için, bunu yapacak process **TLS Termination Proxy** olur.
|
||||
|
||||
TLS Termination Proxy, bir ya da daha fazla **TLS sertifikasına** (HTTPS sertifikası) erişebilir.
|
||||
|
||||
Yukarıda bahsettiğimiz **SNI extension**’ını kullanarak TLS Termination Proxy, bu bağlantı için elindeki TLS (HTTPS) sertifikalarından hangisini kullanacağını kontrol eder; client’ın beklediği domain ile eşleşen sertifikayı seçer.
|
||||
|
||||
Bu örnekte `someapp.example.com` sertifikasını kullanır.
|
||||
|
||||
<img src="/img/deployment/https/https03.drawio.svg">
|
||||
|
||||
Client, bu TLS sertifikasını üreten kuruluşa zaten **güvenir** (bu örnekte Let's Encrypt; birazdan ona da geleceğiz). Bu sayede sertifikanın geçerli olduğunu **doğrulayabilir**.
|
||||
|
||||
Ardından client ve TLS Termination Proxy, sertifikayı kullanarak **TCP iletişiminin geri kalanını nasıl şifreleyeceklerine** karar verir. Böylece **TLS Handshake** kısmı tamamlanır.
|
||||
|
||||
Bundan sonra client ve server arasında **şifreli bir TCP bağlantısı** vardır; TLS’in sağladığı şey budur. Sonra bu bağlantıyı kullanarak gerçek **HTTP iletişimini** başlatabilirler.
|
||||
|
||||
Ve **HTTPS** de tam olarak budur: şifrelenmemiş bir TCP bağlantısı yerine, **güvenli bir TLS bağlantısının içinde** düz **HTTP**’dir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Şifrelemenin HTTP seviyesinde değil, **TCP seviyesinde** gerçekleştiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
### HTTPS Request { #https-request }
|
||||
|
||||
Artık client ile server (özellikle tarayıcı ile TLS Termination Proxy) arasında **şifreli bir TCP bağlantısı** olduğuna göre, **HTTP iletişimi** başlayabilir.
|
||||
|
||||
Dolayısıyla client bir **HTTPS request** gönderir. Bu, şifreli bir TLS bağlantısı üzerinden giden bir HTTP request’tir.
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### Request’in Şifresini Çözme { #decrypt-the-request }
|
||||
|
||||
TLS Termination Proxy, üzerinde anlaşılan şifrelemeyi kullanarak **request’in şifresini çözer** ve **düz (şifresi çözülmüş) HTTP request**’i uygulamayı çalıştıran process’e iletir (ör. FastAPI uygulamasını çalıştıran Uvicorn process’i).
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### HTTP Response { #http-response }
|
||||
|
||||
Uygulama request’i işler ve TLS Termination Proxy’ye **düz (şifrelenmemiş) bir HTTP response** gönderir.
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### HTTPS Response { #https-response }
|
||||
|
||||
TLS Termination Proxy daha sonra response’u, daha önce üzerinde anlaşılan kriptografi ile (başlangıcı `someapp.example.com` sertifikasına dayanan) **şifreler** ve tarayıcıya geri gönderir.
|
||||
|
||||
Sonrasında tarayıcı response’un geçerli olduğunu ve doğru kriptografik anahtarla şifrelendiğini doğrular vb. Ardından **response’un şifresini çözer** ve işler.
|
||||
|
||||
<img src="/img/deployment/https/https07.drawio.svg">
|
||||
|
||||
Client (tarayıcı), response’un doğru server’dan geldiğini bilir; çünkü daha önce **HTTPS sertifikası** ile üzerinde anlaştıkları kriptografiyi kullanmaktadır.
|
||||
|
||||
### Birden Fazla Uygulama { #multiple-applications }
|
||||
|
||||
Aynı server’da (veya server’larda) örneğin başka API programları ya da bir veritabanı gibi **birden fazla uygulama** olabilir.
|
||||
|
||||
Belirli IP ve port kombinasyonunu yalnızca bir process yönetebilir (örneğimizde TLS Termination Proxy). Ancak diğer uygulamalar/process’ler, aynı **public IP + port kombinasyonunu** kullanmaya çalışmadıkları sürece server(lar)da çalışabilir.
|
||||
|
||||
<img src="/img/deployment/https/https08.drawio.svg">
|
||||
|
||||
Bu şekilde TLS Termination Proxy, birden fazla uygulama için **birden fazla domain**’in HTTPS ve sertifika işlerini yönetebilir ve her durumda request’leri doğru uygulamaya iletebilir.
|
||||
|
||||
### Sertifika Yenileme { #certificate-renewal }
|
||||
|
||||
Gelecekte bir noktada, her sertifikanın süresi **dolar** (temin edildikten yaklaşık 3 ay sonra).
|
||||
|
||||
Ardından başka bir program (bazı durumlarda ayrı bir programdır, bazı durumlarda aynı TLS Termination Proxy olabilir) Let's Encrypt ile konuşup sertifika(ları) yeniler.
|
||||
|
||||
<img src="/img/deployment/https/https.drawio.svg">
|
||||
|
||||
**TLS sertifikaları** bir IP adresiyle değil, **domain adıyla ilişkilidir**.
|
||||
|
||||
Bu yüzden sertifikaları yenilemek için, yenileme programı otoriteye (Let's Encrypt) gerçekten o domain’i **"sahiplendiğini" ve kontrol ettiğini** **kanıtlamalıdır**.
|
||||
|
||||
Bunu yapmak ve farklı uygulama ihtiyaçlarını karşılamak için birden fazla yöntem vardır. Yaygın yöntemlerden bazıları:
|
||||
|
||||
* Bazı **DNS kayıtlarını değiştirmek**.
|
||||
* Bunun için yenileme programının DNS provider API’lerini desteklemesi gerekir. Dolayısıyla kullandığınız DNS provider’a bağlı olarak bu seçenek mümkün de olabilir, olmayabilir de.
|
||||
* Domain ile ilişkili public IP adresinde **server olarak çalışmak** (en azından sertifika temin sürecinde).
|
||||
* Yukarıda söylediğimiz gibi, belirli bir IP ve portu yalnızca bir process dinleyebilir.
|
||||
* Bu, aynı TLS Termination Proxy’nin sertifika yenileme sürecini de yönetmesinin neden çok faydalı olduğunun sebeplerinden biridir.
|
||||
* Aksi halde TLS Termination Proxy’yi kısa süreliğine durdurmanız, sertifikaları temin etmek için yenileme programını başlatmanız, sonra bunları TLS Termination Proxy ile yapılandırmanız ve ardından TLS Termination Proxy’yi tekrar başlatmanız gerekebilir. Bu ideal değildir; çünkü TLS Termination Proxy kapalıyken uygulama(lar)ınıza erişilemez.
|
||||
|
||||
Uygulamayı servis etmeye devam ederken tüm bu yenileme sürecini yönetebilmek, TLS sertifikalarını doğrudan uygulama server’ıyla (örn. Uvicorn) kullanmak yerine, TLS Termination Proxy ile HTTPS’i yönetecek **ayrı bir sistem** istemenizin başlıca nedenlerinden biridir.
|
||||
|
||||
## Proxy Forwarded Headers { #proxy-forwarded-headers }
|
||||
|
||||
HTTPS’i bir proxy ile yönetirken, **application server**’ınız (örneğin FastAPI CLI üzerinden Uvicorn) HTTPS süreci hakkında hiçbir şey bilmez; **TLS Termination Proxy** ile düz HTTP üzerinden iletişim kurar.
|
||||
|
||||
Bu **proxy** normalde request’i **application server**’a iletmeden önce, request’in proxy tarafından **forward** edildiğini application server’a bildirmek için bazı HTTP header’larını anlık olarak ekler.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Proxy header’ları şunlardır:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
Buna rağmen **application server**, güvenilen bir **proxy** arkasında olduğunu bilmediği için varsayılan olarak bu header’lara güvenmez.
|
||||
|
||||
Ancak **application server**’ı, **proxy**’nin gönderdiği *forwarded* header’larına güvenecek şekilde yapılandırabilirsiniz. FastAPI CLI kullanıyorsanız, hangi IP’lerden gelen *forwarded* header’lara güvenmesi gerektiğini söylemek için *CLI Option* `--forwarded-allow-ips` seçeneğini kullanabilirsiniz.
|
||||
|
||||
Örneğin **application server** yalnızca güvenilen **proxy**’den iletişim alıyorsa, yalnızca **proxy**’nin kullandığı IP’den request alacağı için `--forwarded-allow-ips="*"` ayarlayıp gelen tüm IP’lere güvenmesini sağlayabilirsiniz.
|
||||
|
||||
Bu sayede uygulama kendi public URL’inin ne olduğunu, HTTPS kullanıp kullanmadığını, domain’i vb. bilebilir.
|
||||
|
||||
Bu, örneğin redirect’leri doğru şekilde yönetmek için faydalıdır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bununla ilgili daha fazlasını [Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} dokümantasyonunda öğrenebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
**HTTPS** kullanmak çok önemlidir ve çoğu durumda oldukça **kritiktir**. Geliştirici olarak HTTPS etrafında harcadığınız çabanın büyük kısmı, aslında **bu kavramları** ve nasıl çalıştıklarını **anlamaktır**.
|
||||
|
||||
Ancak **geliştiriciler için HTTPS**’in temel bilgilerini öğrendikten sonra, her şeyi basitçe yönetmek için farklı araçları kolayca birleştirip yapılandırabilirsiniz.
|
||||
|
||||
Sonraki bölümlerin bazılarında, **FastAPI** uygulamaları için **HTTPS**’i nasıl kuracağınıza dair birkaç somut örnek göstereceğim. 🔒
|
||||
@@ -1,21 +1,23 @@
|
||||
# Deployment (Yayınlama)
|
||||
# Dağıtım { #deployment }
|
||||
|
||||
**FastAPI** uygulamasını deploy etmek oldukça kolaydır.
|
||||
**FastAPI** uygulamasını deploy etmek nispeten kolaydır.
|
||||
|
||||
## Deployment Ne Anlama Gelir?
|
||||
## Dağıtım Ne Anlama Gelir? { #what-does-deployment-mean }
|
||||
|
||||
Bir uygulamayı **deploy** etmek (yayınlamak), uygulamayı **kullanıcılara erişilebilir hale getirmek** için gerekli adımları gerçekleştirmek anlamına gelir.
|
||||
Bir uygulamayı **deploy** etmek, onu **kullanıcılara erişilebilir hale getirmek** için gerekli adımları gerçekleştirmek anlamına gelir.
|
||||
|
||||
Bir **Web API** için bu süreç normalde uygulamayı **uzak bir makineye** yerleştirmeyi, iyi performans, kararlılık vb. özellikler sağlayan bir **sunucu programı** ile **kullanıcılarınızın** uygulamaya etkili ve kesintisiz bir şekilde **erişebilmesini** kapsar.
|
||||
Bir **web API** için bu süreç normalde uygulamayı **uzak bir makineye** yerleştirmeyi, iyi performans, kararlılık vb. özellikler sağlayan bir **sunucu programı** ile **kullanıcılarınızın** uygulamaya etkili ve kesintisiz bir şekilde, sorun yaşamadan **erişebilmesini** kapsar.
|
||||
|
||||
Bu, kodu sürekli olarak değiştirdiğiniz, hata alıp hata giderdiğiniz, geliştirme sunucusunu durdurup yeniden başlattığınız vb. **geliştirme** aşamalarının tam tersidir.
|
||||
Bu, kodu sürekli olarak değiştirdiğiniz, bozup düzelttiğiniz, geliştirme sunucusunu durdurup yeniden başlattığınız vb. **geliştirme** aşamalarının tam tersidir.
|
||||
|
||||
## Deployment Stratejileri
|
||||
## Dağıtım Stratejileri { #deployment-strategies }
|
||||
|
||||
Kullanım durumunuza ve kullandığınız araçlara bağlı olarak bir kaç farklı yol izleyebilirsiniz.
|
||||
Kullanım durumunuza ve kullandığınız araçlara bağlı olarak bunu yapmanın birkaç yolu vardır.
|
||||
|
||||
Bir dizi araç kombinasyonunu kullanarak kendiniz **bir sunucu yayınlayabilirsiniz**, yayınlama sürecinin bir kısmını sizin için gerçekleştiren bir **bulut hizmeti** veya diğer olası seçenekleri kullanabilirsiniz.
|
||||
Bir dizi araç kombinasyonunu kullanarak kendiniz **bir sunucu deploy edebilirsiniz**, yayınlama sürecinin bir kısmını sizin için gerçekleştiren bir **bulut hizmeti** veya diğer olası seçenekleri kullanabilirsiniz.
|
||||
|
||||
Örneğin, FastAPI'nin arkasındaki ekip olarak, FastAPI uygulamalarını buluta mümkün olduğunca akıcı şekilde deploy etmeyi sağlamak için, FastAPI ile çalışmanın aynı geliştirici deneyimini sunarak <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>'u oluşturduk.
|
||||
|
||||
**FastAPI** uygulamasını yayınlarken aklınızda bulundurmanız gereken ana kavramlardan bazılarını size göstereceğim (ancak bunların çoğu diğer web uygulamaları için de geçerlidir).
|
||||
|
||||
Sonraki bölümlerde akılda tutulması gereken diğer ayrıntıları ve yayınlama tekniklerinden bazılarını göreceksiniz. ✨
|
||||
Sonraki bölümlerde akılda tutulması gereken diğer ayrıntıları ve bunu yapmaya yönelik bazı teknikleri göreceksiniz. ✨
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# Bir Sunucuyu Manuel Olarak Çalıştırın { #run-a-server-manually }
|
||||
|
||||
## `fastapi run` Komutunu Kullanın { #use-the-fastapi-run-command }
|
||||
|
||||
Kısacası, FastAPI uygulamanızı sunmak için `fastapi run` kullanın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Bu, çoğu durumda işinizi görür. 😎
|
||||
|
||||
Örneğin bu komutu, **FastAPI** app'inizi bir container içinde, bir sunucuda vb. başlatmak için kullanabilirsiniz.
|
||||
|
||||
## ASGI Sunucuları { #asgi-servers }
|
||||
|
||||
Şimdi biraz daha detaya inelim.
|
||||
|
||||
FastAPI, Python web framework'leri ve sunucularını inşa etmek için kullanılan <abbr title="Asynchronous Server Gateway Interface - Asenkron Sunucu Ağ Geçidi Arayüzü">ASGI</abbr> adlı bir standardı kullanır. FastAPI bir ASGI web framework'üdür.
|
||||
|
||||
Uzak bir sunucu makinesinde **FastAPI** uygulamasını (veya herhangi bir ASGI uygulamasını) çalıştırmak için gereken ana şey, **Uvicorn** gibi bir ASGI server programıdır. `fastapi` komutuyla varsayılan olarak gelen de budur.
|
||||
|
||||
Buna alternatif birkaç seçenek daha vardır, örneğin:
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>: yüksek performanslı bir ASGI server.
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: diğer özelliklerin yanında HTTP/2 ve Trio ile uyumlu bir ASGI server.
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: Django Channels için geliştirilmiş ASGI server.
|
||||
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a>: Python uygulamaları için bir Rust HTTP server.
|
||||
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a>: NGINX Unit, hafif ve çok yönlü bir web uygulaması runtime'ıdır.
|
||||
|
||||
## Sunucu Makinesi ve Sunucu Programı { #server-machine-and-server-program }
|
||||
|
||||
İsimlendirme konusunda akılda tutulması gereken küçük bir detay var. 💡
|
||||
|
||||
"**server**" kelimesi yaygın olarak hem uzak/bulut bilgisayarı (fiziksel veya sanal makine) hem de o makinede çalışan programı (ör. Uvicorn) ifade etmek için kullanılır.
|
||||
|
||||
Dolayısıyla genel olarak "server" dendiğinde, bu iki şeyden birini kast ediyor olabilir.
|
||||
|
||||
Uzak makineden bahsederken genelde **server** denir; ayrıca **machine**, **VM** (virtual machine), **node** ifadeleri de kullanılır. Bunların hepsi, genellikle Linux çalıştıran ve üzerinde programlarınızı çalıştırdığınız bir tür uzak makineyi ifade eder.
|
||||
|
||||
## Sunucu Programını Yükleyin { #install-the-server-program }
|
||||
|
||||
FastAPI'yi kurduğunuzda, production sunucusu olarak Uvicorn da beraberinde gelir ve bunu `fastapi run` komutuyla başlatabilirsiniz.
|
||||
|
||||
Ancak bir ASGI server'ı manuel olarak da kurabilirsiniz.
|
||||
|
||||
Bir [sanal ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden emin olun; ardından server uygulamasını kurabilirsiniz.
|
||||
|
||||
Örneğin Uvicorn'u kurmak için:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Benzer bir süreç, diğer ASGI server programlarının tamamı için de geçerlidir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`standard` eklediğinizde Uvicorn, önerilen bazı ek bağımlılıkları kurar ve kullanır.
|
||||
|
||||
Bunlara, `asyncio` için yüksek performanslı bir drop-in replacement olan ve concurrency performansını ciddi şekilde artıran `uvloop` da dahildir.
|
||||
|
||||
FastAPI'yi `pip install "fastapi[standard]"` gibi bir şekilde kurduğunuzda `uvicorn[standard]` da zaten kurulmuş olur.
|
||||
|
||||
///
|
||||
|
||||
## Sunucu Programını Çalıştırın { #run-the-server-program }
|
||||
|
||||
Bir ASGI server'ı manuel olarak kurduysanız, FastAPI uygulamanızı import edebilmesi için genellikle özel bir formatta bir import string geçirmeniz gerekir:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Not
|
||||
|
||||
`uvicorn main:app` komutu şunları ifade eder:
|
||||
|
||||
* `main`: `main.py` dosyası (Python "module").
|
||||
* `app`: `main.py` içinde `app = FastAPI()` satırıyla oluşturulan nesne.
|
||||
|
||||
Şununla eşdeğerdir:
|
||||
|
||||
```Python
|
||||
from main import app
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
Her alternatif ASGI server programı için benzer bir komut bulunur; daha fazlası için ilgili dokümantasyonlarına bakabilirsiniz.
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Uvicorn ve diğer sunucular, geliştirme sırasında faydalı olan `--reload` seçeneğini destekler.
|
||||
|
||||
`--reload` seçeneği çok daha fazla kaynak tüketir, daha kararsızdır vb.
|
||||
|
||||
**Geliştirme** sırasında çok yardımcı olur, ancak **production** ortamında kullanmamalısınız.
|
||||
|
||||
///
|
||||
|
||||
## Deployment Kavramları { #deployment-concepts }
|
||||
|
||||
Bu örnekler server programını (ör. Uvicorn) çalıştırır; **tek bir process** başlatır, tüm IP'lerde (`0.0.0.0`) ve önceden belirlenmiş bir port'ta (ör. `80`) dinler.
|
||||
|
||||
Temel fikir budur. Ancak muhtemelen şunlar gibi bazı ek konularla da ilgilenmek isteyeceksiniz:
|
||||
|
||||
* Güvenlik - HTTPS
|
||||
* Açılışta çalıştırma
|
||||
* Yeniden başlatmalar
|
||||
* Replikasyon (çalışan process sayısı)
|
||||
* Bellek
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
Sonraki bölümlerde bu kavramların her birini nasıl düşünmeniz gerektiğini ve bunlarla başa çıkmak için kullanabileceğiniz somut örnekleri/stratejileri anlatacağım. 🚀
|
||||
@@ -0,0 +1,139 @@
|
||||
# Server Workers - Worker'larla Uvicorn { #server-workers-uvicorn-with-workers }
|
||||
|
||||
Önceki bölümlerde bahsettiğimiz deployment kavramlarına tekrar bakalım:
|
||||
|
||||
* Güvenlik - HTTPS
|
||||
* Başlangıçta çalıştırma
|
||||
* Yeniden başlatmalar
|
||||
* **Replikasyon (çalışan process sayısı)**
|
||||
* Bellek
|
||||
* Başlatmadan önceki adımlar
|
||||
|
||||
Bu noktaya kadar, dokümantasyondaki tüm tutorial'larla muhtemelen bir **server programı** çalıştırıyordunuz; örneğin Uvicorn'u çalıştıran `fastapi` komutunu kullanarak ve **tek bir process** ile.
|
||||
|
||||
Uygulamaları deploy ederken, **çok çekirdekten (multiple cores)** faydalanmak ve daha fazla request'i karşılayabilmek için büyük olasılıkla **process replikasyonu** (birden fazla process) isteyeceksiniz.
|
||||
|
||||
[Daha önceki Deployment Concepts](concepts.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, kullanabileceğiniz birden fazla strateji var.
|
||||
|
||||
Burada, `fastapi` komutunu kullanarak ya da `uvicorn` komutunu doğrudan çalıştırarak **worker process**'lerle **Uvicorn**'u nasıl kullanacağınızı göstereceğim.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Container kullanıyorsanız (örneğin Docker veya Kubernetes ile), bununla ilgili daha fazlasını bir sonraki bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
Özellikle **Kubernetes** üzerinde çalıştırırken, büyük olasılıkla worker kullanmak **istemeyeceksiniz**; bunun yerine **container başına tek bir Uvicorn process** çalıştırmak daha uygundur. Ancak bunu da o bölümde detaylandıracağım.
|
||||
|
||||
///
|
||||
|
||||
## Birden Fazla Worker { #multiple-workers }
|
||||
|
||||
Komut satırında `--workers` seçeneğiyle birden fazla worker başlatabilirsiniz:
|
||||
|
||||
//// tab | `fastapi`
|
||||
|
||||
`fastapi` komutunu kullanıyorsanız:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run --workers 4 <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started parent process <b>[</b><font color="#34E2E2"><b>27365</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27368</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27369</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27370</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27367</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
//// tab | `uvicorn`
|
||||
|
||||
`uvicorn` komutunu doğrudan kullanmayı tercih ederseniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
|
||||
<font color="#A6E22E">INFO</font>: Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)
|
||||
<font color="#A6E22E">INFO</font>: Started parent process [<font color="#A1EFE4"><b>27365</b></font>]
|
||||
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27368</font>]
|
||||
<font color="#A6E22E">INFO</font>: Waiting for application startup.
|
||||
<font color="#A6E22E">INFO</font>: Application startup complete.
|
||||
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27369</font>]
|
||||
<font color="#A6E22E">INFO</font>: Waiting for application startup.
|
||||
<font color="#A6E22E">INFO</font>: Application startup complete.
|
||||
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27370</font>]
|
||||
<font color="#A6E22E">INFO</font>: Waiting for application startup.
|
||||
<font color="#A6E22E">INFO</font>: Application startup complete.
|
||||
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27367</font>]
|
||||
<font color="#A6E22E">INFO</font>: Waiting for application startup.
|
||||
<font color="#A6E22E">INFO</font>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
Buradaki tek yeni seçenek `--workers`; bu seçenek Uvicorn'a 4 adet worker process başlatmasını söyler.
|
||||
|
||||
Ayrıca her process'in **PID**'inin gösterildiğini de görebilirsiniz: parent process için `27365` (bu **process manager**), her worker process için de bir PID: `27368`, `27369`, `27370` ve `27367`.
|
||||
|
||||
## Deployment Kavramları { #deployment-concepts }
|
||||
|
||||
Burada, uygulamanın çalışmasını **paralelleştirmek**, CPU'daki **çok çekirdekten** yararlanmak ve **daha fazla request** karşılayabilmek için birden fazla **worker**'ı nasıl kullanacağınızı gördünüz.
|
||||
|
||||
Yukarıdaki deployment kavramları listesinden, worker kullanımı ağırlıklı olarak **replikasyon** kısmına yardımcı olur, ayrıca **yeniden başlatmalar** konusunda da az da olsa katkı sağlar. Ancak diğerlerini yine sizin yönetmeniz gerekir:
|
||||
|
||||
* **Güvenlik - HTTPS**
|
||||
* **Başlangıçta çalıştırma**
|
||||
* ***Yeniden başlatmalar***
|
||||
* Replikasyon (çalışan process sayısı)
|
||||
* **Bellek**
|
||||
* **Başlatmadan önceki adımlar**
|
||||
|
||||
## Container'lar ve Docker { #containers-and-docker }
|
||||
|
||||
Bir sonraki bölümde, [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank} üzerinden diğer **deployment kavramlarını** ele almak için kullanabileceğiniz bazı stratejileri anlatacağım.
|
||||
|
||||
Tek bir Uvicorn process çalıştıracak şekilde **sıfırdan kendi image'ınızı oluşturmayı** göstereceğim. Bu oldukça basit bir süreçtir ve **Kubernetes** gibi dağıtık bir container yönetim sistemi kullanırken büyük olasılıkla yapmak isteyeceğiniz şey de budur.
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
**Çok çekirdekli CPU**'lardan faydalanmak ve **birden fazla process'i paralel** çalıştırmak için `fastapi` veya `uvicorn` komutlarıyla `--workers` CLI seçeneğini kullanarak birden fazla worker process çalıştırabilirsiniz.
|
||||
|
||||
Diğer deployment kavramlarını da kendiniz ele alarak **kendi deployment sisteminizi** kuruyorsanız, bu araçları ve fikirleri kullanabilirsiniz.
|
||||
|
||||
Container'larla (örn. Docker ve Kubernetes) **FastAPI**'yi öğrenmek için bir sonraki bölüme göz atın. Bu araçların, diğer **deployment kavramlarını** çözmek için de basit yöntemleri olduğunu göreceksiniz. ✨
|
||||
@@ -0,0 +1,93 @@
|
||||
# FastAPI Sürümleri Hakkında { #about-fastapi-versions }
|
||||
|
||||
**FastAPI** hâlihazırda birçok uygulama ve sistemde production ortamında kullanılmaktadır. Ayrıca test kapsamı %100 seviyesinde tutulmaktadır. Ancak geliştirme süreci hâlâ hızlı şekilde ilerlemektedir.
|
||||
|
||||
Yeni özellikler sık sık eklenir, bug'lar düzenli olarak düzeltilir ve kod sürekli iyileştirilmektedir.
|
||||
|
||||
Bu yüzden mevcut sürümler hâlâ `0.x.x` şeklindedir; bu da her sürümde breaking change olma ihtimalini yansıtır. Bu yaklaşım <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> kurallarını takip eder.
|
||||
|
||||
Şu anda **FastAPI** ile production uygulamaları geliştirebilirsiniz (muhtemelen bir süredir yapıyorsunuz da); sadece kodunuzun geri kalanıyla doğru çalışan bir sürüm kullandığınızdan emin olmanız gerekir.
|
||||
|
||||
## `fastapi` sürümünü sabitleyin { #pin-your-fastapi-version }
|
||||
|
||||
İlk yapmanız gereken, kullandığınız **FastAPI** sürümünü uygulamanızla doğru çalıştığını bildiğiniz belirli bir güncel sürüme "sabitlemek" (pinlemek) olmalı.
|
||||
|
||||
Örneğin, uygulamanızda `0.112.0` sürümünü kullandığınızı varsayalım.
|
||||
|
||||
`requirements.txt` dosyası kullanıyorsanız sürümü şöyle belirtebilirsiniz:
|
||||
|
||||
```txt
|
||||
fastapi[standard]==0.112.0
|
||||
```
|
||||
|
||||
Bu, tam olarak `0.112.0` sürümünü kullanacağınız anlamına gelir.
|
||||
|
||||
Ya da şu şekilde de sabitleyebilirsiniz:
|
||||
|
||||
```txt
|
||||
fastapi[standard]>=0.112.0,<0.113.0
|
||||
```
|
||||
|
||||
Bu da `0.112.0` ve üzeri, ama `0.113.0` altındaki sürümleri kullanacağınız anlamına gelir; örneğin `0.112.2` gibi bir sürüm de kabul edilir.
|
||||
|
||||
Kurulumları yönetmek için `uv`, Poetry, Pipenv gibi başka bir araç (veya benzerleri) kullanıyorsanız, bunların hepsinde paketler için belirli sürümler tanımlamanın bir yolu vardır.
|
||||
|
||||
## Mevcut sürümler { #available-versions }
|
||||
|
||||
Mevcut sürümleri (ör. en güncel son sürümün hangisi olduğunu kontrol etmek için) [Release Notes](../release-notes.md){.internal-link target=_blank} sayfasında görebilirsiniz.
|
||||
|
||||
## Sürümler Hakkında { #about-versions }
|
||||
|
||||
Semantic Versioning kurallarına göre, `1.0.0` altındaki herhangi bir sürüm breaking change içerebilir.
|
||||
|
||||
FastAPI ayrıca "PATCH" sürüm değişikliklerinin bug fix'ler ve breaking olmayan değişiklikler için kullanılması kuralını da takip eder.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
"PATCH" son sayıdır. Örneğin `0.2.3` içinde PATCH sürümü `3`'tür.
|
||||
|
||||
///
|
||||
|
||||
Dolayısıyla şu şekilde bir sürüme sabitleyebilmelisiniz:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Breaking change'ler ve yeni özellikler "MINOR" sürümlerde eklenir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
"MINOR" ortadaki sayıdır. Örneğin `0.2.3` içinde MINOR sürümü `2`'dir.
|
||||
|
||||
///
|
||||
|
||||
## FastAPI Sürümlerini Yükseltme { #upgrading-the-fastapi-versions }
|
||||
|
||||
Uygulamanız için test'ler eklemelisiniz.
|
||||
|
||||
**FastAPI** ile bu çok kolaydır (Starlette sayesinde). Dokümantasyona bakın: [Testing](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
Test'leriniz olduktan sonra **FastAPI** sürümünü daha yeni bir sürüme yükseltebilir ve test'lerinizi çalıştırarak tüm kodunuzun doğru çalıştığından emin olabilirsiniz.
|
||||
|
||||
Her şey çalışıyorsa (ya da gerekli değişiklikleri yaptıktan sonra) ve tüm test'leriniz geçiyorsa, `fastapi` sürümünü o yeni sürüme sabitleyebilirsiniz.
|
||||
|
||||
## Starlette Hakkında { #about-starlette }
|
||||
|
||||
`starlette` sürümünü sabitlememelisiniz.
|
||||
|
||||
**FastAPI**'nin farklı sürümleri, Starlette'in belirli (daha yeni) bir sürümünü kullanır.
|
||||
|
||||
Bu yüzden **FastAPI**'nin doğru Starlette sürümünü kullanmasına izin verebilirsiniz.
|
||||
|
||||
## Pydantic Hakkında { #about-pydantic }
|
||||
|
||||
Pydantic, **FastAPI** için olan test'leri kendi test'lerinin içine dahil eder; bu yüzden Pydantic'in yeni sürümleri (`1.0.0` üzeri) her zaman FastAPI ile uyumludur.
|
||||
|
||||
Pydantic'i sizin için çalışan `1.0.0` üzerindeki herhangi bir sürüme sabitleyebilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
```txt
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
```
|
||||
@@ -0,0 +1,298 @@
|
||||
# Ortam Değişkenleri { #environment-variables }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
"Ortam değişkenleri"nin ne olduğunu ve nasıl kullanılacağını zaten biliyorsanız, bu bölümü atlayabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Ortam değişkeni (genelde "**env var**" olarak da anılır), Python kodunun **dışında**, **işletim sistemi** seviyesinde bulunan ve Python kodunuz (veya diğer programlar) tarafından okunabilen bir değişkendir.
|
||||
|
||||
Ortam değişkenleri; uygulama **ayarları**nı yönetmek, Python’un **kurulumu**nun bir parçası olarak konfigürasyon yapmak vb. durumlarda işe yarar.
|
||||
|
||||
## Env Var Oluşturma ve Kullanma { #create-and-use-env-vars }
|
||||
|
||||
Python’a ihtiyaç duymadan, **shell (terminal)** içinde ortam değişkenleri **oluşturabilir** ve kullanabilirsiniz:
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// You could create an env var MY_NAME with
|
||||
$ export MY_NAME="Wade Wilson"
|
||||
|
||||
// Then you could use it with other programs, like
|
||||
$ echo "Hello $MY_NAME"
|
||||
|
||||
Hello Wade Wilson
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
//// tab | Windows PowerShell
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Create an env var MY_NAME
|
||||
$ $Env:MY_NAME = "Wade Wilson"
|
||||
|
||||
// Use it with other programs, like
|
||||
$ echo "Hello $Env:MY_NAME"
|
||||
|
||||
Hello Wade Wilson
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
## Python’da env var Okuma { #read-env-vars-in-python }
|
||||
|
||||
Ortam değişkenlerini Python’un **dışında** (terminalde veya başka bir yöntemle) oluşturup daha sonra **Python’da okuyabilirsiniz**.
|
||||
|
||||
Örneğin `main.py` adında bir dosyanız şöyle olabilir:
|
||||
|
||||
```Python hl_lines="3"
|
||||
import os
|
||||
|
||||
name = os.getenv("MY_NAME", "World")
|
||||
print(f"Hello {name} from Python")
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> fonksiyonunun ikinci argümanı, bulunamadığında döndürülecek varsayılan (default) değerdir.
|
||||
|
||||
Verilmezse varsayılan olarak `None` olur; burada varsayılan değer olarak `"World"` verdik.
|
||||
|
||||
///
|
||||
|
||||
Sonrasında bu Python programını çalıştırabilirsiniz:
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Here we don't set the env var yet
|
||||
$ python main.py
|
||||
|
||||
// As we didn't set the env var, we get the default value
|
||||
|
||||
Hello World from Python
|
||||
|
||||
// But if we create an environment variable first
|
||||
$ export MY_NAME="Wade Wilson"
|
||||
|
||||
// And then call the program again
|
||||
$ python main.py
|
||||
|
||||
// Now it can read the environment variable
|
||||
|
||||
Hello Wade Wilson from Python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
//// tab | Windows PowerShell
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Here we don't set the env var yet
|
||||
$ python main.py
|
||||
|
||||
// As we didn't set the env var, we get the default value
|
||||
|
||||
Hello World from Python
|
||||
|
||||
// But if we create an environment variable first
|
||||
$ $Env:MY_NAME = "Wade Wilson"
|
||||
|
||||
// And then call the program again
|
||||
$ python main.py
|
||||
|
||||
// Now it can read the environment variable
|
||||
|
||||
Hello Wade Wilson from Python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
Ortam değişkenleri kodun dışında ayarlanabildiği, ama kod tarafından okunabildiği ve dosyalarla birlikte saklanmasının (ör. `git`’e commit edilmesinin) gerekmediği için, konfigürasyon veya **ayarlar** için sıkça kullanılır.
|
||||
|
||||
Ayrıca, bir ortam değişkenini yalnızca **belirli bir program çalıştırımı** için oluşturabilirsiniz; bu değişken sadece o program tarafından, sadece o çalıştırma süresince kullanılabilir.
|
||||
|
||||
Bunu yapmak için, program komutunun hemen öncesinde ve aynı satırda tanımlayın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Create an env var MY_NAME in line for this program call
|
||||
$ MY_NAME="Wade Wilson" python main.py
|
||||
|
||||
// Now it can read the environment variable
|
||||
|
||||
Hello Wade Wilson from Python
|
||||
|
||||
// The env var no longer exists afterwards
|
||||
$ python main.py
|
||||
|
||||
Hello World from Python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu konuyla ilgili daha fazlasını <a href="https://12factor.net/config" class="external-link" target="_blank">Twelve-Factor Uygulaması: Config</a> bölümünde okuyabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Tipler ve Doğrulama { #types-and-validation }
|
||||
|
||||
Bu ortam değişkenleri yalnızca **metin string**’lerini taşıyabilir. Çünkü Python’un dışındadırlar ve diğer programlarla, sistemin geri kalanıyla (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle) uyumlu olmak zorundadırlar.
|
||||
|
||||
Bu, Python’da bir ortam değişkeninden okunan **her değerin `str` olacağı** anlamına gelir. Farklı bir tipe dönüştürme veya doğrulama işlemleri kod içinde yapılmalıdır.
|
||||
|
||||
Uygulama **ayarları**nı yönetmek için ortam değişkenlerini kullanmayı, [İleri Seviye Kullanıcı Rehberi - Ayarlar ve Ortam Değişkenleri](./advanced/settings.md){.internal-link target=_blank} bölümünde daha detaylı öğreneceksiniz.
|
||||
|
||||
## `PATH` Ortam Değişkeni { #path-environment-variable }
|
||||
|
||||
İşletim sistemlerinin (Linux, macOS, Windows) çalıştırılacak programları bulmak için kullandığı **özel** bir ortam değişkeni vardır: **`PATH`**.
|
||||
|
||||
`PATH` değişkeninin değeri uzun bir string’dir; Linux ve macOS’te dizinler iki nokta üst üste `:` ile, Windows’ta ise noktalı virgül `;` ile ayrılır.
|
||||
|
||||
Örneğin `PATH` ortam değişkeni şöyle görünebilir:
|
||||
|
||||
//// tab | Linux, macOS
|
||||
|
||||
```plaintext
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
||||
```
|
||||
|
||||
Bu, sistemin şu dizinlerde program araması gerektiği anlamına gelir:
|
||||
|
||||
* `/usr/local/bin`
|
||||
* `/usr/bin`
|
||||
* `/bin`
|
||||
* `/usr/sbin`
|
||||
* `/sbin`
|
||||
|
||||
////
|
||||
|
||||
//// tab | Windows
|
||||
|
||||
```plaintext
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
|
||||
```
|
||||
|
||||
Bu, sistemin şu dizinlerde program araması gerektiği anlamına gelir:
|
||||
|
||||
* `C:\Program Files\Python312\Scripts`
|
||||
* `C:\Program Files\Python312`
|
||||
* `C:\Windows\System32`
|
||||
|
||||
////
|
||||
|
||||
Terminalde bir **komut** yazdığınızda, işletim sistemi `PATH` ortam değişkeninde listelenen **bu dizinlerin her birinde** programı **arar**.
|
||||
|
||||
Örneğin terminalde `python` yazdığınızda, işletim sistemi bu listedeki **ilk dizinde** `python` adlı bir program arar.
|
||||
|
||||
Bulursa **onu kullanır**. Bulamazsa **diğer dizinlerde** aramaya devam eder.
|
||||
|
||||
### Python Kurulumu ve `PATH`’in Güncellenmesi { #installing-python-and-updating-the-path }
|
||||
|
||||
Python’u kurarken, `PATH` ortam değişkenini güncellemek isteyip istemediğiniz sorulabilir.
|
||||
|
||||
//// tab | Linux, macOS
|
||||
|
||||
Diyelim ki Python’u kurdunuz ve `/opt/custompython/bin` dizinine yüklendi.
|
||||
|
||||
`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `/opt/custompython/bin` yolunu `PATH` ortam değişkenine ekler.
|
||||
|
||||
Şöyle görünebilir:
|
||||
|
||||
```plaintext
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
|
||||
```
|
||||
|
||||
Böylece terminalde `python` yazdığınızda, sistem `/opt/custompython/bin` (son dizin) içindeki Python programını bulur ve onu kullanır.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Windows
|
||||
|
||||
Diyelim ki Python’u kurdunuz ve `C:\opt\custompython\bin` dizinine yüklendi.
|
||||
|
||||
`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `C:\opt\custompython\bin` yolunu `PATH` ortam değişkenine ekler.
|
||||
|
||||
```plaintext
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
|
||||
```
|
||||
|
||||
Böylece terminalde `python` yazdığınızda, sistem `C:\opt\custompython\bin` (son dizin) içindeki Python programını bulur ve onu kullanır.
|
||||
|
||||
////
|
||||
|
||||
Yani şunu yazarsanız:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
//// tab | Linux, macOS
|
||||
|
||||
Sistem `python` programını `/opt/custompython/bin` içinde **bulur** ve çalıştırır.
|
||||
|
||||
Bu, kabaca şunu yazmaya denktir:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ /opt/custompython/bin/python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
//// tab | Windows
|
||||
|
||||
Sistem `python` programını `C:\opt\custompython\bin\python` içinde **bulur** ve çalıştırır.
|
||||
|
||||
Bu, kabaca şunu yazmaya denktir:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ C:\opt\custompython\bin\python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
Bu bilgiler, [Virtual Environments](virtual-environments.md){.internal-link target=_blank} konusunu öğrenirken işinize yarayacak.
|
||||
|
||||
## Sonuç { #conclusion }
|
||||
|
||||
Buraya kadar **ortam değişkenleri**nin ne olduğuna ve Python’da nasıl kullanılacağına dair temel bir fikir edinmiş olmalısınız.
|
||||
|
||||
Ayrıca <a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Ortam Değişkeni için Wikipedia</a> sayfasından daha fazlasını da okuyabilirsiniz.
|
||||
|
||||
Çoğu zaman ortam değişkenlerinin hemen nasıl işe yarayacağı ilk bakışta çok net olmayabilir. Ancak geliştirme yaparken birçok farklı senaryoda tekrar tekrar karşınıza çıkarlar; bu yüzden bunları bilmek faydalıdır.
|
||||
|
||||
Örneğin bir sonraki bölümde, [Virtual Environments](virtual-environments.md) konusunda bu bilgilere ihtiyaç duyacaksınız.
|
||||
@@ -0,0 +1,75 @@
|
||||
# FastAPI CLI { #fastapi-cli }
|
||||
|
||||
**FastAPI CLI**, FastAPI uygulamanızı servis etmek, FastAPI projenizi yönetmek ve daha fazlası için kullanabileceğiniz bir komut satırı programıdır.
|
||||
|
||||
FastAPI'yi kurduğunuzda (ör. `pip install "fastapi[standard]"`), beraberinde `fastapi-cli` adlı bir paket de gelir; bu paket terminalde `fastapi` komutunu sağlar.
|
||||
|
||||
FastAPI uygulamanızı geliştirme için çalıştırmak üzere `fastapi dev` komutunu kullanabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
`fastapi` adlı bu komut satırı programı, **FastAPI CLI**'dır.
|
||||
|
||||
FastAPI CLI, Python programınızın path'ini (ör. `main.py`) alır; `FastAPI` instance'ını (genellikle `app` olarak adlandırılır) otomatik olarak tespit eder, doğru import sürecini belirler ve ardından uygulamayı servis eder.
|
||||
|
||||
Production için bunun yerine `fastapi run` kullanırsınız. 🚀
|
||||
|
||||
İçeride **FastAPI CLI**, yüksek performanslı, production'a hazır bir ASGI server olan <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>'u kullanır. 😎
|
||||
|
||||
## `fastapi dev` { #fastapi-dev }
|
||||
|
||||
`fastapi dev` çalıştırmak, geliştirme modunu başlatır.
|
||||
|
||||
Varsayılan olarak **auto-reload** etkindir; kodunuzda değişiklik yaptığınızda server'ı otomatik olarak yeniden yükler. Bu, kaynak tüketimi yüksek bir özelliktir ve kapalı olduğuna kıyasla daha az stabil olabilir. Sadece geliştirme sırasında kullanmalısınız. Ayrıca yalnızca `127.0.0.1` IP adresini dinler; bu, makinenizin sadece kendisiyle iletişim kurması için kullanılan IP'dir (`localhost`).
|
||||
|
||||
## `fastapi run` { #fastapi-run }
|
||||
|
||||
`fastapi run` çalıştırmak, varsayılan olarak FastAPI'yi production modunda başlatır.
|
||||
|
||||
Varsayılan olarak **auto-reload** kapalıdır. Ayrıca `0.0.0.0` IP adresini dinler; bu, kullanılabilir tüm IP adresleri anlamına gelir. Böylece makineyle iletişim kurabilen herkes tarafından genel erişime açık olur. Bu, normalde production'da çalıştırma şeklidir; örneğin bir container içinde.
|
||||
|
||||
Çoğu durumda (ve genellikle yapmanız gereken şekilde) üst tarafta sizin yerinize HTTPS'i yöneten bir "termination proxy" bulunur. Bu, uygulamanızı nasıl deploy ettiğinize bağlıdır; sağlayıcınız bunu sizin için yapabilir ya da sizin ayrıca kurmanız gerekebilir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bununla ilgili daha fazla bilgiyi [deployment dokümantasyonunda](deployment/index.md){.internal-link target=_blank} bulabilirsiniz.
|
||||
|
||||
///
|
||||
+94
-101
@@ -1,59 +1,55 @@
|
||||
# Özelikler
|
||||
# Özellikler { #features }
|
||||
|
||||
## FastAPI özellikleri
|
||||
## FastAPI Özellikleri { #fastapi-features }
|
||||
|
||||
**FastAPI** sana bunları sağlıyor
|
||||
**FastAPI** size şunları sağlar:
|
||||
|
||||
### Açık standartları temel alır
|
||||
### Açık Standartlara Dayalı { #based-on-open-standards }
|
||||
|
||||
* API oluşturma işlemlerinde <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> buna <abbr title="also known as: endpoints, routes">path</abbr> <abbr title=" HTTP metodları olarak bilinen, POST, GET, PUT, DELETE">operasyonları </abbr>parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi.
|
||||
* Otomatik olarak data modelinin <a href="http://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> ile beraber dokümante edilmesi (OpenAPI'n kendisi zaten JSON Schema'ya dayanıyor).
|
||||
* Titiz bir çalışmanın sonucunda yukarıdaki standartlara uygun bir framework oluşturduk. Standartları pastanın üzerine sonradan eklenmiş bir çilek olarak görmedik.
|
||||
* Ayrıca bu bir çok dilde kullanılabilecek **client code generator** kullanımına da izin veriyor.
|
||||
* API oluşturmada <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>, buna <dfn title="şöyle de bilinir: endpoints, routes">path</dfn> <dfn title="HTTP metodları olarak da bilinir; POST, GET, PUT, DELETE gibi">operasyonları</dfn>, parametreler, request body'leri, güvenlik vb. deklarasyonları dahildir.
|
||||
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> ile otomatik veri modeli dokümantasyonu (OpenAPI zaten JSON Schema'ya dayanır).
|
||||
* Bu standartlar etrafında, titiz bir çalışmanın ardından tasarlandı; sonradan eklenmiş bir katman değil.
|
||||
* Bu sayede birçok dilde otomatik **client code generation** da kullanılabilir.
|
||||
|
||||
### Otomatik dokümantasyon
|
||||
### Otomatik Dokümantasyon { #automatic-docs }
|
||||
|
||||
Etkileşimli API dokümantasyonu ve keşif için web arayüzleri. Framework OpenAPI’ye dayandığından, birden fazla seçenek vardır; varsayılan olarak 2’si dahildir.
|
||||
|
||||
OpenAPI standartlarına dayalı olan bir framework olarak, geliştiricilerin birden çok seçeneği var, varsayılan olarak gelen 2 farklı interaktif API dokümantasyonu ve web kullanıcı arayüzü var.
|
||||
|
||||
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a> interaktif olarak API'ınızı tarayıcı üzerinden çağırıp test edebilmenize olanak sağlıyor.
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a> ile etkileşimli keşif; API’nizi tarayıcıdan doğrudan çağırıp test edin.
|
||||
|
||||

|
||||
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a> ile beraber alternatif API dokümantasyonu.
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a> ile alternatif API dokümantasyonu.
|
||||
|
||||

|
||||
|
||||
### Sadece modern Python
|
||||
### Sadece Modern Python { #just-modern-python }
|
||||
|
||||
Tamamiyle standartlar **Python 3.8**'nın type hintlerine dayanıyor (Pydantic'in sayesinde). Yeni bir syntax öğrenmene gerek yok. Sadece modern Python.
|
||||
Her şey standart **Python type** deklarasyonlarına dayanır (Pydantic sayesinde). Öğrenilecek yeni bir söz dizimi yok. Sadece standart, modern Python.
|
||||
|
||||
Python type’larını nasıl kullanacağınıza dair 2 dakikalık bir hatırlatmaya ihtiyacınız varsa (FastAPI kullanmasanız bile) kısa eğitime göz atın: [Python Types](python-types.md){.internal-link target=_blank}.
|
||||
|
||||
Eğer Python type hintlerini bilmiyorsan veya bir hatırlatmaya ihtiyacın var ise(FastAPI kullanmasan bile) şu iki dakikalık küçük bilgilendirici içeriğe bir göz at: [Python Types](python-types.md){.internal-link target=_blank}.
|
||||
|
||||
Standart Python'u typelarını belirterek yazıyorsun:
|
||||
Türleriyle standart Python yazarsınız:
|
||||
|
||||
```Python
|
||||
from typing import List, Dict
|
||||
from datetime import date
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Değişkeni str olarak belirt
|
||||
# ve o fonksiyon için harika bir editör desteği al
|
||||
# Bir değişkeni str olarak belirt
|
||||
# ve fonksiyon içinde editör desteği al
|
||||
def main(user_id: str):
|
||||
return user_id
|
||||
|
||||
|
||||
# Pydantic modeli
|
||||
# Bir Pydantic modeli
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
joined: date
|
||||
```
|
||||
|
||||
Sonrasında bu şekilde kullanabilirsin
|
||||
Sonra şöyle kullanabilirsiniz:
|
||||
|
||||
```Python
|
||||
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
|
||||
@@ -67,25 +63,26 @@ second_user_data = {
|
||||
my_second_user: User = User(**second_user_data)
|
||||
```
|
||||
|
||||
|
||||
/// info
|
||||
|
||||
`**second_user_data` şu anlama geliyor:
|
||||
`**second_user_data` şu anlama gelir:
|
||||
|
||||
Key-Value çiftini direkt olarak `second_user_data` dictionarysine kaydet , yaptığın şey buna eşit olacak: `User(id=4, name="Mary", joined="2018-11-30")`
|
||||
`second_user_data` dict’indeki anahtar ve değerleri doğrudan anahtar-değer argümanları olarak geç; şu ifadeye eşdeğerdir: `User(id=4, name="Mary", joined="2018-11-30")`
|
||||
|
||||
///
|
||||
|
||||
### Editor desteği
|
||||
### Editör Desteği { #editor-support }
|
||||
|
||||
Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi.
|
||||
Tüm framework, kullanımı kolay ve sezgisel olacak şekilde tasarlandı; en iyi geliştirme deneyimini sağlamak için geliştirmeye başlamadan önce bile alınan kararlar birden çok editörde test edildi.
|
||||
|
||||
Son yapılan Python geliştiricileri anketinde, açık ara <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">en çok kullanılan özellik "oto-tamamlama" idi.</a>.
|
||||
Python geliştirici anketlerinde açıkça görülüyor ki <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">en çok kullanılan özelliklerden biri "otomatik tamamlama"</a>.
|
||||
|
||||
Bütün **FastAPI** frameworkü oto-tamamlama açısından geliştiriciyi tatmin etmek üzerine tasarlandı. Otomatik tamamlama her yerde çalışıyor.
|
||||
Tüm **FastAPI** bunun tatmin edilmesi üzerine kuruldu. Otomatik tamamlama her yerde çalışır.
|
||||
|
||||
Dokümantasyona tekrardan çok nadir olarak geleceksin.
|
||||
Dokümana geri dönmeniz nadiren gerekecek.
|
||||
|
||||
Editörün sana nasıl yardım ettiğine bir bak:
|
||||
Editörünüz şöyle yardımcı olabilir:
|
||||
|
||||
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a> ile:
|
||||
|
||||
@@ -95,115 +92,111 @@ Editörün sana nasıl yardım ettiğine bir bak:
|
||||
|
||||

|
||||
|
||||
Daha önce imkânsız olduğunu düşünebileceğiniz yerlerde bile tamamlama alırsınız. Örneğin, bir request’ten gelen (iç içe de olabilir) JSON body içindeki `price` anahtarı için.
|
||||
|
||||
Daha önceden düşünüp en imkansız diyebileceğin durumlarda bile otomatik tamamlama alacaksın, örnek olarak `price` JSON body içerisinde (nested bir JSON body de olabilirdi.) direkt olarak istekten geliyor, bu durumda bile oto-tammalama sağlıyor.
|
||||
Artık anahtar adlarını yanlış yazmak, dokümana gidip gelmek ya da sonunda `username` mi `user_name` mi kullandığınızı bulmak için sayfayı yukarı aşağı kaydırmak yok.
|
||||
|
||||
Artık key isimlerini yanlış yazma, dokümantasyona dönüp deliler gibi yukarı aşağı sayfada gezmek ve en sonunda `username` mi yoksa `user_name` mi kullandım gibi sorular yok.
|
||||
### Kısa { #short }
|
||||
|
||||
### Kısa
|
||||
Her şey için mantıklı **varsayılanlar** ve her yerde isteğe bağlı yapılandırmalar vardır. Tüm parametreler, ihtiyacınızı karşılayacak şekilde ince ayar yapılarak tanımlamak istediğiniz API’yi oluşturabilir.
|
||||
|
||||
Her şey için mantıklı bir **varsayılanı** var. Parametrelerini opsiyonel olarak tanımlayıp API'nı istediğin gibi modifiye edebilirsin.
|
||||
Ancak varsayılan hâliyle hepsi **“hemen çalışır”**.
|
||||
|
||||
Hepsi varsayılan olarak **çalışıyor**.
|
||||
### Doğrulama { #validation }
|
||||
|
||||
* Çoğu (veya hepsi?) Python **veri tipi** için doğrulama, şunlar dâhil:
|
||||
* JSON nesneleri (`dict`).
|
||||
* Eleman tipleri tanımlanan JSON dizileri (`list`).
|
||||
* Minimum ve maksimum uzunlukları tanımlanan String (`str`) alanları.
|
||||
* Min ve max değerleri olan sayılar (`int`, `float`) vb.
|
||||
|
||||
### Doğrulama
|
||||
|
||||
* Neredeyse bütün (ya da hepsi?) Python **data typeları** için doğrulama, kapsadıkları:
|
||||
* JSON objeleri (`dict`).
|
||||
* JSON array (`list`) item type'ı belirtirken.
|
||||
* String (`str`) parametresi, minimum ve maksimum uzunluk gibi sınırlandırmalar yaparken.
|
||||
* Numaralar (`int`, `float`) maksimum ve minimum gibi sınırlandırmalar yaparken.
|
||||
|
||||
* Bunlar gibi en egzotik typelarla bile doğrulama yapabiliyorsunuz.:
|
||||
* Daha “egzotik” tipler için doğrulama:
|
||||
* URL.
|
||||
* Email.
|
||||
* UUID.
|
||||
* ...ve diğerleri.
|
||||
|
||||
Bütün doğrulama olayları çok güçlü bir kütüphane sayesinde yapılıyor, **Pydantic**.
|
||||
Tüm doğrulama köklü ve sağlam **Pydantic** tarafından yapılır.
|
||||
|
||||
### Güvenlik ve kimlik doğrulama
|
||||
### Güvenlik ve Kimlik Doğrulama { #security-and-authentication }
|
||||
|
||||
Güvenlik ve doğrulama database ve data modellerinden taviz vermeden entegre edilebilir durumda.
|
||||
Güvenlik ve kimlik doğrulama entegredir. Veritabanları veya veri modelleriyle ilgili hiçbir taviz yoktur.
|
||||
|
||||
Bütün güvenlik şemaları OpenAPI'da tanımlanmış durumda, kapsadıkları:
|
||||
OpenAPI’da tanımlanan tüm güvenlik şemaları, şunlar dâhil:
|
||||
|
||||
* HTTP Basic.
|
||||
* **OAuth2** (ve **JWT tokenleriyle** beraber). Bu öğretici içeriğe göz atabilirsin [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
|
||||
* **OAuth2** (ayrıca **JWT token**’larla). Şu eğitime göz atın: [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
|
||||
* API anahtarları:
|
||||
* Headerlar.
|
||||
* Query parametreleri.
|
||||
* Cookies, vs.
|
||||
* Header’larda.
|
||||
* Query parametrelerinde.
|
||||
* Cookie’lerde vb.
|
||||
|
||||
Bütün güvenlik özellikleri Starlette'den geliyor (**session cookies'de** dahil olmak üzere).
|
||||
Buna ek olarak Starlette’in tüm güvenlik özellikleri (**session cookies** dâhil).
|
||||
|
||||
Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı.
|
||||
Tümü, sistemleriniz, veri depolarınız, ilişkisel ve NoSQL veritabanlarınız vb. ile kolayca entegre edilebilen, yeniden kullanılabilir araçlar ve bileşenler olarak inşa edilmiştir.
|
||||
|
||||
### Dependency injection
|
||||
### Dependency Injection { #dependency-injection }
|
||||
|
||||
FastAPI'ın inanılmaz derecede kullanımı kolay, fakat inanılmaz derecede güçlü <abbr title='"components", "resources", "services", "providers" olarak da bilinen'><strong>Dependency Injection </strong></abbr> sistemi var.
|
||||
FastAPI, son derece kolay kullanımlı ama son derece güçlü bir <dfn title='şöyle de bilinir: "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></dfn> sistemine sahiptir.
|
||||
|
||||
* Dependencylerin bile dependencies'i olabiliyor, FastAPI bunun için **graph of "dependency"** yaratıyor.
|
||||
* Hepsi **otomatik olarak** FastAPI tarafından hallediliyor.
|
||||
* Bütün zorunlulukların gelen datalara bağlı olarak farklı gereksinimleri olabiliyor, ilave path operasyonlarının kısıtlamaları ve otomatik dokümantasyonu da ayrıca yapılıyor .
|
||||
* Path operasyonu parametreleri içerisinde belirtilen gereksinimler için bile **Otomatik doğrulama** yapılabiliyor.
|
||||
* Kompleks kimlik doğrulama sistemleri için destek, **database bağlantıları**, vs.
|
||||
* **Taviz yok** hiçbir şeyden taviz vermeden, database frontend vs. Bütün hepsinin kolayca entegre edilebiliyor.
|
||||
* Bağımlılıkların da kendi bağımlılıkları olabilir; böylece bir hiyerarşi veya **bağımlılıklar "grafı"** oluşur.
|
||||
* Tüm süreç framework tarafından **otomatik olarak yönetilir**.
|
||||
* Tüm bağımlılıklar, request’lerden veri talep edebilir ve *path operation* kısıtlarını ve otomatik dokümantasyonu **zenginleştirebilir**.
|
||||
* Bağımlılıklarda tanımlanan *path operation* parametreleri için bile **otomatik doğrulama**.
|
||||
* Karmaşık kullanıcı kimlik doğrulama sistemleri, **veritabanı bağlantıları** vb. için destek.
|
||||
* Veritabanları, frontend’ler vb. ile **taviz yok**; ancak hepsiyle kolay entegrasyon.
|
||||
|
||||
### Sınırsız "plug-inler"
|
||||
### Sınırsız "Plug-in" { #unlimited-plug-ins }
|
||||
|
||||
Başka bir deyişle, plug-inlere ihtiyacımız yok, import edip direkt olarak kullanmaya başlayabiliriz.
|
||||
Başka bir deyişle, onlara gerek yok; ihtiyaç duyduğunuz kodu import edin ve kullanın.
|
||||
|
||||
Bütün entegrasyonlar kullanımı kolay olmak üzere (zorunluluklar ile beraber) tasarlandı, sen bir "plug-in" yaratıp 2 satır kod ile, *path operasyonlarında* kullandığımız syntax ve aynı yapı ile koduna entregre edebilirsin.
|
||||
Her entegrasyon (bağımlılıklar ile) o kadar basit olacak şekilde tasarlanmıştır ki, uygulamanız için, *path operations* ile kullandığınız aynı yapı ve söz dizimiyle sadece 2 satırda bir “plug-in” yazabilirsiniz.
|
||||
|
||||
### Test Edildi { #tested }
|
||||
|
||||
### Test edildi
|
||||
* %100 <dfn title="Otomatik olarak test edilen kod miktarı">test kapsayıcılığı</dfn>.
|
||||
* %100 <dfn title="Python type annotations; bununla editörünüz ve harici araçlar size daha iyi destek verebilir">type annotated</dfn> kod tabanı.
|
||||
* Üretimde kullanılan uygulamalarda kullanılıyor.
|
||||
|
||||
* 100% <abbr title="Kodun ne kadarının test edildiği">test coverage</abbr>.
|
||||
* 100% <abbr title="Python type annotations, with this your editor and external tools can give you better support">typeları belirtilmiş</abbr> codebase.
|
||||
* FastAPI ile yapılan bir çok proje insanlar tarafından kullanılıyor.
|
||||
## Starlette Özellikleri { #starlette-features }
|
||||
|
||||
## Starlette özellikleri
|
||||
**FastAPI**, <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a> ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Starlette kodları da çalışır.
|
||||
|
||||
**FastAPI**, <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a> ile tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Starlette kodu da çalışacaktır.
|
||||
`FastAPI` aslında `Starlette`’in bir alt sınıfıdır. Starlette’i zaten biliyor veya kullanıyorsanız, işlevlerin çoğu aynı şekilde çalışır.
|
||||
|
||||
`FastAPI` aslında `Starlette`'nin bir sub-class'ı. Eğer Starlette'nin nasıl kullanılacağını biliyor isen, çoğu işlevini aynı şekilde yapıyor.
|
||||
**FastAPI** ile **Starlette**’in tüm özelliklerini elde edersiniz (FastAPI, steroid basılmış Starlette gibidir):
|
||||
|
||||
**FastAPI** ile beraber **Starlette**'nin bütün özelliklerine de sahip olacaksınız (FastAPI aslında Starlette'nin steroid basmış hali):
|
||||
|
||||
* Gerçekten etkileyici bir performansa sahip.Python'un ise en hızlı frameworklerinden bir tanesi, <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">**NodeJS** ve **Go** ile ise eşdeğer performansa sahip.</a>.
|
||||
* Cidden etkileyici performans. <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">Mevcut en hızlı Python frameworklerinden biridir; **NodeJS** ve **Go** ile aynı seviyededir</a>.
|
||||
* **WebSocket** desteği.
|
||||
* **GraphQL** desteği.
|
||||
* Kullanım halinde arka plan işlevleri.
|
||||
* Başlatma ve kapatma eventleri(startup and shutdown).
|
||||
* Test sunucusu HTTPX üzerine kurulu.
|
||||
* **CORS**, GZip, Static dosyalar, Streaming responseları.
|
||||
* **Session and Cookie** desteği.
|
||||
* 100% test kapsayıcılığı.
|
||||
* 100% typeları belirtilmiş codebase.
|
||||
* Süreç içi arka plan görevleri.
|
||||
* Başlatma ve kapatma olayları.
|
||||
* HTTPX üzerine kurulu test istemcisi.
|
||||
* **CORS**, GZip, Static Files, Streaming response’lar.
|
||||
* **Session** ve **Cookie** desteği.
|
||||
* %100 test kapsayıcılığı.
|
||||
* %100 type annotated kod tabanı.
|
||||
|
||||
## Pydantic özellikleri
|
||||
## Pydantic Özellikleri { #pydantic-features }
|
||||
|
||||
**FastAPI** ile <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a> tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Pydantic kodu da çalışacaktır.
|
||||
**FastAPI**, <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a> ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Pydantic kodları da çalışır.
|
||||
|
||||
Bunlara Pydantic üzerine kurulu <abbr title="Object-Relational Mapper">ORM</abbr> databaseler ve , <abbr title="Object-Document Mapper">ODM</abbr> kütüphaneler de dahil olmak üzere.
|
||||
Pydantic’e dayanan harici kütüphaneler de dâhildir; veritabanları için <abbr title="Object-Relational Mapper - Nesne-İlişkisel Eşleyici">ORM</abbr>’ler, <abbr title="Object-Document Mapper - Nesne-Belge Eşleyici">ODM</abbr>’ler gibi.
|
||||
|
||||
Bu ayrıca şu anlama da geliyor, bir çok durumda requestten gelen objeyi **direkt olarak database**'e her şeyi otomatik olarak doğrulanmış bir biçimde aktarabilirisin.
|
||||
Bu aynı zamanda, birçok durumda request’ten aldığınız nesneyi **doğrudan veritabanına** iletebileceğiniz anlamına gelir; zira her şey otomatik olarak doğrulanır.
|
||||
|
||||
Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiyle doğrulanmış bir biçimde gönderebilirsiniz.
|
||||
Tersi yönde de geçerlidir; birçok durumda veritabanından aldığınız nesneyi **doğrudan client**’a gönderebilirsiniz.
|
||||
|
||||
**FastAPI** ile beraber **Pydantic**'in bütün özelliklerine sahip olacaksınız (FastAPI data kontrolünü Pydantic'in üzerine kurduğu için):
|
||||
**FastAPI** ile **Pydantic**’in tüm özelliklerini elde edersiniz (FastAPI, tüm veri işlemede Pydantic’e dayanır):
|
||||
|
||||
* **Kafa karıştırmaz**:
|
||||
* Farklı bir syntax öğrenmenize gerek kalmaz,
|
||||
* Eğer Python typelarını nasıl kullanacağını biliyorsan Pydantic kullanmayı da biliyorsundur.
|
||||
* Kullandığın geliştirme araçları ile iyi çalışır **<abbr title="Integrated Development Environment, kod editörüne benzer">IDE</abbr>/<abbr title="Code errorlarınızı inceleyen program">linter</abbr>/brain**:
|
||||
* Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin
|
||||
* **En kompleks** yapıları bile doğrula:
|
||||
* Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula.
|
||||
* Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor
|
||||
* Pydantic, JSON objen ne kadar derin (nested) olursa olsun doğrulamasını ve gösterimini yapıyor
|
||||
* Öğrenmeniz gereken yeni bir şema tanımlama mikro-dili yok.
|
||||
* Python type’larını biliyorsanız Pydantic’i nasıl kullanacağınızı da biliyorsunuz.
|
||||
* **<abbr title="Integrated Development Environment - Tümleşik Geliştirme Ortamı: bir kod editörüne benzer">IDE</abbr>/<dfn title="koddaki hataları denetleyen bir program">linter</dfn>/beyin**’inizle iyi anlaşır:
|
||||
* Pydantic veri yapıları, sizin tanımladığınız sınıfların örnekleridir; bu nedenle doğrulanmış verilerinizle otomatik tamamlama, linting ve mypy sorunsuz çalışır, sezgileriniz de yol gösterir.
|
||||
* **Karmaşık yapıları** doğrulayın:
|
||||
* Hiyerarşik Pydantic modelleri, Python `typing`’in `List` ve `Dict`’i vb. kullanımı.
|
||||
* Doğrulayıcılar (validators), karmaşık veri şemalarının net ve kolay şekilde tanımlanmasını, kontrol edilmesini ve JSON Schema olarak dokümante edilmesini sağlar.
|
||||
* Derinlemesine iç içe **JSON** nesnelerine sahip olabilir, hepsinin doğrulanmasını ve anotasyonlanmasını sağlayabilirsiniz.
|
||||
* **Genişletilebilir**:
|
||||
* Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor.
|
||||
* 100% test kapsayıcılığı.
|
||||
* Pydantic, özel veri tiplerinin tanımlanmasına izin verir; ayrıca validator decorator’üyle bir modeldeki metodlarla doğrulamayı genişletebilirsiniz.
|
||||
* %100 test kapsayıcılığı.
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
# FastAPI'ye Yardım Et - Yardım Al { #help-fastapi-get-help }
|
||||
|
||||
**FastAPI**'yi seviyor musunuz?
|
||||
|
||||
FastAPI'ye, diğer kullanıcılara ve yazara yardım etmek ister misiniz?
|
||||
|
||||
Yoksa **FastAPI** ile ilgili yardım mı almak istiyorsunuz?
|
||||
|
||||
Yardım etmenin çok basit yolları var (bazıları sadece bir-iki tıklama gerektirir).
|
||||
|
||||
Yardım almanın da birkaç yolu var.
|
||||
|
||||
## Bültene abone olun { #subscribe-to-the-newsletter }
|
||||
|
||||
Şunlardan haberdar olmak için (seyrek yayımlanan) [**FastAPI and friends** bültenine](newsletter.md){.internal-link target=_blank} abone olabilirsiniz:
|
||||
|
||||
* FastAPI ve friends ile ilgili haberler 🚀
|
||||
* Rehberler 📝
|
||||
* Özellikler ✨
|
||||
* Geriye dönük uyumsuz değişiklikler 🚨
|
||||
* İpuçları ve püf noktaları ✅
|
||||
|
||||
## X (Twitter) üzerinden FastAPI'yi takip edin { #follow-fastapi-on-x-twitter }
|
||||
|
||||
**FastAPI** ile ilgili en güncel haberleri almak için <a href="https://x.com/fastapi" class="external-link" target="_blank">@fastapi hesabını **X (Twitter)** üzerinde takip edin</a>. 🐦
|
||||
|
||||
## GitHub'da **FastAPI**'ye yıldız verin { #star-fastapi-in-github }
|
||||
|
||||
GitHub'da FastAPI'ye "star" verebilirsiniz (sağ üstteki yıldız butonuna tıklayarak): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
|
||||
|
||||
Yıldız verince, diğer kullanıcılar projeyi daha kolay bulabilir ve başkaları için de faydalı olduğunu görebilir.
|
||||
|
||||
## GitHub repository'sini release'ler için izleyin { #watch-the-github-repository-for-releases }
|
||||
|
||||
GitHub'da FastAPI'yi "watch" edebilirsiniz (sağ üstteki "watch" butonuna tıklayarak): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
|
||||
Orada "Releases only" seçebilirsiniz.
|
||||
|
||||
Böylece **FastAPI**'nin bug fix'ler ve yeni özelliklerle gelen her yeni release'inde (yeni versiyonunda) email ile bildirim alırsınız.
|
||||
|
||||
## Yazarla bağlantı kurun { #connect-with-the-author }
|
||||
|
||||
Yazar olan <a href="https://tiangolo.com" class="external-link" target="_blank">benimle (Sebastián Ramírez / `tiangolo`)</a> bağlantı kurabilirsiniz.
|
||||
|
||||
Şunları yapabilirsiniz:
|
||||
|
||||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Beni **GitHub**'da takip edin</a>.
|
||||
* Size yardımcı olabilecek oluşturduğum diğer Open Source projelere göz atın.
|
||||
* Yeni bir Open Source proje oluşturduğumda haberdar olmak için beni takip edin.
|
||||
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">Beni **X (Twitter)** üzerinde</a> veya <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>'da takip edin.
|
||||
* FastAPI'yi nasıl kullandığınızı anlatın (bunu duymayı seviyorum).
|
||||
* Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun.
|
||||
* Ayrıca (ayrı bir hesap olan) <a href="https://x.com/fastapi" class="external-link" target="_blank">X (Twitter) üzerinde @fastapi hesabını da takip edebilirsiniz</a>.
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Beni **LinkedIn**'de takip edin</a>.
|
||||
* Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun (gerçi X (Twitter)'ı daha sık kullanıyorum 🤷♂).
|
||||
* <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> veya <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a> üzerinde yazdıklarımı okuyun (ya da beni takip edin).
|
||||
* Diğer fikirleri, yazıları ve oluşturduğum araçlarla ilgili içerikleri okuyun.
|
||||
* Yeni bir şey yayınladığımda görmek için beni takip edin.
|
||||
|
||||
## **FastAPI** hakkında tweet atın { #tweet-about-fastapi }
|
||||
|
||||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI** hakkında tweet atın</a> ve neden sevdiğinizi bana ve diğerlerine söyleyin. 🎉
|
||||
|
||||
**FastAPI**'nin nasıl kullanıldığını, nelerini sevdiğinizi, hangi projede/şirkette kullandığınızı vb. duymayı seviyorum.
|
||||
|
||||
## FastAPI için oy verin { #vote-for-fastapi }
|
||||
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Slant'ta **FastAPI** için oy verin</a>.
|
||||
* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">AlternativeTo'da **FastAPI** için oy verin</a>.
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare'de **FastAPI** kullandığınızı belirtin</a>.
|
||||
|
||||
## GitHub'da sorularla başkalarına yardım edin { #help-others-with-questions-in-github }
|
||||
|
||||
Şuralarda insanların sorularına yardımcı olmayı deneyebilirsiniz:
|
||||
|
||||
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
|
||||
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
|
||||
|
||||
Birçok durumda bu soruların cevabını zaten biliyor olabilirsiniz. 🤓
|
||||
|
||||
Eğer insanların sorularına çok yardım ederseniz, resmi bir [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank} olabilirsiniz. 🎉
|
||||
|
||||
Şunu unutmayın: en önemli nokta, nazik olmaya çalışmak. İnsanlar çoğu zaman biriken stresle geliyor ve birçok durumda soruyu en iyi şekilde sormuyor; yine de elinizden geldiğince nazik olmaya çalışın. 🤗
|
||||
|
||||
Amaç, **FastAPI** topluluğunun nazik ve kapsayıcı olması. Aynı zamanda başkalarına zorbalık ya da saygısız davranışları da kabul etmeyin. Birbirimizi kollamalıyız.
|
||||
|
||||
---
|
||||
|
||||
Sorularda (discussions veya issues içinde) başkalarına yardım etmek için şunları yapabilirsiniz:
|
||||
|
||||
### Soruyu anlayın { #understand-the-question }
|
||||
|
||||
* Soru soran kişinin **amacının** ve kullanım senaryosunun ne olduğunu anlayabiliyor musunuz, kontrol edin.
|
||||
|
||||
* Sonra sorunun (büyük çoğunluğu soru olur) **net** olup olmadığına bakın.
|
||||
|
||||
* Birçok durumda kullanıcı kafasında hayali bir çözüm kurup onu sorar; ancak **daha iyi** bir çözüm olabilir. Problemi ve kullanım senaryosunu daha iyi anladıysanız daha iyi bir **alternatif çözüm** önerebilirsiniz.
|
||||
|
||||
* Soruyu anlayamıyorsanız daha fazla **detay** isteyin.
|
||||
|
||||
### Problemi yeniden üretin { #reproduce-the-problem }
|
||||
|
||||
Çoğu durumda ve çoğu soruda, kişinin **orijinal kodu** ile ilgili bir şey vardır.
|
||||
|
||||
Birçok kişi sadece kodun bir parçasını kopyalar, ama bu **problemi yeniden üretmek** için yeterli olmaz.
|
||||
|
||||
* Çalıştırıp aynı hatayı/davranışı görebileceğiniz veya kullanım senaryosunu daha iyi anlayabileceğiniz, yerelde **kopyala-yapıştır** yaparak çalıştırılabilen bir <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">minimal, reproducible, example</a> paylaşmalarını isteyebilirsiniz.
|
||||
|
||||
* Çok cömert hissediyorsanız, problemi anlatan açıklamadan yola çıkarak kendiniz de böyle bir **örnek oluşturmayı** deneyebilirsiniz. Ancak bunun çok zaman alabileceğini unutmayın; çoğu zaman önce problemi netleştirmelerini istemek daha iyidir.
|
||||
|
||||
### Çözüm önerin { #suggest-solutions }
|
||||
|
||||
* Soruyu anlayabildikten sonra olası bir **cevap** verebilirsiniz.
|
||||
|
||||
* Çoğu durumda, yapmak istediklerinden ziyade alttaki **asıl problemi veya kullanım senaryosunu** anlamak daha iyidir; çünkü denedikleri yöntemden daha iyi bir çözüm yolu olabilir.
|
||||
|
||||
### Kapatılmasını isteyin { #ask-to-close }
|
||||
|
||||
Eğer yanıt verirlerse, büyük ihtimalle problemi çözmüşsünüzdür, tebrikler, **kahramansınız**! 🦸
|
||||
|
||||
* Eğer çözüm işe yaradıysa şunları yapmalarını isteyebilirsiniz:
|
||||
|
||||
* GitHub Discussions'ta: ilgili yorumu **answer** olarak işaretlemeleri.
|
||||
* GitHub Issues'ta: issue'yu **close** etmeleri.
|
||||
|
||||
## GitHub repository'sini izleyin { #watch-the-github-repository }
|
||||
|
||||
GitHub'da FastAPI'yi "watch" edebilirsiniz (sağ üstteki "watch" butonuna tıklayarak): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
|
||||
"Releases only" yerine "Watching" seçerseniz biri yeni bir issue veya soru oluşturduğunda bildirim alırsınız. Ayrıca sadece yeni issue'lar, ya da discussions, ya da PR'lar vb. için bildirim almak istediğinizi belirtebilirsiniz.
|
||||
|
||||
Sonra da bu soruları çözmelerine yardımcı olmayı deneyebilirsiniz.
|
||||
|
||||
## Soru Sorun { #ask-questions }
|
||||
|
||||
GitHub repository'sinde örneğin şunlar için <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">yeni bir soru oluşturabilirsiniz</a>:
|
||||
|
||||
* Bir **soru** sorun veya bir **problem** hakkında danışın.
|
||||
* Yeni bir **feature** önerin.
|
||||
|
||||
**Not**: Bunu yaparsanız, ben de sizden başkalarına yardım etmenizi isteyeceğim. 😉
|
||||
|
||||
## Pull Request'leri İnceleyin { #review-pull-requests }
|
||||
|
||||
Başkalarının gönderdiği pull request'leri incelememde bana yardımcı olabilirsiniz.
|
||||
|
||||
Yine, lütfen elinizden geldiğince nazik olmaya çalışın. 🤗
|
||||
|
||||
---
|
||||
|
||||
Bir pull request'i incelerken akılda tutmanız gerekenler:
|
||||
|
||||
### Problemi anlayın { #understand-the-problem }
|
||||
|
||||
* Önce, pull request'in çözmeye çalıştığı **problemi anladığınızdan** emin olun. GitHub Discussion veya issue içinde daha uzun bir tartışması olabilir.
|
||||
|
||||
* Pull request'in aslında hiç gerekmiyor olma ihtimali de yüksektir; çünkü problem **farklı bir şekilde** çözülebilir. Bu durumda bunu önerebilir veya bununla ilgili soru sorabilirsiniz.
|
||||
|
||||
### Style konusunda çok dert etmeyin { #dont-worry-about-style }
|
||||
|
||||
* Commit message tarzı gibi şeyleri çok dert etmeyin; ben commit'leri manuel olarak düzenleyerek squash and merge yapacağım.
|
||||
|
||||
* Style kuralları için de endişelenmeyin; bunları kontrol eden otomatik araçlar zaten var.
|
||||
|
||||
Ek bir style veya tutarlılık ihtiyacı olursa, bunu doğrudan isterim ya da gerekli değişikliklerle üstüne commit eklerim.
|
||||
|
||||
### Kodu kontrol edin { #check-the-code }
|
||||
|
||||
* Kodu okuyup kontrol edin; mantıklı mı bakın, **yerelde çalıştırın** ve gerçekten problemi çözüyor mu görün.
|
||||
|
||||
* Ardından bunu yaptığınızı belirten bir **yorum** yazın; böylece gerçekten kontrol ettiğinizi anlarım.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Ne yazık ki sadece birkaç onayı olan PR'lara körü körüne güvenemem.
|
||||
|
||||
Defalarca, 3, 5 veya daha fazla onayı olan PR'lar oldu; muhtemelen açıklaması çekici olduğu için onay aldılar. Ama PR'lara baktığımda aslında bozuk olduklarını, bug içerdiğini veya iddia ettikleri problemi çözmediklerini gördüm. 😅
|
||||
|
||||
Bu yüzden kodu gerçekten okuyup çalıştırmanız ve bunu yorumlarda bana bildirmeniz çok önemli. 🤓
|
||||
|
||||
///
|
||||
|
||||
* PR bir şekilde basitleştirilebiliyorsa bunu isteyebilirsiniz. Ancak çok didik didik etmeye gerek yok; konuya göre birçok öznel bakış açısı olabilir (benim de olacaktır 🙈). Bu yüzden temel noktalara odaklanmak daha iyi.
|
||||
|
||||
### Testler { #tests }
|
||||
|
||||
* PR'da **testler** olduğunu kontrol etmemde bana yardımcı olun.
|
||||
|
||||
* PR'dan önce testlerin **fail** ettiğini kontrol edin. 🚨
|
||||
|
||||
* PR'dan sonra testlerin **pass** ettiğini kontrol edin. ✅
|
||||
|
||||
* Birçok PR test içermez; test eklemelerini **hatırlatabilirsiniz** veya hatta kendiniz bazı testler **önerebilirsiniz**. Bu, en çok zaman alan işlerden biridir ve burada çok yardımcı olabilirsiniz.
|
||||
|
||||
* Ayrıca neleri denediğinizi yorumlara yazın; böylece kontrol ettiğinizi anlarım. 🤓
|
||||
|
||||
## Pull Request Oluşturun { #create-a-pull-request }
|
||||
|
||||
Örneğin şunlar için Pull Request'lerle kaynak koda [katkıda bulunabilirsiniz](contributing.md){.internal-link target=_blank}:
|
||||
|
||||
* Dokümantasyonda bulduğunuz bir yazım hatasını düzeltmek.
|
||||
* FastAPI hakkında oluşturduğunuz veya bulduğunuz bir makaleyi, videoyu ya da podcast'i <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">bu dosyayı düzenleyerek</a> paylaşmak.
|
||||
* Link'inizi ilgili bölümün başına eklediğinizden emin olun.
|
||||
* Dokümantasyonu kendi dilinize [çevirmeye yardımcı olmak](contributing.md#translations){.internal-link target=_blank}.
|
||||
* Başkalarının yaptığı çevirileri gözden geçirmeye de yardımcı olabilirsiniz.
|
||||
* Yeni dokümantasyon bölümleri önermek.
|
||||
* Mevcut bir issue/bug'ı düzeltmek.
|
||||
* Test eklediğinizden emin olun.
|
||||
* Yeni bir feature eklemek.
|
||||
* Test eklediğinizden emin olun.
|
||||
* İlgiliyse dokümantasyon da eklediğinizden emin olun.
|
||||
|
||||
## FastAPI'nin Bakımına Yardım Edin { #help-maintain-fastapi }
|
||||
|
||||
**FastAPI**'nin bakımını yapmama yardımcı olun! 🤓
|
||||
|
||||
Yapılacak çok iş var ve bunların çoğunu **SİZ** yapabilirsiniz.
|
||||
|
||||
Şu anda yapabileceğiniz ana işler:
|
||||
|
||||
* [GitHub'da sorularla başkalarına yardım edin](#help-others-with-questions-in-github){.internal-link target=_blank} (yukarıdaki bölüme bakın).
|
||||
* [Pull Request'leri inceleyin](#review-pull-requests){.internal-link target=_blank} (yukarıdaki bölüme bakın).
|
||||
|
||||
Bu iki iş, **en çok zamanı alan** işlerdir. FastAPI bakımının ana yükü buradadır.
|
||||
|
||||
Burada yardımcı olursanız, **FastAPI'nin bakımını yapmama yardım etmiş** ve daha **hızlı ve daha iyi ilerlemesini** sağlamış olursunuz. 🚀
|
||||
|
||||
## Sohbete katılın { #join-the-chat }
|
||||
|
||||
FastAPI topluluğundan diğer kişilerle takılmak için 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord chat server</a> 👥 sohbetine katılın.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Sorular için <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>'a sorun; [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank} tarafından yardım alma ihtimaliniz çok daha yüksektir.
|
||||
|
||||
Chat'i sadece genel sohbetler için kullanın.
|
||||
|
||||
///
|
||||
|
||||
### Sorular için chat'i kullanmayın { #dont-use-the-chat-for-questions }
|
||||
|
||||
Chat sistemleri daha "serbest sohbet"e izin verdiği için, çok genel ve yanıtlaması daha zor sorular sormak kolaylaşır; bu nedenle cevap alamayabilirsiniz.
|
||||
|
||||
GitHub'da ise şablon (template) doğru soruyu yazmanız için sizi yönlendirir; böylece daha kolay iyi bir cevap alabilir, hatta bazen sormadan önce problemi kendiniz çözebilirsiniz. Ayrıca GitHub'da (zaman alsa bile) her şeye mutlaka cevap verdiğimden emin olabilirim. Chat sistemlerinde bunu kişisel olarak yapamam. 😅
|
||||
|
||||
Chat sistemlerindeki konuşmalar GitHub kadar kolay aranabilir değildir; bu yüzden soru ve cevaplar sohbet içinde kaybolabilir. Ayrıca [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank} olmak için sadece GitHub'daki katkılar sayılır; dolayısıyla büyük olasılıkla GitHub'da daha fazla ilgi görürsünüz.
|
||||
|
||||
Öte yandan chat sistemlerinde binlerce kullanıcı vardır; bu yüzden neredeyse her zaman konuşacak birini bulma ihtimaliniz yüksektir. 😄
|
||||
|
||||
## Yazara sponsor olun { #sponsor-the-author }
|
||||
|
||||
Eğer **ürününüz/şirketiniz** **FastAPI**'ye bağlıysa veya onunla ilişkiliyse ve FastAPI kullanıcılarına ulaşmak istiyorsanız, <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a> üzerinden yazara (bana) sponsor olabilirsiniz. Tier'a göre dokümantasyonda bir rozet gibi ek faydalar elde edebilirsiniz. 🎁
|
||||
|
||||
---
|
||||
|
||||
Teşekkürler! 🚀
|
||||
@@ -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,13 +38,13 @@ 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.
|
||||
|
||||
Çeşitli fikirleri en popüler Python editörlerinde test ettim: PyCharm, VS Code, Jedi tabanlı editörler.
|
||||
|
||||
Bu test, en son <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">Python Developer Survey</a>'ine göre, kullanıcıların yaklaşık %80'inin kullandığı editörleri kapsıyor.
|
||||
Bu test, en son <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">Python Geliştirici Anketi</a>'ine göre, kullanıcıların yaklaşık %80'inin kullandığı editörleri kapsıyor.
|
||||
|
||||
Bu da demek oluyor ki **FastAPI**, Python geliştiricilerinin %80'inin kullandığı editörlerle test edildi. Ve diğer editörlerin çoğu benzer şekilde çalıştığından, avantajları neredeyse tüm editörlerde çalışacaktır.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Eski 403 Kimlik Doğrulama Hata Durum Kodlarını Kullanma { #use-old-403-authentication-error-status-codes }
|
||||
|
||||
FastAPI `0.122.0` sürümünden önce, entegre security yardımcı araçları başarısız bir kimlik doğrulama (authentication) sonrasında client'a bir hata döndüğünde HTTP durum kodu olarak `403 Forbidden` kullanıyordu.
|
||||
|
||||
FastAPI `0.122.0` sürümünden itibaren ise daha uygun olan HTTP durum kodu `401 Unauthorized` kullanılmakta ve HTTP spesifikasyonlarına uygun olarak response içinde anlamlı bir `WWW-Authenticate` header'ı döndürülmektedir: <a href="https://datatracker.ietf.org/doc/html/rfc7235#section-3.1" class="external-link" target="_blank">RFC 7235</a>, <a href="https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized" class="external-link" target="_blank">RFC 9110</a>.
|
||||
|
||||
Ancak herhangi bir nedenle client'larınız eski davranışa bağlıysa, security class'larınızda `make_not_authenticated_error` metodunu override ederek eski davranışa geri dönebilirsiniz.
|
||||
|
||||
Örneğin, varsayılan `401 Unauthorized` hatası yerine `403 Forbidden` hatası döndüren bir `HTTPBearer` alt sınıfı oluşturabilirsiniz:
|
||||
|
||||
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Fonksiyonun exception instance'ını döndürdüğüne dikkat edin; exception'ı raise etmiyor. Raise işlemi internal kodun geri kalan kısmında yapılıyor.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,56 @@
|
||||
# Koşullu OpenAPI { #conditional-openapi }
|
||||
|
||||
Gerekirse, ayarlar ve environment variable'ları kullanarak OpenAPI'yi ortama göre koşullu şekilde yapılandırabilir, hatta tamamen devre dışı bırakabilirsiniz.
|
||||
|
||||
## Güvenlik, API'ler ve dokümantasyon hakkında { #about-security-apis-and-docs }
|
||||
|
||||
Production ortamında dokümantasyon arayüzlerini gizlemek, API'nizi korumanın yolu olmamalıdır.
|
||||
|
||||
Bu, API'nize ekstra bir güvenlik katmanı eklemez; path operation'lar bulundukları yerde yine erişilebilir olacaktır.
|
||||
|
||||
Kodunuzda bir güvenlik açığı varsa, o açık yine var olmaya devam eder.
|
||||
|
||||
Dokümantasyonu gizlemek, API'nizle nasıl etkileşime geçileceğini anlamayı zorlaştırır ve production'da debug etmeyi de daha zor hale getirebilir. Bu yaklaşım, basitçe <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">Security through obscurity</a> olarak değerlendirilebilir.
|
||||
|
||||
API'nizi güvence altına almak istiyorsanız, yapabileceğiniz daha iyi birçok şey var; örneğin:
|
||||
|
||||
* request body'leriniz ve response'larınız için iyi tanımlanmış Pydantic model'larına sahip olduğunuzdan emin olun.
|
||||
* dependencies kullanarak gerekli izinleri ve rolleri yapılandırın.
|
||||
* Asla düz metin (plaintext) şifre saklamayın, yalnızca password hash'leri saklayın.
|
||||
* pwdlib ve JWT token'ları gibi, iyi bilinen kriptografik araçları uygulayın ve kullanın.
|
||||
* Gerektiğinde OAuth2 scope'ları ile daha ayrıntılı izin kontrolleri ekleyin.
|
||||
* ...vb.
|
||||
|
||||
Yine de, bazı ortamlarda (örn. production) veya environment variable'lardan gelen konfigürasyonlara bağlı olarak API docs'u gerçekten devre dışı bırakmanız gereken çok spesifik bir use case'iniz olabilir.
|
||||
|
||||
## Ayarlar ve env var'lar ile koşullu OpenAPI { #conditional-openapi-from-settings-and-env-vars }
|
||||
|
||||
Üretilen OpenAPI'yi ve docs UI'larını yapılandırmak için aynı Pydantic settings'i kolayca kullanabilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
|
||||
|
||||
Burada `openapi_url` ayarını, varsayılanı `"/openapi.json"` olacak şekilde tanımlıyoruz.
|
||||
|
||||
Ardından `FastAPI` app'ini oluştururken bunu kullanıyoruz.
|
||||
|
||||
Sonrasında, environment variable `OPENAPI_URL`'i boş string olarak ayarlayarak OpenAPI'yi (UI docs dahil) devre dışı bırakabilirsiniz; örneğin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ OPENAPI_URL= uvicorn main:app
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Böylece `/openapi.json`, `/docs` veya `/redoc` URL'lerine giderseniz, aşağıdaki gibi bir `404 Not Found` hatası alırsınız:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": "Not Found"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,70 @@
|
||||
# Swagger UI'yi Yapılandırın { #configure-swagger-ui }
|
||||
|
||||
Bazı ek <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI parametrelerini</a> yapılandırabilirsiniz.
|
||||
|
||||
Bunları yapılandırmak için, `FastAPI()` uygulama nesnesini oluştururken ya da `get_swagger_ui_html()` fonksiyonuna `swagger_ui_parameters` argümanını verin.
|
||||
|
||||
`swagger_ui_parameters`, Swagger UI'ye doğrudan iletilecek yapılandırmaları içeren bir `dict` alır.
|
||||
|
||||
FastAPI, Swagger UI'nin ihtiyaç duyduğu şekilde JavaScript ile uyumlu olsun diye bu yapılandırmaları **JSON**'a dönüştürür.
|
||||
|
||||
## Syntax Highlighting'i Devre Dışı Bırakın { #disable-syntax-highlighting }
|
||||
|
||||
Örneğin, Swagger UI'de syntax highlighting'i devre dışı bırakabilirsiniz.
|
||||
|
||||
Ayarları değiştirmeden bırakırsanız, syntax highlighting varsayılan olarak etkindir:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image02.png">
|
||||
|
||||
Ancak `syntaxHighlight` değerini `False` yaparak devre dışı bırakabilirsiniz:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
|
||||
|
||||
...ve ardından Swagger UI artık syntax highlighting'i göstermeyecektir:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image03.png">
|
||||
|
||||
## Temayı Değiştirin { #change-the-theme }
|
||||
|
||||
Aynı şekilde, `"syntaxHighlight.theme"` anahtarıyla (ortasında bir nokta olduğuna dikkat edin) syntax highlighting temasını ayarlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
|
||||
|
||||
Bu yapılandırma, syntax highlighting renk temasını değiştirir:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image04.png">
|
||||
|
||||
## Varsayılan Swagger UI Parametrelerini Değiştirin { #change-default-swagger-ui-parameters }
|
||||
|
||||
FastAPI, çoğu kullanım senaryosu için uygun bazı varsayılan yapılandırma parametreleriyle gelir.
|
||||
|
||||
Şu varsayılan yapılandırmaları içerir:
|
||||
|
||||
{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
|
||||
|
||||
`swagger_ui_parameters` argümanında farklı bir değer vererek bunların herhangi birini ezebilirsiniz (override).
|
||||
|
||||
Örneğin `deepLinking`'i devre dışı bırakmak için `swagger_ui_parameters`'a şu ayarları geçebilirsiniz:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
|
||||
|
||||
## Diğer Swagger UI Parametreleri { #other-swagger-ui-parameters }
|
||||
|
||||
Kullanabileceğiniz diğer tüm olası yapılandırmaları görmek için, resmi <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI parametreleri dokümantasyonunu</a> okuyun.
|
||||
|
||||
## Yalnızca JavaScript Ayarları { #javascript-only-settings }
|
||||
|
||||
Swagger UI ayrıca bazı yapılandırmaların **yalnızca JavaScript** nesneleri olmasına izin verir (örneğin JavaScript fonksiyonları).
|
||||
|
||||
FastAPI, bu yalnızca JavaScript olan `presets` ayarlarını da içerir:
|
||||
|
||||
```JavaScript
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
]
|
||||
```
|
||||
|
||||
Bunlar string değil, **JavaScript** nesneleridir; dolayısıyla bunları Python kodundan doğrudan geçemezsiniz.
|
||||
|
||||
Böyle yalnızca JavaScript yapılandırmalarına ihtiyacınız varsa, yukarıdaki yöntemlerden birini kullanabilirsiniz: Swagger UI'nin tüm *path operation*'larını override edin ve ihtiyaç duyduğunuz JavaScript'i elle yazın.
|
||||
@@ -0,0 +1,185 @@
|
||||
# Özel Docs UI Statik Varlıkları (Self-Hosting) { #custom-docs-ui-static-assets-self-hosting }
|
||||
|
||||
API dokümanları **Swagger UI** ve **ReDoc** kullanır ve bunların her biri bazı JavaScript ve CSS dosyalarına ihtiyaç duyar.
|
||||
|
||||
Varsayılan olarak bu dosyalar bir <abbr title="Content Delivery Network - İçerik Dağıtım Ağı: Genellikle JavaScript ve CSS gibi statik dosyaları sunan, çoğunlukla birden fazla sunucudan oluşan bir servis. Bu dosyaları istemciye daha yakın bir sunucudan sunarak performansı artırmak için yaygın şekilde kullanılır.">CDN</abbr> üzerinden servis edilir.
|
||||
|
||||
Ancak bunu özelleştirmek mümkündür; belirli bir CDN ayarlayabilir veya dosyaları kendiniz servis edebilirsiniz.
|
||||
|
||||
## JavaScript ve CSS için Özel CDN { #custom-cdn-for-javascript-and-css }
|
||||
|
||||
Diyelim ki farklı bir <abbr title="Content Delivery Network - İçerik Dağıtım Ağı">CDN</abbr> kullanmak istiyorsunuz; örneğin `https://unpkg.com/` kullanmak istiyorsunuz.
|
||||
|
||||
Bu, örneğin bazı URL'leri kısıtlayan bir ülkede yaşıyorsanız faydalı olabilir.
|
||||
|
||||
### Otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs }
|
||||
|
||||
İlk adım, otomatik dokümanları devre dışı bırakmaktır; çünkü varsayılan olarak bunlar varsayılan CDN'i kullanır.
|
||||
|
||||
Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
|
||||
|
||||
### Özel dokümanları ekleyin { #include-the-custom-docs }
|
||||
|
||||
Şimdi özel dokümanlar için *path operation*'ları oluşturabilirsiniz.
|
||||
|
||||
Dokümanlar için HTML sayfalarını üretmek üzere FastAPI'nin dahili fonksiyonlarını yeniden kullanabilir ve gerekli argümanları iletebilirsiniz:
|
||||
|
||||
* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz.
|
||||
* `title`: API'nizin başlığı.
|
||||
* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz.
|
||||
* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. Bu, özel CDN URL'idir.
|
||||
* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. Bu, özel CDN URL'idir.
|
||||
|
||||
ReDoc için de benzer şekilde...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır.
|
||||
|
||||
API'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz.
|
||||
|
||||
Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcısına ihtiyaç duyar.
|
||||
|
||||
///
|
||||
|
||||
### Test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-it }
|
||||
|
||||
Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
|
||||
|
||||
### Test edin { #test-it }
|
||||
|
||||
Artık <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresinden dokümanlarınıza gidebilmeli ve sayfayı yenilediğinizde bu varlıkların yeni CDN'den yüklendiğini görebilmelisiniz.
|
||||
|
||||
## Dokümanlar için JavaScript ve CSS'i Self-Hosting ile barındırma { #self-hosting-javascript-and-css-for-docs }
|
||||
|
||||
JavaScript ve CSS'i self-hosting ile barındırmak, örneğin uygulamanızın İnternet erişimi olmadan (offline), açık İnternet olmadan veya bir lokal ağ içinde bile çalışmaya devam etmesi gerekiyorsa faydalı olabilir.
|
||||
|
||||
Burada bu dosyaları aynı FastAPI uygulamasında nasıl kendiniz servis edeceğinizi ve dokümanların bunları kullanacak şekilde nasıl yapılandırılacağını göreceksiniz.
|
||||
|
||||
### Proje dosya yapısı { #project-file-structure }
|
||||
|
||||
Diyelim ki projenizin dosya yapısı şöyle:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
```
|
||||
|
||||
Şimdi bu statik dosyaları saklamak için bir dizin oluşturun.
|
||||
|
||||
Yeni dosya yapınız şöyle olabilir:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
└── static/
|
||||
```
|
||||
|
||||
### Dosyaları indirin { #download-the-files }
|
||||
|
||||
Dokümanlar için gereken statik dosyaları indirin ve `static/` dizinine koyun.
|
||||
|
||||
Muhtemelen her bir linke sağ tıklayıp "Save link as..." benzeri bir seçenek seçebilirsiniz.
|
||||
|
||||
**Swagger UI** şu dosyaları kullanır:
|
||||
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||
|
||||
**ReDoc** ise şu dosyayı kullanır:
|
||||
|
||||
* <a href="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
|
||||
|
||||
Bundan sonra dosya yapınız şöyle görünebilir:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
└── static
|
||||
├── redoc.standalone.js
|
||||
├── swagger-ui-bundle.js
|
||||
└── swagger-ui.css
|
||||
```
|
||||
|
||||
### Statik dosyaları servis edin { #serve-the-static-files }
|
||||
|
||||
* `StaticFiles` içe aktarın.
|
||||
* Belirli bir path'te bir `StaticFiles()` instance'ını "mount" edin.
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
|
||||
|
||||
### Statik dosyaları test edin { #test-the-static-files }
|
||||
|
||||
Uygulamanızı başlatın ve <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a> adresine gidin.
|
||||
|
||||
**ReDoc** için çok uzun bir JavaScript dosyası görmelisiniz.
|
||||
|
||||
Şuna benzer bir şekilde başlayabilir:
|
||||
|
||||
```JavaScript
|
||||
/*! For license information please see redoc.standalone.js.LICENSE.txt */
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
|
||||
...
|
||||
```
|
||||
|
||||
Bu, uygulamanızdan statik dosyaları servis edebildiğinizi ve dokümanlar için statik dosyaları doğru yere koyduğunuzu doğrular.
|
||||
|
||||
Şimdi uygulamayı, dokümanlar için bu statik dosyaları kullanacak şekilde yapılandırabiliriz.
|
||||
|
||||
### Statik dosyalar için otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs-for-static-files }
|
||||
|
||||
Özel CDN kullanırken olduğu gibi, ilk adım otomatik dokümanları devre dışı bırakmaktır; çünkü bunlar varsayılan olarak CDN kullanır.
|
||||
|
||||
Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
|
||||
|
||||
### Statik dosyalar için özel dokümanları ekleyin { #include-the-custom-docs-for-static-files }
|
||||
|
||||
Özel CDN'de olduğu gibi, artık özel dokümanlar için *path operation*'ları oluşturabilirsiniz.
|
||||
|
||||
Yine FastAPI'nin dahili fonksiyonlarını kullanarak dokümanlar için HTML sayfalarını oluşturabilir ve gerekli argümanları geçebilirsiniz:
|
||||
|
||||
* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz.
|
||||
* `title`: API'nizin başlığı.
|
||||
* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz.
|
||||
* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**.
|
||||
* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**.
|
||||
|
||||
ReDoc için de benzer şekilde...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır.
|
||||
|
||||
API'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz.
|
||||
|
||||
Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcısına ihtiyaç duyar.
|
||||
|
||||
///
|
||||
|
||||
### Statik dosyaları test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-static-files }
|
||||
|
||||
Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
|
||||
|
||||
### Statik Dosyalar UI'ını Test Edin { #test-static-files-ui }
|
||||
|
||||
Artık WiFi bağlantınızı kesip <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresindeki dokümanlarınıza gidebilmeli ve sayfayı yenileyebilmelisiniz.
|
||||
|
||||
Ve İnternet olmasa bile API dokümanlarınızı görebilir ve onunla etkileşime geçebilirsiniz.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Özel Request ve APIRoute sınıfı { #custom-request-and-apiroute-class }
|
||||
|
||||
Bazı durumlarda, `Request` ve `APIRoute` sınıflarının kullandığı mantığı override etmek isteyebilirsiniz.
|
||||
|
||||
Özellikle bu yaklaşım, bir middleware içindeki mantığa iyi bir alternatif olabilir.
|
||||
|
||||
Örneğin, request body uygulamanız tarafından işlenmeden önce okumak veya üzerinde değişiklik yapmak istiyorsanız.
|
||||
|
||||
/// danger | Uyarı
|
||||
|
||||
Bu "ileri seviye" bir özelliktir.
|
||||
|
||||
**FastAPI**'ye yeni başlıyorsanız bu bölümü atlamak isteyebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## Kullanım senaryoları { #use-cases }
|
||||
|
||||
Bazı kullanım senaryoları:
|
||||
|
||||
* JSON olmayan request body'leri JSON'a dönüştürmek (örn. <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>).
|
||||
* gzip ile sıkıştırılmış request body'leri açmak (decompress).
|
||||
* Tüm request body'lerini otomatik olarak loglamak.
|
||||
|
||||
## Özel request body encoding'lerini ele alma { #handling-custom-request-body-encodings }
|
||||
|
||||
Gzip request'lerini açmak için özel bir `Request` alt sınıfını nasıl kullanabileceğimize bakalım.
|
||||
|
||||
Ayrıca, o özel request sınıfını kullanmak için bir `APIRoute` alt sınıfı da oluşturacağız.
|
||||
|
||||
### Özel bir `GzipRequest` sınıfı oluşturun { #create-a-custom-gziprequest-class }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu, nasıl çalıştığını göstermek için hazırlanmış basit bir örnektir; Gzip desteğine ihtiyacınız varsa sağlanan [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} bileşenini kullanabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Önce, uygun bir header mevcut olduğunda body'yi açmak için `Request.body()` metodunu overwrite edecek bir `GzipRequest` sınıfı oluşturuyoruz.
|
||||
|
||||
Header'da `gzip` yoksa body'yi açmayı denemez.
|
||||
|
||||
Böylece aynı route sınıfı, gzip ile sıkıştırılmış veya sıkıştırılmamış request'leri handle edebilir.
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
|
||||
|
||||
### Özel bir `GzipRoute` sınıfı oluşturun { #create-a-custom-gziproute-class }
|
||||
|
||||
Sonra, `GzipRequest`'i kullanacak `fastapi.routing.APIRoute` için özel bir alt sınıf oluşturuyoruz.
|
||||
|
||||
Bu kez `APIRoute.get_route_handler()` metodunu overwrite edeceğiz.
|
||||
|
||||
Bu metot bir fonksiyon döndürür. Bu fonksiyon da request'i alır ve response döndürür.
|
||||
|
||||
Burada bu fonksiyonu, orijinal request'ten bir `GzipRequest` oluşturmak için kullanıyoruz.
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Bir `Request`'in, request ile ilgili metadata'yı içeren bir Python `dict` olan `request.scope` attribute'u vardır.
|
||||
|
||||
Bir `Request` ayrıca `request.receive` içerir; bu, request'in body'sini "almak" (receive etmek) için kullanılan bir fonksiyondur.
|
||||
|
||||
`scope` `dict`'i ve `receive` fonksiyonu, ASGI spesifikasyonunun parçalarıdır.
|
||||
|
||||
Ve bu iki şey, `scope` ve `receive`, yeni bir `Request` instance'ı oluşturmak için gerekenlerdir.
|
||||
|
||||
`Request` hakkında daha fazla bilgi için <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">Starlette'ın Request dokümantasyonuna</a> bakın.
|
||||
|
||||
///
|
||||
|
||||
`GzipRequest.get_route_handler` tarafından döndürülen fonksiyonun farklı yaptığı tek şey, `Request`'i bir `GzipRequest`'e dönüştürmektir.
|
||||
|
||||
Bunu yaptığımızda `GzipRequest`, veriyi (gerekliyse) *path operations*'larımıza geçirmeden önce açma (decompress) işini üstlenir.
|
||||
|
||||
Bundan sonra tüm işleme mantığı aynıdır.
|
||||
|
||||
Ancak `GzipRequest.body` içindeki değişikliklerimiz sayesinde, request body gerektiğinde **FastAPI** tarafından yüklendiğinde otomatik olarak decompress edilir.
|
||||
|
||||
## Bir exception handler içinde request body'ye erişme { #accessing-the-request-body-in-an-exception-handler }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Aynı problemi çözmek için, muhtemelen `RequestValidationError` için özel bir handler içinde `body` kullanmak çok daha kolaydır ([Hataları Ele Alma](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
|
||||
|
||||
Yine de bu örnek geçerlidir ve dahili bileşenlerle nasıl etkileşime geçileceğini gösterir.
|
||||
|
||||
///
|
||||
|
||||
Aynı yaklaşımı bir exception handler içinde request body'ye erişmek için de kullanabiliriz.
|
||||
|
||||
Tek yapmamız gereken, request'i bir `try`/`except` bloğu içinde handle etmek:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
|
||||
|
||||
Bir exception oluşursa, `Request` instance'ı hâlâ scope içinde olacağı için, hatayı handle ederken request body'yi okuyup kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
|
||||
|
||||
## Bir router içinde özel `APIRoute` sınıfı { #custom-apiroute-class-in-a-router }
|
||||
|
||||
Bir `APIRouter` için `route_class` parametresini de ayarlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
|
||||
|
||||
Bu örnekte, `router` altındaki *path operations*'lar özel `TimedRoute` sınıfını kullanır ve response'u üretmek için geçen süreyi içeren ekstra bir `X-Response-Time` header'ı response'ta bulunur:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
|
||||
@@ -0,0 +1,80 @@
|
||||
# OpenAPI'yi Genişletme { #extending-openapi }
|
||||
|
||||
Oluşturulan OpenAPI şemasını değiştirmeniz gereken bazı durumlar olabilir.
|
||||
|
||||
Bu bölümde bunun nasıl yapılacağını göreceksiniz.
|
||||
|
||||
## Normal Süreç { #the-normal-process }
|
||||
|
||||
Normal (varsayılan) süreç şöyledir.
|
||||
|
||||
Bir `FastAPI` uygulamasının (instance) OpenAPI şemasını döndürmesi beklenen bir `.openapi()` metodu vardır.
|
||||
|
||||
Uygulama nesnesi oluşturulurken, `/openapi.json` (ya da `openapi_url` için ne ayarladıysanız o) için bir *path operation* kaydedilir.
|
||||
|
||||
Bu path operation, uygulamanın `.openapi()` metodunun sonucunu içeren bir JSON response döndürür.
|
||||
|
||||
Varsayılan olarak `.openapi()` metodunun yaptığı şey, `.openapi_schema` özelliğinde içerik olup olmadığını kontrol etmek ve varsa onu döndürmektir.
|
||||
|
||||
Eğer yoksa, `fastapi.openapi.utils.get_openapi` konumundaki yardımcı (utility) fonksiyonu kullanarak şemayı üretir.
|
||||
|
||||
Ve `get_openapi()` fonksiyonu şu parametreleri alır:
|
||||
|
||||
* `title`: Dokümanlarda gösterilen OpenAPI başlığı.
|
||||
* `version`: API'nizin sürümü, örn. `2.5.0`.
|
||||
* `openapi_version`: Kullanılan OpenAPI specification sürümü. Varsayılan olarak en günceli: `3.1.0`.
|
||||
* `summary`: API'nin kısa özeti.
|
||||
* `description`: API'nizin açıklaması; markdown içerebilir ve dokümanlarda gösterilir.
|
||||
* `routes`: route'ların listesi; bunların her biri kayıtlı *path operations*'lardır. `app.routes` içinden alınırlar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`summary` parametresi OpenAPI 3.1.0 ve üzeri sürümlerde vardır; FastAPI 0.99.0 ve üzeri tarafından desteklenmektedir.
|
||||
|
||||
///
|
||||
|
||||
## Varsayılanları Ezme { #overriding-the-defaults }
|
||||
|
||||
Yukarıdaki bilgileri kullanarak aynı yardımcı fonksiyonla OpenAPI şemasını üretebilir ve ihtiyacınız olan her parçayı override edebilirsiniz.
|
||||
|
||||
Örneğin, <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">özel bir logo eklemek için ReDoc'un OpenAPI extension'ını</a> ekleyelim.
|
||||
|
||||
### Normal **FastAPI** { #normal-fastapi }
|
||||
|
||||
Önce, tüm **FastAPI** uygulamanızı her zamanki gibi yazın:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
|
||||
|
||||
### OpenAPI Şemasını Üretme { #generate-the-openapi-schema }
|
||||
|
||||
Ardından, bir `custom_openapi()` fonksiyonunun içinde aynı yardımcı fonksiyonu kullanarak OpenAPI şemasını üretin:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
|
||||
|
||||
### OpenAPI Şemasını Değiştirme { #modify-the-openapi-schema }
|
||||
|
||||
Artık OpenAPI şemasındaki `info` "object"'ine özel bir `x-logo` ekleyerek ReDoc extension'ını ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
|
||||
|
||||
### OpenAPI Şemasını Cache'leme { #cache-the-openapi-schema }
|
||||
|
||||
Ürettiğiniz şemayı saklamak için `.openapi_schema` özelliğini bir "cache" gibi kullanabilirsiniz.
|
||||
|
||||
Böylece bir kullanıcı API docs'larınızı her açtığında uygulamanız şemayı tekrar tekrar üretmek zorunda kalmaz.
|
||||
|
||||
Şema yalnızca bir kez üretilecektir; sonraki request'ler için de aynı cache'lenmiş şema kullanılacaktır.
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
|
||||
|
||||
### Metodu Override Etme { #override-the-method }
|
||||
|
||||
Şimdi `.openapi()` metodunu yeni fonksiyonunuzla değiştirebilirsiniz.
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
|
||||
|
||||
### Kontrol Edin { #check-it }
|
||||
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gittiğinizde, özel logonuzu kullandığınızı göreceksiniz (bu örnekte **FastAPI**'nin logosu):
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image01.png">
|
||||
@@ -1,39 +1,39 @@
|
||||
# Genel - Nasıl Yapılır - Tarifler
|
||||
# Genel - Nasıl Yapılır - Tarifler { #general-how-to-recipes }
|
||||
|
||||
Bu sayfada genel ve sıkça sorulan sorular için dokümantasyonun diğer sayfalarına yönlendirmeler bulunmaktadır.
|
||||
Bu sayfada genel veya sık sorulan sorular için dokümantasyonun diğer bölümlerine çeşitli yönlendirmeler bulunmaktadır.
|
||||
|
||||
## Veri Filtreleme - Güvenlik
|
||||
## Veri Filtreleme - Güvenlik { #filter-data-security }
|
||||
|
||||
Döndürmeniz gereken veriden fazlasını döndürmediğinizden emin olmak için, [Tutorial - Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank} sayfasını okuyun.
|
||||
Döndürmeniz gerekenden daha fazla veri döndürmediğinizden emin olmak için, [Tutorial - Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## Dokümantasyon Etiketleri - OpenAPI
|
||||
## Dokümantasyon Etiketleri - OpenAPI { #documentation-tags-openapi }
|
||||
|
||||
*Yol operasyonlarınıza* etiketler ekleyerek dokümantasyon arayüzünde gruplar halinde görünmesini sağlamak için, [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank} sayfasını okuyun.
|
||||
*path operation*'larınıza etiketler eklemek ve dokümantasyon arayüzünde gruplamak için, [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## Dokümantasyon Özeti ve Açıklaması - OpenAPI
|
||||
## Dokümantasyon Özeti ve Açıklaması - OpenAPI { #documentation-summary-and-description-openapi }
|
||||
|
||||
*Yol operasyonlarınıza* özet ve açıklama ekleyip dokümantasyon arayüzünde görünmesini sağlamak için, [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank} sayfasını okuyun.
|
||||
*path operation*'larınıza özet ve açıklama eklemek ve bunları dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## Yanıt Açıklaması Dokümantasyonu - OpenAPI
|
||||
## Dokümantasyon Response Açıklaması - OpenAPI { #documentation-response-description-openapi }
|
||||
|
||||
Dokümantasyon arayüzünde yer alan yanıt açıklamasını tanımlamak için, [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank} sayfasını okuyun.
|
||||
Dokümantasyon arayüzünde gösterilen response açıklamasını tanımlamak için, [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## *Yol Operasyonunu* Kullanımdan Kaldırma - OpenAPI
|
||||
## Dokümantasyonda Bir *Path Operation*'ı Kullanımdan Kaldırma - OpenAPI { #documentation-deprecate-a-path-operation-openapi }
|
||||
|
||||
Bir *yol işlemi*ni kullanımdan kaldırmak ve bunu dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank} sayfasını okuyun.
|
||||
Bir *path operation*'ı kullanımdan kaldırmak ve bunu dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## Herhangi Bir Veriyi JSON Uyumlu Hale Getirme
|
||||
## Herhangi Bir Veriyi JSON Uyumlu Hale Getirme { #convert-any-data-to-json-compatible }
|
||||
|
||||
Herhangi bir veriyi JSON uyumlu hale getirmek için, [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} sayfasını okuyun.
|
||||
Herhangi bir veriyi JSON uyumlu hale getirmek için, [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## OpenAPI Meta Verileri - Dokümantasyon
|
||||
## OpenAPI Meta Verileri - Dokümantasyon { #openapi-metadata-docs }
|
||||
|
||||
OpenAPI şemanıza lisans, sürüm, iletişim vb. meta veriler eklemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md){.internal-link target=_blank} sayfasını okuyun.
|
||||
Lisans, sürüm, iletişim vb. dahil olmak üzere OpenAPI şemanıza meta veriler eklemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## OpenAPI Bağlantı Özelleştirme
|
||||
## OpenAPI Özel URL { #openapi-custom-url }
|
||||
|
||||
OpenAPI bağlantısını özelleştirmek (veya kaldırmak) için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url){.internal-link target=_blank} sayfasını okuyun.
|
||||
OpenAPI URL'ini özelleştirmek (veya kaldırmak) için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
## OpenAPI Dokümantasyon Bağlantıları
|
||||
## OpenAPI Dokümantasyon URL'leri { #openapi-docs-urls }
|
||||
|
||||
Dokümantasyonu arayüzünde kullanılan bağlantıları güncellemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls){.internal-link target=_blank} sayfasını okuyun.
|
||||
Otomatik olarak oluşturulan dokümantasyon kullanıcı arayüzlerinde kullanılan URL'leri güncellemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls){.internal-link target=_blank} dokümantasyonunu okuyun.
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# GraphQL { #graphql }
|
||||
|
||||
**FastAPI**, **ASGI** standardını temel aldığı için ASGI ile uyumlu herhangi bir **GraphQL** kütüphanesini entegre etmek oldukça kolaydır.
|
||||
|
||||
Aynı uygulama içinde normal FastAPI *path operation*'larını GraphQL ile birlikte kullanabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
**GraphQL** bazı çok özel kullanım senaryolarını çözer.
|
||||
|
||||
Yaygın **web API**'lerle karşılaştırıldığında **avantajları** ve **dezavantajları** vardır.
|
||||
|
||||
Kendi senaryonuz için **faydaların**, **olumsuz yönleri** telafi edip etmediğini mutlaka değerlendirin. 🤓
|
||||
|
||||
///
|
||||
|
||||
## GraphQL Kütüphaneleri { #graphql-libraries }
|
||||
|
||||
Aşağıda **ASGI** desteği olan bazı **GraphQL** kütüphaneleri var. Bunları **FastAPI** ile kullanabilirsiniz:
|
||||
|
||||
* <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a> 🍓
|
||||
* <a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">FastAPI dokümantasyonu</a> ile
|
||||
* <a href="https://ariadnegraphql.org/" class="external-link" target="_blank">Ariadne</a>
|
||||
* <a href="https://ariadnegraphql.org/docs/fastapi-integration" class="external-link" target="_blank">FastAPI dokümantasyonu</a> ile
|
||||
* <a href="https://tartiflette.io/" class="external-link" target="_blank">Tartiflette</a>
|
||||
* ASGI entegrasyonu sağlamak için <a href="https://tartiflette.github.io/tartiflette-asgi/" class="external-link" target="_blank">Tartiflette ASGI</a> ile
|
||||
* <a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a>
|
||||
* <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a> ile
|
||||
|
||||
## Strawberry ile GraphQL { #graphql-with-strawberry }
|
||||
|
||||
**GraphQL** ile çalışmanız gerekiyorsa ya da bunu istiyorsanız, <a href="https://strawberry.rocks/" class="external-link" target="_blank">**Strawberry**</a> önerilen kütüphanedir; çünkü tasarımı **FastAPI**'nin tasarımına en yakındır ve her şey **type annotation**'lar üzerine kuruludur.
|
||||
|
||||
Kullanım senaryonuza göre farklı bir kütüphaneyi tercih edebilirsiniz; ancak bana sorarsanız muhtemelen **Strawberry**'yi denemenizi önerirdim.
|
||||
|
||||
Strawberry'yi FastAPI ile nasıl entegre edebileceğinize dair küçük bir ön izleme:
|
||||
|
||||
{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
|
||||
|
||||
Strawberry hakkında daha fazlasını <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry dokümantasyonunda</a> öğrenebilirsiniz.
|
||||
|
||||
Ayrıca <a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">FastAPI ile Strawberry</a> dokümanlarına da göz atın.
|
||||
|
||||
## Starlette'teki Eski `GraphQLApp` { #older-graphqlapp-from-starlette }
|
||||
|
||||
Starlette'in önceki sürümlerinde <a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a> ile entegrasyon için bir `GraphQLApp` sınıfı vardı.
|
||||
|
||||
Bu sınıf Starlette'te kullanımdan kaldırıldı (deprecated). Ancak bunu kullanan bir kodunuz varsa, aynı kullanım senaryosunu kapsayan ve **neredeyse aynı bir interface** sağlayan <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a>'e kolayca **migrate** edebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
GraphQL'e ihtiyacınız varsa, custom class ve type'lar yerine type annotation'lara dayandığı için yine de <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a>'yi incelemenizi öneririm.
|
||||
|
||||
///
|
||||
|
||||
## Daha Fazlasını Öğrenin { #learn-more }
|
||||
|
||||
**GraphQL** hakkında daha fazlasını <a href="https://graphql.org/" class="external-link" target="_blank">resmi GraphQL dokümantasyonunda</a> öğrenebilirsiniz.
|
||||
|
||||
Ayrıca yukarıda bahsedilen kütüphanelerin her biri hakkında, kendi bağlantılarından daha fazla bilgi okuyabilirsiniz.
|
||||
@@ -1,13 +1,13 @@
|
||||
# Nasıl Yapılır - Tarifler
|
||||
# Nasıl Yapılır - Tarifler { #how-to-recipes }
|
||||
|
||||
Burada çeşitli konular hakkında farklı tarifler veya "nasıl yapılır" kılavuzları yer alıyor.
|
||||
Burada **çeşitli konular** hakkında farklı tarifler veya "nasıl yapılır" kılavuzları göreceksiniz.
|
||||
|
||||
Bu fikirlerin büyük bir kısmı aşağı yukarı **bağımsız** olacaktır, çoğu durumda bunları sadece **projenize** hitap ediyorsa incelemelisiniz.
|
||||
Bu fikirlerin büyük bir kısmı aşağı yukarı **bağımsız** olacaktır ve çoğu durumda bunları yalnızca doğrudan **projenize** uygulanıyorsa incelemeniz yeterli olacaktır.
|
||||
|
||||
Projeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve inceleyin, aksi halde bunları atlayabilirsiniz.
|
||||
Projeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve inceleyin; aksi halde muhtemelen bunları atlayabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
**FastAPI**'ı düzgün (ve önerilen) şekilde öğrenmek istiyorsanız [Öğretici - Kullanıcı Rehberi](../tutorial/index.md){.internal-link target=_blank}'ni bölüm bölüm okuyun.
|
||||
**FastAPI**'yi yapılandırılmış bir şekilde (önerilir) **öğrenmek** istiyorsanız bunun yerine [Öğretici - Kullanıcı Rehberi](../tutorial/index.md){.internal-link target=_blank}'ni bölüm bölüm okuyun.
|
||||
|
||||
///
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# Pydantic v1'den Pydantic v2'ye Geçiş { #migrate-from-pydantic-v1-to-pydantic-v2 }
|
||||
|
||||
Eski bir FastAPI uygulamanız varsa, Pydantic'in 1. sürümünü kullanıyor olabilirsiniz.
|
||||
|
||||
FastAPI 0.100.0 sürümü, Pydantic v1 veya v2 ile çalışmayı destekliyordu. Hangisi kuruluysa onu kullanıyordu.
|
||||
|
||||
FastAPI 0.119.0 sürümü, v2'ye geçişi kolaylaştırmak için, Pydantic v2’nin içinden Pydantic v1’e (`pydantic.v1` olarak) kısmi destek ekledi.
|
||||
|
||||
FastAPI 0.126.0 sürümü Pydantic v1 desteğini kaldırdı, ancak bir süre daha `pydantic.v1` desteğini sürdürdü.
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Pydantic ekibi, **Python 3.14** ile başlayarak Python'ın en yeni sürümleri için Pydantic v1 desteğini sonlandırdı.
|
||||
|
||||
Buna `pydantic.v1` de dahildir; Python 3.14 ve üzeri sürümlerde artık desteklenmemektedir.
|
||||
|
||||
Python'ın en yeni özelliklerini kullanmak istiyorsanız, Pydantic v2 kullandığınızdan emin olmanız gerekir.
|
||||
|
||||
///
|
||||
|
||||
Pydantic v1 kullanan eski bir FastAPI uygulamanız varsa, burada onu Pydantic v2'ye nasıl taşıyacağınızı ve kademeli geçişi kolaylaştıran **FastAPI 0.119.0 özelliklerini** göstereceğim.
|
||||
|
||||
## Resmi Kılavuz { #official-guide }
|
||||
|
||||
Pydantic'in v1'den v2'ye resmi bir <a href="https://docs.pydantic.dev/latest/migration/" class="external-link" target="_blank">Migration Guide</a>'ı vardır.
|
||||
|
||||
Ayrıca nelerin değiştiğini, validasyonların artık nasıl daha doğru ve katı olduğunu, olası dikkat edilmesi gereken noktaları (caveat) vb. de içerir.
|
||||
|
||||
Nelerin değiştiğini daha iyi anlamak için okuyabilirsiniz.
|
||||
|
||||
## Testler { #tests }
|
||||
|
||||
Uygulamanız için [testlerinizin](../tutorial/testing.md){.internal-link target=_blank} olduğundan ve bunları continuous integration (CI) üzerinde çalıştırdığınızdan emin olun.
|
||||
|
||||
Bu şekilde yükseltmeyi yapabilir ve her şeyin hâlâ beklendiği gibi çalıştığını doğrulayabilirsiniz.
|
||||
|
||||
## `bump-pydantic` { #bump-pydantic }
|
||||
|
||||
Birçok durumda, özel özelleştirmeler olmadan standart Pydantic modelleri kullanıyorsanız, Pydantic v1'den Pydantic v2'ye geçiş sürecinin büyük kısmını otomatikleştirebilirsiniz.
|
||||
|
||||
Aynı Pydantic ekibinin geliştirdiği <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> aracını kullanabilirsiniz.
|
||||
|
||||
Bu araç, değişmesi gereken kodun büyük bir kısmını otomatik olarak dönüştürmenize yardımcı olur.
|
||||
|
||||
Bundan sonra testleri çalıştırıp her şeyin çalışıp çalışmadığını kontrol edebilirsiniz. Çalışıyorsa işiniz biter. 😎
|
||||
|
||||
## v2 İçinde Pydantic v1 { #pydantic-v1-in-v2 }
|
||||
|
||||
Pydantic v2, `pydantic.v1` adlı bir alt modül olarak Pydantic v1'in tamamını içerir. Ancak bu yapı, Python 3.13'ün üzerindeki sürümlerde artık desteklenmemektedir.
|
||||
|
||||
Bu da şu anlama gelir: Pydantic v2'nin en güncel sürümünü kurup, bu alt modülden eski Pydantic v1 bileşenlerini import ederek, sanki eski Pydantic v1 kuruluymuş gibi kullanabilirsiniz.
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
|
||||
|
||||
### v2 İçinde Pydantic v1 için FastAPI Desteği { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
FastAPI 0.119.0'dan itibaren, v2'ye geçişi kolaylaştırmak için Pydantic v2’nin içinden Pydantic v1 kullanımına yönelik kısmi destek de vardır.
|
||||
|
||||
Dolayısıyla Pydantic'i en güncel 2 sürümüne yükseltip import'ları `pydantic.v1` alt modülünü kullanacak şekilde değiştirebilirsiniz; çoğu durumda bu doğrudan çalışır.
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Pydantic ekibi Python 3.14'ten itibaren yeni Python sürümlerinde Pydantic v1'i artık desteklemediği için, `pydantic.v1` kullanımı da Python 3.14 ve üzeri sürümlerde desteklenmez.
|
||||
|
||||
///
|
||||
|
||||
### Aynı Uygulamada Pydantic v1 ve v2 { #pydantic-v1-and-v2-on-the-same-app }
|
||||
|
||||
Pydantic açısından, alanları (field) Pydantic v1 modelleriyle tanımlanmış bir Pydantic v2 modeli (ya da tersi) kullanmak **desteklenmez**.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "❌ Not Supported"
|
||||
direction TB
|
||||
subgraph V2["Pydantic v2 Model"]
|
||||
V1Field["Pydantic v1 Model"]
|
||||
end
|
||||
subgraph V1["Pydantic v1 Model"]
|
||||
V2Field["Pydantic v2 Model"]
|
||||
end
|
||||
end
|
||||
|
||||
style V2 fill:#f9fff3
|
||||
style V1 fill:#fff6f0
|
||||
style V1Field fill:#fff6f0
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
...ancak aynı uygulamada Pydantic v1 ve v2 kullanarak **ayrı** modeller tanımlayabilirsiniz.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "✅ Supported"
|
||||
direction TB
|
||||
subgraph V2["Pydantic v2 Model"]
|
||||
V2Field["Pydantic v2 Model"]
|
||||
end
|
||||
subgraph V1["Pydantic v1 Model"]
|
||||
V1Field["Pydantic v1 Model"]
|
||||
end
|
||||
end
|
||||
|
||||
style V2 fill:#f9fff3
|
||||
style V1 fill:#fff6f0
|
||||
style V1Field fill:#fff6f0
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
Bazı durumlarda, FastAPI uygulamanızda aynı **path operation** içinde hem Pydantic v1 hem de v2 modellerini kullanmak bile mümkündür:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
Yukarıdaki örnekte input modeli bir Pydantic v1 modelidir; output modeli ( `response_model=ItemV2` ile tanımlanan) ise bir Pydantic v2 modelidir.
|
||||
|
||||
### Pydantic v1 Parametreleri { #pydantic-v1-parameters }
|
||||
|
||||
Pydantic v1 modelleriyle `Body`, `Query`, `Form` vb. parametreler için FastAPI'ye özgü bazı araçları kullanmanız gerekiyorsa, Pydantic v2'ye geçişi tamamlayana kadar bunları `fastapi.temp_pydantic_v1_params` içinden import edebilirsiniz:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
|
||||
|
||||
### Adım Adım Geçiş { #migrate-in-steps }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Önce `bump-pydantic` ile deneyin; testleriniz geçerse ve bu yol çalışırsa tek komutla işi bitirmiş olursunuz. ✨
|
||||
|
||||
///
|
||||
|
||||
`bump-pydantic` sizin senaryonuz için uygun değilse, aynı uygulamada hem Pydantic v1 hem de v2 modellerini birlikte kullanma desteğinden yararlanarak Pydantic v2'ye kademeli şekilde geçebilirsiniz.
|
||||
|
||||
Önce Pydantic'i en güncel 2 sürümüne yükseltip tüm modelleriniz için import'ları `pydantic.v1` kullanacak şekilde değiştirebilirsiniz.
|
||||
|
||||
Ardından modellerinizi Pydantic v1'den v2'ye gruplar hâlinde, adım adım taşımaya başlayabilirsiniz. 🚶
|
||||
@@ -0,0 +1,102 @@
|
||||
# Input ve Output için Ayrı OpenAPI Schema'ları (Ya da Değil) { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
**Pydantic v2** yayınlandığından beri, üretilen OpenAPI eskisine göre biraz daha net ve **doğru**. 😎
|
||||
|
||||
Hatta bazı durumlarda, aynı Pydantic model için OpenAPI içinde input ve output tarafında, **default değerler** olup olmamasına bağlı olarak **iki farklı JSON Schema** bile görebilirsiniz.
|
||||
|
||||
Bunun nasıl çalıştığına ve gerekirse nasıl değiştirebileceğinize bir bakalım.
|
||||
|
||||
## Input ve Output için Pydantic Modelleri { #pydantic-models-for-input-and-output }
|
||||
|
||||
Default değerleri olan bir Pydantic modeliniz olduğunu varsayalım; örneğin şöyle:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
|
||||
|
||||
### Input için Model { #model-for-input }
|
||||
|
||||
Bu modeli şöyle input olarak kullanırsanız:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
|
||||
|
||||
...`description` alanı **zorunlu olmaz**. Çünkü `None` default değerine sahiptir.
|
||||
|
||||
### Dokümanlarda Input Modeli { #input-model-in-docs }
|
||||
|
||||
Bunu dokümanlarda da doğrulayabilirsiniz; `description` alanında **kırmızı yıldız** yoktur, yani required olarak işaretlenmemiştir:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image01.png">
|
||||
</div>
|
||||
|
||||
### Output için Model { #model-for-output }
|
||||
|
||||
Ancak aynı modeli output olarak şöyle kullanırsanız:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
...`description` default değere sahip olduğu için, o alan için **hiçbir şey döndürmeseniz** bile yine de **o default değeri** alır.
|
||||
|
||||
### Output Response Verisi için Model { #model-for-output-response-data }
|
||||
|
||||
Dokümanlarla etkileşip response'u kontrol ederseniz, kod `description` alanlarından birine bir şey eklememiş olsa bile, JSON response default değeri (`null`) içerir:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
|
||||
</div>
|
||||
|
||||
Bu, alanın **her zaman bir değeri olacağı** anlamına gelir; sadece bazen bu değer `None` olabilir (JSON'da `null`).
|
||||
|
||||
Dolayısıyla API'nizi kullanan client'ların bu değerin var olup olmadığını kontrol etmesine gerek yoktur; **alanın her zaman mevcut olacağını varsayabilirler**, sadece bazı durumlarda default değer olan `None` gelecektir.
|
||||
|
||||
Bunu OpenAPI'de ifade etmenin yolu, bu alanı **required** olarak işaretlemektir; çünkü her zaman yer alacaktır.
|
||||
|
||||
Bu nedenle, bir modelin JSON Schema'sı **input mu output mu** kullanıldığına göre farklı olabilir:
|
||||
|
||||
* **input** için `description` **required olmaz**
|
||||
* **output** için **required olur** (ve `None` olabilir; JSON açısından `null`)
|
||||
|
||||
### Dokümanlarda Output Modeli { #model-for-output-in-docs }
|
||||
|
||||
Dokümanlarda output modelini de kontrol edebilirsiniz; **hem** `name` **hem de** `description` alanları **kırmızı yıldız** ile **required** olarak işaretlenmiştir:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image03.png">
|
||||
</div>
|
||||
|
||||
### Dokümanlarda Input ve Output Modelleri { #model-for-input-and-output-in-docs }
|
||||
|
||||
OpenAPI içindeki tüm kullanılabilir Schema'lara (JSON Schema'lara) bakarsanız, iki tane olduğunu göreceksiniz: biri `Item-Input`, diğeri `Item-Output`.
|
||||
|
||||
`Item-Input` için `description` **required değildir**, kırmızı yıldız yoktur.
|
||||
|
||||
Ama `Item-Output` için `description` **required**'dır, kırmızı yıldız vardır.
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image04.png">
|
||||
</div>
|
||||
|
||||
**Pydantic v2**'nin bu özelliğiyle API dokümantasyonunuz daha **hassas** olur; ayrıca autogenerated client'lar ve SDK'lar kullanıyorsanız, onlar da daha tutarlı ve daha iyi bir **developer experience** ile daha doğru üretilir. 🎉
|
||||
|
||||
## Schema'ları Ayırma { #do-not-separate-schemas }
|
||||
|
||||
Bazı durumlarda **input ve output için aynı schema'yı** kullanmak isteyebilirsiniz.
|
||||
|
||||
Bunun muhtemelen en yaygın nedeni, halihazırda autogenerated client kodlarınız/SDK'larınızın olması ve henüz bunların hepsini güncellemek istememenizdir. Büyük ihtimalle bir noktada güncellemek isteyeceksiniz, ama belki şu an değil.
|
||||
|
||||
Bu durumda **FastAPI**'de bu özelliği `separate_input_output_schemas=False` parametresiyle kapatabilirsiniz.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`separate_input_output_schemas` desteği FastAPI `0.102.0` sürümünde eklendi. 🤓
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
|
||||
|
||||
### Dokümanlarda Input ve Output Modelleri için Aynı Schema { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
Artık model için input ve output tarafında tek bir schema olur: sadece `Item`. Ayrıca `description` alanı **required değildir**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
# Bir Veritabanını Test Etmek { #testing-a-database }
|
||||
|
||||
Veritabanları, SQL ve SQLModel hakkında <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel dokümantasyonundan</a> öğrenebilirsiniz. 🤓
|
||||
|
||||
Ayrıca SQLModel'i FastAPI ile kullanmaya dair mini bir <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">tutorial</a> da var. ✨
|
||||
|
||||
Bu tutorial içinde <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/" class="external-link" target="_blank">SQL veritabanlarını test etme</a> hakkında bir bölüm de bulunuyor. 😎
|
||||
+265
-180
@@ -1,14 +1,14 @@
|
||||
# FastAPI
|
||||
# FastAPI { #fastapi }
|
||||
|
||||
<style>
|
||||
.md-content .md-typeset h1 { display: none; }
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com/tr"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI framework, yüksek performanslı, öğrenmesi oldukça kolay, kodlaması hızlı, kullanıma hazır</em>
|
||||
<em>FastAPI framework, yüksek performanslı, öğrenmesi kolay, kodlaması hızlı, production'a hazır</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
||||
@@ -27,59 +27,65 @@
|
||||
|
||||
---
|
||||
|
||||
**Dokümantasyon**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
**Dokümantasyon**: <a href="https://fastapi.tiangolo.com/tr" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Kaynak Kod**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI, Python 'nin standart <abbr title="Tip Belirteçleri: Type Hints">tip belirteçleri</abbr>ne dayalı, modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'tür.
|
||||
FastAPI, Python'un standart type hints'lerine dayalı olarak Python ile API'lar oluşturmak için kullanılan modern ve hızlı (yüksek performanslı) bir web framework'üdür.
|
||||
|
||||
Temel özellikleri şunlardır:
|
||||
|
||||
* **Hızlı**: Çok yüksek performanslı, **NodeJS** ve **Go** ile eşit düzeyde (Starlette ve Pydantic sayesinde). [En hızlı Python framework'lerinden bir tanesidir](#performans).
|
||||
* **Kodlaması Hızlı**: Geliştirme hızını yaklaşık %200 ile %300 aralığında arttırır. *
|
||||
* **Hızlı**: Çok yüksek performanslı, **NodeJS** ve **Go** ile eşit düzeyde (Starlette ve Pydantic sayesinde). [Mevcut en hızlı Python framework'lerinden biri](#performance).
|
||||
* **Kodlaması Hızlı**: Özellik geliştirme hızını yaklaşık %200 ile %300 aralığında artırır. *
|
||||
* **Daha az hata**: İnsan (geliştirici) kaynaklı hataları yaklaşık %40 azaltır. *
|
||||
* **Sezgisel**: Muhteşem bir editör desteği. Her yerde <abbr title="Otomatik Tamamlama: auto-complete, autocompletion, IntelliSense">otomatik tamamlama</abbr>. Hata ayıklama ile daha az zaman harcayacaksınız.
|
||||
* **Kolay**: Öğrenmesi ve kullanması kolay olacak şekilde tasarlandı. Doküman okuma ile daha az zaman harcayacaksınız.
|
||||
* **Kısa**: Kod tekrarı minimize edildi. Her parametre tanımlamasında birden fazla özellik ve daha az hatayla karşılaşacaksınız.
|
||||
* **Güçlü**: Otomatik ve etkileşimli dokümantasyon ile birlikte, kullanıma hazır kod elde edebilirsiniz.
|
||||
* **Standard öncelikli**: API'lar için açık standartlara dayalı (ve tamamen uyumlu); <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (eski adıyla Swagger) ve <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Sezgisel**: Harika bir editör desteği. Her yerde <dfn title="oto-tamamlama, autocompletion, IntelliSense olarak da bilinir">Tamamlama</dfn>. Hata ayıklamaya daha az zaman.
|
||||
* **Kolay**: Kullanımı ve öğrenmesi kolay olacak şekilde tasarlandı. Doküman okumaya daha az zaman.
|
||||
* **Kısa**: Kod tekrarını minimize eder. Her parametre tanımından birden fazla özellik. Daha az hata.
|
||||
* **Sağlam**: Production'a hazır kod elde edersiniz. Otomatik etkileşimli dokümantasyon ile birlikte.
|
||||
* **Standardlara dayalı**: API'lar için açık standartlara dayalıdır (ve tamamen uyumludur); <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (önceden Swagger olarak biliniyordu) ve <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* ilgili kanılar, dahili geliştirme ekibinin geliştirdikleri ürünlere yaptıkları testlere dayanmaktadır.</small>
|
||||
<small>* tahmin, production uygulamalar geliştiren dahili bir geliştirme ekibinin yaptığı testlere dayanmaktadır.</small>
|
||||
|
||||
## Sponsorlar
|
||||
## Sponsorlar { #sponsors }
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
{% if sponsors %}
|
||||
### Keystone Sponsor { #keystone-sponsor }
|
||||
|
||||
{% for sponsor in sponsors.keystone -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
|
||||
### Gold and Silver Sponsors { #gold-and-silver-sponsors }
|
||||
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
{%- for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/tr/fastapi-people/#sponsors" class="external-link" target="_blank">Diğer Sponsorlar</a>
|
||||
<a href="https://fastapi.tiangolo.com/tr/fastapi-people/#sponsors" class="external-link" target="_blank">Diğer sponsorlar</a>
|
||||
|
||||
## Görüşler
|
||||
## Görüşler { #opinions }
|
||||
|
||||
"_[...] Bugünlerde **FastAPI**'ı çok fazla kullanıyorum. [...] Aslında bunu ekibimin **Microsoft'taki Machine Learning servislerinin** tamamında kullanmayı planlıyorum. Bunlardan bazıları **Windows**'un ana ürünlerine ve **Office** ürünlerine entegre ediliyor._"
|
||||
"_[...] Bugünlerde **FastAPI**'ı çok fazla kullanıyorum. [...] Aslında bunu ekibimin **Microsoft'taki ML servislerinin** tamamında kullanmayı planlıyorum. Bunlardan bazıları ana **Windows** ürününe ve bazı **Office** ürünlerine entegre ediliyor._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**FastAPI**'ı **tahminlerimiz**'i sorgulanabilir hale getirecek bir **REST** sunucu oluşturmak için benimsedik/kullanmaya başladık._"
|
||||
"_**predictions** almak için sorgulanabilecek bir **REST** server oluşturmak amacıyla **FastAPI** kütüphanesini benimsedik. [Ludwig için]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix**, **kriz yönetiminde** orkestrasyon yapabilmek için geliştirdiği yeni framework'ü **Dispatch**'in, açık kaynak sürümünü paylaşmaktan gurur duyuyor. [**FastAPI** ile yapıldı.]_"
|
||||
"_**Netflix**, **kriz yönetimi** orkestrasyon framework'ümüz: **Dispatch**'in open-source sürümünü duyurmaktan memnuniyet duyar! [**FastAPI** ile geliştirildi]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
@@ -91,74 +97,70 @@ Temel özellikleri şunlardır:
|
||||
|
||||
---
|
||||
|
||||
"_Dürüst olmak gerekirse, inşa ettiğiniz şey gerçekten sağlam ve profesyonel görünüyor. Birçok açıdan **Hug**'ın olmasını istediğim şey tam da bu - böyle bir şeyi inşa eden birini görmek gerçekten ilham verici._"
|
||||
"_Dürüst olmak gerekirse, inşa ettiğiniz şey gerçekten sağlam ve profesyonel görünüyor. Birçok açıdan, **Hug**'ın olmasını istediğim şey tam da bu - böyle bir şeyi inşa eden birini görmek gerçekten ilham verici._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a>'ın Yaratıcısı</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> yaratıcısı</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_Eğer REST API geliştirmek için **modern bir framework** öğrenme arayışında isen, **FastAPI**'a bir göz at [...] Hızlı, kullanımı ve öğrenmesi kolay. [...]_"
|
||||
"_REST API'lar geliştirmek için **modern bir framework** öğrenmek istiyorsanız, **FastAPI**'a bir göz atın [...] Hızlı, kullanımı ve öğrenmesi kolay [...]_"
|
||||
|
||||
"_**API** servislerimizi **FastAPI**'a taşıdık [...] Sizin de beğeneceğinizi düşünüyoruz. [...]_"
|
||||
"_**API**'larımız için **FastAPI**'a geçtik [...] Bence hoşunuza gidecek [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> kurucuları - <a href="https://spacy.io" target="_blank">spaCy</a> yaratıcıları</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_Python ile kullanıma hazır bir API oluşturmak isteyen herhangi biri için, **FastAPI**'ı şiddetle tavsiye ederim. **Harika tasarlanmış**, **kullanımı kolay** ve **yüksek ölçeklenebilir**, API odaklı geliştirme stratejimizin **ana bileşeni** haline geldi ve Virtual TAC Engineer gibi birçok otomasyon ve servisi yönetiyor._"
|
||||
"_Production'da Python API geliştirmek isteyen herkese **FastAPI**'ı şiddetle tavsiye ederim. **Harika tasarlanmış**, **kullanımı kolay** ve **yüksek ölçeklenebilir**; API-first geliştirme stratejimizin **kilit bir bileşeni** haline geldi ve Virtual TAC Engineer gibi birçok otomasyon ve servise güç veriyor._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## Komut Satırı Uygulamalarının FastAPI'ı: **Typer**
|
||||
## FastAPI mini belgeseli { #fastapi-mini-documentary }
|
||||
|
||||
2025'in sonunda yayınlanan bir <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI mini belgeseli</a> var, online olarak izleyebilirsiniz:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## CLI'ların FastAPI'ı: **Typer** { #typer-the-fastapi-of-clis }
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
Eğer API yerine, terminalde kullanılmak üzere bir <abbr title="Komut Satırı: Command Line Interface">komut satırı uygulaması</abbr> geliştiriyorsanız <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>'a göz atabilirsiniz.
|
||||
Web API yerine terminalde kullanılacak bir <abbr title="Command Line Interface - Komut Satırı Arayüzü">CLI</abbr> uygulaması geliştiriyorsanız <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>'a göz atın.
|
||||
|
||||
**Typer** kısaca FastAPI'ın küçük kardeşi. Ve hedefi komut satırı uygulamalarının **FastAPI'ı** olmak. ⌨️ 🚀
|
||||
**Typer**, FastAPI'ın küçük kardeşi. Ve hedefi CLI'ların **FastAPI'ı** olmak. ⌨️ 🚀
|
||||
|
||||
## Gereksinimler
|
||||
## Gereksinimler { #requirements }
|
||||
|
||||
FastAPI iki devin omuzları üstünde duruyor:
|
||||
|
||||
* Web tarafı için <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>.
|
||||
* Data tarafı için <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>.
|
||||
* Web kısımları için <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>.
|
||||
* Data kısımları için <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>.
|
||||
|
||||
## Kurulum
|
||||
## Kurulum { #installation }
|
||||
|
||||
Bir <a href="https://fastapi.tiangolo.com/tr/virtual-environments/" class="external-link" target="_blank">virtual environment</a> oluşturup etkinleştirelim ve ardından FastAPI'ı yükleyelim:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install fastapi
|
||||
$ pip install "fastapi[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Uygulamamızı kullanılabilir hale getirmek için <a href="http://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> ya da <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a> gibi bir ASGI sunucusuna ihtiyacımız olacak.
|
||||
**Not**: Tüm terminallerde çalıştığından emin olmak için `"fastapi[standard]"` ifadesini tırnak içinde yazdığınızdan emin olun.
|
||||
|
||||
<div class="termy">
|
||||
## Örnek { #example }
|
||||
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
### Oluşturalım { #create-it }
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Örnek
|
||||
|
||||
### Kodu Oluşturalım
|
||||
|
||||
* `main.py` adında bir dosya oluşturup içine şu kodu yapıştıralım:
|
||||
Şu içerikle `main.py` adında bir dosya oluşturalım:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -170,18 +172,16 @@ 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}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>Ya da <code>async def</code>...</summary>
|
||||
<summary>Ya da <code>async def</code> kullanalım...</summary>
|
||||
|
||||
Eğer kodunuzda `async` / `await` varsa, `async def` kullanalım:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
Eğer kodunuz `async` / `await` kullanıyorsa, `async def` kullanın:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -193,28 +193,41 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**Not**:
|
||||
|
||||
Eğer bu konu hakkında bilginiz yoksa <a href="https://fastapi.tiangolo.com/tr/async/#in-a-hurry" target="_blank">`async` ve `await`</a> dokümantasyonundaki _"Aceleniz mi var?"_ kısmını kontrol edebilirsiniz.
|
||||
Eğer bilmiyorsanız, dokümanlardaki <a href="https://fastapi.tiangolo.com/tr/async/#in-a-hurry" target="_blank">`async` ve `await`</a> hakkında _"Aceleniz mi var?"_ bölümüne bakın.
|
||||
|
||||
</details>
|
||||
|
||||
### Kodu Çalıştıralım
|
||||
### Çalıştıralım { #run-it }
|
||||
|
||||
Sunucuyu aşağıdaki komutla çalıştıralım:
|
||||
Sunucuyu şu komutla çalıştıralım:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ fastapi dev main.py
|
||||
|
||||
╭────────── FastAPI CLI - Development mode ───────────╮
|
||||
│ │
|
||||
│ Serving at: http://127.0.0.1:8000 │
|
||||
│ │
|
||||
│ API docs: http://127.0.0.1:8000/docs │
|
||||
│ │
|
||||
│ Running in development mode, for production use: │
|
||||
│ │
|
||||
│ fastapi run │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────╯
|
||||
|
||||
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Started reloader process [2248755] using WatchFiles
|
||||
INFO: Started server process [2248757]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
@@ -222,58 +235,56 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary><code>uvicorn main:app --reload</code> komutuyla ilgili...</summary>
|
||||
<summary><code>fastapi dev main.py</code> komutu hakkında...</summary>
|
||||
|
||||
`uvicorn main:app` komutunu şu şekilde açıklayabiliriz:
|
||||
`fastapi dev` komutu, `main.py` dosyanızı okur, içindeki **FastAPI** uygulamasını algılar ve <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> kullanarak bir server başlatır.
|
||||
|
||||
* `main`: dosya olan `main.py` (yani Python "modülü").
|
||||
* `app`: ise `main.py` dosyasının içerisinde `app = FastAPI()` satırında oluşturduğumuz `FastAPI` nesnesi.
|
||||
* `--reload`: kod değişikliklerinin ardından sunucuyu otomatik olarak yeniden başlatır. Bu parameteyi sadece geliştirme aşamasında kullanmalıyız.
|
||||
Varsayılan olarak `fastapi dev`, local geliştirme için auto-reload etkin şekilde başlar.
|
||||
|
||||
Daha fazla bilgi için <a href="https://fastapi.tiangolo.com/tr/fastapi-cli/" target="_blank">FastAPI CLI dokümantasyonu</a>'nu okuyabilirsiniz.
|
||||
|
||||
</details>
|
||||
|
||||
### Şimdi de Kontrol Edelim
|
||||
### Kontrol Edelim { #check-it }
|
||||
|
||||
Tarayıcımızda şu bağlantıyı açalım <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
Tarayıcınızda şu bağlantıyı açın: <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
Aşağıdaki gibi bir JSON yanıtıyla karşılaşacağız:
|
||||
Şu JSON response'unu göreceksiniz:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
Az önce oluşturduğumuz API:
|
||||
Artık şunları yapan bir API oluşturdunuz:
|
||||
|
||||
* `/` ve `/items/{item_id}` <abbr title="Adres / Yol: Path ">_yollarına_</abbr> HTTP isteği alabilir.
|
||||
* İki _yolda_ `GET` <em>operasyonlarını</em> (HTTP _metodları_ olarak da bilinen) kabul ediyor.
|
||||
* `/items/{item_id}` _yolu_ `item_id` adında bir _yol parametresine_ sahip ve bu parametre `int` değer almak zorundadır.
|
||||
* `/items/{item_id}` _yolu_ `q` adında bir _yol parametresine_ sahip ve bu parametre opsiyonel olmakla birlikte, `str` değer almak zorundadır.
|
||||
* `/` ve `/items/{item_id}` _path_'lerinde HTTP request'leri alır.
|
||||
* Her iki _path_ de `GET` <em>operasyonlarını</em> (HTTP _method_'ları olarak da bilinir) kabul eder.
|
||||
* `/items/{item_id}` _path_'i, `int` olması gereken `item_id` adlı bir _path parameter_'a sahiptir.
|
||||
* `/items/{item_id}` _path_'i, opsiyonel `str` bir _query parameter_ olan `q`'ya sahiptir.
|
||||
|
||||
### Etkileşimli API Dokümantasyonu
|
||||
### Etkileşimli API dokümantasyonu { #interactive-api-docs }
|
||||
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> bağlantısını açalım.
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
|
||||
|
||||
<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanan otomatik etkileşimli bir API dokümantasyonu göreceğiz:
|
||||
Otomatik etkileşimli API dokümantasyonunu göreceksiniz (<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanır):
|
||||
|
||||

|
||||
|
||||
### Alternatif API Dokümantasyonu
|
||||
### Alternatif API dokümantasyonu { #alternative-api-docs }
|
||||
|
||||
Şimdi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> bağlantısını açalım.
|
||||
Ve şimdi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gidin.
|
||||
|
||||
<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan otomatik dokümantasyonu göreceğiz:
|
||||
Alternatif otomatik dokümantasyonu göreceksiniz (<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanır):
|
||||
|
||||

|
||||
|
||||
## Örneği Güncelleyelim
|
||||
## Örneği Güncelleyelim { #example-upgrade }
|
||||
|
||||
Şimdi `main.py` dosyasını, `PUT` isteğiyle birlikte bir gövde alacak şekilde değiştirelim.
|
||||
Şimdi `main.py` dosyasını, `PUT` request'iyle gelen bir body alacak şekilde değiştirelim.
|
||||
|
||||
<abbr title="Gövde: Body">Gövde</abbr>yi Pydantic sayesinde standart python tiplerini kullanarak tanımlayalım.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
Body'yi Pydantic sayesinde standart Python tiplerini kullanarak tanımlayalım.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -283,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -292,7 +303,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}
|
||||
|
||||
|
||||
@@ -301,174 +312,248 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
Sunucu otomatik olarak yeniden başlamış olmalı (çünkü yukarıda `uvicorn` komutuyla birlikte `--reload` parametresini kullandık).
|
||||
`fastapi dev` server'ı otomatik olarak yeniden yüklemelidir.
|
||||
|
||||
### Etkileşimli API Dokümantasyonundaki Değişimi Görelim
|
||||
### Etkileşimli API dokümantasyonu güncellemesi { #interactive-api-docs-upgrade }
|
||||
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> bağlantısına tekrar gidelim.
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
|
||||
|
||||
* Etkileşimli API dokümantasyonu, yeni gövdede dahil olmak üzere otomatik olarak güncellenmiş olacak:
|
||||
* Etkileşimli API dokümantasyonu, yeni body dahil olacak şekilde otomatik olarak güncellenecek:
|
||||
|
||||

|
||||
|
||||
* "Try it out" butonuna tıklayalım, bu işlem API parametleri üzerinde değişiklik yapmamıza ve doğrudan API ile etkileşime geçmemize imkan sağlayacak:
|
||||
* "Try it out" butonuna tıklayın; parametreleri doldurmanıza ve API ile doğrudan etkileşime girmenize olanak sağlar:
|
||||
|
||||

|
||||
|
||||
* Şimdi "Execute" butonuna tıklayalım, kullanıcı arayüzü API'ımız ile bağlantı kurup parametreleri gönderecek ve sonucu ekranımıza getirecek:
|
||||
* Sonra "Execute" butonuna tıklayın; kullanıcı arayüzü API'nız ile iletişim kuracak, parametreleri gönderecek, sonuçları alacak ve ekranda gösterecek:
|
||||
|
||||

|
||||
|
||||
### Alternatif API Dokümantasyonundaki Değişimi Görelim
|
||||
### Alternatif API dokümantasyonu güncellemesi { #alternative-api-docs-upgrade }
|
||||
|
||||
Şimdi ise <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> bağlantısına tekrar gidelim.
|
||||
Ve şimdi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gidin.
|
||||
|
||||
* Alternatif dokümantasyonda yaptığımız değişiklikler ile birlikte yeni sorgu parametresi ve gövde bilgisi ile güncelemiş olacak:
|
||||
* Alternatif dokümantasyon da yeni query parameter ve body'yi yansıtacak:
|
||||
|
||||

|
||||
|
||||
### Özet
|
||||
### Özet { #recap }
|
||||
|
||||
Özetlemek gerekirse, parametrelerin, gövdenin, vb. veri tiplerini fonksiyon parametreleri olarak **bir kere** tanımlıyoruz.
|
||||
Özetle, parametrelerin, body'nin vb. type'larını fonksiyon parametreleri olarak **bir kere** tanımlarsınız.
|
||||
|
||||
Bu işlemi standart modern Python tipleriyle yapıyoruz.
|
||||
Bunu standart modern Python tipleriyle yaparsınız.
|
||||
|
||||
Yeni bir sözdizimi yapısını, bir kütüphane özel metod veya sınıfları öğrenmeye gerek yoktur.
|
||||
Yeni bir syntax, belirli bir kütüphanenin method'larını ya da class'larını vb. öğrenmeniz gerekmez.
|
||||
|
||||
Hepsi sadece **Python** standartlarına dayalıdır.
|
||||
Sadece standart **Python**.
|
||||
|
||||
Örnek olarak, `int` tanımlamak için:
|
||||
Örneğin bir `int` için:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
```
|
||||
|
||||
ya da daha kompleks herhangi bir python modelini tanımlayabiliriz, örneğin `Item` modeli için:
|
||||
ya da daha karmaşık bir `Item` modeli için:
|
||||
|
||||
```Python
|
||||
item: Item
|
||||
```
|
||||
|
||||
...ve sadece kısa bir parametre tipi belirterek elde ettiklerimiz:
|
||||
...ve bu tek tanımla şunları elde edersiniz:
|
||||
|
||||
* Editör desteğiyle birlikte:
|
||||
* Otomatik tamamlama.
|
||||
* Tip kontrolü.
|
||||
* Veri Doğrulama:
|
||||
* Veri geçerli değilse, otomatik olarak açıklayıcı hatalar gösterir.
|
||||
* Çok <abbr title="Derin / İç içe: Nested">derin</abbr> JSON nesnelerinde bile doğrulama yapar.
|
||||
* Gelen verinin <abbr title="Dönüşüm: serialization, parsing, marshalling olarak da biliniyor">dönüşümünü</abbr> aşağıdaki veri tiplerini kullanarak gerçekleştirir:
|
||||
* Şunlar dahil editör desteği:
|
||||
* Completion.
|
||||
* Type kontrolleri.
|
||||
* Verinin doğrulanması:
|
||||
* Veri geçersiz olduğunda otomatik ve anlaşılır hatalar.
|
||||
* Çok derin iç içe JSON nesneleri için bile doğrulama.
|
||||
* Girdi verisinin <dfn title="şöyle de bilinir: serileştirme, ayrıştırma, marshalling">Dönüşümü</dfn>: network'ten gelen veriyi Python verisine ve type'larına çevirir. Şunlardan okur:
|
||||
* JSON.
|
||||
* Yol parametreleri.
|
||||
* Sorgu parametreleri.
|
||||
* Çerezler.
|
||||
* Headers.
|
||||
* Formlar.
|
||||
* Dosyalar.
|
||||
* Giden verinin <abbr title="Dönüşüm: serialization, parsing, marshalling olarak da biliniyor">dönüşümünü</abbr> aşağıdaki veri tiplerini kullanarak gerçekleştirir (JSON olarak):
|
||||
* Python tiplerinin (`str`, `int`, `float`, `bool`, `list`, vb) dönüşümü.
|
||||
* `datetime` nesnesi.
|
||||
* `UUID` nesnesi.
|
||||
* Path parameter'lar.
|
||||
* Query parameter'lar.
|
||||
* Cookie'ler.
|
||||
* Header'lar.
|
||||
* Form'lar.
|
||||
* File'lar.
|
||||
* Çıktı verisinin <dfn title="şöyle de bilinir: serileştirme, ayrıştırma, marshalling">Dönüşümü</dfn>: Python verisini ve type'larını network verisine çevirir (JSON olarak):
|
||||
* Python type'larını dönüştürür (`str`, `int`, `float`, `bool`, `list`, vb.).
|
||||
* `datetime` nesneleri.
|
||||
* `UUID` nesneleri.
|
||||
* Veritabanı modelleri.
|
||||
* ve çok daha fazlası...
|
||||
* 2 alternatif kullanıcı arayüzü dahil olmak üzere, otomatik etkileşimli API dokümantasyonu sağlar:
|
||||
* ...ve daha fazlası.
|
||||
* 2 alternatif kullanıcı arayüzü dahil otomatik etkileşimli API dokümantasyonu:
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Az önceki örneğe geri dönelim, **FastAPI**'ın yapacaklarına bir bakış atalım:
|
||||
Önceki kod örneğine dönersek, **FastAPI** şunları yapacaktır:
|
||||
|
||||
* `item_id`'nin `GET` ve `PUT` istekleri için, yolda olup olmadığının kontol edecek.
|
||||
* `item_id`'nin `GET` ve `PUT` istekleri için, tipinin `int` olduğunu doğrulayacak.
|
||||
* Eğer değilse, sebebini belirten bir hata mesajı gösterecek.
|
||||
* Opsiyonel bir `q` parametresinin `GET` isteği içinde (`http://127.0.0.1:8000/items/foo?q=somequery` gibi) olup olmadığını kontrol edecek
|
||||
* `q` parametresini `= None` ile oluşturduğumuz için, opsiyonel bir parametre olacak.
|
||||
* Eğer `None` olmasa zorunlu bir parametre olacaktı (`PUT` metodunun gövdesinde olduğu gibi).
|
||||
* `PUT` isteği için `/items/{item_id}`'nin gövdesini, JSON olarak doğrulayıp okuyacak:
|
||||
* `name` adında zorunlu bir parametre olup olmadığını ve varsa tipinin `str` olup olmadığını kontol edecek.
|
||||
* `price` adında zorunlu bir parametre olup olmadığını ve varsa tipinin `float` olup olmadığını kontol edecek.
|
||||
* `is_offer` adında opsiyonel bir parametre olup olmadığını ve varsa tipinin `float` olup olmadığını kontol edecek.
|
||||
* Bunların hepsi en derin JSON nesnelerinde bile çalışacak.
|
||||
* Verilerin JSON'a ve JSON'ın python nesnesine dönüşümü otomatik olarak yapılacak.
|
||||
* Her şeyi OpenAPI ile uyumlu bir şekilde otomatik olarak dokümanlayacak ve bunlarda aşağıdaki gibi kullanılabilecek:
|
||||
* `GET` ve `PUT` request'leri için path'te `item_id` olduğunu doğrular.
|
||||
* `GET` ve `PUT` request'leri için `item_id`'nin type'ının `int` olduğunu doğrular.
|
||||
* Değilse, client faydalı ve anlaşılır bir hata görür.
|
||||
* `GET` request'leri için `q` adlı opsiyonel bir query parameter olup olmadığını kontrol eder (`http://127.0.0.1:8000/items/foo?q=somequery` örneğindeki gibi).
|
||||
* `q` parametresi `= None` ile tanımlandığı için opsiyoneldir.
|
||||
* `None` olmasaydı zorunlu olurdu (tıpkı `PUT` örneğindeki body gibi).
|
||||
* `/items/{item_id}`'ye yapılan `PUT` request'leri için body'yi JSON olarak okur:
|
||||
* `str` olması gereken, zorunlu `name` alanı olduğunu kontrol eder.
|
||||
* `float` olması gereken, zorunlu `price` alanı olduğunu kontrol eder.
|
||||
* Varsa, `bool` olması gereken opsiyonel `is_offer` alanını kontrol eder.
|
||||
* Bunların hepsi çok derin iç içe JSON nesneleri için de çalışır.
|
||||
* JSON'a ve JSON'dan dönüşümü otomatik yapar.
|
||||
* Her şeyi OpenAPI ile dokümante eder; bu dokümantasyon şunlar tarafından kullanılabilir:
|
||||
* Etkileşimli dokümantasyon sistemleri.
|
||||
* Bir çok programlama dili için otomatik istemci kodu üretim sistemleri.
|
||||
* İki ayrı etkileşimli dokümantasyon arayüzünü doğrudan sağlayacak.
|
||||
* Birçok dil için otomatik client kodu üretim sistemleri.
|
||||
* 2 etkileşimli dokümantasyon web arayüzünü doğrudan sunar.
|
||||
|
||||
---
|
||||
|
||||
Daha yeni başladık ama çalışma mantığını çoktan anlamış oldunuz.
|
||||
Daha yolun başındayız, ama bunun nasıl çalıştığı hakkında fikri kaptınız.
|
||||
|
||||
Şimdi aşağıdaki satırı değiştirmeyi deneyin:
|
||||
Şu satırı değiştirmeyi deneyin:
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...bundan:
|
||||
...şundan:
|
||||
|
||||
```Python
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
...buna:
|
||||
...şuna:
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...ve editörünün veri tiplerini bildiğini ve otomatik tamamladığını göreceksiniz:
|
||||
...ve editörünüzün alanları otomatik tamamladığını ve type'larını bildiğini görün:
|
||||
|
||||

|
||||
|
||||
Daha fazal özellik içeren, daha eksiksiz bir örnek için <a href="https://fastapi.tiangolo.com/tr/tutorial/">Öğretici - Kullanıcı Rehberi</a> sayfasını ziyaret edebilirsin.
|
||||
Daha fazla özellik içeren daha kapsamlı bir örnek için <a href="https://fastapi.tiangolo.com/tr/tutorial/">Öğretici - Kullanıcı Rehberi</a>'ne bakın.
|
||||
|
||||
**Spoiler**: Öğretici - Kullanıcı rehberi şunları içerir:
|
||||
**Spoiler alert**: öğretici - kullanıcı rehberi şunları içerir:
|
||||
|
||||
* **Parameterlerin**, **headers**, **çerezler**, **form alanları** ve **dosyalar** olarak tanımlanması.
|
||||
* `maximum_length` ya da `regex` gibi **doğrulama kısıtlamalarının** nasıl yapılabileceği.
|
||||
* Çok güçlü ve kullanımı kolay **<abbr title="Bağımlılık Enjeksiyonu: components, resources, providers, services, injectables olarak da biliniyor.">Bağımlılık Enjeksiyonu</abbr>** sistemi oluşturmayı.
|
||||
* Güvenlik ve kimlik doğrulama, **JWT tokenleri** ile **OAuth2** desteği, ve **HTTP Basic** doğrulaması.
|
||||
* İleri seviye fakat bir o kadarda basit olan **çok derin JSON modelleri** (Pydantic sayesinde).
|
||||
* **GraphQL** entegrasyonu: <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> ve diğer kütüphaneleri kullanarak.
|
||||
* Diğer ekstra özellikler (Starlette sayesinde):
|
||||
* **WebSocketler**
|
||||
* HTTPX ve `pytest` sayesinde aşırı kolay testler.
|
||||
* **parameter**'ların farklı yerlerden: **header**'lar, **cookie**'ler, **form alanları** ve **file**'lar olarak tanımlanması.
|
||||
* `maximum_length` ya da `regex` gibi **doğrulama kısıtlamalarının** nasıl ayarlanacağı.
|
||||
* Çok güçlü ve kullanımı kolay bir **<dfn title="şöyle de bilinir: bileşenler, kaynaklar, sağlayıcılar, servisler, enjekte edilebilirler">Bağımlılık Enjeksiyonu</dfn>** sistemi.
|
||||
* **JWT tokens** ve **HTTP Basic** auth ile **OAuth2** desteği dahil güvenlik ve kimlik doğrulama.
|
||||
* **Çok derin iç içe JSON modelleri** tanımlamak için daha ileri (ama aynı derecede kolay) teknikler (Pydantic sayesinde).
|
||||
* <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> ve diğer kütüphaneler ile **GraphQL** entegrasyonu.
|
||||
* Starlette sayesinde gelen birçok ek özellik:
|
||||
* **WebSockets**
|
||||
* HTTPX ve `pytest` tabanlı aşırı kolay testler
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...ve daha fazlası.
|
||||
|
||||
## Performans
|
||||
### Uygulamanızı deploy edin (opsiyonel) { #deploy-your-app-optional }
|
||||
|
||||
Bağımsız TechEmpower kıyaslamaları gösteriyor ki, Uvicorn ile çalıştırılan **FastAPI** uygulamaları <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">en hızlı Python framework'lerinden birisi</a>, sadece Starlette ve Uvicorn'dan yavaş, ki FastAPI bunların üzerine kurulu bir kütüphanedir.
|
||||
İsterseniz FastAPI uygulamanızı <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>'a deploy edebilirsiniz; eğer henüz yapmadıysanız gidip bekleme listesine katılın. 🚀
|
||||
|
||||
Daha fazla bilgi için, bu bölüme bir göz at <a href="https://fastapi.tiangolo.com/tr/benchmarks/" class="internal-link" target="_blank">Kıyaslamalar</a>.
|
||||
Zaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek bir komutla deploy edebilirsiniz.
|
||||
|
||||
## Opsiyonel Gereksinimler
|
||||
Deploy etmeden önce, giriş yaptığınızdan emin olun:
|
||||
|
||||
Pydantic tarafında kullanılan:
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Sonra uygulamanızı deploy edin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hepsi bu! Artık uygulamanıza bu URL'den erişebilirsiniz. ✨
|
||||
|
||||
#### FastAPI Cloud hakkında { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**, **FastAPI**'ın arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.
|
||||
|
||||
**Bir API'ı build etmek**, **deploy etmek** ve **erişmek** süreçlerini minimum eforla kolaylaştırır.
|
||||
|
||||
FastAPI ile uygulama geliştirmenin sağladığı aynı **developer experience**'ı, onları cloud'a **deploy etmeye** de taşır. 🎉
|
||||
|
||||
FastAPI Cloud, *FastAPI and friends* open source projelerinin ana sponsoru ve finansman sağlayıcısıdır. ✨
|
||||
|
||||
#### Diğer cloud sağlayıcılarına deploy { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI open source'tur ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.
|
||||
|
||||
FastAPI uygulamalarını onlarla deploy etmek için cloud sağlayıcınızın rehberlerini takip edin. 🤓
|
||||
|
||||
## Performans { #performance }
|
||||
|
||||
Bağımsız TechEmpower kıyaslamaları, Uvicorn altında çalışan **FastAPI** uygulamalarının <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">mevcut en hızlı Python framework'lerinden biri</a> olduğunu gösteriyor; sadece Starlette ve Uvicorn'un kendisinin gerisinde (FastAPI tarafından dahili olarak kullanılır). (*)
|
||||
|
||||
Daha iyi anlamak için <a href="https://fastapi.tiangolo.com/tr/benchmarks/" class="internal-link" target="_blank">Kıyaslamalar</a> bölümüne bakın.
|
||||
|
||||
## Bağımlılıklar { #dependencies }
|
||||
|
||||
FastAPI, Pydantic ve Starlette'a bağımlıdır.
|
||||
|
||||
### `standard` Bağımlılıkları { #standard-dependencies }
|
||||
|
||||
FastAPI'ı `pip install "fastapi[standard]"` ile yüklediğinizde, opsiyonel bağımlılıkların `standard` grubuyla birlikte gelir:
|
||||
|
||||
Pydantic tarafından kullanılanlar:
|
||||
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - email doğrulaması için.
|
||||
|
||||
Starlette tarafından kullanılanlar:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient` kullanmak istiyorsanız gereklidir.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - varsayılan template yapılandırmasını kullanmak istiyorsanız gereklidir.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - `request.form()` ile, form <dfn title="HTTP request'ten gelen string'i Python verisine dönüştürme">"ayrıştırma"</dfn> desteği istiyorsanız gereklidir.
|
||||
|
||||
FastAPI tarafından kullanılanlar:
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - uygulamanızı yükleyen ve servis eden server için. Buna, yüksek performanslı servis için gereken bazı bağımlılıkları (örn. `uvloop`) içeren `uvicorn[standard]` dahildir.
|
||||
* `fastapi-cli[standard]` - `fastapi` komutunu sağlamak için.
|
||||
* Buna, FastAPI uygulamanızı <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>'a deploy etmenizi sağlayan `fastapi-cloud-cli` dahildir.
|
||||
|
||||
### `standard` Bağımlılıkları Olmadan { #without-standard-dependencies }
|
||||
|
||||
`standard` opsiyonel bağımlılıklarını dahil etmek istemiyorsanız, `pip install fastapi` ile kurabilirsiniz.
|
||||
|
||||
### `fastapi-cloud-cli` Olmadan { #without-fastapi-cloud-cli }
|
||||
|
||||
FastAPI'ı standard bağımlılıklarla ama `fastapi-cloud-cli` olmadan kurmak istiyorsanız, `pip install "fastapi[standard-no-fastapi-cloud-cli]"` ile yükleyebilirsiniz.
|
||||
|
||||
### Ek Opsiyonel Bağımlılıklar { #additional-optional-dependencies }
|
||||
|
||||
Yüklemek isteyebileceğiniz bazı ek bağımlılıklar da vardır.
|
||||
|
||||
Ek opsiyonel Pydantic bağımlılıkları:
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - ayar yönetimi için.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - Pydantic ile birlikte kullanılabilecek ek tipler için.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - Pydantic ile kullanılacak ek type'lar için.
|
||||
|
||||
Starlette tarafında kullanılan:
|
||||
Ek opsiyonel FastAPI bağımlılıkları:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Eğer `TestClient` yapısını kullanacaksanız gereklidir.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Eğer varsayılan template konfigürasyonunu kullanacaksanız gereklidir.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Eğer `request.form()` ile form <abbr title="HTTP isteği ile gelen string veriyi Python nesnesine çevirme.">dönüşümü</abbr> desteğini kullanacaksanız gereklidir.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` desteği için gerekli.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - `SchemaGenerator` desteği için gerekli (Muhtemelen FastAPI kullanırken ihtiyacınız olmaz).
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse` kullanmak istiyorsanız gereklidir.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse` kullanmak istiyorsanız gereklidir.
|
||||
|
||||
Hem FastAPI hem de Starlette tarafından kullanılan:
|
||||
## Lisans { #license }
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - oluşturduğumuz uygulamayı servis edecek web sunucusu görevini üstlenir.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse` kullanacaksanız gereklidir.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse` kullanacaksanız gerekli.
|
||||
|
||||
Bunların hepsini `pip install fastapi[all]` ile yükleyebilirsin.
|
||||
|
||||
## Lisans
|
||||
|
||||
Bu proje, MIT lisansı şartları altında lisanslanmıştır.
|
||||
Bu proje MIT lisansı şartları altında lisanslanmıştır.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Öğren
|
||||
# Öğren { #learn }
|
||||
|
||||
**FastAPI** öğrenmek için giriş bölümleri ve öğreticiler burada yer alıyor.
|
||||
|
||||
Burayı, bir **kitap**, bir **kurs**, ve FastAPI öğrenmenin **resmi** ve önerilen yolu olarak düşünülebilirsiniz. 😎
|
||||
Burayı, bir **kitap**, bir **kurs**, FastAPI öğrenmenin **resmi** ve önerilen yolu olarak düşünebilirsiniz. 😎
|
||||
|
||||
@@ -1,84 +1,28 @@
|
||||
# Proje oluşturma - Şablonlar
|
||||
# Full Stack FastAPI Şablonu { #full-stack-fastapi-template }
|
||||
|
||||
Başlamak için bir proje oluşturucu kullanabilirsiniz, çünkü sizin için önceden yapılmış birçok başlangıç kurulumu, güvenlik, veritabanı ve temel API endpoinlerini içerir.
|
||||
Şablonlar genellikle belirli bir kurulumla gelir, ancak esnek ve özelleştirilebilir olacak şekilde tasarlanırlar. Bu sayede şablonu projenizin gereksinimlerine göre değiştirip uyarlayabilir, çok iyi bir başlangıç noktası olarak kullanabilirsiniz. 🏁
|
||||
|
||||
Bir proje oluşturucu, her zaman kendi ihtiyaçlarınıza göre güncellemeniz ve uyarlamanız gereken esnek bir kuruluma sahip olacaktır, ancak bu, projeniz için iyi bir başlangıç noktası olabilir.
|
||||
Bu şablonu başlangıç için kullanabilirsiniz; çünkü ilk kurulumun, güvenliğin, veritabanının ve bazı API endpoint'lerinin önemli bir kısmı sizin için zaten hazırlanmıştır.
|
||||
|
||||
## Full Stack FastAPI PostgreSQL
|
||||
GitHub Repository: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
## Full Stack FastAPI Şablonu - Teknoloji Yığını ve Özellikler { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
|
||||
### Full Stack FastAPI PostgreSQL - Özellikler
|
||||
|
||||
* Full **Docker** entegrasyonu (Docker based).
|
||||
* Docker Swarm Mode ile deployment.
|
||||
* **Docker Compose** entegrasyonu ve lokal geliştirme için optimizasyon.
|
||||
* Uvicorn ve Gunicorn ile **Production ready** Python web server'ı.
|
||||
* Python <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> backend:
|
||||
* **Hızlı**: **NodeJS** ve **Go** ile eşit, çok yüksek performans (Starlette ve Pydantic'e teşekkürler).
|
||||
* **Sezgisel**: Editor desteğı. <abbr title="auto-complete, IntelliSense gibi isimlerle de bilinir">Otomatik tamamlama</abbr>. Daha az debugging.
|
||||
* **Kolay**: Kolay öğrenip kolay kullanmak için tasarlandı. Daha az döküman okuma daha çok iş.
|
||||
* **Kısa**: Minimum kod tekrarı. Her parametre bildiriminde birden çok özellik.
|
||||
* **Güçlü**: Production-ready. Otomatik interaktif dökümantasyon.
|
||||
* **Standartlara dayalı**: API'ler için açık standartlara dayanır (ve tamamen uyumludur): <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> ve <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Şeması</a>.
|
||||
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Birçok diger özelliği**</a> dahili otomatik doğrulama, serialization, interaktif dokümantasyon, OAuth2 JWT token ile authentication, vb.
|
||||
* **Güvenli şifreleme** .
|
||||
* **JWT token** kimlik doğrulama.
|
||||
* **SQLAlchemy** models (Flask dan bağımsızdır. Celery worker'ları ile kullanılabilir).
|
||||
* Kullanıcılar için temel başlangıç modeli (gerektiği gibi değiştirin ve kaldırın).
|
||||
* **Alembic** migration.
|
||||
* **CORS** (Cross Origin Resource Sharing).
|
||||
* **Celery** worker'ları ile backend içerisinden seçilen işleri çalıştırabilirsiniz.
|
||||
* **Pytest**'e dayalı, Docker ile entegre REST backend testleri ile veritabanından bağımsız olarak tam API etkileşimini test edebilirsiniz. Docker'da çalıştığı için her seferinde sıfırdan yeni bir veri deposu oluşturabilir (böylece ElasticSearch, MongoDB, CouchDB veya ne istersen kullanabilirsin ve sadece API'nin çalışıp çalışmadığını test edebilirsin).
|
||||
* Atom Hydrogen veya Visual Studio Code Jupyter gibi uzantılarla uzaktan veya Docker içi geliştirme için **Jupyter Çekirdekleri** ile kolay Python entegrasyonu.
|
||||
* **Vue** ile frontend:
|
||||
* Vue CLI ile oluşturulmuş.
|
||||
* Dahili **JWT kimlik doğrulama**.
|
||||
* Dahili Login.
|
||||
* Login sonrası, Kontrol paneli.
|
||||
* Kullanıcı oluşturma ve düzenleme kontrol paneli
|
||||
* Kendi kendine kullanıcı sürümü.
|
||||
* **Vuex**.
|
||||
* **Vue-router**.
|
||||
* **Vuetify** güzel material design kompanentleri için.
|
||||
* **TypeScript**.
|
||||
* **Nginx** tabanlı Docker sunucusu (Vue-router için yapılandırılmış).
|
||||
* Docker ile multi-stage yapı, böylece kodu derlemeniz, kaydetmeniz veya işlemeniz gerekmez.
|
||||
* Derleme zamanında Frontend testi (devre dışı bırakılabilir).
|
||||
* Mümkün olduğu kadar modüler yapılmıştır, bu nedenle kutudan çıktığı gibi çalışır, ancak Vue CLI ile yeniden oluşturabilir veya ihtiyaç duyduğunuz şekilde oluşturabilir ve istediğinizi yeniden kullanabilirsiniz.
|
||||
* **PGAdmin** PostgreSQL database admin tool'u, PHPMyAdmin ve MySQL ile kolayca değiştirilebilir.
|
||||
* **Flower** ile Celery job'larını monitörleme.
|
||||
* **Traefik** ile backend ve frontend arasında yük dengeleme, böylece her ikisini de aynı domain altında, path ile ayrılmış, ancak farklı kapsayıcılar tarafından sunulabilirsiniz.
|
||||
* Let's Encrypt **HTTPS** sertifikalarının otomatik oluşturulması dahil olmak üzere Traefik entegrasyonu.
|
||||
* GitLab **CI** (sürekli entegrasyon), backend ve frontend testi dahil.
|
||||
|
||||
## Full Stack FastAPI Couchbase
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
⚠️ **UYARI** ⚠️
|
||||
|
||||
Sıfırdan bir projeye başlıyorsanız alternatiflerine bakın.
|
||||
|
||||
Örneğin, <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> daha iyi bir alternatif olabilir, aktif olarak geliştiriliyor ve kullanılıyor. Ve yeni özellik ve ilerlemelere sahip.
|
||||
|
||||
İsterseniz Couchbase tabanlı generator'ı kullanmakta özgürsünüz, hala iyi çalışıyor olmalı ve onunla oluşturulmuş bir projeniz varsa bu da sorun değil (ve muhtemelen zaten ihtiyaçlarınıza göre güncellediniz).
|
||||
|
||||
Bununla ilgili daha fazla bilgiyi repo belgelerinde okuyabilirsiniz.
|
||||
|
||||
## Full Stack FastAPI MongoDB
|
||||
|
||||
... müsaitliğime ve diğer faktörlere bağlı olarak daha sonra gelebilir. 😅 🎉
|
||||
|
||||
## Machine Learning modelleri, spaCy ve FastAPI
|
||||
|
||||
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
|
||||
|
||||
### Machine Learning modelleri, spaCy ve FastAPI - Features
|
||||
|
||||
* **spaCy** NER model entegrasyonu.
|
||||
* **Azure Cognitive Search** yerleşik istek biçimi.
|
||||
* Uvicorn ve Gunicorn ile **Production ready** Python web server'ı.
|
||||
* Dahili **Azure DevOps** Kubernetes (AKS) CI/CD deployment.
|
||||
* **Multilingual**, Proje kurulumu sırasında spaCy'nin yerleşik dillerinden birini kolayca seçin.
|
||||
* **Esnetilebilir** diğer frameworkler (Pytorch, Tensorflow) ile de çalışır sadece spaCy değil.
|
||||
- ⚡ Python backend API için [**FastAPI**](https://fastapi.tiangolo.com/tr).
|
||||
- 🧰 Python SQL veritabanı etkileşimleri (ORM) için [SQLModel](https://sqlmodel.tiangolo.com).
|
||||
- 🔍 FastAPI'nin kullandığı; veri doğrulama ve ayarlar yönetimi için [Pydantic](https://docs.pydantic.dev).
|
||||
- 💾 SQL veritabanı olarak [PostgreSQL](https://www.postgresql.org).
|
||||
- 🚀 frontend için [React](https://react.dev).
|
||||
- 💃 TypeScript, hooks, Vite ve modern bir frontend stack'inin diğer parçalarını kullanır.
|
||||
- 🎨 frontend component'leri için [Tailwind CSS](https://tailwindcss.com) ve [shadcn/ui](https://ui.shadcn.com).
|
||||
- 🤖 Otomatik üretilen bir frontend client.
|
||||
- 🧪 End-to-End testleri için [Playwright](https://playwright.dev).
|
||||
- 🦇 Dark mode desteği.
|
||||
- 🐋 Geliştirme ve production için [Docker Compose](https://www.docker.com).
|
||||
- 🔒 Varsayılan olarak güvenli password hashing.
|
||||
- 🔑 JWT (JSON Web Token) authentication.
|
||||
- 📫 E-posta tabanlı şifre kurtarma.
|
||||
- ✅ [Pytest](https://pytest.org) ile testler.
|
||||
- 📞 Reverse proxy / load balancer olarak [Traefik](https://traefik.io).
|
||||
- 🚢 Docker Compose kullanarak deployment talimatları; otomatik HTTPS sertifikalarını yönetmek için bir frontend Traefik proxy'sini nasıl kuracağınız dahil.
|
||||
- 🏭 GitHub Actions tabanlı CI (continuous integration) ve CD (continuous deployment).
|
||||
|
||||
+183
-148
@@ -1,76 +1,74 @@
|
||||
# Python Veri Tiplerine Giriş
|
||||
# Python Tiplerine Giriş { #python-types-intro }
|
||||
|
||||
Python isteğe bağlı olarak "tip belirteçlerini" destekler.
|
||||
Python, isteğe bağlı "type hints" (diğer adıyla "type annotations") desteğine sahiptir.
|
||||
|
||||
**"Tip belirteçleri"** bir değişkenin <abbr title="örneğin: str, int, float, bool">tipinin</abbr> belirtilmesine olanak sağlayan özel bir sözdizimidir.
|
||||
Bu **"type hints"** veya annotations, bir değişkenin <dfn title="örneğin: str, int, float, bool">tip</dfn>'ini bildirmeye yarayan özel bir sözdizimidir.
|
||||
|
||||
Değişkenlerin tiplerini belirterek editör ve araçlardan daha fazla destek alabilirsiniz.
|
||||
Değişkenleriniz için tip bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.
|
||||
|
||||
Bu pythonda tip belirteçleri için **hızlı bir başlangıç / bilgi tazeleme** rehberidir . Bu rehber **FastAPI** kullanmak için gereken minimum konuyu kapsar ki bu da çok az bir miktardır.
|
||||
Bu, Python type hints hakkında sadece **hızlı bir eğitim / bilgi tazeleme** dokümanıdır. **FastAPI** ile kullanmak için gereken minimum bilgiyi kapsar... ki aslında bu çok azdır.
|
||||
|
||||
**FastAPI' nin** tamamı bu tür tip belirteçleri ile donatılmıştır ve birçok avantaj sağlamaktadır.
|
||||
**FastAPI** tamamen bu type hints üzerine kuruludur; bunlar ona birçok avantaj ve fayda sağlar.
|
||||
|
||||
**FastAPI** kullanmayacak olsanız bile tür belirteçleri hakkında bilgi edinmenizde fayda var.
|
||||
Ancak hiç **FastAPI** kullanmasanız bile, bunlar hakkında biraz öğrenmeniz size fayda sağlayacaktır.
|
||||
|
||||
/// note | Not
|
||||
|
||||
Python uzmanıysanız ve tip belirteçleri ilgili her şeyi zaten biliyorsanız, sonraki bölüme geçin.
|
||||
Eğer bir Python uzmanıysanız ve type hints hakkında her şeyi zaten biliyorsanız, sonraki bölüme geçin.
|
||||
|
||||
///
|
||||
|
||||
## Motivasyon
|
||||
## Motivasyon { #motivation }
|
||||
|
||||
Basit bir örnek ile başlayalım:
|
||||
Basit bir örnekle başlayalım:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001.py *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py *}
|
||||
|
||||
|
||||
Programın çıktısı:
|
||||
Bu programı çalıştırınca şu çıktıyı alırsınız:
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
|
||||
Fonksiyon sırayla şunları yapar:
|
||||
Fonksiyon şunları yapar:
|
||||
|
||||
* `first_name` ve `last_name` değerlerini alır.
|
||||
* `title()` ile değişkenlerin ilk karakterlerini büyütür.
|
||||
* Değişkenleri aralarında bir boşlukla beraber <abbr title="Onları bir bütün olarak sırayla birleştirir.">Birleştirir</abbr>.
|
||||
* `title()` ile her birinin ilk harfini büyük harfe çevirir.
|
||||
* Ortada bir boşluk olacak şekilde <dfn title="Onları tek bir bütün olarak bir araya getirir. İçerikler art arda gelir.">Birleştirir</dfn>.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
|
||||
|
||||
|
||||
### Düzenle
|
||||
### Düzenleyelim { #edit-it }
|
||||
|
||||
Bu çok basit bir program.
|
||||
|
||||
Ama şimdi sıfırdan yazdığınızı hayal edin.
|
||||
Ama şimdi bunu sıfırdan yazdığınızı hayal edin.
|
||||
|
||||
Bir noktada fonksiyonun tanımına başlayacaktınız, parametreleri hazır hale getirdiniz...
|
||||
Bir noktada fonksiyon tanımını yazmaya başlamış olacaktınız, parametreler hazır...
|
||||
|
||||
Ama sonra "ilk harfi büyük harfe dönüştüren yöntemi" çağırmanız gerekir.
|
||||
Ama sonra "ilk harfi büyük harfe çeviren method"u çağırmanız gerekiyor.
|
||||
|
||||
`upper` mıydı ? Yoksa `uppercase`' mi? `first_uppercase`? `capitalize`?
|
||||
`upper` mıydı? `uppercase` miydi? `first_uppercase`? `capitalize`?
|
||||
|
||||
Ardından, programcıların en iyi arkadaşı olan otomatik tamamlama ile denediniz.
|
||||
Sonra eski programcı dostuyla denersiniz: editör autocomplete.
|
||||
|
||||
'first_name', ardından bir nokta ('.') yazıp otomatik tamamlamayı tetiklemek için 'Ctrl+Space' tuşlarına bastınız.
|
||||
Fonksiyonun ilk parametresi olan `first_name`'i yazarsınız, sonra bir nokta (`.`) ve ardından autocomplete'i tetiklemek için `Ctrl+Space`'e basarsınız.
|
||||
|
||||
Ancak, ne yazık ki, yararlı hiçbir şey elde edemediniz:
|
||||
Ama ne yazık ki, işe yarar bir şey göremezsiniz:
|
||||
|
||||
<img src="/img/python-types/image01.png">
|
||||
|
||||
### Tipleri ekle
|
||||
### Tipleri ekleyelim { #add-types }
|
||||
|
||||
Önceki sürümden sadece bir satırı değiştirelim.
|
||||
Önceki sürümden tek bir satırı değiştirelim.
|
||||
|
||||
Tam olarak bu parçayı, işlevin parametrelerini değiştireceğiz:
|
||||
Fonksiyonun parametreleri olan şu parçayı:
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
```
|
||||
|
||||
ve bu hale getireceğiz:
|
||||
şuna çevireceğiz:
|
||||
|
||||
```Python
|
||||
first_name: str, last_name: str
|
||||
@@ -78,58 +76,55 @@ ve bu hale getireceğiz:
|
||||
|
||||
Bu kadar.
|
||||
|
||||
İşte bunlar "tip belirteçleri":
|
||||
Bunlar "type hints":
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
|
||||
|
||||
|
||||
Bu, aşağıdaki gibi varsayılan değerleri bildirmekle aynı şey değildir:
|
||||
Bu, aşağıdaki gibi default değerler bildirmekle aynı şey değildir:
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
```
|
||||
|
||||
Bu tamamen farklı birşey
|
||||
Bu farklı bir şey.
|
||||
|
||||
İki nokta üst üste (`:`) kullanıyoruz , eşittir (`=`) değil.
|
||||
Eşittir (`=`) değil, iki nokta (`:`) kullanıyoruz.
|
||||
|
||||
Normalde tip belirteçleri eklemek, kod üzerinde olacakları değiştirmez.
|
||||
Ve type hints eklemek, normalde onlarsız ne oluyorsa onu değiştirmez.
|
||||
|
||||
Şimdi programı sıfırdan birdaha yazdığınızı hayal edin.
|
||||
Ama şimdi, type hints ile o fonksiyonu oluşturmanın ortasında olduğunuzu tekrar hayal edin.
|
||||
|
||||
Aynı noktada, `Ctrl+Space` ile otomatik tamamlamayı tetiklediniz ve şunu görüyorsunuz:
|
||||
Aynı noktada, `Ctrl+Space` ile autocomplete'i tetiklemeye çalışırsınız ve şunu görürsünüz:
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
Aradığınızı bulana kadar seçenekleri kaydırabilirsiniz:
|
||||
Bununla birlikte, seçenekleri görerek kaydırabilirsiniz; ta ki "tanıdık gelen" seçeneği bulana kadar:
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## Daha fazla motivasyon
|
||||
## Daha fazla motivasyon { #more-motivation }
|
||||
|
||||
Bu fonksiyon, zaten tür belirteçlerine sahip:
|
||||
Şu fonksiyona bakın, zaten type hints içeriyor:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
|
||||
|
||||
|
||||
Editör değişkenlerin tiplerini bildiğinden, yalnızca otomatik tamamlama değil, hata kontrolleri de sağlar:
|
||||
Editör değişkenlerin tiplerini bildiği için, sadece completion değil, aynı zamanda hata kontrolleri de alırsınız:
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
Artık `age` değişkenini `str(age)` olarak kullanmanız gerektiğini biliyorsunuz:
|
||||
Artık bunu düzeltmeniz gerektiğini, `age`'i `str(age)` ile string'e çevirmeniz gerektiğini biliyorsunuz:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
|
||||
|
||||
## Tipleri Bildirmek { #declaring-types }
|
||||
|
||||
## Tip bildirme
|
||||
Type hints bildirmek için ana yeri az önce gördünüz: fonksiyon parametreleri.
|
||||
|
||||
Az önce tip belirteçlerinin en çok kullanıldığı yeri gördünüz.
|
||||
Bu, **FastAPI** ile kullanırken de onları en çok kullanacağınız yerdir.
|
||||
|
||||
**FastAPI**ile çalışırken tip belirteçlerini en çok kullanacağımız yer yine fonksiyonlardır.
|
||||
### Basit tipler { #simple-types }
|
||||
|
||||
### Basit tipler
|
||||
|
||||
Yalnızca `str` değil, tüm standart Python tiplerinin bildirebilirsiniz.
|
||||
Sadece `str` değil, tüm standart Python tiplerini bildirebilirsiniz.
|
||||
|
||||
Örneğin şunları kullanabilirsiniz:
|
||||
|
||||
@@ -138,176 +133,216 @@ Yalnızca `str` değil, tüm standart Python tiplerinin bildirebilirsiniz.
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
|
||||
|
||||
### `typing` modülü { #typing-module }
|
||||
|
||||
Bazı ek kullanım durumları için standart kütüphanedeki `typing` modülünden bazı şeyleri import etmeniz gerekebilir. Örneğin bir şeyin "herhangi bir tip" olabileceğini bildirmek istediğinizde, `typing` içindeki `Any`'yi kullanabilirsiniz:
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
|
||||
### Tip parametreleri ile Generic tipler
|
||||
def some_function(data: Any):
|
||||
print(data)
|
||||
```
|
||||
|
||||
"dict", "list", "set" ve "tuple" gibi diğer değerleri içerebilen bazı veri yapıları vardır. Ve dahili değerlerinin de tip belirtecleri olabilir.
|
||||
### Generic tipler { #generic-types }
|
||||
|
||||
Bu tipleri ve dahili tpileri bildirmek için standart Python modülünü "typing" kullanabilirsiniz.
|
||||
Bazı tipler, köşeli parantez içinde "type parameters" alarak iç tiplerini tanımlayabilir; örneğin "string listesi" `list[str]` olarak bildirilir.
|
||||
|
||||
Bu tür tip belirteçlerini desteklemek için özel olarak mevcuttur.
|
||||
Bu şekilde type parameter alabilen tiplere **Generic types** veya **Generics** denir.
|
||||
|
||||
#### `List`
|
||||
Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içinde tiplerle):
|
||||
|
||||
Örneğin `str` değerlerden oluşan bir `list` tanımlayalım.
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
From `typing`, import `List` (büyük harf olan `L` ile):
|
||||
#### List { #list }
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[1] *}
|
||||
Örneğin, `str`'lerden oluşan bir `list` olan bir değişken tanımlayalım.
|
||||
|
||||
Değişkeni, aynı iki nokta (`:`) sözdizimiyle bildirin.
|
||||
|
||||
Değişkenin tipini yine iki nokta üstüste (`:`) ile belirleyin.
|
||||
Tip olarak `list` yazın.
|
||||
|
||||
tip olarak `List` kullanın.
|
||||
`list`, bazı iç tipleri barındıran bir tip olduğundan, bunları köşeli parantez içine yazarsınız:
|
||||
|
||||
Liste, bazı dahili tipleri içeren bir tür olduğundan, bunları köşeli parantez içine alırsınız:
|
||||
{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[4] *}
|
||||
/// info | Bilgi
|
||||
|
||||
Köşeli parantez içindeki bu iç tiplere "type parameters" denir.
|
||||
|
||||
/// tip | Ipucu
|
||||
|
||||
Köşeli parantez içindeki bu dahili tiplere "tip parametreleri" denir.
|
||||
|
||||
Bu durumda `str`, `List`e iletilen tür parametresidir.
|
||||
Bu durumda `str`, `list`'e verilen type parameter'dır.
|
||||
|
||||
///
|
||||
|
||||
Bunun anlamı şudur: "`items` değişkeni bir `list`tir ve bu listedeki öğelerin her biri bir `str`dir".
|
||||
Bu şu demektir: "`items` değişkeni bir `list` ve bu listedeki her bir öğe `str`".
|
||||
|
||||
Bunu yaparak, düzenleyicinizin listedeki öğeleri işlerken bile destek sağlamasını sağlayabilirsiniz:
|
||||
Bunu yaparak, editörünüz listeden öğeleri işlerken bile destek sağlayabilir:
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Tip belirteçleri olmadan, bunu başarmak neredeyse imkansızdır.
|
||||
Tipler olmadan, bunu başarmak neredeyse imkansızdır.
|
||||
|
||||
`item` değişkeninin `items` listesindeki öğelerden biri olduğuna dikkat edin.
|
||||
`item` değişkeninin, `items` listesindeki elemanlardan biri olduğuna dikkat edin.
|
||||
|
||||
Ve yine, editör bunun bir `str` olduğunu biliyor ve bunun için destek sağlıyor.
|
||||
Ve yine de editör bunun bir `str` olduğunu bilir ve buna göre destek sağlar.
|
||||
|
||||
#### `Tuple` ve `Set`
|
||||
#### Tuple ve Set { #tuple-and-set }
|
||||
|
||||
`Tuple` ve `set`lerin tiplerini bildirmek için de aynısını yapıyoruz:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
|
||||
|
||||
|
||||
Bu şu anlama geliyor:
|
||||
|
||||
* `items_t` değişkeni sırasıyla `int`, `int`, ve `str` tiplerinden oluşan bir `tuple` türündedir .
|
||||
* `items_s` ise her öğesi `bytes` türünde olan bir `set` örneğidir.
|
||||
|
||||
#### `Dict`
|
||||
|
||||
Bir `dict` tanımlamak için virgülle ayrılmış iki parametre verebilirsiniz.
|
||||
|
||||
İlk tip parametresi `dict` değerinin `key` değeri içindir.
|
||||
|
||||
İkinci parametre ise `dict` değerinin `value` değeri içindir:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
|
||||
`tuple`'ları ve `set`'leri bildirmek için de aynısını yaparsınız:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
|
||||
|
||||
Bu şu anlama gelir:
|
||||
|
||||
* `prices` değişkeni `dict` tipindedir:
|
||||
* `dict` değişkeninin `key` değeri `str` tipindedir (herbir item'ın "name" değeri).
|
||||
* `dict` değişkeninin `value` değeri `float` tipindedir (lherbir item'ın "price" değeri).
|
||||
* `items_t` değişkeni 3 öğeli bir `tuple`'dır: bir `int`, bir başka `int` ve bir `str`.
|
||||
* `items_s` değişkeni bir `set`'tir ve her bir öğesi `bytes` tipindedir.
|
||||
|
||||
#### `Optional`
|
||||
#### Dict { #dict }
|
||||
|
||||
`Optional` bir değişkenin `str`gibi bir tipi olabileceğini ama isteğe bağlı olarak tipinin `None` olabileceğini belirtir:
|
||||
Bir `dict` tanımlamak için, virgülle ayrılmış 2 type parameter verirsiniz.
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009.py!}
|
||||
İlk type parameter, `dict`'in key'leri içindir.
|
||||
|
||||
İkinci type parameter, `dict`'in value'ları içindir:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
|
||||
|
||||
Bu şu anlama gelir:
|
||||
|
||||
* `prices` değişkeni bir `dict`'tir:
|
||||
* Bu `dict`'in key'leri `str` tipindedir (örneğin her bir öğenin adı).
|
||||
* Bu `dict`'in value'ları `float` tipindedir (örneğin her bir öğenin fiyatı).
|
||||
|
||||
#### Union { #union }
|
||||
|
||||
Bir değişkenin **birkaç tipten herhangi biri** olabileceğini bildirebilirsiniz; örneğin bir `int` veya bir `str`.
|
||||
|
||||
Bunu tanımlamak için, her iki tipi ayırmak üzere <dfn title='başka adıyla "bit düzeyinde veya operatörü", ancak burada o anlamı önemli değil'>dikey çizgi (`|`)</dfn> kullanırsınız.
|
||||
|
||||
Buna "union" denir, çünkü değişken bu iki tip kümesinin birleşimindeki herhangi bir şey olabilir.
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
||||
```
|
||||
|
||||
`str` yerine `Optional[str]` kullanmak editorün bu değerin her zaman `str` tipinde değil bazen `None` tipinde de olabileceğini belirtir ve hataları tespit etmemizde yardımcı olur.
|
||||
Bu, `item`'ın `int` veya `str` olabileceği anlamına gelir.
|
||||
|
||||
#### Generic tipler
|
||||
#### Muhtemelen `None` { #possibly-none }
|
||||
|
||||
Köşeli parantez içinde tip parametreleri alan bu türler, örneğin:
|
||||
Bir değerin `str` gibi bir tipi olabileceğini ama aynı zamanda `None` da olabileceğini bildirebilirsiniz.
|
||||
|
||||
* `List`
|
||||
* `Tuple`
|
||||
* `Set`
|
||||
* `Dict`
|
||||
* `Optional`
|
||||
* ...and others.
|
||||
//// tab | Python 3.10+
|
||||
|
||||
**Generic types** yada **Generics** olarak adlandırılır.
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial009_py310.py!}
|
||||
```
|
||||
|
||||
### Tip olarak Sınıflar
|
||||
////
|
||||
|
||||
Bir değişkenin tipini bir sınıf ile bildirebilirsiniz.
|
||||
Sadece `str` yerine `str | None` kullanmak, aslında değer `None` olabilecekken her zaman `str` olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olur.
|
||||
|
||||
Diyelim ki `name` değerine sahip `Person` sınıfınız var:
|
||||
### Tip olarak sınıflar { #classes-as-types }
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
|
||||
Bir sınıfı da bir değişkenin tipi olarak bildirebilirsiniz.
|
||||
|
||||
Örneğin, adı olan bir `Person` sınıfınız olsun:
|
||||
|
||||
Sonra bir değişkeni 'Person' tipinde tanımlayabilirsiniz:
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
|
||||
Sonra bir değişkeni `Person` tipinde olacak şekilde bildirebilirsiniz:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
|
||||
|
||||
Ve yine bütün editör desteğini alırsınız:
|
||||
Ve sonra, yine tüm editör desteğini alırsınız:
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
## Pydantic modelleri
|
||||
Bunun "`one_person`, `Person` sınıfının bir **instance**'ıdır" anlamına geldiğine dikkat edin.
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> veri doğrulaması yapmak için bir Python kütüphanesidir.
|
||||
"`one_person`, `Person` adlı **class**'tır" anlamına gelmez.
|
||||
|
||||
Verilerin "biçimini" niteliklere sahip sınıflar olarak düzenlersiniz.
|
||||
## Pydantic modelleri { #pydantic-models }
|
||||
|
||||
Ve her niteliğin bir türü vardır.
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, data validation yapmak için bir Python kütüphanesidir.
|
||||
|
||||
Sınıfın bazı değerlerle bir örneğini oluşturursunuz ve değerleri doğrular, bunları uygun türe dönüştürür ve size tüm verileri içeren bir nesne verir.
|
||||
Verinin "shape"'ini attribute'lara sahip sınıflar olarak tanımlarsınız.
|
||||
|
||||
Ve ortaya çıkan nesne üzerindeki bütün editör desteğini alırsınız.
|
||||
Ve her attribute'un bir tipi vardır.
|
||||
|
||||
Resmi Pydantic dokümanlarından alınmıştır:
|
||||
Ardından o sınıfın bir instance'ını bazı değerlerle oluşturursunuz; bu değerleri doğrular, uygun tipe dönüştürür (gerekliyse) ve size tüm veriyi içeren bir nesne verir.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011.py *}
|
||||
Ve bu ortaya çıkan nesne ile tüm editör desteğini alırsınız.
|
||||
|
||||
Resmî Pydantic dokümanlarından bir örnek:
|
||||
|
||||
/// info
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
|
||||
Daha fazla şey öğrenmek için <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic'i takip edin</a>.
|
||||
/// info | Bilgi
|
||||
|
||||
Daha fazlasını öğrenmek için <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic'in dokümanlarına bakın</a>.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** tamamen Pydantic'e dayanmaktadır.
|
||||
**FastAPI** tamamen Pydantic üzerine kuruludur.
|
||||
|
||||
Daha fazlasini görmek için [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
|
||||
Bunların pratikte nasıl çalıştığını [Eğitim - Kullanım Kılavuzu](tutorial/index.md){.internal-link target=_blank} içinde çok daha fazla göreceksiniz.
|
||||
|
||||
## **FastAPI** tip belirteçleri
|
||||
## Metadata Annotations ile Type Hints { #type-hints-with-metadata-annotations }
|
||||
|
||||
**FastAPI** birkaç şey yapmak için bu tür tip belirteçlerinden faydalanır.
|
||||
Python'da ayrıca, `Annotated` kullanarak bu type hints içine **ek <dfn title="Veri hakkında veri; bu durumda tip hakkında bilgi, örneğin bir açıklama.">üstveri</dfn>** koymayı sağlayan bir özellik de vardır.
|
||||
|
||||
**FastAPI** ile parametre tiplerini bildirirsiniz ve şunları elde edersiniz:
|
||||
`Annotated`'ı `typing` içinden import edebilirsiniz.
|
||||
|
||||
* **Editor desteği**.
|
||||
* **Tip kontrolü**.
|
||||
{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
|
||||
|
||||
...ve **FastAPI** aynı belirteçleri şunlar için de kullanıyor:
|
||||
Python'un kendisi bu `Annotated` ile bir şey yapmaz. Editörler ve diğer araçlar için tip hâlâ `str`'dir.
|
||||
|
||||
* **Gereksinimleri tanımlama**: request path parameters, query parameters, headers, bodies, dependencies, ve benzeri gereksinimlerden
|
||||
* **Verileri çevirme**: Gönderilen veri tipinden istenilen veri tipine çevirme.
|
||||
* **Verileri doğrulama**: Her gönderilen verinin:
|
||||
* doğrulanması ve geçersiz olduğunda **otomatik hata** oluşturma.
|
||||
* OpenAPI kullanarak apinizi **Belgeleyin** :
|
||||
* bu daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzü tarafından kullanılır.
|
||||
Ama **FastAPI**'ye uygulamanızın nasıl davranmasını istediğinize dair ek metadata sağlamak için `Annotated` içindeki bu alanı kullanabilirsiniz.
|
||||
|
||||
Bütün bunlar kulağa soyut gelebilir. Merak etme. Tüm bunları çalışırken göreceksiniz. [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
|
||||
Hatırlanması gereken önemli nokta: `Annotated`'a verdiğiniz **ilk *type parameter***, **gerçek tip**tir. Geri kalanı ise diğer araçlar için metadatadır.
|
||||
|
||||
Önemli olan, standart Python türlerini tek bir yerde kullanarak (daha fazla sınıf, dekoratör vb. eklemek yerine), **FastAPI**'nin bizim için işi yapmasını sağlamak.
|
||||
Şimdilik, sadece `Annotated`'ın var olduğunu ve bunun standart Python olduğunu bilmeniz yeterli. 😎
|
||||
|
||||
/// info
|
||||
İleride bunun ne kadar **güçlü** olabildiğini göreceksiniz.
|
||||
|
||||
Tüm öğreticiyi zaten okuduysanız ve türler hakkında daha fazla bilgi için geri döndüyseniz, iyi bir kaynak:<a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank"> the "cheat sheet" from `mypy`</a>.
|
||||
/// tip | İpucu
|
||||
|
||||
Bunun **standart Python** olması, editörünüzde mümkün olan **en iyi developer experience**'ı almaya devam edeceğiniz anlamına gelir; kodu analiz etmek ve refactor etmek için kullandığınız araçlarla da, vb. ✨
|
||||
|
||||
Ayrıca kodunuzun pek çok başka Python aracı ve kütüphanesiyle çok uyumlu olacağı anlamına gelir. 🚀
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI**'de type hints { #type-hints-in-fastapi }
|
||||
|
||||
**FastAPI**, birkaç şey yapmak için bu type hints'ten faydalanır.
|
||||
|
||||
**FastAPI** ile type hints kullanarak parametreleri bildirirsiniz ve şunları elde edersiniz:
|
||||
|
||||
* **Editör desteği**.
|
||||
* **Tip kontrolleri**.
|
||||
|
||||
...ve **FastAPI** aynı bildirimleri şunlar için de kullanır:
|
||||
|
||||
* **Gereksinimleri tanımlamak**: request path parameters, query parameters, headers, bodies, bağımlılıklar (dependencies), vb.
|
||||
* **Veriyi dönüştürmek**: request'ten gerekli tipe.
|
||||
* **Veriyi doğrulamak**: her request'ten gelen veriyi:
|
||||
* Veri geçersiz olduğunda client'a dönen **otomatik hatalar** üretmek.
|
||||
* OpenAPI kullanarak API'yi **dokümante etmek**:
|
||||
* bu, daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzleri tarafından kullanılır.
|
||||
|
||||
Bunların hepsi kulağa soyut gelebilir. Merak etmeyin. Tüm bunları [Eğitim - Kullanım Kılavuzu](tutorial/index.md){.internal-link target=_blank} içinde çalışırken göreceksiniz.
|
||||
|
||||
Önemli olan, standart Python tiplerini tek bir yerde kullanarak (daha fazla sınıf, decorator vb. eklemek yerine), **FastAPI**'nin sizin için işin büyük kısmını yapmasıdır.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Tüm tutorial'ı zaten bitirdiyseniz ve tipler hakkında daha fazlasını görmek için geri döndüyseniz, iyi bir kaynak: <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`'nin "cheat sheet"i</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Kaynaklar
|
||||
# Kaynaklar { #resources }
|
||||
|
||||
Ek kaynaklar, dış bağlantılar, makaleler ve daha fazlası. ✈️
|
||||
Ek kaynaklar, dış bağlantılar ve daha fazlası. ✈️
|
||||
|
||||
@@ -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â LLM'ini 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)
|
||||
|
||||
///
|
||||
@@ -0,0 +1,84 @@
|
||||
# Arka Plan Görevleri { #background-tasks }
|
||||
|
||||
Response döndürüldükten *sonra* çalıştırılacak arka plan görevleri tanımlayabilirsiniz.
|
||||
|
||||
Bu, request’ten sonra yapılması gereken; ancak client’ın response’u almadan önce tamamlanmasını beklemesine gerek olmayan işlemler için kullanışlıdır.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* Bir işlem gerçekleştirdikten sonra gönderilen email bildirimleri:
|
||||
* Bir email server’a bağlanmak ve email göndermek genellikle "yavaş" olduğundan (birkaç saniye), response’u hemen döndürüp email bildirimini arka planda gönderebilirsiniz.
|
||||
* Veri işleme:
|
||||
* Örneğin, yavaş bir süreçten geçmesi gereken bir dosya aldığınızı düşünün; "Accepted" (HTTP 202) response’u döndürüp dosyayı arka planda işleyebilirsiniz.
|
||||
|
||||
## `BackgroundTasks` Kullanımı { #using-backgroundtasks }
|
||||
|
||||
Önce `BackgroundTasks`’i import edin ve *path operation function*’ınızda `BackgroundTasks` tip bildirimi olan bir parametre tanımlayın:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
|
||||
|
||||
**FastAPI**, sizin için `BackgroundTasks` tipinde bir obje oluşturur ve onu ilgili parametre olarak geçirir.
|
||||
|
||||
## Bir Görev Fonksiyonu Oluşturun { #create-a-task-function }
|
||||
|
||||
Arka plan görevi olarak çalıştırılacak bir fonksiyon oluşturun.
|
||||
|
||||
Bu, parametre alabilen standart bir fonksiyondur.
|
||||
|
||||
`async def` de olabilir, normal `def` de olabilir; **FastAPI** bunu doğru şekilde nasıl ele alacağını bilir.
|
||||
|
||||
Bu örnekte görev fonksiyonu bir dosyaya yazacaktır (email göndermeyi simüle ediyor).
|
||||
|
||||
Ve yazma işlemi `async` ve `await` kullanmadığı için fonksiyonu normal `def` ile tanımlarız:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
|
||||
|
||||
## Arka Plan Görevini Ekleyin { #add-the-background-task }
|
||||
|
||||
*Path operation function*’ınızın içinde, görev fonksiyonunuzu `.add_task()` metodu ile *background tasks* objesine ekleyin:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
|
||||
|
||||
`.add_task()` şu argümanları alır:
|
||||
|
||||
* Arka planda çalıştırılacak bir görev fonksiyonu (`write_notification`).
|
||||
* Görev fonksiyonuna sırayla geçirilecek argümanlar (`email`).
|
||||
* Görev fonksiyonuna geçirilecek keyword argümanlar (`message="some notification"`).
|
||||
|
||||
## Dependency Injection { #dependency-injection }
|
||||
|
||||
`BackgroundTasks` kullanımı dependency injection sistemiyle de çalışır; `BackgroundTasks` tipinde bir parametreyi birden fazla seviyede tanımlayabilirsiniz: bir *path operation function* içinde, bir dependency’de (dependable), bir sub-dependency’de, vb.
|
||||
|
||||
**FastAPI** her durumda ne yapılacağını ve aynı objenin nasıl yeniden kullanılacağını bilir; böylece tüm arka plan görevleri birleştirilir ve sonrasında arka planda çalıştırılır:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
|
||||
|
||||
Bu örnekte, response gönderildikten *sonra* mesajlar `log.txt` dosyasına yazılacaktır.
|
||||
|
||||
Request’te bir query varsa, log’a bir arka plan göreviyle yazılır.
|
||||
|
||||
Ardından *path operation function* içinde oluşturulan başka bir arka plan görevi, `email` path parametresini kullanarak bir mesaj yazar.
|
||||
|
||||
## Teknik Detaylar { #technical-details }
|
||||
|
||||
`BackgroundTasks` sınıfı doğrudan <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>’dan gelir.
|
||||
|
||||
`fastapi` üzerinden import edebilmeniz ve yanlışlıkla `starlette.background` içindeki alternatif `BackgroundTask`’i (sonunda `s` olmadan) import etmemeniz için FastAPI’nin içine doğrudan import/eklenmiştir.
|
||||
|
||||
Sadece `BackgroundTasks` (ve `BackgroundTask` değil) kullanarak, bunu bir *path operation function* parametresi olarak kullanmak ve gerisini **FastAPI**’nin sizin için halletmesini sağlamak mümkündür; tıpkı `Request` objesini doğrudan kullanırken olduğu gibi.
|
||||
|
||||
FastAPI’de `BackgroundTask`’i tek başına kullanmak hâlâ mümkündür; ancak bu durumda objeyi kendi kodunuzda oluşturmanız ve onu içeren bir Starlette `Response` döndürmeniz gerekir.
|
||||
|
||||
Daha fazla detayı <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">Starlette’in Background Tasks için resmi dokümantasyonunda</a> görebilirsiniz.
|
||||
|
||||
## Dikkat Edilmesi Gerekenler { #caveat }
|
||||
|
||||
Yoğun arka plan hesaplamaları yapmanız gerekiyorsa ve bunun aynı process tarafından çalıştırılmasına şart yoksa (örneğin memory, değişkenler vb. paylaşmanız gerekmiyorsa), <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a> gibi daha büyük araçları kullanmak size fayda sağlayabilir.
|
||||
|
||||
Bunlar genellikle daha karmaşık konfigurasyonlar ve RabbitMQ veya Redis gibi bir mesaj/iş kuyruğu yöneticisi gerektirir; ancak arka plan görevlerini birden fazla process’te ve özellikle birden fazla server’da çalıştırmanıza olanak tanırlar.
|
||||
|
||||
Ancak aynı **FastAPI** app’i içindeki değişkenlere ve objelere erişmeniz gerekiyorsa veya küçük arka plan görevleri (email bildirimi göndermek gibi) yapacaksanız, doğrudan `BackgroundTasks` kullanabilirsiniz.
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Arka plan görevleri eklemek için *path operation function*’larda ve dependency’lerde parametre olarak `BackgroundTasks`’i import edip kullanın.
|
||||
@@ -0,0 +1,504 @@
|
||||
# Daha Büyük Uygulamalar - Birden Fazla Dosya { #bigger-applications-multiple-files }
|
||||
|
||||
Bir uygulama veya web API geliştirirken, her şeyi tek bir dosyaya sığdırabilmek nadirdir.
|
||||
|
||||
**FastAPI**, tüm esnekliği korurken uygulamanızı yapılandırmanıza yardımcı olan pratik bir araç sunar.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Flask'ten geliyorsanız, bu yapı Flask'in Blueprints'ine denk gelir.
|
||||
|
||||
///
|
||||
|
||||
## Örnek Bir Dosya Yapısı { #an-example-file-structure }
|
||||
|
||||
Diyelim ki şöyle bir dosya yapınız var:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Birden fazla `__init__.py` dosyası var: her dizinde veya alt dizinde bir tane.
|
||||
|
||||
Bu sayede bir dosyadaki kodu diğerine import edebilirsiniz.
|
||||
|
||||
Örneğin `app/main.py` içinde şöyle bir satırınız olabilir:
|
||||
|
||||
```
|
||||
from app.routers import items
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
* `app` dizini her şeyi içerir. Ayrıca boş bir `app/__init__.py` dosyası olduğu için bir "Python package" (bir "Python module" koleksiyonu) olur: `app`.
|
||||
* İçinde bir `app/main.py` dosyası vardır. Bir Python package'in (içinde `__init__.py` dosyası olan bir dizinin) içinde olduğundan, o package'in bir "module"’üdür: `app.main`.
|
||||
* Benzer şekilde `app/dependencies.py` dosyası da bir "module"’dür: `app.dependencies`.
|
||||
* `app/routers/` adında bir alt dizin vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu bir "Python subpackage"’dir: `app.routers`.
|
||||
* `app/routers/items.py` dosyası `app/routers/` package’i içinde olduğundan bir submodule’dür: `app.routers.items`.
|
||||
* `app/routers/users.py` için de aynı şekilde, başka bir submodule’dür: `app.routers.users`.
|
||||
* `app/internal/` adında bir alt dizin daha vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu da bir "Python subpackage"’dir: `app.internal`.
|
||||
* Ve `app/internal/admin.py` dosyası başka bir submodule’dür: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
Aynı dosya yapısı, yorumlarla birlikte:
|
||||
|
||||
```bash
|
||||
.
|
||||
├── app # "app" bir Python package'idir
|
||||
│ ├── __init__.py # bu dosya, "app"i bir "Python package" yapar
|
||||
│ ├── main.py # "main" module'ü, örn. import app.main
|
||||
│ ├── dependencies.py # "dependencies" module'ü, örn. import app.dependencies
|
||||
│ └── routers # "routers" bir "Python subpackage"idir
|
||||
│ │ ├── __init__.py # "routers"ı bir "Python subpackage" yapar
|
||||
│ │ ├── items.py # "items" submodule'ü, örn. import app.routers.items
|
||||
│ │ └── users.py # "users" submodule'ü, örn. import app.routers.users
|
||||
│ └── internal # "internal" bir "Python subpackage"idir
|
||||
│ ├── __init__.py # "internal"ı bir "Python subpackage" yapar
|
||||
│ └── admin.py # "admin" submodule'ü, örn. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
|
||||
Diyelim ki sadece kullanıcıları yönetmeye ayrılmış dosyanız `/app/routers/users.py` içindeki submodule olsun.
|
||||
|
||||
Kullanıcılarla ilgili *path operation*’ları, kodun geri kalanından ayrı tutmak istiyorsunuz; böylece düzenli kalır.
|
||||
|
||||
Ancak bu hâlâ aynı **FastAPI** uygulaması/web API’sinin bir parçasıdır (aynı "Python Package" içinde).
|
||||
|
||||
Bu module için *path operation*’ları `APIRouter` kullanarak oluşturabilirsiniz.
|
||||
|
||||
### `APIRouter` Import Edin { #import-apirouter }
|
||||
|
||||
`FastAPI` class’ında yaptığınız gibi import edip bir "instance" oluşturursunuz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
### `APIRouter` ile *Path Operations* { #path-operations-with-apirouter }
|
||||
|
||||
Sonra bunu kullanarak *path operation*’larınızı tanımlarsınız.
|
||||
|
||||
`FastAPI` class’ını nasıl kullanıyorsanız aynı şekilde kullanın:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
`APIRouter`’ı "mini bir `FastAPI`" class’ı gibi düşünebilirsiniz.
|
||||
|
||||
Aynı seçeneklerin hepsi desteklenir.
|
||||
|
||||
Aynı `parameters`, `responses`, `dependencies`, `tags`, vb.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu örnekte değişkenin adı `router`. Ancak istediğiniz gibi adlandırabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Bu `APIRouter`’ı ana `FastAPI` uygulamasına ekleyeceğiz; ama önce dependency’lere ve bir diğer `APIRouter`’a bakalım.
|
||||
|
||||
## Dependencies { #dependencies }
|
||||
|
||||
Uygulamanın birden fazla yerinde kullanılacak bazı dependency’lere ihtiyacımız olacağını görüyoruz.
|
||||
|
||||
Bu yüzden onları ayrı bir `dependencies` module’üne koyuyoruz (`app/dependencies.py`).
|
||||
|
||||
Şimdi, özel bir `X-Token` header'ını okumak için basit bir dependency kullanalım:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Örneği basit tutmak için uydurma bir header kullanıyoruz.
|
||||
|
||||
Ancak gerçek senaryolarda, entegre [Security yardımcı araçlarını](security/index.md){.internal-link target=_blank} kullanarak daha iyi sonuç alırsınız.
|
||||
|
||||
///
|
||||
|
||||
## `APIRouter` ile Başka Bir Module { #another-module-with-apirouter }
|
||||
|
||||
Diyelim ki uygulamanızdaki "items" ile ilgili endpoint'ler de `app/routers/items.py` module’ünde olsun.
|
||||
|
||||
Şunlar için *path operation*’larınız var:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
Bu, `app/routers/users.py` ile aynı yapıdadır.
|
||||
|
||||
Ancak biraz daha akıllı davranıp kodu sadeleştirmek istiyoruz.
|
||||
|
||||
Bu module’deki tüm *path operation*’ların şu ortak özelliklere sahip olduğunu biliyoruz:
|
||||
|
||||
* Path `prefix`: `/items`.
|
||||
* `tags`: (tek bir tag: `items`).
|
||||
* Ek `responses`.
|
||||
* `dependencies`: hepsinin, oluşturduğumuz `X-Token` dependency’sine ihtiyacı var.
|
||||
|
||||
Dolayısıyla bunları her *path operation*’a tek tek eklemek yerine `APIRouter`’a ekleyebiliriz.
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Her *path operation*’ın path’i aşağıdaki gibi `/` ile başlamak zorunda olduğundan:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
async def read_item(item_id: str):
|
||||
...
|
||||
```
|
||||
|
||||
...prefix’in sonunda `/` olmamalıdır.
|
||||
|
||||
Yani bu örnekte prefix `/items` olur.
|
||||
|
||||
Ayrıca, bu router içindeki tüm *path operation*’lara uygulanacak bir `tags` listesi ve ek `responses` da ekleyebiliriz.
|
||||
|
||||
Ve router’daki tüm *path operation*’lara eklenecek, her request için çalıştırılıp çözülecek bir `dependencies` listesi de ekleyebiliriz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
[ *path operation decorator*’larındaki dependency’lerde](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} olduğu gibi, *path operation function*’ınıza herhangi bir değer aktarılmayacağını unutmayın.
|
||||
|
||||
///
|
||||
|
||||
Sonuç olarak item path’leri artık:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
...tam da istediğimiz gibi olur.
|
||||
|
||||
* Hepsi, içinde tek bir string `"items"` bulunan bir tag listesiyle işaretlenir.
|
||||
* Bu "tags", özellikle otomatik interaktif dokümantasyon sistemleri (OpenAPI) için çok faydalıdır.
|
||||
* Hepsi önceden tanımlı `responses`’ları içerir.
|
||||
* Bu *path operation*’ların hepsinde, öncesinde `dependencies` listesi değerlendirilip çalıştırılır.
|
||||
* Ayrıca belirli bir *path operation* içinde dependency tanımlarsanız, **onlar da çalıştırılır**.
|
||||
* Önce router dependency’leri, sonra decorator’daki [`dependencies`](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, sonra da normal parametre dependency’leri çalışır.
|
||||
* Ayrıca [`scopes` ile `Security` dependency’leri](../advanced/security/oauth2-scopes.md){.internal-link target=_blank} de ekleyebilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`APIRouter` içinde `dependencies` kullanmak, örneğin bir grup *path operation* için kimlik doğrulamayı zorunlu kılmakta kullanılabilir. Dependency’leri tek tek her birine eklemeseniz bile.
|
||||
|
||||
///
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
`prefix`, `tags`, `responses` ve `dependencies` parametreleri (çoğu başka örnekte olduğu gibi) kod tekrarını önlemenize yardımcı olan, **FastAPI**’nin bir özelliğidir.
|
||||
|
||||
///
|
||||
|
||||
### Dependency'leri Import Edin { #import-the-dependencies }
|
||||
|
||||
Bu kod `app.routers.items` module’ünde, yani `app/routers/items.py` dosyasında duruyor.
|
||||
|
||||
Dependency function’ını ise `app.dependencies` module’ünden, yani `app/dependencies.py` dosyasından almamız gerekiyor.
|
||||
|
||||
Bu yüzden dependency’ler için `..` ile relative import kullanıyoruz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
|
||||
#### Relative Import Nasıl Çalışır { #how-relative-imports-work }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Import’ların nasıl çalıştığını çok iyi biliyorsanız, bir sonraki bölüme geçin.
|
||||
|
||||
///
|
||||
|
||||
Tek bir nokta `.`, örneğin:
|
||||
|
||||
```Python
|
||||
from .dependencies import get_token_header
|
||||
```
|
||||
|
||||
şu anlama gelir:
|
||||
|
||||
* Bu module’ün (yani `app/routers/items.py` dosyasının) bulunduğu package içinden başla ( `app/routers/` dizini)...
|
||||
* `dependencies` module’ünü bul (`app/routers/dependencies.py` gibi hayali bir dosya)...
|
||||
* ve oradan `get_token_header` function’ını import et.
|
||||
|
||||
Ama o dosya yok; bizim dependency’lerimiz `app/dependencies.py` dosyasında.
|
||||
|
||||
Uygulama/dosya yapımızın nasıl göründüğünü hatırlayın:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
---
|
||||
|
||||
İki nokta `..`, örneğin:
|
||||
|
||||
```Python
|
||||
from ..dependencies import get_token_header
|
||||
```
|
||||
|
||||
şu anlama gelir:
|
||||
|
||||
* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)...
|
||||
* üst (parent) package’e çık (`app/` dizini)...
|
||||
* burada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)...
|
||||
* ve oradan `get_token_header` function’ını import et.
|
||||
|
||||
Bu doğru şekilde çalışır! 🎉
|
||||
|
||||
---
|
||||
|
||||
Aynı şekilde, üç nokta `...` kullansaydık:
|
||||
|
||||
```Python
|
||||
from ...dependencies import get_token_header
|
||||
```
|
||||
|
||||
şu anlama gelirdi:
|
||||
|
||||
* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)...
|
||||
* üst package’e çık (`app/` dizini)...
|
||||
* sonra bir üstüne daha çık (orada bir üst package yok; `app` en üst seviye 😱)...
|
||||
* ve orada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)...
|
||||
* ve oradan `get_token_header` function’ını import et.
|
||||
|
||||
Bu, `app/` dizininin üstünde, kendi `__init__.py` dosyası olan başka bir package’e işaret ederdi. Ama bizde böyle bir şey yok. Dolayısıyla bu örnekte hata verirdi. 🚨
|
||||
|
||||
Artık nasıl çalıştığını bildiğinize göre, uygulamalarınız ne kadar karmaşık olursa olsun relative import’ları kullanabilirsiniz. 🤓
|
||||
|
||||
### Özel `tags`, `responses` ve `dependencies` Ekleyin { #add-some-custom-tags-responses-and-dependencies }
|
||||
|
||||
`/items` prefix’ini ya da `tags=["items"]` değerini her *path operation*’a tek tek eklemiyoruz; çünkü bunları `APIRouter`’a ekledik.
|
||||
|
||||
Ama yine de belirli bir *path operation*’a uygulanacak _ek_ `tags` tanımlayabilir, ayrıca o *path operation*’a özel `responses` ekleyebiliriz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu son *path operation*’da tag kombinasyonu şöyle olur: `["items", "custom"]`.
|
||||
|
||||
Ayrıca dokümantasyonda iki response da görünür: biri `404`, diğeri `403`.
|
||||
|
||||
///
|
||||
|
||||
## Ana `FastAPI` { #the-main-fastapi }
|
||||
|
||||
Şimdi `app/main.py` module’üne bakalım.
|
||||
|
||||
Burada `FastAPI` class’ını import edip kullanırsınız.
|
||||
|
||||
Bu dosya, uygulamanızda her şeyi bir araya getiren ana dosya olacak.
|
||||
|
||||
Mantığın büyük kısmı artık kendi module’lerinde yaşayacağı için ana dosya oldukça basit kalır.
|
||||
|
||||
### `FastAPI` Import Edin { #import-fastapi }
|
||||
|
||||
Normal şekilde bir `FastAPI` class’ı oluşturursunuz.
|
||||
|
||||
Hatta her `APIRouter` için olan dependency’lerle birleştirilecek [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank} bile tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
|
||||
### `APIRouter` Import Edin { #import-the-apirouter }
|
||||
|
||||
Şimdi `APIRouter` içeren diğer submodule’leri import ediyoruz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
|
||||
|
||||
`app/routers/users.py` ve `app/routers/items.py` dosyaları aynı Python package’i olan `app`’in parçası olan submodule’ler olduğu için, onları "relative import" ile tek bir nokta `.` kullanarak import edebiliriz.
|
||||
|
||||
### Import Nasıl Çalışır { #how-the-importing-works }
|
||||
|
||||
Şu bölüm:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
şu anlama gelir:
|
||||
|
||||
* Bu module’ün (yani `app/main.py` dosyasının) bulunduğu package içinden başla (`app/` dizini)...
|
||||
* `routers` subpackage’ini bul (`app/routers/` dizini)...
|
||||
* ve buradan `items` submodule’ünü (`app/routers/items.py`) ve `users` submodule’ünü (`app/routers/users.py`) import et...
|
||||
|
||||
`items` module’ünün içinde `router` adında bir değişken vardır (`items.router`). Bu, `app/routers/items.py` dosyasında oluşturduğumuz aynı değişkendir; bir `APIRouter` nesnesidir.
|
||||
|
||||
Sonra aynı işlemi `users` module’ü için de yaparız.
|
||||
|
||||
Ayrıca şöyle de import edebilirdik:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
İlk sürüm "relative import"tur:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
İkinci sürüm "absolute import"tur:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
Python Packages ve Modules hakkında daha fazlası için, <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">Python'ın Modules ile ilgili resmi dokümantasyonunu</a> okuyun.
|
||||
|
||||
///
|
||||
|
||||
### İsim Çakışmalarını Önleyin { #avoid-name-collisions }
|
||||
|
||||
`items` submodule’ünü doğrudan import ediyoruz; sadece içindeki `router` değişkenini import etmiyoruz.
|
||||
|
||||
Çünkü `users` submodule’ünde de `router` adlı başka bir değişken var.
|
||||
|
||||
Eğer şöyle sırayla import etseydik:
|
||||
|
||||
```Python
|
||||
from .routers.items import router
|
||||
from .routers.users import router
|
||||
```
|
||||
|
||||
`users` içindeki `router`, `items` içindeki `router`’ın üstüne yazardı ve ikisini aynı anda kullanamazdık.
|
||||
|
||||
Bu yüzden ikisini de aynı dosyada kullanabilmek için submodule’leri doğrudan import ediyoruz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### `users` ve `items` için `APIRouter`’ları Dahil Edin { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Şimdi `users` ve `items` submodule’lerindeki `router`’ları dahil edelim:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`users.router`, `app/routers/users.py` dosyasının içindeki `APIRouter`’ı içerir.
|
||||
|
||||
`items.router` ise `app/routers/items.py` dosyasının içindeki `APIRouter`’ı içerir.
|
||||
|
||||
///
|
||||
|
||||
`app.include_router()` ile her bir `APIRouter`’ı ana `FastAPI` uygulamasına ekleyebiliriz.
|
||||
|
||||
Böylece o router içindeki tüm route’lar uygulamanın bir parçası olarak dahil edilir.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Aslında içeride, `APIRouter` içinde tanımlanan her *path operation* için bir *path operation* oluşturur.
|
||||
|
||||
Yani perde arkasında, her şey tek bir uygulamaymış gibi çalışır.
|
||||
|
||||
///
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Router’ları dahil ederken performans konusunda endişelenmeniz gerekmez.
|
||||
|
||||
Bu işlem mikrosaniyeler sürer ve sadece startup sırasında olur.
|
||||
|
||||
Dolayısıyla performansı etkilemez. ⚡
|
||||
|
||||
///
|
||||
|
||||
### Özel `prefix`, `tags`, `responses` ve `dependencies` ile Bir `APIRouter` Dahil Edin { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
|
||||
Şimdi, kurumunuzun size `app/internal/admin.py` dosyasını verdiğini düşünelim.
|
||||
|
||||
Bu dosyada, kurumunuzun birden fazla proje arasında paylaştığı bazı admin *path operation*’larını içeren bir `APIRouter` var.
|
||||
|
||||
Bu örnekte çok basit olacak. Ancak kurum içinde başka projelerle paylaşıldığı için, bunu değiştirip `prefix`, `dependencies`, `tags` vs. doğrudan `APIRouter`’a ekleyemediğimizi varsayalım:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
|
||||
Yine de bu `APIRouter`’ı dahil ederken özel bir `prefix` ayarlamak istiyoruz ki tüm *path operation*’ları `/admin` ile başlasın; ayrıca bu projede hâlihazırda kullandığımız `dependencies` ile güvene almak, `tags` ve `responses` eklemek istiyoruz.
|
||||
|
||||
Orijinal `APIRouter`’ı değiştirmeden, bu parametreleri `app.include_router()`’a vererek hepsini tanımlayabiliriz:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
|
||||
|
||||
Böylece orijinal `APIRouter` değişmeden kalır; yani aynı `app/internal/admin.py` dosyasını kurum içindeki diğer projelerle de paylaşmaya devam edebiliriz.
|
||||
|
||||
Sonuç olarak, uygulamamızda `admin` module’ündeki her bir *path operation* şunlara sahip olur:
|
||||
|
||||
* `/admin` prefix’i.
|
||||
* `admin` tag’i.
|
||||
* `get_token_header` dependency’si.
|
||||
* `418` response’u. 🍵
|
||||
|
||||
Ancak bu sadece bizim uygulamamızdaki o `APIRouter` için geçerlidir; onu kullanan diğer kodlar için değil.
|
||||
|
||||
Dolayısıyla örneğin diğer projeler aynı `APIRouter`’ı farklı bir authentication yöntemiyle kullanabilir.
|
||||
|
||||
### Bir *Path Operation* Dahil Edin { #include-a-path-operation }
|
||||
|
||||
*Path operation*’ları doğrudan `FastAPI` uygulamasına da ekleyebiliriz.
|
||||
|
||||
Burada bunu yapıyoruz... sadece yapabildiğimizi göstermek için 🤷:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
|
||||
|
||||
ve `app.include_router()` ile eklenen diğer tüm *path operation*’larla birlikte doğru şekilde çalışır.
|
||||
|
||||
/// info | Çok Teknik Detaylar
|
||||
|
||||
**Not**: Bu oldukça teknik bir detay; büyük ihtimalle **direkt geçebilirsiniz**.
|
||||
|
||||
---
|
||||
|
||||
`APIRouter`’lar "mount" edilmez; uygulamanın geri kalanından izole değildir.
|
||||
|
||||
Çünkü *path operation*’larını OpenAPI şemasına ve kullanıcı arayüzlerine dahil etmek istiyoruz.
|
||||
|
||||
Onları tamamen izole edip bağımsız şekilde "mount" edemediğimiz için, *path operation*’lar doğrudan eklenmek yerine "klonlanır" (yeniden oluşturulur).
|
||||
|
||||
///
|
||||
|
||||
## Otomatik API Dokümanını Kontrol Edin { #check-the-automatic-api-docs }
|
||||
|
||||
Şimdi uygulamanızı çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev app/main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ve dokümanları <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresinde açın.
|
||||
|
||||
Tüm submodule’lerdeki path’leri, doğru path’ler (ve prefix’ler) ve doğru tag’lerle birlikte içeren otomatik API dokümanını göreceksiniz:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Aynı Router'ı Farklı `prefix` ile Birden Fazla Kez Dahil Edin { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
`.include_router()` ile aynı router’ı farklı prefix’ler kullanarak birden fazla kez de dahil edebilirsiniz.
|
||||
|
||||
Örneğin aynı API’yi `/api/v1` ve `/api/latest` gibi farklı prefix’ler altında sunmak için faydalı olabilir.
|
||||
|
||||
Bu, muhtemelen ihtiyacınız olmayan ileri seviye bir kullanımdır; ancak gerekirse diye mevcut.
|
||||
|
||||
## Bir `APIRouter`’ı Başka Birine Dahil Edin { #include-an-apirouter-in-another }
|
||||
|
||||
Bir `APIRouter`’ı `FastAPI` uygulamasına dahil ettiğiniz gibi, bir `APIRouter`’ı başka bir `APIRouter`’a da şu şekilde dahil edebilirsiniz:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
`router`’ı `FastAPI` uygulamasına dahil etmeden önce bunu yaptığınızdan emin olun; böylece `other_router` içindeki *path operation*’lar da dahil edilmiş olur.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Body - Alanlar { #body-fields }
|
||||
|
||||
`Query`, `Path` ve `Body` ile *path operation function* parametrelerinde ek doğrulama ve metadata tanımlayabildiğiniz gibi, Pydantic modellerinin içinde de Pydantic'in `Field`'ını kullanarak doğrulama ve metadata tanımlayabilirsiniz.
|
||||
|
||||
## `Field`'ı import edin { #import-field }
|
||||
|
||||
Önce import etmeniz gerekir:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`Field`'ın, diğerlerinin (`Query`, `Path`, `Body` vb.) aksine `fastapi`'den değil doğrudan `pydantic`'den import edildiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
## Model attribute'larını tanımlayın { #declare-model-attributes }
|
||||
|
||||
Ardından `Field`'ı model attribute'larıyla birlikte kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
|
||||
|
||||
`Field`, `Query`, `Path` ve `Body` ile aynı şekilde çalışır; aynı parametrelerin tamamına sahiptir, vb.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Aslında, `Query`, `Path` ve birazdan göreceğiniz diğerleri, ortak bir `Param` sınıfının alt sınıflarından nesneler oluşturur; `Param` sınıfı da Pydantic'in `FieldInfo` sınıfının bir alt sınıfıdır.
|
||||
|
||||
Pydantic'in `Field`'ı da `FieldInfo`'nun bir instance'ını döndürür.
|
||||
|
||||
`Body` ayrıca doğrudan `FieldInfo`'nun bir alt sınıfından nesneler döndürür. Daha sonra göreceğiniz başka bazıları da `Body` sınıfının alt sınıflarıdır.
|
||||
|
||||
`fastapi`'den `Query`, `Path` ve diğerlerini import ettiğinizde, bunların aslında özel sınıflar döndüren fonksiyonlar olduğunu unutmayın.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Type, varsayılan değer ve `Field` ile tanımlanan her model attribute'unun yapısının, *path operation function* parametresiyle aynı olduğuna dikkat edin; sadece `Path`, `Query` ve `Body` yerine `Field` kullanılmıştır.
|
||||
|
||||
///
|
||||
|
||||
## Ek bilgi ekleyin { #add-extra-information }
|
||||
|
||||
`Field`, `Query`, `Body` vb. içinde ek bilgi tanımlayabilirsiniz. Bu bilgiler oluşturulan JSON Schema'ya dahil edilir.
|
||||
|
||||
Örnek (examples) tanımlamayı öğrenirken, dokümanların ilerleyen kısımlarında ek bilgi ekleme konusunu daha ayrıntılı göreceksiniz.
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`Field`'a geçirilen ekstra key'ler, uygulamanız için üretilen OpenAPI schema'sında da yer alır.
|
||||
Bu key'ler OpenAPI spesifikasyonunun bir parçası olmak zorunda olmadığından, örneğin [OpenAPI validator](https://validator.swagger.io/) gibi bazı OpenAPI araçları üretilen schema'nızla çalışmayabilir.
|
||||
|
||||
///
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Model attribute'ları için ek doğrulamalar ve metadata tanımlamak üzere Pydantic'in `Field`'ını kullanabilirsiniz.
|
||||
|
||||
Ayrıca, ek keyword argument'ları kullanarak JSON Schema'ya ekstra metadata da iletebilirsiniz.
|
||||
@@ -0,0 +1,169 @@
|
||||
# Body - Birden Fazla Parametre { #body-multiple-parameters }
|
||||
|
||||
Artık `Path` ve `Query` kullanmayı gördüğümüze göre, request body bildirimlerinin daha ileri kullanım senaryolarına bakalım.
|
||||
|
||||
## `Path`, `Query` ve body parametrelerini karıştırma { #mix-path-query-and-body-parameters }
|
||||
|
||||
Öncelikle, elbette `Path`, `Query` ve request body parametre bildirimlerini serbestçe karıştırabilirsiniz ve **FastAPI** ne yapacağını bilir.
|
||||
|
||||
Ayrıca, varsayılan değeri `None` yaparak body parametrelerini opsiyonel olarak da tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bu durumda body'den alınacak `item` opsiyoneldir. Çünkü varsayılan değeri `None` olarak ayarlanmıştır.
|
||||
|
||||
///
|
||||
|
||||
## Birden fazla body parametresi { #multiple-body-parameters }
|
||||
|
||||
Önceki örnekte, *path operation*'lar `Item`'ın özelliklerini içeren bir JSON body beklerdi, örneğin:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
```
|
||||
|
||||
Ancak birden fazla body parametresi de tanımlayabilirsiniz; örneğin `item` ve `user`:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
|
||||
|
||||
|
||||
Bu durumda **FastAPI**, fonksiyonda birden fazla body parametresi olduğunu fark eder (iki parametre de Pydantic modelidir).
|
||||
|
||||
Bunun üzerine, body içinde anahtar (field name) olarak parametre adlarını kullanır ve şu şekilde bir body bekler:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
},
|
||||
"user": {
|
||||
"username": "dave",
|
||||
"full_name": "Dave Grohl"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// note | Not
|
||||
|
||||
`item` daha öncekiyle aynı şekilde tanımlanmış olsa bile, artık body içinde `item` anahtarı altında gelmesi beklenir.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI**, request'ten otomatik dönüşümü yapar; böylece `item` parametresi kendi içeriğini alır, `user` için de aynı şekilde olur.
|
||||
|
||||
Birleşik verinin validasyonunu yapar ve OpenAPI şeması ile otomatik dokümantasyonda da bunu bu şekilde dokümante eder.
|
||||
|
||||
## Body içinde tekil değerler { #singular-values-in-body }
|
||||
|
||||
Query ve path parametreleri için ek veri tanımlamak üzere `Query` ve `Path` olduğu gibi, **FastAPI** bunların karşılığı olarak `Body` de sağlar.
|
||||
|
||||
Örneğin, önceki modeli genişleterek, aynı body içinde `item` ve `user` dışında bir de `importance` anahtarı olmasını isteyebilirsiniz.
|
||||
|
||||
Bunu olduğu gibi tanımlarsanız, tekil bir değer olduğu için **FastAPI** bunun bir query parametresi olduğunu varsayar.
|
||||
|
||||
Ama `Body` kullanarak, **FastAPI**'ye bunu body içinde başka bir anahtar olarak ele almasını söyleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
|
||||
Bu durumda **FastAPI** şu şekilde bir body bekler:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
},
|
||||
"user": {
|
||||
"username": "dave",
|
||||
"full_name": "Dave Grohl"
|
||||
},
|
||||
"importance": 5
|
||||
}
|
||||
```
|
||||
|
||||
Yine veri tiplerini dönüştürür, validate eder, dokümante eder, vb.
|
||||
|
||||
## Birden fazla body parametresi ve query { #multiple-body-params-and-query }
|
||||
|
||||
Elbette ihtiyaç duyduğunuzda, body parametrelerine ek olarak query parametreleri de tanımlayabilirsiniz.
|
||||
|
||||
Varsayılan olarak tekil değerler query parametresi olarak yorumlandığı için, ayrıca `Query` eklemeniz gerekmez; şöyle yazmanız yeterlidir:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`Body`, `Query`, `Path` ve daha sonra göreceğiniz diğerleriyle aynı ek validasyon ve metadata parametrelerine de sahiptir.
|
||||
|
||||
///
|
||||
|
||||
## Tek bir body parametresini gömme { #embed-a-single-body-parameter }
|
||||
|
||||
Diyelim ki Pydantic'teki `Item` modelinden gelen yalnızca tek bir `item` body parametreniz var.
|
||||
|
||||
Varsayılan olarak **FastAPI**, body'nin doğrudan bu modelin içeriği olmasını bekler.
|
||||
|
||||
Ancak, ek body parametreleri tanımladığınızda olduğu gibi, `item` anahtarı olan bir JSON ve onun içinde modelin içeriğini beklemesini istiyorsanız, `Body`'nin özel parametresi olan `embed`'i kullanabilirsiniz:
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
```
|
||||
|
||||
yani şöyle:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
|
||||
|
||||
Bu durumda **FastAPI** şu şekilde bir body bekler:
|
||||
|
||||
```JSON hl_lines="2"
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
şunun yerine:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
```
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Bir request yalnızca tek bir body içerebilse de, *path operation function*'ınıza birden fazla body parametresi ekleyebilirsiniz.
|
||||
|
||||
Ancak **FastAPI** bunu yönetir; fonksiyonunuza doğru veriyi verir ve *path operation* içinde doğru şemayı validate edip dokümante eder.
|
||||
|
||||
Ayrıca tekil değerlerin body'nin bir parçası olarak alınmasını da tanımlayabilirsiniz.
|
||||
|
||||
Ve yalnızca tek bir parametre tanımlanmış olsa bile, **FastAPI**'ye body'yi bir anahtarın içine gömmesini söyleyebilirsiniz.
|
||||
@@ -0,0 +1,220 @@
|
||||
# Body - İç İçe Modeller { #body-nested-models }
|
||||
|
||||
**FastAPI** ile (Pydantic sayesinde) istediğiniz kadar derin iç içe geçmiş modelleri tanımlayabilir, doğrulayabilir, dokümante edebilir ve kullanabilirsiniz.
|
||||
|
||||
## List alanları { #list-fields }
|
||||
|
||||
Bir attribute’u bir alt tipe sahip olacak şekilde tanımlayabilirsiniz. Örneğin, bir Python `list`:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
|
||||
|
||||
Bu, `tags`’in bir list olmasını sağlar; ancak list’in elemanlarının tipini belirtmez.
|
||||
|
||||
## Tip parametresi olan list alanları { #list-fields-with-type-parameter }
|
||||
|
||||
Ancak Python’da, iç tipleri olan list’leri (ya da "type parameter" içeren tipleri) tanımlamanın belirli bir yolu vardır:
|
||||
|
||||
### Tip parametresiyle bir `list` tanımlayın { #declare-a-list-with-a-type-parameter }
|
||||
|
||||
`list`, `dict`, `tuple` gibi type parameter (iç tip) alan tipleri tanımlamak için, iç tipi(leri) köşeli parantezlerle "type parameter" olarak verin: `[` ve `]`
|
||||
|
||||
```Python
|
||||
my_list: list[str]
|
||||
```
|
||||
|
||||
Bu, tip tanımları için standart Python sözdizimidir.
|
||||
|
||||
İç tipleri olan model attribute’ları için de aynı standart sözdizimini kullanın.
|
||||
|
||||
Dolayısıyla örneğimizde, `tags`’i özel olarak bir "string list’i" yapabiliriz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
|
||||
|
||||
## Set tipleri { #set-types }
|
||||
|
||||
Sonra bunu düşününce, tag’lerin tekrar etmemesi gerektiğini fark ederiz; büyük ihtimalle benzersiz string’ler olmalıdır.
|
||||
|
||||
Python’da benzersiz öğelerden oluşan kümeler için özel bir veri tipi vardır: `set`.
|
||||
|
||||
O zaman `tags`’i string’lerden oluşan bir set olarak tanımlayabiliriz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
|
||||
|
||||
Böylece duplicate veri içeren bir request alsanız bile, bu veri benzersiz öğelerden oluşan bir set’e dönüştürülür.
|
||||
|
||||
Ve bu veriyi ne zaman output etseniz, kaynakta duplicate olsa bile, benzersiz öğelerden oluşan bir set olarak output edilir.
|
||||
|
||||
Ayrıca buna göre annotate / dokümante edilir.
|
||||
|
||||
## İç İçe Modeller { #nested-models }
|
||||
|
||||
Bir Pydantic modelinin her attribute’unun bir tipi vardır.
|
||||
|
||||
Ancak bu tip, kendi başına başka bir Pydantic modeli de olabilir.
|
||||
|
||||
Yani belirli attribute adları, tipleri ve validation kurallarıyla derin iç içe JSON "object"leri tanımlayabilirsiniz.
|
||||
|
||||
Hem de istediğiniz kadar iç içe.
|
||||
|
||||
### Bir alt model tanımlayın { #define-a-submodel }
|
||||
|
||||
Örneğin bir `Image` modeli tanımlayabiliriz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
|
||||
|
||||
### Alt modeli tip olarak kullanın { #use-the-submodel-as-a-type }
|
||||
|
||||
Ardından bunu bir attribute’un tipi olarak kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
Bu da **FastAPI**’nin aşağıdakine benzer bir body bekleyeceği anlamına gelir:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2,
|
||||
"tags": ["rock", "metal", "bar"],
|
||||
"image": {
|
||||
"url": "http://example.com/baz.jpg",
|
||||
"name": "The Foo live"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Yine, sadece bu tanımı yaparak **FastAPI** ile şunları elde edersiniz:
|
||||
|
||||
* Editör desteği (tamamlama vb.), iç içe modeller için bile
|
||||
* Veri dönüştürme
|
||||
* Veri doğrulama (validation)
|
||||
* Otomatik dokümantasyon
|
||||
|
||||
## Özel tipler ve doğrulama { #special-types-and-validation }
|
||||
|
||||
`str`, `int`, `float` vb. normal tekil tiplerin yanında, `str`’den türeyen daha karmaşık tekil tipleri de kullanabilirsiniz.
|
||||
|
||||
Tüm seçenekleri görmek için <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydantic Türlerine Genel Bakış</a> sayfasına göz atın. Sonraki bölümde bazı örnekleri göreceksiniz.
|
||||
|
||||
Örneğin `Image` modelinde bir `url` alanımız olduğuna göre, bunu `str` yerine Pydantic’in `HttpUrl` tipinden bir instance olacak şekilde tanımlayabiliriz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
|
||||
|
||||
String’in geçerli bir URL olup olmadığı kontrol edilir ve JSON Schema / OpenAPI’de de buna göre dokümante edilir.
|
||||
|
||||
## Alt modellerden oluşan list’lere sahip attribute’lar { #attributes-with-lists-of-submodels }
|
||||
|
||||
Pydantic modellerini `list`, `set` vb. tiplerin alt tipi olarak da kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
|
||||
|
||||
Bu, aşağıdaki gibi bir JSON body bekler (dönüştürür, doğrular, dokümante eder vb.):
|
||||
|
||||
```JSON hl_lines="11"
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2,
|
||||
"tags": [
|
||||
"rock",
|
||||
"metal",
|
||||
"bar"
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"url": "http://example.com/baz.jpg",
|
||||
"name": "The Foo live"
|
||||
},
|
||||
{
|
||||
"url": "http://example.com/dave.jpg",
|
||||
"name": "The Baz"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`images` key’inin artık image object’lerinden oluşan bir list içerdiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
## Çok derin iç içe modeller { #deeply-nested-models }
|
||||
|
||||
İstediğiniz kadar derin iç içe modeller tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`Offer`’ın bir `Item` list’i olduğuna, `Item`’ların da opsiyonel bir `Image` list’ine sahip olduğuna dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
## Sadece list olan body’ler { #bodies-of-pure-lists }
|
||||
|
||||
Beklediğiniz JSON body’nin en üst seviye değeri bir JSON `array` (Python’da `list`) ise, tipi Pydantic modellerinde olduğu gibi fonksiyonun parametresinde tanımlayabilirsiniz:
|
||||
|
||||
```Python
|
||||
images: list[Image]
|
||||
```
|
||||
|
||||
şu örnekte olduğu gibi:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
|
||||
|
||||
## Her yerde editör desteği { #editor-support-everywhere }
|
||||
|
||||
Ve her yerde editör desteği alırsınız.
|
||||
|
||||
List içindeki öğeler için bile:
|
||||
|
||||
<img src="/img/tutorial/body-nested-models/image01.png">
|
||||
|
||||
Pydantic modelleri yerine doğrudan `dict` ile çalışsaydınız bu tür bir editör desteğini alamazdınız.
|
||||
|
||||
Ancak bunlarla uğraşmanız da gerekmez; gelen dict’ler otomatik olarak dönüştürülür ve output’unuz da otomatik olarak JSON’a çevrilir.
|
||||
|
||||
## Rastgele `dict` body’leri { #bodies-of-arbitrary-dicts }
|
||||
|
||||
Body’yi, key’leri bir tipte ve value’ları başka bir tipte olan bir `dict` olarak da tanımlayabilirsiniz.
|
||||
|
||||
Bu şekilde (Pydantic modellerinde olduğu gibi) geçerli field/attribute adlarının önceden ne olduğunu bilmeniz gerekmez.
|
||||
|
||||
Bu, önceden bilmediğiniz key’leri almak istediğiniz durumlarda faydalıdır.
|
||||
|
||||
---
|
||||
|
||||
Bir diğer faydalı durum da key’lerin başka bir tipte olmasını istediğiniz zamandır (ör. `int`).
|
||||
|
||||
Burada göreceğimiz şey de bu.
|
||||
|
||||
Bu durumda, `int` key’lere ve `float` value’lara sahip olduğu sürece herhangi bir `dict` kabul edersiniz:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
JSON key olarak yalnızca `str` destekler, bunu unutmayın.
|
||||
|
||||
Ancak Pydantic otomatik veri dönüştürme yapar.
|
||||
|
||||
Yani API client’larınız key’leri sadece string olarak gönderebilse bile, bu string’ler saf tamsayı içeriyorsa Pydantic bunları dönüştürür ve doğrular.
|
||||
|
||||
Ve `weights` olarak aldığınız `dict`, gerçekte `int` key’lere ve `float` value’lara sahip olur.
|
||||
|
||||
///
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
**FastAPI** ile Pydantic modellerinin sağladığı en yüksek esnekliği elde ederken, kodunuzu da basit, kısa ve şık tutarsınız.
|
||||
|
||||
Üstelik tüm avantajlarla birlikte:
|
||||
|
||||
* Editör desteği (her yerde tamamlama!)
|
||||
* Veri dönüştürme (diğer adıyla parsing / serialization)
|
||||
* Veri doğrulama (validation)
|
||||
* Schema dokümantasyonu
|
||||
* Otomatik dokümanlar
|
||||
@@ -0,0 +1,100 @@
|
||||
# Body - Güncellemeler { #body-updates }
|
||||
|
||||
## `PUT` ile değiştirerek güncelleme { #update-replacing-with-put }
|
||||
|
||||
Bir öğeyi güncellemek için <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a> operasyonunu kullanabilirsiniz.
|
||||
|
||||
Girdi verisini JSON olarak saklanabilecek bir formata (ör. bir NoSQL veritabanı ile) dönüştürmek için `jsonable_encoder` kullanabilirsiniz. Örneğin, `datetime` değerlerini `str`'ye çevirmek gibi.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
|
||||
`PUT`, mevcut verinin yerine geçmesi gereken veriyi almak için kullanılır.
|
||||
|
||||
### Değiştirerek güncelleme uyarısı { #warning-about-replacing }
|
||||
|
||||
Bu, `bar` öğesini `PUT` ile, body içinde şu verilerle güncellemek isterseniz:
|
||||
|
||||
```Python
|
||||
{
|
||||
"name": "Barz",
|
||||
"price": 3,
|
||||
"description": None,
|
||||
}
|
||||
```
|
||||
|
||||
zaten kayıtlı olan `"tax": 20.2` alanını içermediği için, input model `"tax": 10.5` varsayılan değerini kullanacaktır.
|
||||
|
||||
Ve veri, bu "yeni" `tax` değeri olan `10.5` ile kaydedilecektir.
|
||||
|
||||
## `PATCH` ile kısmi güncellemeler { #partial-updates-with-patch }
|
||||
|
||||
Veriyi *kısmen* güncellemek için <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> operasyonunu da kullanabilirsiniz.
|
||||
|
||||
Bu, yalnızca güncellemek istediğiniz veriyi gönderip, geri kalanını olduğu gibi bırakabileceğiniz anlamına gelir.
|
||||
|
||||
/// note | Not
|
||||
|
||||
`PATCH`, `PUT`'a göre daha az yaygın kullanılır ve daha az bilinir.
|
||||
|
||||
Hatta birçok ekip, kısmi güncellemeler için bile yalnızca `PUT` kullanır.
|
||||
|
||||
Bunları nasıl isterseniz öyle kullanmakta **özgürsünüz**; **FastAPI** herhangi bir kısıtlama dayatmaz.
|
||||
|
||||
Ancak bu kılavuz, aşağı yukarı, bunların nasıl kullanılması amaçlandığını gösterir.
|
||||
|
||||
///
|
||||
|
||||
### Pydantic'in `exclude_unset` parametresini kullanma { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Kısmi güncellemeler almak istiyorsanız, Pydantic modelinin `.model_dump()` metodundaki `exclude_unset` parametresini kullanmak çok faydalıdır.
|
||||
|
||||
Örneğin: `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
Bu, `item` modeli oluşturulurken set edilmiş verileri içeren; varsayılan değerleri hariç tutan bir `dict` üretir.
|
||||
|
||||
Sonrasında bunu, yalnızca set edilmiş (request'te gönderilmiş) veriyi içeren; varsayılan değerleri atlayan bir `dict` üretmek için kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
|
||||
### Pydantic'in `update` parametresini kullanma { #using-pydantics-update-parameter }
|
||||
|
||||
Artık `.model_copy()` ile mevcut modelin bir kopyasını oluşturup, güncellenecek verileri içeren bir `dict` ile `update` parametresini geçebilirsiniz.
|
||||
|
||||
Örneğin: `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
|
||||
### Kısmi güncellemeler özeti { #partial-updates-recap }
|
||||
|
||||
Özetle, kısmi güncelleme uygulamak için şunları yaparsınız:
|
||||
|
||||
* (İsteğe bağlı olarak) `PUT` yerine `PATCH` kullanın.
|
||||
* Kayıtlı veriyi alın.
|
||||
* Bu veriyi bir Pydantic modeline koyun.
|
||||
* Input modelinden, varsayılan değerler olmadan bir `dict` üretin (`exclude_unset` kullanarak).
|
||||
* Bu şekilde, modelinizdeki varsayılan değerlerle daha önce saklanmış değerlerin üzerine yazmak yerine, yalnızca kullanıcının gerçekten set ettiği değerleri güncellersiniz.
|
||||
* Kayıtlı modelin bir kopyasını oluşturun ve alınan kısmi güncellemeleri kullanarak attribute'larını güncelleyin (`update` parametresini kullanarak).
|
||||
* Kopyalanan modeli DB'nizde saklanabilecek bir şeye dönüştürün (ör. `jsonable_encoder` kullanarak).
|
||||
* Bu, modelin `.model_dump()` metodunu yeniden kullanmaya benzer; ancak değerlerin JSON'a dönüştürülebilecek veri tiplerine çevrilmesini garanti eder (ör. `datetime` -> `str`).
|
||||
* Veriyi DB'nize kaydedin.
|
||||
* Güncellenmiş modeli döndürün.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Aynı tekniği HTTP `PUT` operasyonu ile de kullanabilirsiniz.
|
||||
|
||||
Ancak buradaki örnek `PATCH` kullanıyor, çünkü bu kullanım senaryoları için tasarlanmıştır.
|
||||
|
||||
///
|
||||
|
||||
/// note | Not
|
||||
|
||||
Input modelin yine de doğrulandığına dikkat edin.
|
||||
|
||||
Dolayısıyla, tüm attribute'ların atlanabildiği kısmi güncellemeler almak istiyorsanız, tüm attribute'ları optional olarak işaretlenmiş (varsayılan değerlerle veya `None` ile) bir modele ihtiyacınız vardır.
|
||||
|
||||
**Güncelleme** için tüm değerleri optional olan modeller ile **oluşturma** için zorunlu değerlere sahip modelleri ayırmak için, [Extra Models](extra-models.md){.internal-link target=_blank} bölümünde anlatılan fikirleri kullanabilirsiniz.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,166 @@
|
||||
# Request Body { #request-body }
|
||||
|
||||
Bir client'ten (örneğin bir tarayıcıdan) API'nize veri göndermeniz gerektiğinde, bunu **request body** olarak gönderirsiniz.
|
||||
|
||||
Bir **request** body, client'in API'nize gönderdiği veridir. Bir **response** body ise API'nizin client'e gönderdiği veridir.
|
||||
|
||||
API'niz neredeyse her zaman bir **response** body göndermek zorundadır. Ancak client'lerin her zaman **request body** göndermesi gerekmez; bazen sadece bir path isterler, belki birkaç query parametresiyle birlikte, ama body göndermezler.
|
||||
|
||||
Bir **request** body tanımlamak için, tüm gücü ve avantajlarıyla <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> modellerini kullanırsınız.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Veri göndermek için şunlardan birini kullanmalısınız: `POST` (en yaygını), `PUT`, `DELETE` veya `PATCH`.
|
||||
|
||||
`GET` request'i ile body göndermek, spesifikasyonlarda tanımsız bir davranıştır; yine de FastAPI bunu yalnızca çok karmaşık/uç kullanım senaryoları için destekler.
|
||||
|
||||
Önerilmediği için Swagger UI ile etkileşimli dokümanlar, `GET` kullanırken body için dokümantasyonu göstermez ve aradaki proxy'ler bunu desteklemeyebilir.
|
||||
|
||||
///
|
||||
|
||||
## Pydantic'in `BaseModel`'ini import edin { #import-pydantics-basemodel }
|
||||
|
||||
Önce, `pydantic` içinden `BaseModel`'i import etmeniz gerekir:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
|
||||
## Veri modelinizi oluşturun { #create-your-data-model }
|
||||
|
||||
Sonra veri modelinizi, `BaseModel`'den kalıtım alan bir class olarak tanımlarsınız.
|
||||
|
||||
Tüm attribute'lar için standart Python type'larını kullanın:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
|
||||
Query parametrelerini tanımlarken olduğu gibi, bir model attribute'ü default bir değere sahipse zorunlu değildir. Aksi halde zorunludur. Sadece opsiyonel yapmak için `None` kullanın.
|
||||
|
||||
Örneğin, yukarıdaki model şu şekilde bir JSON "`object`" (veya Python `dict`) tanımlar:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "An optional description",
|
||||
"price": 45.2,
|
||||
"tax": 3.5
|
||||
}
|
||||
```
|
||||
|
||||
...`description` ve `tax` opsiyonel olduğu için (default değerleri `None`), şu JSON "`object`" da geçerli olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"price": 45.2
|
||||
}
|
||||
```
|
||||
|
||||
## Parametre olarak tanımlayın { #declare-it-as-a-parameter }
|
||||
|
||||
Bunu *path operation*'ınıza eklemek için, path ve query parametrelerini tanımladığınız şekilde tanımlayın:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
|
||||
...ve type'ını, oluşturduğunuz model olan `Item` olarak belirtin.
|
||||
|
||||
## Sonuçlar { #results }
|
||||
|
||||
Sadece bu Python type tanımıyla, **FastAPI** şunları yapar:
|
||||
|
||||
* Request'in body'sini JSON olarak okur.
|
||||
* İlgili type'lara dönüştürür (gerekirse).
|
||||
* Veriyi doğrular (validate eder).
|
||||
* Veri geçersizse, tam olarak nerede ve hangi verinin hatalı olduğunu söyleyen, anlaşılır bir hata döndürür.
|
||||
* Aldığı veriyi `item` parametresi içinde size verir.
|
||||
* Fonksiyonda bunun type'ını `Item` olarak tanımladığınız için, tüm attribute'lar ve type'ları için editor desteğini (tamamlama vb.) de alırsınız.
|
||||
* Modeliniz için <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> tanımları üretir; projeniz için anlamlıysa bunları başka yerlerde de kullanabilirsiniz.
|
||||
* Bu şemalar üretilen OpenAPI şemasının bir parçası olur ve otomatik dokümantasyon <abbr title="User Interfaces - Kullanıcı Arayüzleri">UIs</abbr> tarafından kullanılır.
|
||||
|
||||
## Otomatik dokümanlar { #automatic-docs }
|
||||
|
||||
Modellerinizin JSON Schema'ları, OpenAPI tarafından üretilen şemanın bir parçası olur ve etkileşimli API dokümanlarında gösterilir:
|
||||
|
||||
<img src="/img/tutorial/body/image01.png">
|
||||
|
||||
Ayrıca, ihtiyaç duyan her *path operation* içindeki API dokümanlarında da kullanılır:
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## Editor desteği { #editor-support }
|
||||
|
||||
Editor'ünüzde, fonksiyonunuzun içinde her yerde type hint'leri ve tamamlama (completion) alırsınız (Pydantic modeli yerine `dict` alsaydınız bu olmazdı):
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
Yanlış type işlemleri için hata kontrolleri de alırsınız:
|
||||
|
||||
<img src="/img/tutorial/body/image04.png">
|
||||
|
||||
Bu bir tesadüf değil; tüm framework bu tasarımın etrafında inşa edildi.
|
||||
|
||||
Ayrıca, bunun tüm editor'lerle çalışacağından emin olmak için herhangi bir implementasyon yapılmadan önce tasarım aşamasında kapsamlı şekilde test edildi.
|
||||
|
||||
Hatta bunu desteklemek için Pydantic'in kendisinde bile bazı değişiklikler yapıldı.
|
||||
|
||||
Önceki ekran görüntüleri <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a> ile alınmıştır.
|
||||
|
||||
Ancak <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> ve diğer Python editor'lerinin çoğunda da aynı editor desteğini alırsınız:
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Editor olarak <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> kullanıyorsanız, <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a> kullanabilirsiniz.
|
||||
|
||||
Pydantic modelleri için editor desteğini şu açılardan iyileştirir:
|
||||
|
||||
* auto-completion
|
||||
* type checks
|
||||
* refactoring
|
||||
* searching
|
||||
* inspections
|
||||
|
||||
///
|
||||
|
||||
## Modeli kullanın { #use-the-model }
|
||||
|
||||
Fonksiyonun içinde model nesnesinin tüm attribute'larına doğrudan erişebilirsiniz:
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
## Request body + path parametreleri { #request-body-path-parameters }
|
||||
|
||||
Path parametrelerini ve request body'yi aynı anda tanımlayabilirsiniz.
|
||||
|
||||
**FastAPI**, path parametreleriyle eşleşen fonksiyon parametrelerinin **path'ten alınması** gerektiğini ve Pydantic model olarak tanımlanan fonksiyon parametrelerinin **request body'den alınması** gerektiğini anlayacaktır.
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Request body + path + query parametreleri { #request-body-path-query-parameters }
|
||||
|
||||
**body**, **path** ve **query** parametrelerini aynı anda da tanımlayabilirsiniz.
|
||||
|
||||
**FastAPI** bunların her birini tanır ve veriyi doğru yerden alır.
|
||||
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
|
||||
Fonksiyon parametreleri şu şekilde tanınır:
|
||||
|
||||
* Parametre, **path** içinde de tanımlıysa path parametresi olarak kullanılır.
|
||||
* Parametre **tekil bir type**'taysa (`int`, `float`, `str`, `bool` vb.), **query** parametresi olarak yorumlanır.
|
||||
* Parametre bir **Pydantic model** type'ı olarak tanımlandıysa, request **body** olarak yorumlanır.
|
||||
|
||||
/// note | Not
|
||||
|
||||
FastAPI, `q` değerinin zorunlu olmadığını `= None` default değerinden anlayacaktır.
|
||||
|
||||
`str | None`, FastAPI tarafından bu değerin zorunlu olmadığını belirlemek için kullanılmaz; FastAPI bunun zorunlu olmadığını `= None` default değeri olduğu için bilir.
|
||||
|
||||
Ancak type annotation'larını eklemek, editor'ünüzün size daha iyi destek vermesini ve hataları yakalamasını sağlar.
|
||||
|
||||
///
|
||||
|
||||
## Pydantic olmadan { #without-pydantic }
|
||||
|
||||
Pydantic modellerini kullanmak istemiyorsanız, **Body** parametrelerini de kullanabilirsiniz. [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank} dokümanına bakın.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Cookie Parametre Modelleri { #cookie-parameter-models }
|
||||
|
||||
Birbirleriyle ilişkili bir **cookie** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. 🍪
|
||||
|
||||
Bu sayede **model'i yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation ve metadata'yı tek seferde tanımlayabilirsiniz. 😎
|
||||
|
||||
/// note | Not
|
||||
|
||||
This is supported since FastAPI version `0.115.0`. 🤓
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Aynı teknik `Query`, `Cookie` ve `Header` için de geçerlidir. 😎
|
||||
|
||||
///
|
||||
|
||||
## Pydantic Model ile Cookies { #cookies-with-a-pydantic-model }
|
||||
|
||||
İhtiyacınız olan **cookie** parametrelerini bir **Pydantic model** içinde tanımlayın ve ardından parametreyi `Cookie` olarak bildirin:
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
|
||||
|
||||
**FastAPI**, request ile gelen **cookies** içinden **her bir field** için veriyi **extract** eder ve size tanımladığınız Pydantic model'i verir.
|
||||
|
||||
## Dokümanları Kontrol Edin { #check-the-docs }
|
||||
|
||||
Tanımlanan cookie'leri `/docs` altındaki docs UI'da görebilirsiniz:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/cookie-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Tarayıcıların cookie'leri özel biçimlerde ve arka planda yönetmesi nedeniyle, **JavaScript**'in cookie'lere erişmesine kolayca izin vermediğini aklınızda bulundurun.
|
||||
|
||||
`/docs` altındaki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz.
|
||||
|
||||
Ancak verileri **doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez; dolayısıyla hiç değer girmemişsiniz gibi bir **error** mesajı görürsünüz.
|
||||
|
||||
///
|
||||
|
||||
## Fazladan Cookie'leri Yasaklayın { #forbid-extra-cookies }
|
||||
|
||||
Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir) almak istediğiniz cookie'leri **kısıtlamak** isteyebilirsiniz.
|
||||
|
||||
API'niz artık kendi <dfn title="Bu bir şaka, sadece bilginize. Cookie onaylarıyla ilgisi yok, ama API'nin de artık zavallı cookie'leri reddedebilmesi komik. Bir cookie alın. 🍪">cookie onayı</dfn>'nı kontrol etme gücüne sahip. 🤪🍪
|
||||
|
||||
Pydantic'in model configuration'ını kullanarak `extra` olan herhangi bir field'ı `forbid` edebilirsiniz:
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
Bir client **fazladan cookie** göndermeye çalışırsa, bir **error** response alır.
|
||||
|
||||
Onayınızı almak için bunca çaba harcayan zavallı cookie banner'ları... <dfn title="Bu da başka bir şaka. Dikkate almayın. Cookie'niz için biraz kahve alın. ☕">API'nin bunu reddetmesi için</dfn>. 🍪
|
||||
|
||||
Örneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker` <dfn title="Noel Baba cookie eksikliğini onaylamıyor. 🎅 Tamam, artık cookie şakası yok.">cookie'ye izin verilmiyor</dfn> diyen bir **error** response alır:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "extra_forbidden",
|
||||
"loc": ["cookie", "santa_tracker"],
|
||||
"msg": "Extra inputs are not permitted",
|
||||
"input": "good-list-please",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Özet { #summary }
|
||||
|
||||
**FastAPI**'de <dfn title="Gitmeden önce son bir cookie alın. 🍪">**cookie**</dfn> tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎
|
||||
@@ -1,35 +1,45 @@
|
||||
# Çerez (Cookie) Parametreleri
|
||||
# Cookie (Çerez) Parametreleri { #cookie-parameters }
|
||||
|
||||
`Query` (Sorgu) ve `Path` (Yol) parametrelerini tanımladığınız şekilde çerez parametreleri tanımlayabilirsiniz.
|
||||
`Query` ve `Path` parametrelerini tanımladığınız şekilde Cookie parametreleri tanımlayabilirsiniz.
|
||||
|
||||
## Import `Cookie`
|
||||
## `Cookie`'yi Import Edin { #import-cookie }
|
||||
|
||||
Öncelikle, `Cookie`'yi projenize dahil edin:
|
||||
Öncelikle, `Cookie`'yi import edin:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## `Cookie` Parametrelerini Tanımlayın
|
||||
## `Cookie` Parametrelerini Tanımlayın { #declare-cookie-parameters }
|
||||
|
||||
Çerez parametrelerini `Path` veya `Query` tanımlaması yapar gibi tanımlayın.
|
||||
Ardından, `Path` ve `Query` ile aynı yapıyı kullanarak Cookie parametrelerini tanımlayın.
|
||||
|
||||
İlk değer varsayılan değerdir; tüm ekstra doğrulama veya belirteç parametrelerini kullanabilirsiniz:
|
||||
Varsayılan değeri ve tüm ekstra doğrulama veya annotation parametrelerini tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`Cookie` sınıfı `Path` ve `Query` sınıflarının kardeşidir. Diğerleri gibi `Param` sınıfını miras alan bir sınıftır.
|
||||
`Cookie`, `Path` ve `Query`'nin "kardeş" sınıfıdır. O da aynı ortak `Param` sınıfından miras alır.
|
||||
|
||||
Ancak `fastapi`'dan projenize dahil ettiğiniz `Query`, `Path`, `Cookie` ve diğerleri aslında özel sınıflar döndüren birer fonksiyondur.
|
||||
Ancak `fastapi`'dan `Query`, `Path`, `Cookie` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıflar döndüren fonksiyonlardır, bunu unutmayın.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Çerez tanımlamak için `Cookie` sınıfını kullanmanız gerekmektedir, aksi taktirde parametreler sorgu parametreleri olarak yorumlanır.
|
||||
Cookie'leri tanımlamak için `Cookie` kullanmanız gerekir, aksi halde parametreler query parametreleri olarak yorumlanır.
|
||||
|
||||
///
|
||||
|
||||
## Özet
|
||||
/// info | Bilgi
|
||||
|
||||
Çerez tanımlamalarını `Cookie` sınıfını kullanarak `Query` ve `Path` tanımlar gibi tanımlayın.
|
||||
**Tarayıcılar cookie'leri** özel şekillerde ve arka planda işlediği için, **JavaScript**'in onlara dokunmasına kolayca izin **vermezler**.
|
||||
|
||||
`/docs` adresindeki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz.
|
||||
|
||||
Ancak **veriyi doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez ve herhangi bir değer yazmamışsınız gibi bir **hata** mesajı görürsünüz.
|
||||
|
||||
///
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
`Query` ve `Path` ile aynı ortak deseni kullanarak, cookie'leri `Cookie` ile tanımlayın.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
|
||||
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS veya "Cross-Origin Resource Sharing"</a>, tarayıcıda çalışan bir frontend’in JavaScript kodunun bir backend ile iletişim kurduğu ve backend’in frontend’den farklı bir "origin"de olduğu durumları ifade eder.
|
||||
|
||||
## Origin { #origin }
|
||||
|
||||
Origin; protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`) ve port’un (`80`, `443`, `8080`) birleşimidir.
|
||||
|
||||
Dolayısıyla şunların hepsi farklı origin’lerdir:
|
||||
|
||||
* `http://localhost`
|
||||
* `https://localhost`
|
||||
* `http://localhost:8080`
|
||||
|
||||
Hepsi `localhost` üzerinde olsa bile, farklı protocol veya port kullandıkları için farklı "origin" sayılırlar.
|
||||
|
||||
## Adımlar { #steps }
|
||||
|
||||
Diyelim ki tarayıcınızda `http://localhost:8080` adresinde çalışan bir frontend’iniz var ve JavaScript’i, `http://localhost` adresinde çalışan bir backend ile iletişim kurmaya çalışıyor (port belirtmediğimiz için tarayıcı varsayılan port olan `80`’i kullanacaktır).
|
||||
|
||||
Bu durumda tarayıcı, `:80`-backend’e bir HTTP `OPTIONS` request’i gönderir. Eğer backend, bu farklı origin’den (`http://localhost:8080`) gelen iletişimi yetkilendiren uygun header’ları gönderirse, `:8080`-tarayıcı frontend’deki JavaScript’in `:80`-backend’e request göndermesine izin verir.
|
||||
|
||||
Bunu sağlayabilmek için `:80`-backend’in bir "allowed origins" listesi olmalıdır.
|
||||
|
||||
Bu örnekte `:8080`-frontend’in doğru çalışması için listede `http://localhost:8080` bulunmalıdır.
|
||||
|
||||
## Wildcard'lar { #wildcards }
|
||||
|
||||
Listeyi `"*"` (bir "wildcard") olarak tanımlayıp, hepsine izin verildiğini söylemek de mümkündür.
|
||||
|
||||
Ancak bu, credentials içeren her şeyi hariç tutarak yalnızca belirli iletişim türlerine izin verir: Cookie’ler, Bearer Token’larla kullanılanlar gibi Authorization header’ları, vb.
|
||||
|
||||
Bu yüzden her şeyin düzgün çalışması için, izin verilen origin’leri açıkça belirtmek daha iyidir.
|
||||
|
||||
## `CORSMiddleware` Kullanımı { #use-corsmiddleware }
|
||||
|
||||
Bunu **FastAPI** uygulamanızda `CORSMiddleware` ile yapılandırabilirsiniz.
|
||||
|
||||
* `CORSMiddleware`’i import edin.
|
||||
* İzin verilen origin’lerden (string) oluşan bir liste oluşturun.
|
||||
* Bunu **FastAPI** uygulamanıza bir "middleware" olarak ekleyin.
|
||||
|
||||
Ayrıca backend’in şunlara izin verip vermediğini de belirtebilirsiniz:
|
||||
|
||||
* Credentials (Authorization header’ları, Cookie’ler, vb).
|
||||
* Belirli HTTP method’ları (`POST`, `PUT`) veya wildcard `"*"` ile hepsini.
|
||||
* Belirli HTTP header’ları veya wildcard `"*"` ile hepsini.
|
||||
|
||||
{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
|
||||
|
||||
|
||||
`CORSMiddleware` implementasyonu tarafından kullanılan varsayılan parametreler kısıtlayıcıdır; bu nedenle tarayıcıların Cross-Domain bağlamında kullanmasına izin vermek için belirli origin’leri, method’ları veya header’ları açıkça etkinleştirmeniz gerekir.
|
||||
|
||||
Aşağıdaki argümanlar desteklenir:
|
||||
|
||||
* `allow_origins` - Cross-origin request yapmasına izin verilmesi gereken origin’lerin listesi. Örn. `['https://example.org', 'https://www.example.org']`. Herhangi bir origin’e izin vermek için `['*']` kullanabilirsiniz.
|
||||
* `allow_origin_regex` - Cross-origin request yapmasına izin verilmesi gereken origin’lerle eşleşecek bir regex string’i. Örn. `'https://.*\.example\.org'`.
|
||||
* `allow_methods` - Cross-origin request’lerde izin verilmesi gereken HTTP method’larının listesi. Varsayılanı `['GET']`. Tüm standart method’lara izin vermek için `['*']` kullanabilirsiniz.
|
||||
* `allow_headers` - Cross-origin request’lerde desteklenmesi gereken HTTP request header’larının listesi. Varsayılanı `[]`. Tüm header’lara izin vermek için `['*']` kullanabilirsiniz. `Accept`, `Accept-Language`, `Content-Language` ve `Content-Type` header’larına <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">basit CORS request'leri</a> için her zaman izin verilir.
|
||||
* `allow_credentials` - Cross-origin request’ler için cookie desteği olup olmayacağını belirtir. Varsayılanı `False`.
|
||||
|
||||
`allow_credentials` `True` olarak ayarlanmışsa, `allow_origins`, `allow_methods` ve `allow_headers` değerlerinin hiçbiri `['*']` olamaz. Hepsinin <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">açıkça belirtilmesi</a> gerekir.
|
||||
|
||||
* `expose_headers` - Tarayıcının erişebilmesi gereken response header’larını belirtir. Varsayılanı `[]`.
|
||||
* `max_age` - Tarayıcıların CORS response’larını cache’lemesi için saniye cinsinden azami süreyi ayarlar. Varsayılanı `600`.
|
||||
|
||||
Middleware iki özel HTTP request türüne yanıt verir...
|
||||
|
||||
### CORS preflight request'leri { #cors-preflight-requests }
|
||||
|
||||
Bunlar, `Origin` ve `Access-Control-Request-Method` header’larına sahip herhangi bir `OPTIONS` request’idir.
|
||||
|
||||
Bu durumda middleware gelen request’i intercept eder ve uygun CORS header’larıyla yanıt verir; bilgilendirme amaçlı olarak da `200` veya `400` response döndürür.
|
||||
|
||||
### Basit request'ler { #simple-requests }
|
||||
|
||||
`Origin` header’ı olan herhangi bir request. Bu durumda middleware request’i normal şekilde geçirir, ancak response’a uygun CORS header’larını ekler.
|
||||
|
||||
## Daha Fazla Bilgi { #more-info }
|
||||
|
||||
<abbr title="Cross-Origin Resource Sharing - Kökenler Arası Kaynak Paylaşımı">CORS</abbr> hakkında daha fazla bilgi için <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS dokümantasyonu</a>na bakın.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.middleware.cors import CORSMiddleware` şeklinde de kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.middleware` içinde bazı middleware’ler sağlar. Ancak mevcut middleware’lerin çoğu doğrudan Starlette’ten gelir.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,113 @@
|
||||
# Debugging { #debugging }
|
||||
|
||||
Visual Studio Code veya PyCharm gibi editörünüzde debugger'ı bağlayabilirsiniz.
|
||||
|
||||
## `uvicorn`'ı Çağırma { #call-uvicorn }
|
||||
|
||||
FastAPI uygulamanızda `uvicorn`'ı import edip doğrudan çalıştırın:
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
### `__name__ == "__main__"` Hakkında { #about-name-main }
|
||||
|
||||
`__name__ == "__main__"` ifadesinin temel amacı, dosyanız şu şekilde çağrıldığında çalışacak:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python myapp.py
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
ancak başka bir dosya onu import ettiğinde çalışmayacak bir kod bölümüne sahip olmaktır, örneğin:
|
||||
|
||||
```Python
|
||||
from myapp import app
|
||||
```
|
||||
|
||||
#### Daha fazla detay { #more-details }
|
||||
|
||||
Dosyanızın adının `myapp.py` olduğunu varsayalım.
|
||||
|
||||
Şu şekilde çalıştırırsanız:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python myapp.py
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Python tarafından otomatik oluşturulan, dosyanızın içindeki `__name__` adlı dahili değişkenin değeri `"__main__"` string'i olur.
|
||||
|
||||
Dolayısıyla şu bölüm:
|
||||
|
||||
```Python
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
```
|
||||
|
||||
çalışır.
|
||||
|
||||
---
|
||||
|
||||
Ancak modülü (dosyayı) import ederseniz bu gerçekleşmez.
|
||||
|
||||
Yani örneğin `importer.py` adında başka bir dosyanız var ve içinde şunlar bulunuyorsa:
|
||||
|
||||
```Python
|
||||
from myapp import app
|
||||
|
||||
# Some more code
|
||||
```
|
||||
|
||||
bu durumda `myapp.py` içindeki otomatik oluşturulan `__name__` değişkeni `"__main__"` değerine sahip olmaz.
|
||||
|
||||
Bu yüzden şu satır:
|
||||
|
||||
```Python
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
```
|
||||
|
||||
çalıştırılmaz.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Daha fazla bilgi için <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">resmi Python dokümantasyonuna</a> bakın.
|
||||
|
||||
///
|
||||
|
||||
## Kodunuzu Debugger ile Çalıştırma { #run-your-code-with-your-debugger }
|
||||
|
||||
Uvicorn server'ını doğrudan kodunuzdan çalıştırdığınız için, Python programınızı (FastAPI uygulamanızı) debugger'dan doğrudan başlatabilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
Örneğin Visual Studio Code'da şunları yapabilirsiniz:
|
||||
|
||||
* "Debug" paneline gidin.
|
||||
* "Add configuration..." seçin.
|
||||
* "Python" seçin
|
||||
* "`Python: Current File (Integrated Terminal)`" seçeneğiyle debugger'ı çalıştırın.
|
||||
|
||||
Böylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb.
|
||||
|
||||
Aşağıdaki gibi görünebilir:
|
||||
|
||||
<img src="/img/tutorial/debugging/image01.png">
|
||||
|
||||
---
|
||||
|
||||
PyCharm kullanıyorsanız şunları yapabilirsiniz:
|
||||
|
||||
* "Run" menüsünü açın.
|
||||
* "Debug..." seçeneğini seçin.
|
||||
* Bir context menü açılır.
|
||||
* Debug edilecek dosyayı seçin (bu örnekte `main.py`).
|
||||
|
||||
Böylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb.
|
||||
|
||||
Aşağıdaki gibi görünebilir:
|
||||
|
||||
<img src="/img/tutorial/debugging/image02.png">
|
||||
@@ -0,0 +1,288 @@
|
||||
# Dependency Olarak Class'lar { #classes-as-dependencies }
|
||||
|
||||
**Dependency Injection** sistemine daha derinlemesine geçmeden önce, bir önceki örneği geliştirelim.
|
||||
|
||||
## Önceki Örnekten Bir `dict` { #a-dict-from-the-previous-example }
|
||||
|
||||
Önceki örnekte, dependency'mizden ("dependable") bir `dict` döndürüyorduk:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
Ama sonra *path operation function* içindeki `commons` parametresinde bir `dict` alıyoruz.
|
||||
|
||||
Ve biliyoruz ki editor'ler `dict`'ler için çok fazla destek (ör. completion) veremez; çünkü key'lerini ve value type'larını bilemezler.
|
||||
|
||||
Daha iyisini yapabiliriz...
|
||||
|
||||
## Bir Şeyi Dependency Yapan Nedir { #what-makes-a-dependency }
|
||||
|
||||
Şimdiye kadar dependency'leri function olarak tanımlanmış şekilde gördünüz.
|
||||
|
||||
Ancak dependency tanımlamanın tek yolu bu değil (muhtemelen en yaygını bu olsa da).
|
||||
|
||||
Buradaki kritik nokta, bir dependency'nin "callable" olması gerektiğidir.
|
||||
|
||||
Python'da "**callable**", Python'ın bir function gibi "çağırabildiği" her şeydir.
|
||||
|
||||
Yani elinizde `something` adlı bir nesne varsa (function _olmak zorunda değil_) ve onu şöyle "çağırabiliyorsanız" (çalıştırabiliyorsanız):
|
||||
|
||||
```Python
|
||||
something()
|
||||
```
|
||||
|
||||
veya
|
||||
|
||||
```Python
|
||||
something(some_argument, some_keyword_argument="foo")
|
||||
```
|
||||
|
||||
o zaman bu bir "callable" demektir.
|
||||
|
||||
## Dependency Olarak Class'lar { #classes-as-dependencies_1 }
|
||||
|
||||
Python'da bir class'tan instance oluştururken de aynı söz dizimini kullandığınızı fark etmiş olabilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
```Python
|
||||
class Cat:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
|
||||
|
||||
fluffy = Cat(name="Mr Fluffy")
|
||||
```
|
||||
|
||||
Bu durumda `fluffy`, `Cat` class'ının bir instance'ıdır.
|
||||
|
||||
Ve `fluffy` oluşturmak için `Cat`'i "çağırmış" olursunuz.
|
||||
|
||||
Dolayısıyla bir Python class'ı da bir **callable**'dır.
|
||||
|
||||
O zaman **FastAPI** içinde bir Python class'ını dependency olarak kullanabilirsiniz.
|
||||
|
||||
FastAPI'nin aslında kontrol ettiği şey, bunun bir "callable" olması (function, class ya da başka bir şey) ve tanımlı parametreleridir.
|
||||
|
||||
Eğer **FastAPI**'de bir dependency olarak bir "callable" verirseniz, FastAPI o "callable" için parametreleri analiz eder ve bunları *path operation function* parametreleriyle aynı şekilde işler. Sub-dependency'ler dahil.
|
||||
|
||||
Bu, hiç parametresi olmayan callable'lar için de geçerlidir. Tıpkı hiç parametresi olmayan *path operation function*'larda olduğu gibi.
|
||||
|
||||
O zaman yukarıdaki `common_parameters` adlı "dependable" dependency'sini `CommonQueryParams` class'ına çevirebiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
|
||||
|
||||
Class instance'ını oluşturmak için kullanılan `__init__` metoduna dikkat edin:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
|
||||
|
||||
...bizim önceki `common_parameters` ile aynı parametrelere sahip:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
|
||||
|
||||
Bu parametreler, dependency'yi "çözmek" için **FastAPI**'nin kullanacağı şeylerdir.
|
||||
|
||||
Her iki durumda da şunlar olacak:
|
||||
|
||||
* `str` olan opsiyonel bir `q` query parametresi.
|
||||
* Default değeri `0` olan `int` tipinde bir `skip` query parametresi.
|
||||
* Default değeri `100` olan `int` tipinde bir `limit` query parametresi.
|
||||
|
||||
Her iki durumda da veriler dönüştürülecek, doğrulanacak, OpenAPI şemasında dokümante edilecek, vb.
|
||||
|
||||
## Kullanalım { #use-it }
|
||||
|
||||
Artık bu class'ı kullanarak dependency'nizi tanımlayabilirsiniz.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
|
||||
|
||||
**FastAPI**, `CommonQueryParams` class'ını çağırır. Bu, o class'ın bir "instance"ını oluşturur ve bu instance, sizin function'ınıza `commons` parametresi olarak geçirilir.
|
||||
|
||||
## Type Annotation vs `Depends` { #type-annotation-vs-depends }
|
||||
|
||||
Yukarıdaki kodda `CommonQueryParams`'ı iki kez yazdığımıza dikkat edin:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Şuradaki son `CommonQueryParams`:
|
||||
|
||||
```Python
|
||||
... Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
...FastAPI'nin dependency'nin ne olduğunu anlamak için gerçekten kullandığı şeydir.
|
||||
|
||||
FastAPI tanımlanan parametreleri buradan çıkarır ve aslında çağıracağı şey de budur.
|
||||
|
||||
---
|
||||
|
||||
Bu durumda, şuradaki ilk `CommonQueryParams`:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, ...
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams ...
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...**FastAPI** için özel bir anlam taşımaz. FastAPI bunu veri dönüştürme, doğrulama vb. için kullanmaz (çünkü bunlar için `Depends(CommonQueryParams)` kullanıyor).
|
||||
|
||||
Hatta şunu bile yazabilirsiniz:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[Any, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...şu örnekte olduğu gibi:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
|
||||
|
||||
Ancak type'ı belirtmeniz önerilir; böylece editor'ünüz `commons` parametresine ne geçirileceğini bilir ve size code completion, type check'leri vb. konularda yardımcı olur:
|
||||
|
||||
<img src="/img/tutorial/dependencies/image02.png">
|
||||
|
||||
## Kısayol { #shortcut }
|
||||
|
||||
Ama burada bir miktar kod tekrarımız olduğunu görüyorsunuz; `CommonQueryParams`'ı iki kez yazıyoruz:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
**FastAPI**, bu durumlar için bir kısayol sağlar: dependency'nin *özellikle* FastAPI'nin bir instance oluşturmak için "çağıracağı" bir class olduğu durumlar.
|
||||
|
||||
Bu özel durumlarda şunu yapabilirsiniz:
|
||||
|
||||
Şunu yazmak yerine:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...şunu yazarsınız:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends()]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated Olmadan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü kullanmayı tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends()
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Dependency'yi parametrenin type'ı olarak tanımlarsınız ve `Depends(CommonQueryParams)` içinde class'ı *yeniden* yazmak yerine, parametre vermeden `Depends()` kullanırsınız.
|
||||
|
||||
Aynı örnek şu hale gelir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
|
||||
|
||||
...ve **FastAPI** ne yapması gerektiğini bilir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu size faydalı olmaktan çok kafa karıştırıcı geliyorsa, kullanmayın; buna *ihtiyacınız* yok.
|
||||
|
||||
Bu sadece bir kısayoldur. Çünkü **FastAPI** kod tekrarını en aza indirmenize yardımcı olmayı önemser.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,69 @@
|
||||
# Path Operation Decorator'lerinde Dependency'ler { #dependencies-in-path-operation-decorators }
|
||||
|
||||
Bazı durumlarda bir dependency'nin döndürdüğü değere *path operation function* içinde gerçekten ihtiyacınız olmaz.
|
||||
|
||||
Ya da dependency zaten bir değer döndürmüyordur.
|
||||
|
||||
Ancak yine de çalıştırılmasını/çözülmesini istersiniz.
|
||||
|
||||
Bu gibi durumlarda, `Depends` ile bir *path operation function* parametresi tanımlamak yerine, *path operation decorator*'üne `dependencies` adında bir `list` ekleyebilirsiniz.
|
||||
|
||||
## *Path Operation Decorator*'üne `dependencies` Ekleyin { #add-dependencies-to-the-path-operation-decorator }
|
||||
|
||||
*Path operation decorator*, opsiyonel bir `dependencies` argümanı alır.
|
||||
|
||||
Bu, `Depends()` öğelerinden oluşan bir `list` olmalıdır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
|
||||
|
||||
Bu dependency'ler normal dependency'lerle aynı şekilde çalıştırılır/çözülür. Ancak (eğer bir değer döndürüyorlarsa) bu değer *path operation function*'ınıza aktarılmaz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bazı editörler, kullanılmayan function parametrelerini kontrol eder ve bunları hata olarak gösterebilir.
|
||||
|
||||
Bu `dependencies` yaklaşımıyla, editör/araç hatalarına takılmadan dependency'lerin çalıştırılmasını sağlayabilirsiniz.
|
||||
|
||||
Ayrıca kodunuzda kullanılmayan bir parametreyi gören yeni geliştiricilerin bunun gereksiz olduğunu düşünmesi gibi bir kafa karışıklığını da azaltabilir.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bu örnekte uydurma özel header'lar olan `X-Key` ve `X-Token` kullanıyoruz.
|
||||
|
||||
Ancak gerçek senaryolarda, security uygularken, entegre [Security yardımcı araçlarını (bir sonraki bölüm)](../security/index.md){.internal-link target=_blank} kullanmak size daha fazla fayda sağlar.
|
||||
|
||||
///
|
||||
|
||||
## Dependency Hataları ve Return Değerleri { #dependencies-errors-and-return-values }
|
||||
|
||||
Normalde kullandığınız aynı dependency *function*'larını burada da kullanabilirsiniz.
|
||||
|
||||
### Dependency Gereksinimleri { #dependency-requirements }
|
||||
|
||||
Request gereksinimleri (header'lar gibi) veya başka alt dependency'ler tanımlayabilirler:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
|
||||
|
||||
### Exception Fırlatmak { #raise-exceptions }
|
||||
|
||||
Bu dependency'ler, normal dependency'lerde olduğu gibi `raise` ile exception fırlatabilir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
|
||||
|
||||
### Return Değerleri { #return-values }
|
||||
|
||||
Ayrıca değer döndürebilirler ya da döndürmeyebilirler; dönen değer kullanılmayacaktır.
|
||||
|
||||
Yani başka bir yerde zaten kullandığınız, değer döndüren normal bir dependency'yi tekrar kullanabilirsiniz; değer kullanılmasa bile dependency çalıştırılacaktır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
|
||||
|
||||
## Bir *Path Operation* Grubu İçin Dependency'ler { #dependencies-for-a-group-of-path-operations }
|
||||
|
||||
Daha sonra, muhtemelen birden fazla dosya kullanarak daha büyük uygulamaları nasıl yapılandıracağınızı okurken ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), bir *path operation* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz.
|
||||
|
||||
## Global Dependency'ler { #global-dependencies }
|
||||
|
||||
Sırada, dependency'leri tüm `FastAPI` uygulamasına nasıl ekleyeceğimizi göreceğiz; böylece her *path operation* için geçerli olacaklar.
|
||||
@@ -0,0 +1,288 @@
|
||||
# `yield` ile Dependency'ler { #dependencies-with-yield }
|
||||
|
||||
FastAPI, işini bitirdikten sonra <dfn title='bazen "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code" vb. olarak da adlandırılır'>ek adımlar</dfn> çalıştıran dependency'leri destekler.
|
||||
|
||||
Bunu yapmak için `return` yerine `yield` kullanın ve ek adımları (kodu) `yield` satırından sonra yazın.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Her dependency için yalnızca bir kez `yield` kullandığınızdan emin olun.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Şunlarla kullanılabilen herhangi bir fonksiyon:
|
||||
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> veya
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
|
||||
bir **FastAPI** dependency'si olarak kullanılabilir.
|
||||
|
||||
Hatta FastAPI bu iki decorator'ı içeride (internally) kullanır.
|
||||
|
||||
///
|
||||
|
||||
## `yield` ile Bir Veritabanı Dependency'si { #a-database-dependency-with-yield }
|
||||
|
||||
Örneğin bunu, bir veritabanı session'ı oluşturmak ve iş bittikten sonra kapatmak için kullanabilirsiniz.
|
||||
|
||||
Response oluşturulmadan önce yalnızca `yield` satırına kadar olan (ve `yield` dahil) kod çalıştırılır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
|
||||
|
||||
`yield` edilen değer, *path operation*'lara ve diğer dependency'lere enjekte edilen (injected) değerdir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
|
||||
|
||||
Response'dan sonra `yield` satırını takip eden kod çalıştırılır:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`async` ya da normal fonksiyonlar kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, normal dependency'lerde olduğu gibi her ikisinde de doğru şekilde davranır.
|
||||
|
||||
///
|
||||
|
||||
## `yield` ve `try` ile Bir Dependency { #a-dependency-with-yield-and-try }
|
||||
|
||||
`yield` kullanan bir dependency içinde bir `try` bloğu kullanırsanız, dependency kullanılırken fırlatılan (raised) herhangi bir exception'ı alırsınız.
|
||||
|
||||
Örneğin, başka bir dependency'de veya bir *path operation* içinde çalışan bir kod, bir veritabanı transaction'ını "rollback" yaptıysa ya da başka bir exception oluşturduysa, o exception dependency'nizde size gelir.
|
||||
|
||||
Dolayısıyla `except SomeException` ile dependency içinde o spesifik exception'ı yakalayabilirsiniz.
|
||||
|
||||
Aynı şekilde, exception olsun ya da olmasın çıkış (exit) adımlarının çalıştırılmasını garanti etmek için `finally` kullanabilirsiniz.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
|
||||
|
||||
## `yield` ile Alt Dependency'ler { #sub-dependencies-with-yield }
|
||||
|
||||
Her boyutta ve şekilde alt dependency'ler ve alt dependency "ağaçları" (trees) oluşturabilirsiniz; bunların herhangi biri veya hepsi `yield` kullanabilir.
|
||||
|
||||
**FastAPI**, `yield` kullanan her dependency'deki "exit code"'un doğru sırayla çalıştırılmasını sağlar.
|
||||
|
||||
Örneğin, `dependency_c`, `dependency_b`'ye; `dependency_b` de `dependency_a`'ya bağlı olabilir:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
|
||||
|
||||
Ve hepsi `yield` kullanabilir.
|
||||
|
||||
Bu durumda `dependency_c`, exit code'unu çalıştırabilmek için `dependency_b`'den gelen değerin (burada `dep_b`) hâlâ erişilebilir olmasına ihtiyaç duyar.
|
||||
|
||||
Aynı şekilde `dependency_b` de exit code'u için `dependency_a`'dan gelen değerin (burada `dep_a`) erişilebilir olmasına ihtiyaç duyar.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
|
||||
|
||||
Benzer şekilde, bazı dependency'ler `yield`, bazıları `return` kullanabilir ve bunların bazıları diğerlerine bağlı olabilir.
|
||||
|
||||
Ayrıca birden fazla `yield` kullanan dependency gerektiren tek bir dependency'niz de olabilir, vb.
|
||||
|
||||
İstediğiniz herhangi bir dependency kombinasyonunu kullanabilirsiniz.
|
||||
|
||||
**FastAPI** her şeyin doğru sırada çalışmasını sağlar.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
Bu, Python'un <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">Context Managers</a> yapısı sayesinde çalışır.
|
||||
|
||||
**FastAPI** bunu sağlamak için içeride onları kullanır.
|
||||
|
||||
///
|
||||
|
||||
## `yield` ve `HTTPException` ile Dependency'ler { #dependencies-with-yield-and-httpexception }
|
||||
|
||||
`yield` kullanan dependency'lerde `try` bloklarıyla bazı kodları çalıştırıp ardından `finally` sonrasında exit code çalıştırabileceğinizi gördünüz.
|
||||
|
||||
Ayrıca `except` ile fırlatılan exception'ı yakalayıp onunla bir şey yapabilirsiniz.
|
||||
|
||||
Örneğin `HTTPException` gibi farklı bir exception fırlatabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu biraz ileri seviye bir tekniktir ve çoğu durumda gerçekten ihtiyaç duymazsınız; çünkü exception'ları (`HTTPException` dahil) uygulamanızın geri kalan kodundan, örneğin *path operation function* içinden fırlatabilirsiniz.
|
||||
|
||||
Ama ihtiyaç duyarsanız diye burada. 🤓
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
|
||||
|
||||
Exception yakalayıp buna göre özel bir response oluşturmak istiyorsanız bir [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} oluşturun.
|
||||
|
||||
## `yield` ve `except` ile Dependency'ler { #dependencies-with-yield-and-except }
|
||||
|
||||
`yield` kullanan bir dependency içinde `except` ile bir exception yakalar ve bunu tekrar fırlatmazsanız (ya da yeni bir exception fırlatmazsanız), FastAPI normal Python'da olduğu gibi bir exception olduğunu fark edemez:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
|
||||
|
||||
Bu durumda client, biz `HTTPException` veya benzeri bir şey fırlatmadığımız için olması gerektiği gibi *HTTP 500 Internal Server Error* response'u görür; ancak server **hiç log üretmez** ve hatanın ne olduğuna dair başka bir işaret de olmaz. 😱
|
||||
|
||||
### `yield` ve `except` Kullanan Dependency'lerde Her Zaman `raise` Edin { #always-raise-in-dependencies-with-yield-and-except }
|
||||
|
||||
`yield` kullanan bir dependency içinde bir exception yakalarsanız, başka bir `HTTPException` veya benzeri bir şey fırlatmıyorsanız, **orijinal exception'ı tekrar raise etmelisiniz**.
|
||||
|
||||
Aynı exception'ı `raise` ile tekrar fırlatabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
|
||||
|
||||
Artık client yine aynı *HTTP 500 Internal Server Error* response'unu alır, ama server log'larda bizim özel `InternalError`'ımızı görür. 😎
|
||||
|
||||
## `yield` Kullanan Dependency'lerin Çalıştırılması { #execution-of-dependencies-with-yield }
|
||||
|
||||
Çalıştırma sırası kabaca aşağıdaki diyagramdaki gibidir. Zaman yukarıdan aşağı akar. Her sütun, etkileşime giren veya kod çalıştıran parçalardan birini temsil eder.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant handler as Exception handler
|
||||
participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,operation: Can raise exceptions, including HTTPException
|
||||
client ->> dep: Start request
|
||||
Note over dep: Run code up to yield
|
||||
opt raise Exception
|
||||
dep -->> handler: Raise Exception
|
||||
handler -->> client: HTTP error response
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> dep: Raise Exception (e.g. HTTPException)
|
||||
opt handle
|
||||
dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
|
||||
end
|
||||
handler -->> client: HTTP error response
|
||||
end
|
||||
|
||||
operation ->> client: Return response to client
|
||||
Note over client,operation: Response is already sent, can't change it anymore
|
||||
opt Tasks
|
||||
operation -->> tasks: Send background tasks
|
||||
end
|
||||
opt Raise other exception
|
||||
tasks -->> tasks: Handle exceptions in the background task code
|
||||
end
|
||||
```
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Client'a yalnızca **tek bir response** gönderilir. Bu, error response'lardan biri olabilir ya da *path operation*'dan dönen response olabilir.
|
||||
|
||||
Bu response'lardan biri gönderildikten sonra başka bir response gönderilemez.
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
*Path operation function* içindeki koddan herhangi bir exception raise ederseniz, `HTTPException` dahil olmak üzere bu exception `yield` kullanan dependency'lere aktarılır. Çoğu durumda, doğru şekilde ele alındığından emin olmak için `yield` kullanan dependency'den aynı exception'ı (veya yeni bir tanesini) yeniden raise etmek istersiniz.
|
||||
|
||||
///
|
||||
|
||||
## Erken Çıkış ve `scope` { #early-exit-and-scope }
|
||||
|
||||
Normalde `yield` kullanan dependency'lerin exit code'u, client'a response gönderildikten **sonra** çalıştırılır.
|
||||
|
||||
Ama *path operation function*'dan döndükten sonra dependency'yi kullanmayacağınızı biliyorsanız, `Depends(scope="function")` kullanarak FastAPI'ye dependency'yi *path operation function* döndükten sonra kapatmasını, ancak **response gönderilmeden önce** kapatmasını söyleyebilirsiniz.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
|
||||
|
||||
`Depends()` şu değerleri alabilen bir `scope` parametresi alır:
|
||||
|
||||
* `"function"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat, *path operation function* bittikten sonra bitir, ancak response client'a geri gönderilmeden **önce** sonlandır. Yani dependency fonksiyonu, *path operation **function***'ın **etrafında** çalıştırılır.
|
||||
* `"request"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat (`"function"` kullanımına benzer), ancak response client'a geri gönderildikten **sonra** sonlandır. Yani dependency fonksiyonu, **request** ve response döngüsünün **etrafında** çalıştırılır.
|
||||
|
||||
Belirtilmezse ve dependency `yield` kullanıyorsa, varsayılan olarak `scope` `"request"` olur.
|
||||
|
||||
### Alt dependency'ler için `scope` { #scope-for-sub-dependencies }
|
||||
|
||||
`scope="request"` (varsayılan) ile bir dependency tanımladığınızda, herhangi bir alt dependency'nin `scope` değeri de `"request"` olmalıdır.
|
||||
|
||||
Ancak `scope` değeri `"function"` olan bir dependency, hem `"function"` hem de `"request"` scope'una sahip dependency'lere bağlı olabilir.
|
||||
|
||||
Bunun nedeni, bir dependency'nin exit code'unu alt dependency'lerden önce çalıştırabilmesi gerekmesidir; çünkü exit code sırasında hâlâ onları kullanması gerekebilir.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant dep_req as Dep scope="request"
|
||||
participant dep_func as Dep scope="function"
|
||||
participant operation as Path Operation
|
||||
|
||||
client ->> dep_req: Start request
|
||||
Note over dep_req: Run code up to yield
|
||||
dep_req ->> dep_func: Pass dependency
|
||||
Note over dep_func: Run code up to yield
|
||||
dep_func ->> operation: Run path operation with dependency
|
||||
operation ->> dep_func: Return from path operation
|
||||
Note over dep_func: Run code after yield
|
||||
Note over dep_func: ✅ Dependency closed
|
||||
dep_func ->> client: Send response to client
|
||||
Note over client: Response sent
|
||||
Note over dep_req: Run code after yield
|
||||
Note over dep_req: ✅ Dependency closed
|
||||
```
|
||||
|
||||
## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
`yield` kullanan dependency'ler, zaman içinde farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için gelişti.
|
||||
|
||||
FastAPI'nin farklı sürümlerinde nelerin değiştiğini görmek isterseniz, advanced guide'da şu bölümü okuyabilirsiniz: [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}.
|
||||
## Context Managers { #context-managers }
|
||||
|
||||
### "Context Managers" Nedir? { #what-are-context-managers }
|
||||
|
||||
"Context Managers", `with` ifadesiyle kullanabildiğiniz Python nesneleridir.
|
||||
|
||||
Örneğin, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">bir dosyayı okumak için `with` kullanabilirsiniz</a>:
|
||||
|
||||
```Python
|
||||
with open("./somefile.txt") as f:
|
||||
contents = f.read()
|
||||
print(contents)
|
||||
```
|
||||
|
||||
Temelde `open("./somefile.txt")`, "Context Manager" olarak adlandırılan bir nesne oluşturur.
|
||||
|
||||
`with` bloğu bittiğinde, exception olsa bile dosyanın kapatılmasını garanti eder.
|
||||
|
||||
`yield` ile bir dependency oluşturduğunuzda, **FastAPI** içeride bunun için bir context manager oluşturur ve bazı ilgili başka araçlarla birleştirir.
|
||||
|
||||
### `yield` kullanan dependency'lerde context manager kullanma { #using-context-managers-in-dependencies-with-yield }
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu, az çok "ileri seviye" bir fikirdir.
|
||||
|
||||
**FastAPI**'ye yeni başlıyorsanız şimdilik bunu atlamak isteyebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
Python'da Context Manager'ları, <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">iki method'a sahip bir class oluşturarak: `__enter__()` ve `__exit__()`</a> yaratabilirsiniz.
|
||||
|
||||
Ayrıca dependency fonksiyonunun içinde `with` veya `async with` ifadeleri kullanarak **FastAPI**'de `yield` kullanan dependency'lerin içinde de kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bir context manager oluşturmanın başka bir yolu da şunlardır:
|
||||
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> veya
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
|
||||
Bunları, tek bir `yield` içeren bir fonksiyonu decorate etmek için kullanabilirsiniz.
|
||||
|
||||
FastAPI, `yield` kullanan dependency'ler için içeride bunu yapar.
|
||||
|
||||
Ancak FastAPI dependency'leri için bu decorator'ları kullanmak zorunda değilsiniz (hatta kullanmamalısınız).
|
||||
|
||||
FastAPI bunu sizin yerinize içeride yapar.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,16 @@
|
||||
# Global Dependencies { #global-dependencies }
|
||||
|
||||
Bazı uygulama türlerinde, tüm uygulama için dependency eklemek isteyebilirsiniz.
|
||||
|
||||
[`dependencies`'i *path operation decorator*'larına ekleyebildiğiniz](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} gibi, `FastAPI` uygulamasına da ekleyebilirsiniz.
|
||||
|
||||
Bu durumda, uygulamadaki tüm *path operation*'lara uygulanırlar:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
|
||||
|
||||
|
||||
Ve [*path operation decorator*'larına `dependencies` ekleme](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} bölümündeki tüm fikirler hâlâ geçerlidir; ancak bu sefer, uygulamadaki tüm *path operation*'lar için geçerli olur.
|
||||
|
||||
## *Path operations* grupları için Dependencies { #dependencies-for-groups-of-path-operations }
|
||||
|
||||
İleride, daha büyük uygulamaları nasıl yapılandıracağınızı ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}) okurken, muhtemelen birden fazla dosyayla birlikte, bir *path operations* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz.
|
||||
@@ -0,0 +1,250 @@
|
||||
# Bağımlılıklar { #dependencies }
|
||||
|
||||
**FastAPI**, çok güçlü ama aynı zamanda sezgisel bir **<dfn title="diğer adları: components, resources, providers, services, injectables">Bağımlılık Enjeksiyonu</dfn>** sistemine sahiptir.
|
||||
|
||||
Kullanımı çok basit olacak şekilde tasarlanmıştır ve herhangi bir geliştiricinin diğer bileşenleri **FastAPI** ile entegre etmesini kolaylaştırır.
|
||||
|
||||
## "Dependency Injection" Nedir? { #what-is-dependency-injection }
|
||||
|
||||
Programlamada **"Dependency Injection"**, kodunuzun (bu örnekte *path operation function*'larınızın) çalışmak ve kullanmak için ihtiyaç duyduğu şeyleri: "dependencies" (bağımlılıklar) olarak beyan edebilmesi anlamına gelir.
|
||||
|
||||
Ardından bu sistem (bu örnekte **FastAPI**), kodunuza gerekli bağımlılıkları sağlamak ("inject" etmek) için gereken her şeyi sizin yerinize halleder.
|
||||
|
||||
Bu yaklaşım, şunlara ihtiyaç duyduğunuzda özellikle faydalıdır:
|
||||
|
||||
* Paylaşılan bir mantığa sahip olmak (aynı kod mantığını tekrar tekrar kullanmak).
|
||||
* Veritabanı bağlantılarını paylaşmak.
|
||||
* Güvenlik, authentication, rol gereksinimleri vb. kuralları zorunlu kılmak.
|
||||
* Ve daha birçok şey...
|
||||
|
||||
Tüm bunları, kod tekrarını minimumda tutarak yaparsınız.
|
||||
|
||||
## İlk Adımlar { #first-steps }
|
||||
|
||||
Çok basit bir örneğe bakalım. Şimdilik o kadar basit olacak ki pek işe yaramayacak.
|
||||
|
||||
Ama bu sayede **Dependency Injection** sisteminin nasıl çalıştığına odaklanabiliriz.
|
||||
|
||||
### Bir dependency (bağımlılık) veya "dependable" Oluşturun { #create-a-dependency-or-dependable }
|
||||
|
||||
Önce dependency'e odaklanalım.
|
||||
|
||||
Bu, bir *path operation function*'ın alabileceği parametrelerin aynısını alabilen basit bir fonksiyondur:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
|
||||
|
||||
Bu kadar.
|
||||
|
||||
**2 satır**.
|
||||
|
||||
Ve tüm *path operation function*'larınızla aynı şekle ve yapıya sahiptir.
|
||||
|
||||
Bunu, "decorator" olmadan (yani `@app.get("/some-path")` olmadan) yazılmış bir *path operation function* gibi düşünebilirsiniz.
|
||||
|
||||
Ayrıca istediğiniz herhangi bir şeyi döndürebilir.
|
||||
|
||||
Bu örnekte, bu dependency şunları bekler:
|
||||
|
||||
* `str` olan, opsiyonel bir query parametresi `q`.
|
||||
* `int` olan, opsiyonel bir query parametresi `skip` ve varsayılanı `0`.
|
||||
* `int` olan, opsiyonel bir query parametresi `limit` ve varsayılanı `100`.
|
||||
|
||||
Sonra da bu değerleri içeren bir `dict` döndürür.
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
FastAPI, `Annotated` desteğini 0.95.0 sürümünde ekledi (ve önermeye başladı).
|
||||
|
||||
Daha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalıştığınızda hata alırsınız.
|
||||
|
||||
`Annotated` kullanmadan önce **FastAPI** sürümünü en az 0.95.1'e yükseltmek için [FastAPI sürümünü yükseltin](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
### `Depends`'i Import Edin { #import-depends }
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
### "Dependant" İçinde Dependency'yi Tanımlayın { #declare-the-dependency-in-the-dependant }
|
||||
|
||||
*Path operation function* parametrelerinizde `Body`, `Query` vb. kullandığınız gibi, yeni bir parametreyle `Depends` kullanın:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
|
||||
|
||||
Fonksiyon parametrelerinde `Depends`'i `Body`, `Query` vb. ile aynı şekilde kullansanız da `Depends` biraz farklı çalışır.
|
||||
|
||||
`Depends`'e yalnızca tek bir parametre verirsiniz.
|
||||
|
||||
Bu parametre, bir fonksiyon gibi bir şey olmalıdır.
|
||||
|
||||
Onu doğrudan **çağırmazsınız** (sonuna parantez eklemezsiniz), sadece `Depends()`'e parametre olarak verirsiniz.
|
||||
|
||||
Ve bu fonksiyon da, *path operation function*'lar gibi parametre alır.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Fonksiyonların dışında başka hangi "şeylerin" dependency olarak kullanılabildiğini bir sonraki bölümde göreceksiniz.
|
||||
|
||||
///
|
||||
|
||||
Yeni bir request geldiğinde, **FastAPI** şunları sizin yerinize yapar:
|
||||
|
||||
* Dependency ("dependable") fonksiyonunuzu doğru parametrelerle çağırır.
|
||||
* Fonksiyonunuzun sonucunu alır.
|
||||
* Bu sonucu *path operation function*'ınızdaki parametreye atar.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
common_parameters(["common_parameters"])
|
||||
read_items["/items/"]
|
||||
read_users["/users/"]
|
||||
|
||||
common_parameters --> read_items
|
||||
common_parameters --> read_users
|
||||
```
|
||||
|
||||
Bu şekilde paylaşılan kodu bir kez yazarsınız ve onu *path operation*'larda çağırma işini **FastAPI** halleder.
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Dikkat edin: Bunu "register" etmek ya da benzeri bir şey yapmak için özel bir class oluşturup **FastAPI**'ye bir yere geçirmeniz gerekmez.
|
||||
|
||||
Sadece `Depends`'e verirsiniz ve gerisini **FastAPI** nasıl yapacağını bilir.
|
||||
|
||||
///
|
||||
|
||||
## `Annotated` Dependency'lerini Paylaşın { #share-annotated-dependencies }
|
||||
|
||||
Yukarıdaki örneklerde, ufak bir **kod tekrarı** olduğunu görüyorsunuz.
|
||||
|
||||
`common_parameters()` dependency'sini kullanmanız gerektiğinde, type annotation ve `Depends()` içeren parametrenin tamamını yazmanız gerekir:
|
||||
|
||||
```Python
|
||||
commons: Annotated[dict, Depends(common_parameters)]
|
||||
```
|
||||
|
||||
Ancak `Annotated` kullandığımız için bu `Annotated` değerini bir değişkende saklayıp birden fazla yerde kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu aslında standart Python'dır; buna "type alias" denir ve **FastAPI**'ye özel bir şey değildir.
|
||||
|
||||
Ama **FastAPI**, `Annotated` dahil Python standartları üzerine kurulu olduğu için bu tekniği kodunuzda kullanabilirsiniz. 😎
|
||||
|
||||
///
|
||||
|
||||
Dependency'ler beklediğiniz gibi çalışmaya devam eder ve **en güzel kısmı** da şudur: **type bilgisi korunur**. Bu da editörünüzün size **autocompletion**, **inline errors** vb. sağlamaya devam edeceği anlamına gelir. `mypy` gibi diğer araçlar için de aynısı geçerlidir.
|
||||
|
||||
Bu özellikle, **büyük bir kod tabanında**, aynı dependency'leri **birçok *path operation*** içinde tekrar tekrar kullandığınızda çok faydalı olacaktır.
|
||||
|
||||
## `async` Olsa da Olmasa da { #to-async-or-not-to-async }
|
||||
|
||||
Dependency'ler de **FastAPI** tarafından çağrılacağı için (tıpkı *path operation function*'larınız gibi), fonksiyonları tanımlarken aynı kurallar geçerlidir.
|
||||
|
||||
`async def` ya da normal `def` kullanabilirsiniz.
|
||||
|
||||
Ayrıca normal `def` *path operation function*'ları içinde `async def` dependency tanımlayabilir veya `async def` *path operation function*'ları içinde `def` dependency kullanabilirsiniz vb.
|
||||
|
||||
Fark etmez. **FastAPI** ne yapacağını bilir.
|
||||
|
||||
/// note | Not
|
||||
|
||||
Eğer bilmiyorsanız, dokümanlarda `async` ve `await` için [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} bölümüne bakın.
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI ile Entegre { #integrated-with-openapi }
|
||||
|
||||
Dependency'lerinizin (ve alt dependency'lerin) tüm request tanımları, doğrulamaları ve gereksinimleri aynı OpenAPI şemasına entegre edilir.
|
||||
|
||||
Bu nedenle interaktif dokümanlar, bu dependency'lerden gelen tüm bilgileri de içerir:
|
||||
|
||||
<img src="/img/tutorial/dependencies/image01.png">
|
||||
|
||||
## Basit Kullanım { #simple-usage }
|
||||
|
||||
Şöyle düşünürseniz: *Path operation function*'lar, bir *path* ve *operation* eşleştiğinde kullanılacak şekilde tanımlanır; ardından **FastAPI** fonksiyonu doğru parametrelerle çağırır ve request'ten veriyi çıkarır.
|
||||
|
||||
Aslında tüm (veya çoğu) web framework'ü de aynı şekilde çalışır.
|
||||
|
||||
Bu fonksiyonları hiçbir zaman doğrudan çağırmazsınız. Onları framework'ünüz (bu örnekte **FastAPI**) çağırır.
|
||||
|
||||
Dependency Injection sistemiyle, *path operation function*'ınızın, ondan önce çalıştırılması gereken başka bir şeye de "bağlı" olduğunu **FastAPI**'ye söyleyebilirsiniz; **FastAPI** bunu çalıştırır ve sonuçları "inject" eder.
|
||||
|
||||
Aynı "dependency injection" fikri için kullanılan diğer yaygın terimler:
|
||||
|
||||
* resources
|
||||
* providers
|
||||
* services
|
||||
* injectables
|
||||
* components
|
||||
|
||||
## **FastAPI** Plug-in'leri { #fastapi-plug-ins }
|
||||
|
||||
Entegrasyonlar ve "plug-in"ler **Dependency Injection** sistemi kullanılarak inşa edilebilir. Ancak aslında **"plug-in" oluşturmanıza gerek yoktur**; çünkü dependency'leri kullanarak *path operation function*'larınıza sunulabilecek sınırsız sayıda entegrasyon ve etkileşim tanımlayabilirsiniz.
|
||||
|
||||
Dependency'ler, çok basit ve sezgisel bir şekilde oluşturulabilir. Böylece ihtiyacınız olan Python package'larını import edip, API fonksiyonlarınızla birkaç satır kodla *kelimenin tam anlamıyla* entegre edebilirsiniz.
|
||||
|
||||
İlerleyen bölümlerde ilişkisel ve NoSQL veritabanları, güvenlik vb. konularda bunun örneklerini göreceksiniz.
|
||||
|
||||
## **FastAPI** Uyumluluğu { #fastapi-compatibility }
|
||||
|
||||
Dependency injection sisteminin sadeliği, **FastAPI**'yi şunlarla uyumlu hale getirir:
|
||||
|
||||
* tüm ilişkisel veritabanları
|
||||
* NoSQL veritabanları
|
||||
* harici paketler
|
||||
* harici API'ler
|
||||
* authentication ve authorization sistemleri
|
||||
* API kullanım izleme (monitoring) sistemleri
|
||||
* response verisi injection sistemleri
|
||||
* vb.
|
||||
|
||||
## Basit ve Güçlü { #simple-and-powerful }
|
||||
|
||||
Hiyerarşik dependency injection sistemi tanımlamak ve kullanmak çok basit olsa da, hâlâ oldukça güçlüdür.
|
||||
|
||||
Kendileri de dependency tanımlayabilen dependency'ler tanımlayabilirsiniz.
|
||||
|
||||
Sonuçta hiyerarşik bir dependency ağacı oluşur ve **Dependency Injection** sistemi tüm bu dependency'leri (ve alt dependency'lerini) sizin için çözer ve her adımda sonuçları sağlar ("inject" eder).
|
||||
|
||||
Örneğin, 4 API endpoint'iniz (*path operation*) olduğunu varsayalım:
|
||||
|
||||
* `/items/public/`
|
||||
* `/items/private/`
|
||||
* `/users/{user_id}/activate`
|
||||
* `/items/pro/`
|
||||
|
||||
O zaman her biri için farklı izin gereksinimlerini yalnızca dependency'ler ve alt dependency'lerle ekleyebilirsiniz:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
current_user(["current_user"])
|
||||
active_user(["active_user"])
|
||||
admin_user(["admin_user"])
|
||||
paying_user(["paying_user"])
|
||||
|
||||
public["/items/public/"]
|
||||
private["/items/private/"]
|
||||
activate_user["/users/{user_id}/activate"]
|
||||
pro_items["/items/pro/"]
|
||||
|
||||
current_user --> active_user
|
||||
active_user --> admin_user
|
||||
active_user --> paying_user
|
||||
|
||||
current_user --> public
|
||||
active_user --> private
|
||||
admin_user --> activate_user
|
||||
paying_user --> pro_items
|
||||
```
|
||||
|
||||
## **OpenAPI** ile Entegre { #integrated-with-openapi_1 }
|
||||
|
||||
Bu dependency'lerin tümü, gereksinimlerini beyan ederken aynı zamanda *path operation*'larınıza parametreler, doğrulamalar vb. da ekler.
|
||||
|
||||
**FastAPI**, bunların hepsini OpenAPI şemasına eklemekle ilgilenir; böylece interaktif dokümantasyon sistemlerinde gösterilir.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Alt Bağımlılıklar { #sub-dependencies }
|
||||
|
||||
**Alt bağımlılıkları** olan bağımlılıklar oluşturabilirsiniz.
|
||||
|
||||
İhtiyacınız olduğu kadar **derine** gidebilirler.
|
||||
|
||||
Bunları çözme işini **FastAPI** üstlenir.
|
||||
|
||||
## İlk bağımlılık "dependable" { #first-dependency-dependable }
|
||||
|
||||
Şöyle bir ilk bağımlılık ("dependable") oluşturabilirsiniz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
|
||||
|
||||
Burada `q` adında opsiyonel bir query parametresi `str` olarak tanımlanır ve sonra doğrudan geri döndürülür.
|
||||
|
||||
Bu oldukça basit (pek faydalı değil), ama alt bağımlılıkların nasıl çalıştığına odaklanmamıza yardımcı olacak.
|
||||
|
||||
## İkinci bağımlılık: "dependable" ve "dependant" { #second-dependency-dependable-and-dependant }
|
||||
|
||||
Ardından, aynı zamanda kendi içinde bir bağımlılık da tanımlayan başka bir bağımlılık fonksiyonu (bir "dependable") oluşturabilirsiniz (yani o da bir "dependant" olur):
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
|
||||
|
||||
Tanımlanan parametrelere odaklanalım:
|
||||
|
||||
* Bu fonksiyonun kendisi bir bağımlılık ("dependable") olmasına rağmen, ayrıca başka bir bağımlılık daha tanımlar (başka bir şeye "depends" olur).
|
||||
* `query_extractor`'a bağlıdır ve ondan dönen değeri `q` parametresine atar.
|
||||
* Ayrıca `last_query` adında opsiyonel bir cookie'yi `str` olarak tanımlar.
|
||||
* Kullanıcı herhangi bir query `q` sağlamadıysa, daha önce cookie'ye kaydettiğimiz en son kullanılan query'yi kullanırız.
|
||||
|
||||
## Bağımlılığı Kullanma { #use-the-dependency }
|
||||
|
||||
Sonra bu bağımlılığı şöyle kullanabiliriz:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Dikkat edin, *path operation function* içinde yalnızca tek bir bağımlılık tanımlıyoruz: `query_or_cookie_extractor`.
|
||||
|
||||
Ancak **FastAPI**, `query_or_cookie_extractor`'ı çağırmadan önce `query_extractor`'ı önce çözmesi gerektiğini bilir ve onun sonucunu `query_or_cookie_extractor`'a aktarır.
|
||||
|
||||
///
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
query_extractor(["query_extractor"])
|
||||
query_or_cookie_extractor(["query_or_cookie_extractor"])
|
||||
|
||||
read_query["/items/"]
|
||||
|
||||
query_extractor --> query_or_cookie_extractor --> read_query
|
||||
```
|
||||
|
||||
## Aynı Bağımlılığı Birden Fazla Kez Kullanma { #using-the-same-dependency-multiple-times }
|
||||
|
||||
Bağımlılıklarınızdan biri aynı *path operation* için birden fazla kez tanımlanırsa (örneğin birden fazla bağımlılığın ortak bir alt bağımlılığı varsa), **FastAPI** o alt bağımlılığı request başına yalnızca bir kez çağıracağını bilir.
|
||||
|
||||
Dönen değeri bir <dfn title="Hesaplanan/üretilen değerleri saklayıp, tekrar hesaplamak yerine yeniden kullanmayı sağlayan bir yardımcı araç/sistem.">"önbellek"</dfn> içinde saklar ve aynı request içinde buna ihtiyaç duyan tüm "dependant"lara aktarır; böylece aynı request için bağımlılığı tekrar tekrar çağırmaz.
|
||||
|
||||
Daha ileri bir senaryoda, "cached" değeri kullanmak yerine aynı request içinde her adımda (muhtemelen birden fazla kez) bağımlılığın çağrılması gerektiğini biliyorsanız, `Depends` kullanırken `use_cache=False` parametresini ayarlayabilirsiniz:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ Annotated olmayan
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Mümkünse `Annotated` sürümünü tercih edin.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Burada kullanılan havalı terimlerin ötesinde, **Dependency Injection** sistemi aslında oldukça basittir.
|
||||
|
||||
*Path operation function*'lara benzeyen fonksiyonlardan ibarettir.
|
||||
|
||||
Yine de çok güçlüdür ve keyfi derecede derin iç içe geçmiş bağımlılık "graph"ları (ağaçları) tanımlamanıza izin verir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bu basit örneklerle çok faydalı görünmeyebilir.
|
||||
|
||||
Ancak **security** ile ilgili bölümlerde bunun ne kadar işe yaradığını göreceksiniz.
|
||||
|
||||
Ayrıca size ne kadar kod kazandırdığını da göreceksiniz.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,35 @@
|
||||
# JSON Uyumlu Encoder { #json-compatible-encoder }
|
||||
|
||||
Bazı durumlarda, bir veri tipini (örneğin bir Pydantic model) JSON ile uyumlu bir şeye (örneğin `dict`, `list` vb.) dönüştürmeniz gerekebilir.
|
||||
|
||||
Örneğin, bunu bir veritabanında saklamanız gerekiyorsa.
|
||||
|
||||
Bunun için **FastAPI**, `jsonable_encoder()` fonksiyonunu sağlar.
|
||||
|
||||
## `jsonable_encoder` Kullanımı { #using-the-jsonable-encoder }
|
||||
|
||||
Yalnızca JSON ile uyumlu veri kabul eden bir veritabanınız olduğunu düşünelim: `fake_db`.
|
||||
|
||||
Örneğin bu veritabanı, JSON ile uyumlu olmadıkları için `datetime` objelerini kabul etmez.
|
||||
|
||||
Dolayısıyla bir `datetime` objesinin, <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO formatında</a> veriyi içeren bir `str`'e dönüştürülmesi gerekir.
|
||||
|
||||
Aynı şekilde bu veritabanı bir Pydantic model'i (attribute'lara sahip bir obje) de kabul etmez; yalnızca bir `dict` kabul eder.
|
||||
|
||||
Bunun için `jsonable_encoder` kullanabilirsiniz.
|
||||
|
||||
Bir Pydantic model gibi bir obje alır ve JSON ile uyumlu bir versiyonunu döndürür:
|
||||
|
||||
{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
|
||||
|
||||
Bu örnekte, Pydantic model'i bir `dict`'e, `datetime`'ı da bir `str`'e dönüştürür.
|
||||
|
||||
Bu fonksiyonun çağrılmasıyla elde edilen sonuç, Python standardındaki <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a> ile encode edilebilecek bir şeydir.
|
||||
|
||||
JSON formatında (string olarak) veriyi içeren büyük bir `str` döndürmez. Bunun yerine, tüm değerleri ve alt değerleri JSON ile uyumlu olacak şekilde, Python’un standart bir veri yapısını (örneğin bir `dict`) döndürür.
|
||||
|
||||
/// note | Not
|
||||
|
||||
`jsonable_encoder`, aslında **FastAPI** tarafından veriyi dönüştürmek için internal olarak kullanılır. Ancak birçok farklı senaryoda da oldukça faydalıdır.
|
||||
|
||||
///
|
||||
@@ -0,0 +1,62 @@
|
||||
# Ek Veri Tipleri { #extra-data-types }
|
||||
|
||||
Şimdiye kadar şunlar gibi yaygın veri tiplerini kullanıyordunuz:
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
* `str`
|
||||
* `bool`
|
||||
|
||||
Ancak daha karmaşık veri tiplerini de kullanabilirsiniz.
|
||||
|
||||
Ve yine, şimdiye kadar gördüğünüz özelliklerin aynısına sahip olursunuz:
|
||||
|
||||
* Harika editör desteği.
|
||||
* Gelen request'lerden veri dönüştürme.
|
||||
* response verileri için veri dönüştürme.
|
||||
* Veri doğrulama.
|
||||
* Otomatik annotation ve dokümantasyon.
|
||||
|
||||
## Diğer veri tipleri { #other-data-types }
|
||||
|
||||
Kullanabileceğiniz ek veri tiplerinden bazıları şunlardır:
|
||||
|
||||
* `UUID`:
|
||||
* Birçok veritabanı ve sistemde ID olarak yaygın kullanılan, standart bir "Universally Unique Identifier".
|
||||
* request'lerde ve response'larda `str` olarak temsil edilir.
|
||||
* `datetime.datetime`:
|
||||
* Python `datetime.datetime`.
|
||||
* request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15T15:53:00+05:00`.
|
||||
* `datetime.date`:
|
||||
* Python `datetime.date`.
|
||||
* request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`.
|
||||
* `datetime.time`:
|
||||
* Python `datetime.time`.
|
||||
* request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`.
|
||||
* `datetime.timedelta`:
|
||||
* Python `datetime.timedelta`.
|
||||
* request'lerde ve response'larda toplam saniye sayısını ifade eden bir `float` olarak temsil edilir.
|
||||
* Pydantic, bunu ayrıca bir "ISO 8601 time diff encoding" olarak temsil etmeye de izin verir, daha fazla bilgi için <a href="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers" class="external-link" target="_blank">dokümanlara bakın</a>.
|
||||
* `frozenset`:
|
||||
* request'lerde ve response'larda, `set` ile aynı şekilde ele alınır:
|
||||
* request'lerde bir list okunur, tekrarlar kaldırılır ve `set`'e dönüştürülür.
|
||||
* response'larda `set`, `list`'e dönüştürülür.
|
||||
* Üretilen schema, `set` değerlerinin benzersiz olduğunu belirtir (JSON Schema'nın `uniqueItems` özelliğini kullanarak).
|
||||
* `bytes`:
|
||||
* Standart Python `bytes`.
|
||||
* request'lerde ve response'larda `str` gibi ele alınır.
|
||||
* Üretilen schema, bunun `binary` "format"ına sahip bir `str` olduğunu belirtir.
|
||||
* `Decimal`:
|
||||
* Standart Python `Decimal`.
|
||||
* request'lerde ve response'larda `float` ile aynı şekilde işlenir.
|
||||
* Geçerli tüm Pydantic veri tiplerini burada görebilirsiniz: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Pydantic data types</a>.
|
||||
|
||||
## Örnek { #example }
|
||||
|
||||
Yukarıdaki tiplerden bazılarını kullanan parametrelere sahip bir örnek *path operation* şöyle:
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
|
||||
|
||||
Fonksiyonun içindeki parametrelerin doğal veri tiplerinde olduğunu unutmayın; örneğin normal tarih işlemleri yapabilirsiniz:
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
|
||||
@@ -0,0 +1,211 @@
|
||||
# Ek Modeller { #extra-models }
|
||||
|
||||
Önceki örnekten devam edersek, birbiriyle ilişkili birden fazla modelin olması oldukça yaygındır.
|
||||
|
||||
Bu durum özellikle kullanıcı modellerinde sık görülür, çünkü:
|
||||
|
||||
* **input modeli** bir `password` içerebilmelidir.
|
||||
* **output modeli** `password` içermemelidir.
|
||||
* **database modeli** büyük ihtimalle hash'lenmiş bir `password` tutmalıdır.
|
||||
|
||||
/// danger | Tehlike
|
||||
|
||||
Kullanıcının düz metin (plaintext) `password`'ünü asla saklamayın. Her zaman sonradan doğrulayabileceğiniz "güvenli bir hash" saklayın.
|
||||
|
||||
Eğer bilmiyorsanız, "password hash" nedir konusunu [güvenlik bölümlerinde](security/simple-oauth2.md#password-hashing){.internal-link target=_blank} öğreneceksiniz.
|
||||
|
||||
///
|
||||
|
||||
## Birden Çok Model { #multiple-models }
|
||||
|
||||
`password` alanlarıyla birlikte modellerin genel olarak nasıl görünebileceğine ve nerelerde kullanılacaklarına dair bir fikir:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
### `**user_in.model_dump()` Hakkında { #about-user-in-model-dump }
|
||||
|
||||
#### Pydantic'in `.model_dump()` Metodu { #pydantics-model-dump }
|
||||
|
||||
`user_in`, `UserIn` sınıfına ait bir Pydantic modelidir.
|
||||
|
||||
Pydantic modellerinde, model verilerini içeren bir `dict` döndüren `.model_dump()` metodu bulunur.
|
||||
|
||||
Yani, şöyle bir Pydantic nesnesi `user_in` oluşturursak:
|
||||
|
||||
```Python
|
||||
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
|
||||
```
|
||||
|
||||
ve sonra şunu çağırırsak:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
artık `user_dict` değişkeninde modelin verilerini içeren bir `dict` vardır (Pydantic model nesnesi yerine bir `dict` elde etmiş oluruz).
|
||||
|
||||
Ve eğer şunu çağırırsak:
|
||||
|
||||
```Python
|
||||
print(user_dict)
|
||||
```
|
||||
|
||||
şöyle bir Python `dict` elde ederiz:
|
||||
|
||||
```Python
|
||||
{
|
||||
'username': 'john',
|
||||
'password': 'secret',
|
||||
'email': 'john.doe@example.com',
|
||||
'full_name': None,
|
||||
}
|
||||
```
|
||||
|
||||
#### Bir `dict`'i Unpack Etmek { #unpacking-a-dict }
|
||||
|
||||
`user_dict` gibi bir `dict` alıp bunu bir fonksiyona (ya da sınıfa) `**user_dict` ile gönderirsek, Python bunu "unpack" eder. Yani `user_dict` içindeki key ve value'ları doğrudan key-value argümanları olarak geçirir.
|
||||
|
||||
Dolayısıyla, yukarıdaki `user_dict` ile devam edersek, şunu yazmak:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
şuna eşdeğer bir sonuç üretir:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username="john",
|
||||
password="secret",
|
||||
email="john.doe@example.com",
|
||||
full_name=None,
|
||||
)
|
||||
```
|
||||
|
||||
Ya da daha net şekilde, `user_dict`'i doğrudan kullanarak, gelecekte içeriği ne olursa olsun:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username = user_dict["username"],
|
||||
password = user_dict["password"],
|
||||
email = user_dict["email"],
|
||||
full_name = user_dict["full_name"],
|
||||
)
|
||||
```
|
||||
|
||||
#### Bir Pydantic Modelinden Diğerinin İçeriğiyle Pydantic Model Oluşturmak { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Yukarıdaki örnekte `user_dict`'i `user_in.model_dump()` ile elde ettiğimiz için, şu kod:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
şuna eşdeğerdir:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...çünkü `user_in.model_dump()` bir `dict` döndürür ve biz de bunu `UserInDB`'ye `**` önekiyle vererek Python'ın "unpack" etmesini sağlarız.
|
||||
|
||||
Böylece, bir Pydantic modelindeki verilerden başka bir Pydantic model üretmiş oluruz.
|
||||
|
||||
#### Bir `dict`'i Unpack Etmek ve Ek Keyword'ler { #unpacking-a-dict-and-extra-keywords }
|
||||
|
||||
Sonrasında, aşağıdaki gibi ek keyword argümanı `hashed_password=hashed_password` eklemek:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...şuna benzer bir sonuca dönüşür:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username = user_dict["username"],
|
||||
password = user_dict["password"],
|
||||
email = user_dict["email"],
|
||||
full_name = user_dict["full_name"],
|
||||
hashed_password = hashed_password,
|
||||
)
|
||||
```
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Ek destek fonksiyonları olan `fake_password_hasher` ve `fake_save_user` sadece verinin olası bir akışını göstermek içindir; elbette gerçek bir güvenlik sağlamazlar.
|
||||
|
||||
///
|
||||
|
||||
## Tekrarı Azaltma { #reduce-duplication }
|
||||
|
||||
Kod tekrarını azaltmak, **FastAPI**'nin temel fikirlerinden biridir.
|
||||
|
||||
Kod tekrarı; bug, güvenlik problemi, kodun senkron dışına çıkması (bir yeri güncelleyip diğerlerini güncellememek) gibi sorunların olasılığını artırır.
|
||||
|
||||
Bu modellerin hepsi verinin büyük bir kısmını paylaşıyor ve attribute adlarını ve type'larını tekrar ediyor.
|
||||
|
||||
Daha iyisini yapabiliriz.
|
||||
|
||||
Diğer modellerimiz için temel olacak bir `UserBase` modeli tanımlayabiliriz. Sonra da bu modelden türeyen (subclass) modeller oluşturup onun attribute'larını (type deklarasyonları, doğrulama vb.) miras aldırabiliriz.
|
||||
|
||||
Tüm veri dönüştürme, doğrulama, dokümantasyon vb. her zamanki gibi çalışmaya devam eder.
|
||||
|
||||
Bu sayede modeller arasındaki farkları (plaintext `password` olan, `hashed_password` olan ve `password` olmayan) sadece o farklılıklar olarak tanımlayabiliriz:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
|
||||
|
||||
## `Union` veya `anyOf` { #union-or-anyof }
|
||||
|
||||
Bir response'u iki ya da daha fazla type'ın `Union`'ı olarak tanımlayabilirsiniz; bu, response'un bunlardan herhangi biri olabileceği anlamına gelir.
|
||||
|
||||
OpenAPI'de bu `anyOf` ile tanımlanır.
|
||||
|
||||
Bunu yapmak için standart Python type hint'i olan <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>'ı kullanın:
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bir <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a> tanımlarken en spesifik type'ı önce, daha az spesifik olanı sonra ekleyin. Aşağıdaki örnekte daha spesifik olan `PlaneItem`, `Union[PlaneItem, CarItem]` içinde `CarItem`'dan önce gelir.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
|
||||
|
||||
### Python 3.10'da `Union` { #union-in-python-3-10 }
|
||||
|
||||
Bu örnekte `Union[PlaneItem, CarItem]` değerini `response_model` argümanına veriyoruz.
|
||||
|
||||
Bunu bir **type annotation** içine koymak yerine bir **argümana değer** olarak geçtiğimiz için, Python 3.10'da bile `Union` kullanmamız gerekiyor.
|
||||
|
||||
Eğer bu bir type annotation içinde olsaydı, dikey çizgiyi kullanabilirdik:
|
||||
|
||||
```Python
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
Ancak bunu `response_model=PlaneItem | CarItem` atamasına koyarsak hata alırız; çünkü Python bunu bir type annotation olarak yorumlamak yerine `PlaneItem` ile `CarItem` arasında **geçersiz bir işlem** yapmaya çalışır.
|
||||
|
||||
## Model Listesi { #list-of-models }
|
||||
|
||||
Aynı şekilde, nesne listesi döndüren response'ları da tanımlayabilirsiniz.
|
||||
|
||||
Bunun için standart Python `list`'i kullanın:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
## Rastgele `dict` ile Response { #response-with-arbitrary-dict }
|
||||
|
||||
Bir Pydantic modeli kullanmadan, sadece key ve value type'larını belirterek düz, rastgele bir `dict` ile de response tanımlayabilirsiniz.
|
||||
|
||||
Bu, geçerli field/attribute adlarını (Pydantic modeli için gerekli olurdu) önceden bilmiyorsanız kullanışlıdır.
|
||||
|
||||
Bu durumda `dict` kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Her duruma göre birden fazla Pydantic modeli kullanın ve gerekirse özgürce inheritance uygulayın.
|
||||
|
||||
Bir entity'nin farklı "state"lere sahip olması gerekiyorsa, o entity için tek bir veri modeli kullanmak zorunda değilsiniz. Örneğin `password` içeren, `password_hash` içeren ve `password` içermeyen state'lere sahip kullanıcı "entity"si gibi.
|
||||
@@ -1,102 +1,118 @@
|
||||
# İlk Adımlar
|
||||
# İlk Adımlar { #first-steps }
|
||||
|
||||
En sade FastAPI dosyası şu şekilde görünür:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py *}
|
||||
|
||||
Yukarıdaki içeriği bir `main.py` dosyasına kopyalayalım.
|
||||
Yukarıdakini `main.py` adlı bir dosyaya kopyalayın.
|
||||
|
||||
Uygulamayı çalıştıralım:
|
||||
Canlı sunucuyu çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Not
|
||||
|
||||
`uvicorn main:app` komutunu şu şekilde açıklayabiliriz:
|
||||
|
||||
* `main`: dosya olan `main.py` (yani Python "modülü").
|
||||
* `app`: ise `main.py` dosyasının içerisinde `app = FastAPI()` satırında oluşturduğumuz `FastAPI` nesnesi.
|
||||
* `--reload`: kod değişikliklerinin ardından sunucuyu otomatik olarak yeniden başlatır. Bu parameteyi sadece geliştirme aşamasında kullanmalıyız.
|
||||
|
||||
///
|
||||
|
||||
Çıktı olarak şöyle bir satır ile karşılaşacaksınız:
|
||||
Çıktıda, şuna benzer bir satır göreceksiniz:
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Bu satır, yerel makinenizde uygulamanızın çalıştığı bağlantıyı gösterir.
|
||||
Bu satır, uygulamanızın yerel makinenizde hangi URL'de sunulduğunu gösterir.
|
||||
|
||||
### Kontrol Edelim
|
||||
### Kontrol Edelim { #check-it }
|
||||
|
||||
Tarayıcınızı açıp <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> bağlantısına gidin.
|
||||
Tarayıcınızı açıp <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresine gidin.
|
||||
|
||||
Şu şekilde bir JSON yanıtı ile karşılaşacağız:
|
||||
Şu şekilde bir JSON response göreceksiniz:
|
||||
|
||||
```JSON
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### Etkileşimli API Dokümantasyonu
|
||||
### Etkileşimli API Dokümantasyonu { #interactive-api-docs }
|
||||
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> bağlantısını açalım.
|
||||
Şimdi <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
|
||||
|
||||
<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanan otomatik etkileşimli bir API dokümantasyonu göreceğiz:
|
||||
Otomatik etkileşimli API dokümantasyonunu ( <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanan) göreceksiniz:
|
||||
|
||||

|
||||
|
||||
### Alternatif API Dokümantasyonu
|
||||
### Alternatif API Dokümantasyonu { #alternative-api-docs }
|
||||
|
||||
Şimdi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> bağlantısını açalım.
|
||||
Ve şimdi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gidin.
|
||||
|
||||
<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan otomatik dokümantasyonu göreceğiz:
|
||||
Alternatif otomatik dokümantasyonu ( <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan) göreceksiniz:
|
||||
|
||||

|
||||
|
||||
### OpenAPI
|
||||
### OpenAPI { #openapi }
|
||||
|
||||
**FastAPI**, **OpenAPI** standardını kullanarak tüm API'ınızın tamamını tanımlayan bir "şema" oluşturur.
|
||||
**FastAPI**, API'ları tanımlamak için **OpenAPI** standardını kullanarak tüm API'nızın tamamını içeren bir "şema" üretir.
|
||||
|
||||
#### "Şema"
|
||||
#### "Şema" { #schema }
|
||||
|
||||
"Şema", bir şeyin tanımı veya açıklamasıdır. Geliştirilen koddan ziyade soyut bir açıklamadır.
|
||||
"Şema", bir şeyin tanımı veya açıklamasıdır. Onu uygulayan kod değil, sadece soyut bir açıklamadır.
|
||||
|
||||
#### API "Şeması"
|
||||
#### API "şeması" { #api-schema }
|
||||
|
||||
Bu durumda, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>, API şemasını nasıl tanımlayacağınızı belirten bir şartnamedir.
|
||||
Bu durumda, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>, API'nızın şemasını nasıl tanımlayacağınızı belirleyen bir şartnamedir.
|
||||
|
||||
Bu şema tanımı, API yollarınızla birlikte yollarınızın aldığı olası parametreler gibi tanımlamaları içerir.
|
||||
Bu şema tanımı, API path'leriniz, alabilecekleri olası parametreler vb. şeyleri içerir.
|
||||
|
||||
#### Veri "Şeması"
|
||||
#### Veri "şeması" { #data-schema }
|
||||
|
||||
"Şema" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.
|
||||
|
||||
Bu durumda, JSON özellikleri ve sahip oldukları veri türleri gibi anlamlarına gelir.
|
||||
Bu durumda, JSON attribute'ları ve sahip oldukları veri türleri vb. anlamına gelir.
|
||||
|
||||
#### OpenAPI ve JSON Şema
|
||||
#### OpenAPI ve JSON Schema { #openapi-and-json-schema }
|
||||
|
||||
OpenAPI, API'niz için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Şema** kullanılarak API'niz tarafından gönderilen ve alınan verilerin tanımlarını (veya "şemalarını") içerir.
|
||||
OpenAPI, API'nız için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Schema** kullanılarak API'nız tarafından gönderilen ve alınan verilerin tanımlarını (veya "şemalarını") içerir.
|
||||
|
||||
#### `openapi.json` Dosyasına Göz At
|
||||
#### `openapi.json` Dosyasına Göz At { #check-the-openapi-json }
|
||||
|
||||
Ham OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'ınızın tanımlamalarını içeren bir JSON (şeması) oluşturur.
|
||||
Ham OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nızın açıklamalarını içeren bir JSON (şema) üretir.
|
||||
|
||||
Bu şemayı direkt olarak <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a> bağlantısından görüntüleyebilirsiniz.
|
||||
Bunu doğrudan şuradan görebilirsiniz: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
|
||||
Aşağıdaki gibi başlayan bir JSON ile karşılaşacaksınız:
|
||||
Şuna benzer bir şekilde başlayan bir JSON gösterecektir:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -119,79 +135,87 @@ Aşağıdaki gibi başlayan bir JSON ile karşılaşacaksınız:
|
||||
...
|
||||
```
|
||||
|
||||
#### OpenAPI Ne İşe Yarar?
|
||||
#### OpenAPI Ne İşe Yarar? { #what-is-openapi-for }
|
||||
|
||||
OpenAPI şeması, FastAPI projesinde bulunan iki etkileşimli dokümantasyon sistemine güç veren şeydir.
|
||||
OpenAPI şeması, dahil edilen iki etkileşimli dokümantasyon sistemine güç veren şeydir.
|
||||
|
||||
OpenAPI'ya dayalı düzinelerce alternatif etkileşimli dokümantasyon aracı mevcuttur. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
|
||||
Ve OpenAPI tabanlı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
|
||||
|
||||
Ayrıca, API'ınızla iletişim kuracak önyüz, mobil veya IoT uygulamaları gibi istemciler için otomatik olarak kod oluşturabilirsiniz.
|
||||
Ayrıca, API'nızla iletişim kuran istemciler için otomatik olarak kod üretmekte de kullanabilirsiniz. Örneğin frontend, mobil veya IoT uygulamaları.
|
||||
|
||||
## Adım Adım Özetleyelim
|
||||
### Uygulamanızı Yayınlayın (opsiyonel) { #deploy-your-app-optional }
|
||||
|
||||
### Adım 1: `FastAPI`yı Projemize Dahil Edelim
|
||||
İsterseniz FastAPI uygulamanızı <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>'a deploy edebilirsiniz; henüz katılmadıysanız gidip bekleme listesine yazılın. 🚀
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
|
||||
Zaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek komutla deploy edebilirsiniz.
|
||||
|
||||
`FastAPI`, API'niz için tüm işlevselliği sağlayan bir Python sınıfıdır.
|
||||
Deploy etmeden önce giriş yaptığınızdan emin olun:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ardından uygulamanızı deploy edin:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Bu kadar! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨
|
||||
|
||||
## Adım Adım Özetleyelim { #recap-step-by-step }
|
||||
|
||||
### Adım 1: `FastAPI` import edin { #step-1-import-fastapi }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
|
||||
|
||||
`FastAPI`, API'nız için tüm işlevselliği sağlayan bir Python class'ıdır.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`FastAPI` doğrudan `Starlette`'i miras alan bir sınıftır.
|
||||
`FastAPI`, doğrudan `Starlette`'ten miras alan bir class'tır.
|
||||
|
||||
<a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>'in tüm işlevselliğini `FastAPI` ile de kullanabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
### Adım 2: Bir `FastAPI` "Örneği" Oluşturalım
|
||||
### Adım 2: bir `FastAPI` "instance"ı oluşturun { #step-2-create-a-fastapi-instance }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
|
||||
|
||||
Burada `app` değişkeni `FastAPI` sınıfının bir örneği olacaktır.
|
||||
Burada `app` değişkeni `FastAPI` class'ının bir "instance"ı olacaktır.
|
||||
|
||||
Bu, tüm API'yı oluşturmak için ana etkileşim noktası olacaktır.
|
||||
Bu, tüm API'nızı oluşturmak için ana etkileşim noktası olacaktır.
|
||||
|
||||
Bu `app` değişkeni, `uvicorn` komutunda atıfta bulunulan değişkenin ta kendisidir.
|
||||
### Adım 3: bir *path operation* oluşturun { #step-3-create-a-path-operation }
|
||||
|
||||
<div class="termy">
|
||||
#### Path { #path }
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
Buradaki "Path", URL'in ilk `/` işaretinden başlayarak son kısmını ifade eder.
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Uygulamanızı aşağıdaki gibi oluşturursanız:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
|
||||
|
||||
Ve bunu `main.py` dosyasına yerleştirirseniz eğer `uvicorn` komutunu şu şekilde çalıştırabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:my_awesome_api --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Adım 3: Bir *Yol Operasyonu* Oluşturalım
|
||||
|
||||
#### <abbr title="Yol: Path">Yol</abbr>
|
||||
|
||||
Burada "yol" bağlantıda bulunan ilk `/` ile başlayan ve sonrasında gelen kısmı ifade eder.
|
||||
|
||||
Yani, şu şekilde bir bağlantıda:
|
||||
Yani, şu şekilde bir URL'de:
|
||||
|
||||
```
|
||||
https://example.com/items/foo
|
||||
```
|
||||
|
||||
... yol şöyle olur:
|
||||
...path şöyle olur:
|
||||
|
||||
```
|
||||
/items/foo
|
||||
@@ -199,77 +223,77 @@ https://example.com/items/foo
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
"Yol" genellikle "<abbr title="Endpoint: Bitim Noktası">endpoint</abbr>" veya "<abbr title="Route: Yönlendirme/Yön">route</abbr>" olarak adlandırılır.
|
||||
Bir "path" genellikle "endpoint" veya "route" olarak da adlandırılır.
|
||||
|
||||
///
|
||||
|
||||
Bir API oluştururken, "yol", "kaynaklar" ile "endişeleri" ayırmanın ana yöntemidir.
|
||||
Bir API oluştururken, "path", "concerns" ve "resources" ayrımını yapmanın ana yoludur.
|
||||
|
||||
#### Operasyonlar
|
||||
#### Operation { #operation }
|
||||
|
||||
Burada "operasyon" HTTP "metodlarından" birini ifade eder.
|
||||
Burada "Operation", HTTP "method"larından birini ifade eder.
|
||||
|
||||
Bunlardan biri:
|
||||
Şunlardan biri:
|
||||
|
||||
* `POST`
|
||||
* `GET`
|
||||
* `PUT`
|
||||
* `DELETE`
|
||||
|
||||
...veya daha az kullanılan diğerleri:
|
||||
...ve daha egzotik olanlar:
|
||||
|
||||
* `OPTIONS`
|
||||
* `HEAD`
|
||||
* `PATCH`
|
||||
* `TRACE`
|
||||
|
||||
HTTP protokolünde, bu "metodlardan" birini (veya daha fazlasını) kullanarak her bir yol ile iletişim kurabilirsiniz.
|
||||
HTTP protokolünde, her bir path ile bu "method"lardan biri (veya birden fazlası) ile iletişim kurabilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
API oluştururkan, belirli bir amaca hizmet eden belirli HTTP metodlarını kullanırsınız.
|
||||
API oluştururken, normalde belirli bir aksiyon için bu spesifik HTTP method'larını kullanırsınız.
|
||||
|
||||
Normalde kullanılan:
|
||||
Normalde şunları kullanırsınız:
|
||||
|
||||
* `POST`: veri oluşturmak.
|
||||
* `GET`: veri okumak.
|
||||
* `PUT`: veriyi güncellemek.
|
||||
* `DELETE`: veriyi silmek.
|
||||
* `POST`: veri oluşturmak için.
|
||||
* `GET`: veri okumak için.
|
||||
* `PUT`: veriyi güncellemek için.
|
||||
* `DELETE`: veriyi silmek için.
|
||||
|
||||
Bu nedenle, OpenAPI'da HTTP metodlarından her birine "operasyon" denir.
|
||||
Bu nedenle, OpenAPI'da HTTP method'larının her birine "operation" denir.
|
||||
|
||||
Biz de onları "**operasyonlar**" olarak adlandıracağız.
|
||||
Biz de bunlara "**operation**" diyeceğiz.
|
||||
|
||||
#### Bir *Yol Operasyonu Dekoratörü* Tanımlayalım
|
||||
#### Bir *path operation decorator* tanımlayın { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
`@app.get("/")` dekoratörü, **FastAPI**'a hemen altındaki fonksiyonun aşağıdaki durumlardan sorumlu olduğunu söyler:
|
||||
`@app.get("/")`, **FastAPI**'a hemen altındaki fonksiyonun şuraya giden request'leri ele almakla sorumlu olduğunu söyler:
|
||||
|
||||
* <abbr title="Bir HTTP GET metodu"><code>get</code> operasyonu</abbr> ile
|
||||
* `/` yoluna gelen istekler
|
||||
* path `/`
|
||||
* <dfn title="bir HTTP GET methodu"><code>get</code> operation</dfn> kullanarak
|
||||
|
||||
/// info | `@decorator` Bilgisi
|
||||
|
||||
Python'da `@something` sözdizimi "<abbr title="Decorator">dekoratör</abbr>" olarak adlandırılır.
|
||||
Python'daki `@something` söz dizimi "decorator" olarak adlandırılır.
|
||||
|
||||
Dekoratörler, dekoratif bir şapka gibi (sanırım terim buradan geliyor) fonksiyonların üzerlerine yerleştirilirler.
|
||||
Onu bir fonksiyonun üstüne koyarsınız. Güzel, dekoratif bir şapka gibi (sanırım terim de buradan geliyor).
|
||||
|
||||
Bir "dekoratör" hemen altında bulunan fonksiyonu alır ve o fonksiyon ile bazı işlemler gerçekleştirir.
|
||||
Bir "decorator", altındaki fonksiyonu alır ve onunla bir şey yapar.
|
||||
|
||||
Bizim durumumuzda, kullandığımız dekoratör, **FastAPI**'a altındaki fonksiyonun `/` yoluna gelen `get` metodlu isteklerden sorumlu olduğunu söyler.
|
||||
Bizim durumumuzda bu decorator, **FastAPI**'a altındaki fonksiyonun **path** `/` ile **operation** `get`'e karşılık geldiğini söyler.
|
||||
|
||||
Bu bir **yol operasyonu dekoratörüdür**.
|
||||
Bu, "**path operation decorator**"dır.
|
||||
|
||||
///
|
||||
|
||||
Ayrıca diğer operasyonları da kullanabilirsiniz:
|
||||
Diğer operation'ları da kullanabilirsiniz:
|
||||
|
||||
* `@app.post()`
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
|
||||
Daha az kullanılanları da kullanabilirsiniz:
|
||||
Ve daha egzotik olanları:
|
||||
|
||||
* `@app.options()`
|
||||
* `@app.head()`
|
||||
@@ -278,58 +302,79 @@ Daha az kullanılanları da kullanabilirsiniz:
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Her işlemi (HTTP metod) istediğiniz gibi kullanmakta özgürsünüz.
|
||||
Her bir operation'ı (HTTP method'unu) istediğiniz gibi kullanmakta özgürsünüz.
|
||||
|
||||
**FastAPI** herhangi bir özel amacı veya anlamı olması konusunda ısrarcı olmaz.
|
||||
**FastAPI** herhangi bir özel anlamı zorunlu kılmaz.
|
||||
|
||||
Buradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.
|
||||
|
||||
Mesela GraphQL kullanırkan genelde tüm işlemleri yalnızca `POST` operasyonunu kullanarak gerçekleştirirsiniz.
|
||||
Örneğin GraphQL kullanırken, normalde tüm aksiyonları yalnızca `POST` operation'ları kullanarak gerçekleştirirsiniz.
|
||||
|
||||
///
|
||||
|
||||
### Adım 4: **Yol Operasyonu Fonksiyonunu** Tanımlayın
|
||||
### Adım 4: **path operation function**'ı tanımlayın { #step-4-define-the-path-operation-function }
|
||||
|
||||
Aşağıdaki, bizim **yol operasyonu fonksiyonumuzdur**:
|
||||
Bu bizim "**path operation function**"ımız:
|
||||
|
||||
* **yol**: `/`
|
||||
* **operasyon**: `get`
|
||||
* **fonksiyon**: "dekoratör"ün (`@app.get("/")`'in) altındaki fonksiyondur.
|
||||
* **path**: `/`.
|
||||
* **operation**: `get`.
|
||||
* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")`'in altındaki).
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
|
||||
|
||||
Bu bir Python fonksiyonudur.
|
||||
|
||||
Bu fonksiyon bir `GET` işlemi kullanılarak "`/`" bağlantısına bir istek geldiğinde **FastAPI** tarafından çağrılır.
|
||||
**FastAPI**, "`/`" URL'ine `GET` operation kullanarak bir request aldığında bu fonksiyonu çağıracaktır.
|
||||
|
||||
Bu durumda bu fonksiyon bir `async` fonksiyondur.
|
||||
Bu durumda, bu bir `async` fonksiyondur.
|
||||
|
||||
---
|
||||
|
||||
Bu fonksiyonu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz.
|
||||
Bunu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Eğer farkı bilmiyorsanız, [Async: *"Aceleniz mi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} sayfasını kontrol edebilirsiniz.
|
||||
Eğer farkı bilmiyorsanız, [Async: *"Aceleniz mi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} sayfasına bakın.
|
||||
|
||||
///
|
||||
|
||||
### Adım 5: İçeriği Geri Döndürün
|
||||
### Adım 5: içeriği döndürün { #step-5-return-the-content }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
|
||||
|
||||
Bir `dict`, `list` veya `str`, `int` gibi tekil değerler döndürebilirsiniz.
|
||||
Bir `dict`, `list`, `str`, `int` vb. tekil değerler döndürebilirsiniz.
|
||||
|
||||
Ayrıca, Pydantic modelleri de döndürebilirsiniz (bu konu ileriki aşamalarda irdelenecektir).
|
||||
Ayrıca Pydantic modelleri de döndürebilirsiniz (bununla ilgili daha fazlasını ileride göreceksiniz).
|
||||
|
||||
Otomatik olarak JSON'a dönüştürülecek (ORM'ler vb. dahil) başka birçok nesne ve model vardır. En beğendiklerinizi kullanmayı deneyin, yüksek ihtimalle destekleniyordur.
|
||||
Otomatik olarak JSON'a dönüştürülecek (ORM'ler vb. dahil) başka birçok nesne ve model vardır. En sevdiğiniz nesne/model'leri kullanmayı deneyin; büyük ihtimalle zaten destekleniyordur.
|
||||
|
||||
## Özet
|
||||
### Adım 6: Deploy edin { #step-6-deploy-it }
|
||||
|
||||
* `FastAPI`'yı projemize dahil ettik.
|
||||
* Bir `app` örneği oluşturduk.
|
||||
* Bir **yol operasyonu dekoratörü** (`@app.get("/")` gibi) yazdık.
|
||||
* Bir **yol operasyonu fonksiyonu** (`def root(): ...` gibi) yazdık.
|
||||
* Geliştirme sunucumuzu (`uvicorn main:app --reload` gibi) çalıştırdık.
|
||||
Uygulamanızı tek komutla **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**'a deploy edin: `fastapi deploy`. 🎉
|
||||
|
||||
#### FastAPI Cloud Hakkında { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**, **FastAPI**'ın arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.
|
||||
|
||||
Minimum eforla bir API'ı **oluşturma**, **deploy etme** ve **erişme** sürecini sadeleştirir.
|
||||
|
||||
FastAPI ile uygulama geliştirirken yaşadığınız aynı **developer experience**'ı, onları buluta **deploy etme** aşamasına da taşır. 🎉
|
||||
|
||||
FastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨
|
||||
|
||||
#### Diğer cloud sağlayıcılarına deploy edin { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI açık kaynaklıdır ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.
|
||||
|
||||
FastAPI uygulamalarını onlarla deploy etmek için cloud sağlayıcınızın kılavuzlarını takip edin. 🤓
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
* `FastAPI` import edin.
|
||||
* Bir `app` instance'ı oluşturun.
|
||||
* `@app.get("/")` gibi decorator'ları kullanarak bir **path operation decorator** yazın.
|
||||
* Bir **path operation function** tanımlayın; örneğin `def root(): ...`.
|
||||
* `fastapi dev` komutunu kullanarak geliştirme sunucusunu çalıştırın.
|
||||
* İsterseniz `fastapi deploy` ile uygulamanızı deploy edin.
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
# Hataları Yönetme { #handling-errors }
|
||||
|
||||
API’nizi kullanan bir client’a hata bildirmek zorunda olduğunuz pek çok durum vardır.
|
||||
|
||||
Bu client; frontend’i olan bir tarayıcı, başka birinin yazdığı bir kod, bir IoT cihazı vb. olabilir.
|
||||
|
||||
Client’a şunları söylemeniz gerekebilir:
|
||||
|
||||
* Client’ın bu işlem için yeterli yetkisi yok.
|
||||
* Client’ın bu kaynağa erişimi yok.
|
||||
* Client’ın erişmeye çalıştığı öğe mevcut değil.
|
||||
* vb.
|
||||
|
||||
Bu durumlarda genellikle **400** aralığında (**400** ile **499** arası) bir **HTTP status code** döndürürsünüz.
|
||||
|
||||
Bu, 200 HTTP status code’larına (200 ile 299 arası) benzer. Bu "200" status code’ları, request’in bir şekilde "başarılı" olduğunu ifade eder.
|
||||
|
||||
400 aralığındaki status code’lar ise hatanın client tarafından kaynaklandığını gösterir.
|
||||
|
||||
Şu meşhur **"404 Not Found"** hatalarını (ve şakalarını) hatırlıyor musunuz?
|
||||
|
||||
## `HTTPException` Kullanma { #use-httpexception }
|
||||
|
||||
Client’a hata içeren HTTP response’ları döndürmek için `HTTPException` kullanırsınız.
|
||||
|
||||
### `HTTPException`’ı Import Etme { #import-httpexception }
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
|
||||
|
||||
### Kodunuzda Bir `HTTPException` Raise Etme { #raise-an-httpexception-in-your-code }
|
||||
|
||||
`HTTPException`, API’lerle ilgili ek veriler içeren normal bir Python exception’ıdır.
|
||||
|
||||
Python exception’ı olduğu için `return` etmezsiniz, `raise` edersiniz.
|
||||
|
||||
Bu aynı zamanda şunu da ifade eder: *path operation function*’ınızın içinde çağırdığınız bir yardımcı (utility) fonksiyonun içindeyken `HTTPException` raise ederseniz, *path operation function* içindeki kodun geri kalanı çalışmaz; request’i hemen sonlandırır ve `HTTPException` içindeki HTTP hatasını client’a gönderir.
|
||||
|
||||
Bir değer döndürmek yerine exception raise etmenin faydası, Dependencies ve Security bölümünde daha da netleşecektir.
|
||||
|
||||
Bu örnekte, client var olmayan bir ID ile bir item istediğinde, `404` status code’u ile bir exception raise edelim:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||||
|
||||
### Ortaya Çıkan Response { #the-resulting-response }
|
||||
|
||||
Client `http://example.com/items/foo` (bir `item_id` `"foo"`) isterse, HTTP status code olarak 200 ve şu JSON response’u alır:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": "The Foo Wrestlers"
|
||||
}
|
||||
```
|
||||
|
||||
Ancak client `http://example.com/items/bar` (mevcut olmayan bir `item_id` `"bar"`) isterse, HTTP status code olarak 404 ("not found" hatası) ve şu JSON response’u alır:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": "Item not found"
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Bir `HTTPException` raise ederken, `detail` parametresine sadece `str` değil, JSON’a dönüştürülebilen herhangi bir değer geçebilirsiniz.
|
||||
|
||||
Örneğin `dict`, `list` vb. geçebilirsiniz.
|
||||
|
||||
Bunlar **FastAPI** tarafından otomatik olarak işlenir ve JSON’a dönüştürülür.
|
||||
|
||||
///
|
||||
|
||||
## Özel Header’lar Eklemek { #add-custom-headers }
|
||||
|
||||
Bazı durumlarda HTTP hata response’una özel header’lar eklemek faydalıdır. Örneğin bazı güvenlik türlerinde.
|
||||
|
||||
Muhtemelen bunu doğrudan kendi kodunuzda kullanmanız gerekmeyecek.
|
||||
|
||||
Ama ileri seviye bir senaryo için ihtiyaç duyarsanız, özel header’lar ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||||
|
||||
## Özel Exception Handler’ları Kurmak { #install-custom-exception-handlers }
|
||||
|
||||
<a href="https://www.starlette.dev/exceptions/" class="external-link" target="_blank">Starlette’in aynı exception yardımcı araçlarıyla</a> özel exception handler’lar ekleyebilirsiniz.
|
||||
|
||||
Diyelim ki sizin (ya da kullandığınız bir kütüphanenin) `raise` edebileceği `UnicornException` adında özel bir exception’ınız var.
|
||||
|
||||
Ve bu exception’ı FastAPI ile global olarak handle etmek istiyorsunuz.
|
||||
|
||||
`@app.exception_handler()` ile özel bir exception handler ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
|
||||
|
||||
Burada `/unicorns/yolo` için request atarsanız, *path operation* bir `UnicornException` `raise` eder.
|
||||
|
||||
Ancak bu, `unicorn_exception_handler` tarafından handle edilir.
|
||||
|
||||
Böylece HTTP status code’u `418` olan, JSON içeriği şu şekilde temiz bir hata response’u alırsınız:
|
||||
|
||||
```JSON
|
||||
{"message": "Oops! yolo did something. There goes a rainbow..."}
|
||||
```
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.requests import Request` ve `from starlette.responses import JSONResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir. `Request` için de aynısı geçerlidir.
|
||||
|
||||
///
|
||||
|
||||
## Varsayılan Exception Handler’ları Override Etmek { #override-the-default-exception-handlers }
|
||||
|
||||
**FastAPI** bazı varsayılan exception handler’lara sahiptir.
|
||||
|
||||
Bu handler’lar, `HTTPException` `raise` ettiğinizde ve request geçersiz veri içerdiğinde varsayılan JSON response’ları döndürmekten sorumludur.
|
||||
|
||||
Bu exception handler’ları kendi handler’larınızla override edebilirsiniz.
|
||||
|
||||
### Request Validation Exception’larını Override Etmek { #override-request-validation-exceptions }
|
||||
|
||||
Bir request geçersiz veri içerdiğinde, **FastAPI** içeride `RequestValidationError` raise eder.
|
||||
|
||||
Ve bunun için varsayılan bir exception handler da içerir.
|
||||
|
||||
Override etmek için `RequestValidationError`’ı import edin ve exception handler’ı `@app.exception_handler(RequestValidationError)` ile decorate edin.
|
||||
|
||||
Exception handler, bir `Request` ve exception’ı alır.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
|
||||
|
||||
Artık `/items/foo`’ya giderseniz, şu varsayılan JSON hatası yerine:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
şu şekilde bir metin (text) versiyonu alırsınız:
|
||||
|
||||
```
|
||||
Validation errors:
|
||||
Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
|
||||
```
|
||||
|
||||
### `HTTPException` Hata Handler’ını Override Etmek { #override-the-httpexception-error-handler }
|
||||
|
||||
Benzer şekilde `HTTPException` handler’ını da override edebilirsiniz.
|
||||
|
||||
Örneğin bu hatalar için JSON yerine plain text response döndürmek isteyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.responses import PlainTextResponse` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir.
|
||||
|
||||
///
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`RequestValidationError`, validation hatasının gerçekleştiği dosya adı ve satır bilgilerini içerir; isterseniz bunu log’larınıza ilgili bilgilerle birlikte yazdırabilirsiniz.
|
||||
|
||||
Ancak bu, eğer sadece string’e çevirip bu bilgiyi doğrudan response olarak döndürürseniz sisteminiz hakkında bir miktar bilgi sızdırabileceğiniz anlamına gelir. Bu yüzden burada kod, her bir hatayı ayrı ayrı çıkarıp gösterir.
|
||||
|
||||
///
|
||||
|
||||
### `RequestValidationError` Body’sini Kullanmak { #use-the-requestvalidationerror-body }
|
||||
|
||||
`RequestValidationError`, geçersiz veriyle aldığı `body`’yi içerir.
|
||||
|
||||
Uygulamanızı geliştirirken body’yi log’lamak, debug etmek, kullanıcıya döndürmek vb. için bunu kullanabilirsiniz.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
|
||||
|
||||
Şimdi şu gibi geçersiz bir item göndermeyi deneyin:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"title": "towel",
|
||||
"size": "XL"
|
||||
}
|
||||
```
|
||||
|
||||
Aldığınız body’yi de içeren, verinin geçersiz olduğunu söyleyen bir response alırsınız:
|
||||
|
||||
```JSON hl_lines="12-15"
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"body",
|
||||
"size"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"title": "towel",
|
||||
"size": "XL"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### FastAPI’nin `HTTPException`’ı vs Starlette’in `HTTPException`’ı { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
|
||||
**FastAPI**’nin kendi `HTTPException`’ı vardır.
|
||||
|
||||
Ve **FastAPI**’nin `HTTPException` hata sınıfı, Starlette’in `HTTPException` hata sınıfından kalıtım alır (inherit).
|
||||
|
||||
Tek fark şudur: **FastAPI**’nin `HTTPException`’ı `detail` alanı için JSON’a çevrilebilir herhangi bir veri kabul ederken, Starlette’in `HTTPException`’ı burada sadece string kabul eder.
|
||||
|
||||
Bu yüzden kodunuzda her zamanki gibi **FastAPI**’nin `HTTPException`’ını raise etmeye devam edebilirsiniz.
|
||||
|
||||
Ancak bir exception handler register ederken, bunu Starlette’in `HTTPException`’ı için register etmelisiniz.
|
||||
|
||||
Böylece Starlette’in internal kodunun herhangi bir bölümü ya da bir Starlette extension/plug-in’i Starlette `HTTPException` raise ederse, handler’ınız bunu yakalayıp (catch) handle edebilir.
|
||||
|
||||
Bu örnekte, iki `HTTPException`’ı da aynı kodda kullanabilmek için Starlette’in exception’ı `StarletteHTTPException` olarak yeniden adlandırılıyor:
|
||||
|
||||
```Python
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
```
|
||||
|
||||
### **FastAPI**’nin Exception Handler’larını Yeniden Kullanmak { #reuse-fastapis-exception-handlers }
|
||||
|
||||
Exception’ı, **FastAPI**’nin aynı varsayılan exception handler’larıyla birlikte kullanmak isterseniz, varsayılan exception handler’ları `fastapi.exception_handlers` içinden import edip yeniden kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||||
|
||||
Bu örnekte sadece oldukça açıklayıcı bir mesajla hatayı yazdırıyorsunuz; ama fikir anlaşılıyor. Exception’ı kullanıp ardından varsayılan exception handler’ları olduğu gibi yeniden kullanabilirsiniz.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Header Parametre Modelleri { #header-parameter-models }
|
||||
|
||||
Birbiriyle ilişkili **header parametreleri**nden oluşan bir grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz.
|
||||
|
||||
Bu sayede modeli **birden fazla yerde yeniden kullanabilir**, ayrıca tüm parametreler için doğrulamaları ve metadata bilgilerini tek seferde tanımlayabilirsiniz. 😎
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Pydantic Model ile Header Parametreleri { #header-parameters-with-a-pydantic-model }
|
||||
|
||||
İhtiyacınız olan **header parametreleri**ni bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Header` olarak belirtin:
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
|
||||
|
||||
**FastAPI**, request içindeki **headers** bölümünden **her alan** için veriyi **çıkarır** ve size tanımladığınız Pydantic model örneğini verir.
|
||||
|
||||
## Dokümanları Kontrol Edin { #check-the-docs }
|
||||
|
||||
Gerekli header'ları `/docs` altındaki doküman arayüzünde görebilirsiniz:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/header-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
## Ek Header'ları Yasaklayın { #forbid-extra-headers }
|
||||
|
||||
Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), kabul etmek istediğiniz header'ları **kısıtlamak** isteyebilirsiniz.
|
||||
|
||||
Pydantic'in model yapılandırmasını kullanarak `extra` alanları `forbid` edebilirsiniz:
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
Bir client bazı **ek header'lar** göndermeye çalışırsa, **hata** response'u alır.
|
||||
|
||||
Örneğin client, değeri `plumbus` olan bir `tool` header'ı göndermeye çalışırsa, `tool` header parametresine izin verilmediğini söyleyen bir **hata** response'u alır:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "extra_forbidden",
|
||||
"loc": ["header", "tool"],
|
||||
"msg": "Extra inputs are not permitted",
|
||||
"input": "plumbus",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Alt Çizgileri Dönüştürmeyi Kapatın { #disable-convert-underscores }
|
||||
|
||||
Normal header parametrelerinde olduğu gibi, parametre adlarında alt çizgi karakterleri olduğunda bunlar **otomatik olarak tireye dönüştürülür**.
|
||||
|
||||
Örneğin kodda `save_data` adlı bir header parametreniz varsa, beklenen HTTP header `save-data` olur ve dokümanlarda da bu şekilde görünür.
|
||||
|
||||
Herhangi bir sebeple bu otomatik dönüşümü kapatmanız gerekiyorsa, header parametreleri için kullandığınız Pydantic model'lerde de bunu devre dışı bırakabilirsiniz.
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`convert_underscores` değerini `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların alt çizgi içeren header'ların kullanımına izin vermediğini unutmayın.
|
||||
|
||||
///
|
||||
|
||||
## Özet { #summary }
|
||||
|
||||
**FastAPI**'de **headers** tanımlamak için **Pydantic model** kullanabilirsiniz. 😎
|
||||
@@ -0,0 +1,91 @@
|
||||
# Header Parametreleri { #header-parameters }
|
||||
|
||||
`Query`, `Path` ve `Cookie` parametrelerini nasıl tanımlıyorsanız, Header parametrelerini de aynı şekilde tanımlayabilirsiniz.
|
||||
|
||||
## `Header`'ı Import Edin { #import-header }
|
||||
|
||||
Önce `Header`'ı import edin:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## `Header` Parametrelerini Tanımlayın { #declare-header-parameters }
|
||||
|
||||
Ardından header parametrelerini, `Path`, `Query` ve `Cookie` ile kullandığınız yapının aynısıyla tanımlayın.
|
||||
|
||||
Default değeri ve ek validation ya da annotation parametrelerinin tamamını belirleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`Header`, `Path`, `Query` ve `Cookie`'nin "kardeş" sınıfıdır. Ayrıca aynı ortak `Param` sınıfından kalıtım alır.
|
||||
|
||||
Ancak şunu unutmayın: `fastapi`'den `Query`, `Path`, `Header` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıfları döndüren fonksiyonlardır.
|
||||
|
||||
///
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Header'ları tanımlamak için `Header` kullanmanız gerekir; aksi halde parametreler query parametreleri olarak yorumlanır.
|
||||
|
||||
///
|
||||
|
||||
## Otomatik Dönüştürme { #automatic-conversion }
|
||||
|
||||
`Header`, `Path`, `Query` ve `Cookie`'nin sağladıklarına ek olarak küçük bir ekstra işlevsellik sunar.
|
||||
|
||||
Standart header'ların çoğu, "hyphen" karakteri (diğer adıyla "minus symbol" (`-`)) ile ayrılır.
|
||||
|
||||
Ancak `user-agent` gibi bir değişken adı Python'da geçersizdir.
|
||||
|
||||
Bu yüzden, default olarak `Header`, header'ları almak ve dokümante etmek için parametre adlarındaki underscore (`_`) karakterlerini hyphen (`-`) ile dönüştürür.
|
||||
|
||||
Ayrıca HTTP header'ları büyük/küçük harfe duyarlı değildir; dolayısıyla onları standart Python stiliyle (diğer adıyla "snake_case") tanımlayabilirsiniz.
|
||||
|
||||
Yani `User_Agent` gibi bir şey yazıp ilk harfleri büyütmeniz gerekmeden, Python kodunda normalde kullandığınız gibi `user_agent` kullanabilirsiniz.
|
||||
|
||||
Herhangi bir nedenle underscore'ların hyphen'lara otomatik dönüştürülmesini kapatmanız gerekirse, `Header`'ın `convert_underscores` parametresini `False` yapın:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
`convert_underscores`'u `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların underscore içeren header'ların kullanımına izin vermediğini unutmayın.
|
||||
|
||||
///
|
||||
|
||||
## Yinelenen Header'lar { #duplicate-headers }
|
||||
|
||||
Yinelenen header'lar almak mümkündür. Yani aynı header'ın birden fazla değeri olabilir.
|
||||
|
||||
Bu tür durumları, type tanımında bir list kullanarak belirtebilirsiniz.
|
||||
|
||||
Yinelenen header'daki tüm değerleri Python `list` olarak alırsınız.
|
||||
|
||||
Örneğin, birden fazla kez gelebilen `X-Token` header'ını tanımlamak için şöyle yazabilirsiniz:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
|
||||
|
||||
Eğer bu *path operation* ile iki HTTP header göndererek iletişim kurarsanız:
|
||||
|
||||
```
|
||||
X-Token: foo
|
||||
X-Token: bar
|
||||
```
|
||||
|
||||
response şöyle olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"X-Token values": [
|
||||
"bar",
|
||||
"foo"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Header'ları `Header` ile tanımlayın; `Query`, `Path` ve `Cookie` ile kullanılan ortak kalıbı burada da kullanın.
|
||||
|
||||
Değişkenlerinizdeki underscore'lar konusunda endişelenmeyin, **FastAPI** bunları dönüştürmeyi halleder.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Eğitim - Kullanıcı Rehberi { #tutorial-user-guide }
|
||||
|
||||
Bu eğitim, **FastAPI**'yi özelliklerinin çoğuyla birlikte adım adım nasıl kullanacağınızı gösterir.
|
||||
|
||||
Her bölüm bir öncekilerin üzerine kademeli olarak eklenir, ancak konular birbirinden ayrılacak şekilde yapılandırılmıştır; böylece API ihtiyaçlarınıza göre doğrudan belirli bir konuya gidip aradığınızı bulabilirsiniz.
|
||||
|
||||
Ayrıca, ileride tekrar dönüp tam olarak ihtiyaç duyduğunuz şeyi görebileceğiniz bir referans olarak da tasarlanmıştır.
|
||||
|
||||
## Kodu Çalıştırın { #run-the-code }
|
||||
|
||||
Tüm code block'lar kopyalanıp doğrudan kullanılabilir (zaten test edilmiş Python dosyalarıdır).
|
||||
|
||||
Örneklerden herhangi birini çalıştırmak için, kodu `main.py` adlı bir dosyaya kopyalayın ve şu komutla `fastapi dev`'i başlatın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Kodu yazmanız ya da kopyalayıp düzenlemeniz ve yerelinizde çalıştırmanız **şiddetle önerilir**.
|
||||
|
||||
Editörünüzde kullanmak FastAPI'nin avantajlarını gerçekten gösterir: ne kadar az kod yazmanız gerektiğini, type check'leri, autocompletion'ı vb. görürsünüz.
|
||||
|
||||
---
|
||||
|
||||
## FastAPI'yi Kurun { #install-fastapi }
|
||||
|
||||
İlk adım FastAPI'yi kurmaktır.
|
||||
|
||||
Bir [sanal ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, etkinleştirin ve ardından **FastAPI'yi kurun**:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Not
|
||||
|
||||
`pip install "fastapi[standard]"` ile kurduğunuzda, bazı varsayılan opsiyonel standard bağımlılıklarla birlikte gelir. Bunlara `fastapi-cloud-cli` da dahildir; bu sayede <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>'a deploy edebilirsiniz.
|
||||
|
||||
Bu opsiyonel bağımlılıkları istemiyorsanız bunun yerine `pip install fastapi` kurabilirsiniz.
|
||||
|
||||
Standard bağımlılıkları kurmak istiyor ama `fastapi-cloud-cli` olmasın diyorsanız, `pip install "fastapi[standard-no-fastapi-cloud-cli]"` ile kurabilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
## İleri Düzey Kullanıcı Rehberi { #advanced-user-guide }
|
||||
|
||||
Bu **Eğitim - Kullanıcı Rehberi**'ni bitirdikten sonra daha sonra okuyabileceğiniz bir **İleri Düzey Kullanıcı Rehberi** de var.
|
||||
|
||||
**İleri Düzey Kullanıcı Rehberi** bunun üzerine inşa eder, aynı kavramları kullanır ve size bazı ek özellikler öğretir.
|
||||
|
||||
Ancak önce **Eğitim - Kullanıcı Rehberi**'ni (şu anda okuduğunuz bölümü) okumalısınız.
|
||||
|
||||
Yalnızca **Eğitim - Kullanıcı Rehberi** ile eksiksiz bir uygulama oluşturabilmeniz hedeflenmiştir; ardından ihtiyaçlarınıza göre, **İleri Düzey Kullanıcı Rehberi**'ndeki ek fikirlerden bazılarını kullanarak farklı şekillerde genişletebilirsiniz.
|
||||
@@ -0,0 +1,120 @@
|
||||
# Metadata ve Doküman URL'leri { #metadata-and-docs-urls }
|
||||
|
||||
**FastAPI** uygulamanızda çeşitli metadata yapılandırmalarını özelleştirebilirsiniz.
|
||||
|
||||
## API için Metadata { #metadata-for-api }
|
||||
|
||||
OpenAPI spesifikasyonunda ve otomatik API doküman arayüzlerinde kullanılan şu alanları ayarlayabilirsiniz:
|
||||
|
||||
| Parametre | Tip | Açıklama |
|
||||
|------------|------|-------------|
|
||||
| `title` | `str` | API'nin başlığı. |
|
||||
| `summary` | `str` | API'nin kısa özeti. <small>OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut.</small> |
|
||||
| `description` | `str` | API'nin kısa açıklaması. Markdown kullanabilir. |
|
||||
| `version` | `string` | API'nin sürümü. Bu, OpenAPI'nin değil, kendi uygulamanızın sürümüdür. Örneğin `2.5.0`. |
|
||||
| `terms_of_service` | `str` | API'nin Kullanım Koşulları (Terms of Service) için bir URL. Verilirse, URL formatında olmalıdır. |
|
||||
| `contact` | `dict` | Yayınlanan API için iletişim bilgileri. Birden fazla alan içerebilir. <details><summary><code>contact</code> alanları</summary><table><thead><tr><th>Parametre</th><th>Tip</th><th>Açıklama</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>İletişim kişisi/kuruluşunu tanımlayan ad.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>İletişim bilgilerine işaret eden URL. URL formatında OLMALIDIR.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>İletişim kişisi/kuruluşunun e-posta adresi. E-posta adresi formatında OLMALIDIR.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | Yayınlanan API için lisans bilgileri. Birden fazla alan içerebilir. <details><summary><code>license_info</code> alanları</summary><table><thead><tr><th>Parametre</th><th>Tip</th><th>Açıklama</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ZORUNLU</strong> (<code>license_info</code> ayarlanmışsa). API için kullanılan lisans adı.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API için bir <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> lisans ifadesi. <code>identifier</code> alanı, <code>url</code> alanıyla karşılıklı olarak dışlayıcıdır (ikisi aynı anda kullanılamaz). <small>OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API için kullanılan lisansa ait URL. URL formatında OLMALIDIR.</td></tr></tbody></table></details> |
|
||||
|
||||
Şu şekilde ayarlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`description` alanına Markdown yazabilirsiniz; çıktı tarafında render edilir.
|
||||
|
||||
///
|
||||
|
||||
Bu yapılandırmayla otomatik API dokümanları şöyle görünür:
|
||||
|
||||
<img src="/img/tutorial/metadata/image01.png">
|
||||
|
||||
## License identifier { #license-identifier }
|
||||
|
||||
OpenAPI 3.1.0 ve FastAPI 0.99.0 sürümünden itibaren, `license_info` içinde `url` yerine bir `identifier` da ayarlayabilirsiniz.
|
||||
|
||||
Örneğin:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
|
||||
|
||||
## Tag'ler için Metadata { #metadata-for-tags }
|
||||
|
||||
`openapi_tags` parametresiyle, path operation'larınızı gruplamak için kullandığınız farklı tag'ler adına ek metadata da ekleyebilirsiniz.
|
||||
|
||||
Bu parametre, her tag için bir sözlük (dictionary) içeren bir liste alır.
|
||||
|
||||
Her sözlük şunları içerebilir:
|
||||
|
||||
* `name` (**zorunlu**): *path operation*'larda ve `APIRouter`'larda `tags` parametresinde kullandığınız tag adıyla aynı olan bir `str`.
|
||||
* `description`: tag için kısa bir açıklama içeren `str`. Markdown içerebilir ve doküman arayüzünde gösterilir.
|
||||
* `externalDocs`: harici dokümanları tanımlayan bir `dict`:
|
||||
* `description`: harici dokümanlar için kısa açıklama içeren `str`.
|
||||
* `url` (**zorunlu**): harici dokümantasyonun URL'sini içeren `str`.
|
||||
|
||||
### Tag'ler için metadata oluşturun { #create-metadata-for-tags }
|
||||
|
||||
`users` ve `items` tag'lerini içeren bir örnekle deneyelim.
|
||||
|
||||
Tag'leriniz için metadata oluşturup `openapi_tags` parametresine geçin:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
|
||||
|
||||
Açıklamaların içinde Markdown kullanabileceğinizi unutmayın; örneğin "login" kalın (**login**) ve "fancy" italik (_fancy_) olarak gösterilecektir.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Kullandığınız tüm tag'ler için metadata eklemek zorunda değilsiniz.
|
||||
|
||||
///
|
||||
|
||||
### Tag'lerinizi kullanın { #use-your-tags }
|
||||
|
||||
*path operation*'larınızı (ve `APIRouter`'ları) farklı tag'lere atamak için `tags` parametresini kullanın:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Tag'ler hakkında daha fazlası için: [Path Operation Configuration](path-operation-configuration.md#tags){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
### Dokümanları kontrol edin { #check-the-docs }
|
||||
|
||||
Artık dokümanlara baktığınızda, eklediğiniz tüm metadata gösterilir:
|
||||
|
||||
<img src="/img/tutorial/metadata/image02.png">
|
||||
|
||||
### Tag sırası { #order-of-tags }
|
||||
|
||||
Her tag metadata sözlüğünün listedeki sırası, doküman arayüzünde gösterilecek sırayı da belirler.
|
||||
|
||||
Örneğin alfabetik sıralamada `users`, `items`'tan sonra gelirdi; ancak listedeki ilk sözlük olarak `users` metadata'sını eklediğimiz için, dokümanlarda önce o görünür.
|
||||
|
||||
## OpenAPI URL'si { #openapi-url }
|
||||
|
||||
Varsayılan olarak OpenAPI şeması `/openapi.json` adresinden sunulur.
|
||||
|
||||
Ancak bunu `openapi_url` parametresiyle yapılandırabilirsiniz.
|
||||
|
||||
Örneğin `/api/v1/openapi.json` adresinden sunulacak şekilde ayarlamak için:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
|
||||
|
||||
OpenAPI şemasını tamamen kapatmak isterseniz `openapi_url=None` ayarlayabilirsiniz; bu, onu kullanan dokümantasyon arayüzlerini de devre dışı bırakır.
|
||||
|
||||
## Doküman URL'leri { #docs-urls }
|
||||
|
||||
Dahil gelen iki dokümantasyon arayüzünü yapılandırabilirsiniz:
|
||||
|
||||
* **Swagger UI**: `/docs` adresinden sunulur.
|
||||
* URL'sini `docs_url` parametresiyle ayarlayabilirsiniz.
|
||||
* `docs_url=None` ayarlayarak devre dışı bırakabilirsiniz.
|
||||
* **ReDoc**: `/redoc` adresinden sunulur.
|
||||
* URL'sini `redoc_url` parametresiyle ayarlayabilirsiniz.
|
||||
* `redoc_url=None` ayarlayarak devre dışı bırakabilirsiniz.
|
||||
|
||||
Örneğin Swagger UI'yi `/documentation` adresinden sunup ReDoc'u kapatmak için:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
|
||||
@@ -0,0 +1,95 @@
|
||||
# Middleware { #middleware }
|
||||
|
||||
**FastAPI** uygulamalarına middleware ekleyebilirsiniz.
|
||||
|
||||
"Middleware", herhangi bir özel *path operation* tarafından işlenmeden önce her **request** ile çalışan bir fonksiyondur. Ayrıca geri döndürmeden önce her **response** ile de çalışır.
|
||||
|
||||
* Uygulamanıza gelen her **request**'i alır.
|
||||
* Ardından o **request** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir.
|
||||
* Sonra **request**'i uygulamanın geri kalanı tarafından işlenmesi için iletir (bir *path operation* tarafından).
|
||||
* Ardından uygulama tarafından üretilen **response**'u alır (bir *path operation* tarafından).
|
||||
* Sonra o **response** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir.
|
||||
* Son olarak **response**'u döndürür.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`yield` ile dependency'leriniz varsa, çıkış (exit) kodu middleware'den *sonra* çalışır.
|
||||
|
||||
Herhangi bir background task varsa ([Background Tasks](background-tasks.md){.internal-link target=_blank} bölümünde ele alınıyor, ileride göreceksiniz), bunlar tüm middleware'ler *tamamlandıktan sonra* çalışır.
|
||||
|
||||
///
|
||||
|
||||
## Middleware Oluşturma { #create-a-middleware }
|
||||
|
||||
Bir middleware oluşturmak için bir fonksiyonun üzerine `@app.middleware("http")` decorator'ünü kullanırsınız.
|
||||
|
||||
Middleware fonksiyonu şunları alır:
|
||||
|
||||
* `request`.
|
||||
* Parametre olarak `request` alacak bir `call_next` fonksiyonu.
|
||||
* Bu fonksiyon `request`'i ilgili *path operation*'a iletir.
|
||||
* Ardından ilgili *path operation* tarafından üretilen `response`'u döndürür.
|
||||
* Sonrasında `response`'u döndürmeden önce ayrıca değiştirebilirsiniz.
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Özel (proprietary) header'lar <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` prefix'i kullanılarak</a> eklenebilir, bunu aklınızda tutun.
|
||||
|
||||
Ancak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS konfigürasyonlarınıza ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) eklemeniz gerekir. Bunun için, <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette'ın CORS dokümanlarında</a> belgelenen `expose_headers` parametresini kullanın.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette.requests import Request` da kullanabilirdiniz.
|
||||
|
||||
**FastAPI** bunu geliştirici olarak size kolaylık olsun diye sunar. Ancak doğrudan Starlette'tan gelir.
|
||||
|
||||
///
|
||||
|
||||
### `response`'tan Önce ve Sonra { #before-and-after-the-response }
|
||||
|
||||
Herhangi bir *path operation* `request`'i almadan önce, `request` ile birlikte çalışacak kod ekleyebilirsiniz.
|
||||
|
||||
Ayrıca `response` üretildikten sonra, geri döndürmeden önce de kod çalıştırabilirsiniz.
|
||||
|
||||
Örneğin, request'i işleyip response üretmenin kaç saniye sürdüğünü içeren `X-Process-Time` adlı özel bir header ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Burada `time.time()` yerine <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> kullanıyoruz, çünkü bu kullanım senaryolarında daha hassas olabilir. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Birden Fazla Middleware Çalıştırma Sırası { #multiple-middleware-execution-order }
|
||||
|
||||
`@app.middleware()` decorator'ü veya `app.add_middleware()` metodu ile birden fazla middleware eklediğinizde, eklenen her yeni middleware uygulamayı sarar ve bir stack oluşturur. En son eklenen middleware en *dıştaki* (outermost), ilk eklenen ise en *içteki* (innermost) olur.
|
||||
|
||||
Request tarafında önce en *dıştaki* middleware çalışır.
|
||||
|
||||
Response tarafında ise en son o çalışır.
|
||||
|
||||
Örneğin:
|
||||
|
||||
```Python
|
||||
app.add_middleware(MiddlewareA)
|
||||
app.add_middleware(MiddlewareB)
|
||||
```
|
||||
|
||||
Bu, aşağıdaki çalıştırma sırasını oluşturur:
|
||||
|
||||
* **Request**: MiddlewareB → MiddlewareA → route
|
||||
|
||||
* **Response**: route → MiddlewareA → MiddlewareB
|
||||
|
||||
Bu stack davranışı, middleware'lerin öngörülebilir ve kontrol edilebilir bir sırayla çalıştırılmasını sağlar.
|
||||
|
||||
## Diğer Middleware'ler { #other-middlewares }
|
||||
|
||||
Diğer middleware'ler hakkında daha fazlasını daha sonra [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank} bölümünde okuyabilirsiniz.
|
||||
|
||||
Bir sonraki bölümde, middleware ile <abbr title="Cross-Origin Resource Sharing - Çapraz Kaynak Paylaşımı">CORS</abbr>'un nasıl ele alınacağını göreceksiniz.
|
||||
@@ -0,0 +1,107 @@
|
||||
# Path Operation Yapılandırması { #path-operation-configuration }
|
||||
|
||||
Onu yapılandırmak için *path operation decorator*’ınıza geçebileceğiniz çeşitli parametreler vardır.
|
||||
|
||||
/// warning | Uyarı
|
||||
|
||||
Bu parametrelerin *path operation function*’ınıza değil, doğrudan *path operation decorator*’ına verildiğine dikkat edin.
|
||||
|
||||
///
|
||||
|
||||
## Response Status Code { #response-status-code }
|
||||
|
||||
*Path operation*’ınızın response’unda kullanılacak (HTTP) `status_code`’u tanımlayabilirsiniz.
|
||||
|
||||
`404` gibi `int` kodu doğrudan verebilirsiniz.
|
||||
|
||||
Ancak her sayısal kodun ne işe yaradığını hatırlamıyorsanız, `status` içindeki kısayol sabitlerini kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
Bu status code response’da kullanılacak ve OpenAPI şemasına eklenecektir.
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`from starlette import status` da kullanabilirsiniz.
|
||||
|
||||
**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için `starlette.status`’u `fastapi.status` olarak da sunar. Ancak kaynağı doğrudan Starlette’tir.
|
||||
|
||||
///
|
||||
|
||||
## Tags { #tags }
|
||||
|
||||
*Path operation*’ınıza tag ekleyebilirsiniz; `tags` parametresine `str` öğelerinden oluşan bir `list` verin (genellikle tek bir `str`):
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
|
||||
|
||||
Bunlar OpenAPI şemasına eklenecek ve otomatik dokümantasyon arayüzleri tarafından kullanılacaktır:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image01.png">
|
||||
|
||||
### Enum ile Tags { #tags-with-enums }
|
||||
|
||||
Büyük bir uygulamanız varsa, zamanla **birden fazla tag** birikebilir ve ilişkili *path operation*’lar için her zaman **aynı tag**’i kullandığınızdan emin olmak isteyebilirsiniz.
|
||||
|
||||
Bu durumlarda tag’leri bir `Enum` içinde tutmak mantıklı olabilir.
|
||||
|
||||
**FastAPI** bunu düz string’lerde olduğu gibi aynı şekilde destekler:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
|
||||
|
||||
## Özet ve açıklama { #summary-and-description }
|
||||
|
||||
Bir `summary` ve `description` ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## Docstring’den Açıklama { #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 <dfn title="dokümantasyon için kullanılan, fonksiyon içinde ilk ifade olarak yer alan (herhangi bir değişkene atanmayan) çok satırlı string">docstring</dfn> 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).
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
|
||||
|
||||
Interactive docs’ta şöyle kullanılacaktır:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image02.png">
|
||||
|
||||
## Response description { #response-description }
|
||||
|
||||
`response_description` parametresi ile response açıklamasını belirtebilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`response_description` özellikle response’u ifade eder; `description` ise genel olarak *path operation*’ı ifade eder.
|
||||
|
||||
///
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
OpenAPI, her *path operation* için bir response description zorunlu kılar.
|
||||
|
||||
Bu yüzden siz sağlamazsanız, **FastAPI** otomatik olarak "Successful response" üretir.
|
||||
|
||||
///
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image03.png">
|
||||
|
||||
## Bir *path operation*’ı Deprecate Etmek { #deprecate-a-path-operation }
|
||||
|
||||
Bir *path operation*’ı kaldırmadan, <dfn title="eskimiş, kullanılması önerilmez">deprecated</dfn> olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
|
||||
|
||||
Interactive docs’ta deprecated olduğu net şekilde işaretlenecektir:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image04.png">
|
||||
|
||||
Deprecated olan ve olmayan *path operation*’ların nasıl göründüğüne bakın:
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image05.png">
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
*Path operation*’larınızı, *path operation decorator*’larına parametre geçirerek kolayca yapılandırabilir ve metadata ekleyebilirsiniz.
|
||||
@@ -0,0 +1,154 @@
|
||||
# Path Parametreleri ve Sayısal Doğrulamalar { #path-parameters-and-numeric-validations }
|
||||
|
||||
`Query` ile query parametreleri için daha fazla doğrulama ve metadata tanımlayabildiğiniz gibi, `Path` ile de path parametreleri için aynı tür doğrulama ve metadata tanımlayabilirsiniz.
|
||||
|
||||
## `Path`'i İçe Aktarın { #import-path }
|
||||
|
||||
Önce `fastapi` içinden `Path`'i ve `Annotated`'ı içe aktarın:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
FastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve bunu önermeye başladı).
|
||||
|
||||
Daha eski bir sürüm kullanıyorsanız, `Annotated` kullanmaya çalıştığınızda hata alırsınız.
|
||||
|
||||
`Annotated` kullanmadan önce mutlaka FastAPI sürümünü en az 0.95.1 olacak şekilde [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## Metadata Tanımlayın { #declare-metadata }
|
||||
|
||||
`Query` için geçerli olan parametrelerin aynısını tanımlayabilirsiniz.
|
||||
|
||||
Örneğin, `item_id` path parametresi için bir `title` metadata değeri tanımlamak isterseniz şunu yazabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bir path parametresi her zaman zorunludur, çünkü path'in bir parçası olmak zorundadır. `None` ile tanımlasanız veya bir varsayılan değer verseniz bile bu hiçbir şeyi değiştirmez; yine her zaman zorunlu olur.
|
||||
|
||||
///
|
||||
|
||||
## Parametreleri İhtiyacınıza Göre Sıralayın { #order-the-parameters-as-you-need }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir.
|
||||
|
||||
///
|
||||
|
||||
Diyelim ki query parametresi `q`'yu zorunlu bir `str` olarak tanımlamak istiyorsunuz.
|
||||
|
||||
Ayrıca bu parametre için başka bir şey tanımlamanız gerekmiyor; dolayısıyla `Query` kullanmanıza da aslında gerek yok.
|
||||
|
||||
Ancak `item_id` path parametresi için yine de `Path` kullanmanız gerekiyor. Ve bir sebepten `Annotated` kullanmak istemiyorsunuz.
|
||||
|
||||
Python, "default" değeri olan bir parametreyi, "default" değeri olmayan bir parametreden önce yazarsanız şikayet eder.
|
||||
|
||||
Ama bunların sırasını değiştirebilir ve default değeri olmayan parametreyi (query parametresi `q`) en başa koyabilirsiniz.
|
||||
|
||||
Bu **FastAPI** için önemli değildir. FastAPI parametreleri isimlerine, tiplerine ve default tanımlarına (`Query`, `Path`, vb.) göre tespit eder; sırayla ilgilenmez.
|
||||
|
||||
Dolayısıyla fonksiyonunuzu şöyle tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Ancak şunu unutmayın: `Annotated` kullanırsanız bu problem olmaz; çünkü `Query()` veya `Path()` için fonksiyon parametresi default değerlerini kullanmıyorsunuz.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
|
||||
|
||||
## Parametreleri İhtiyacınıza Göre Sıralayın: Küçük Hileler { #order-the-parameters-as-you-need-tricks }
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir.
|
||||
|
||||
///
|
||||
|
||||
İşte bazen işe yarayan **küçük bir hile**; ama çok sık ihtiyacınız olmayacak.
|
||||
|
||||
Şunları yapmak istiyorsanız:
|
||||
|
||||
* `q` query parametresini `Query` kullanmadan ve herhangi bir default değer vermeden tanımlamak
|
||||
* `item_id` path parametresini `Path` kullanarak tanımlamak
|
||||
* bunları farklı bir sırada yazmak
|
||||
* `Annotated` kullanmamak
|
||||
|
||||
...Python bunun için küçük, özel bir sözdizimi sunar.
|
||||
|
||||
Fonksiyonun ilk parametresi olarak `*` geçin.
|
||||
|
||||
Python bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keyword argument (anahtar-değer çiftleri) olarak çağrılması gerektiğini bilir; buna <abbr title="Kökeni: K-ey W-ord Arg-uments"><code>kwargs</code></abbr> da denir. Default değerleri olmasa bile.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
|
||||
|
||||
### `Annotated` ile Daha İyi { #better-with-annotated }
|
||||
|
||||
Şunu da unutmayın: `Annotated` kullanırsanız, fonksiyon parametresi default değerlerini kullanmadığınız için bu sorun ortaya çıkmaz ve muhtemelen `*` kullanmanız da gerekmez.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Sayı Doğrulamaları: Büyük Eşit { #number-validations-greater-than-or-equal }
|
||||
|
||||
`Query` ve `Path` (ve ileride göreceğiniz diğerleri) ile sayı kısıtları tanımlayabilirsiniz.
|
||||
|
||||
Burada `ge=1` ile, `item_id` değerinin `1`'den "`g`reater than or `e`qual" olacak şekilde bir tam sayı olması gerekir.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
|
||||
|
||||
## Sayı Doğrulamaları: Büyük ve Küçük Eşit { #number-validations-greater-than-and-less-than-or-equal }
|
||||
|
||||
Aynısı şunlar için de geçerlidir:
|
||||
|
||||
* `gt`: `g`reater `t`han
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
|
||||
|
||||
## Sayı Doğrulamaları: `float` Değerler, Büyük ve Küçük { #number-validations-floats-greater-than-and-less-than }
|
||||
|
||||
Sayı doğrulamaları `float` değerler için de çalışır.
|
||||
|
||||
Burada <abbr title="greater than - büyüktür"><code>gt</code></abbr> tanımlayabilmek (sadece <abbr title="greater than or equal - büyük veya eşittir"><code>ge</code></abbr> değil) önemli hale gelir. Çünkü örneğin bir değerin `0`'dan büyük olmasını isteyebilirsiniz; `1`'den küçük olsa bile.
|
||||
|
||||
Bu durumda `0.5` geçerli bir değer olur. Ancak `0.0` veya `0` geçerli olmaz.
|
||||
|
||||
Aynısı <abbr title="less than - küçüktür"><code>lt</code></abbr> için de geçerlidir.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
`Query`, `Path` (ve henüz görmedikleriniz) ile metadata ve string doğrulamalarını, [Query Parametreleri ve String Doğrulamalar](query-params-str-validations.md){.internal-link target=_blank} bölümündekiyle aynı şekilde tanımlayabilirsiniz.
|
||||
|
||||
Ayrıca sayısal doğrulamalar da tanımlayabilirsiniz:
|
||||
|
||||
* `gt`: `g`reater `t`han
|
||||
* `ge`: `g`reater than or `e`qual
|
||||
* `lt`: `l`ess `t`han
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
`Query`, `Path` ve ileride göreceğiniz diğer class'lar ortak bir `Param` class'ının alt class'larıdır.
|
||||
|
||||
Hepsi, gördüğünüz ek doğrulama ve metadata parametrelerini paylaşır.
|
||||
|
||||
///
|
||||
|
||||
/// note | Teknik Detaylar
|
||||
|
||||
`Query`, `Path` ve diğerlerini `fastapi` içinden import ettiğinizde, bunlar aslında birer fonksiyondur.
|
||||
|
||||
Çağrıldıklarında, aynı isme sahip class'ların instance'larını döndürürler.
|
||||
|
||||
Yani `Query`'yi import edersiniz; bu bir fonksiyondur. Onu çağırdığınızda, yine `Query` adlı bir class'ın instance'ını döndürür.
|
||||
|
||||
Bu fonksiyonlar (class'ları doğrudan kullanmak yerine) editörünüzün type'larıyla ilgili hata işaretlememesi için vardır.
|
||||
|
||||
Bu sayede, bu hataları yok saymak üzere özel ayarlar eklemeden normal editörünüzü ve coding araçlarınızı kullanabilirsiniz.
|
||||
|
||||
///
|
||||
@@ -1,34 +1,34 @@
|
||||
# Yol Parametreleri
|
||||
# Yol Parametreleri { #path-parameters }
|
||||
|
||||
Yol "parametrelerini" veya "değişkenlerini" Python <abbr title="String Biçimleme: Format String">string biçimlemede</abbr> kullanılan sözdizimi ile tanımlayabilirsiniz.
|
||||
Python <abbr title="String Biçimleme: Format String">string biçimlemede</abbr> kullanılan sözdizimiyle path "parametreleri"ni veya "değişkenleri"ni tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
|
||||
{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
|
||||
|
||||
Yol parametresi olan `item_id`'nin değeri, fonksiyonunuza `item_id` argümanı olarak aktarılacaktır.
|
||||
Path parametresi `item_id`'nin değeri, fonksiyonunuza `item_id` argümanı olarak aktarılacaktır.
|
||||
|
||||
Eğer bu örneği çalıştırıp <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> sayfasına giderseniz, şöyle bir çıktı ile karşılaşırsınız:
|
||||
Yani, bu örneği çalıştırıp <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> adresine giderseniz, şöyle bir response görürsünüz:
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
```
|
||||
|
||||
## Tip İçeren Yol Parametreleri
|
||||
## Tip İçeren Yol Parametreleri { #path-parameters-with-types }
|
||||
|
||||
Standart Python tip belirteçlerini kullanarak yol parametresinin tipini fonksiyonun içerisinde tanımlayabilirsiniz.
|
||||
Standart Python tip belirteçlerini kullanarak path parametresinin tipini fonksiyonun içinde tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
|
||||
{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Bu durumda, `item_id` bir `int` olarak tanımlanacaktır.
|
||||
Bu durumda, `item_id` bir `int` olarak tanımlanır.
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Bu sayede, fonksiyon içerisinde hata denetimi, kod tamamlama gibi konularda editör desteğine kavuşacaksınız.
|
||||
Bu sayede, fonksiyon içinde hata denetimi, kod tamamlama vb. konularda editör desteğine kavuşursunuz.
|
||||
|
||||
///
|
||||
|
||||
## Veri <abbr title="Dönüşüm: serialization, parsing ve marshalling olarak da biliniyor">Dönüşümü</abbr>
|
||||
## Veri <dfn title="diğer adlarıyla: serileştirme, ayrıştırma, marshalling">dönüştürme</dfn> { #data-conversion }
|
||||
|
||||
Eğer bu örneği çalıştırıp tarayıcınızda <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a> sayfasını açarsanız, şöyle bir yanıt ile karşılaşırsınız:
|
||||
Bu örneği çalıştırıp tarayıcınızda <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a> adresini açarsanız, şöyle bir response görürsünüz:
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
@@ -36,15 +36,15 @@ Eğer bu örneği çalıştırıp tarayıcınızda <a href="http://127.0.0.1:800
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Dikkatinizi çekerim ki, fonksiyonunuzun aldığı (ve döndürdüğü) değer olan `3` bir string `"3"` değil aksine bir Python `int`'idir.
|
||||
Dikkat edin: fonksiyonunuzun aldığı (ve döndürdüğü) değer olan `3`, string `"3"` değil, bir Python `int`'idir.
|
||||
|
||||
Bu tanımlamayla birlikte, **FastAPI** size otomatik istek <abbr title="HTTP isteği ile birlikte gelen string'i Python verisine dönüştürme">"ayrıştırma"</abbr> özelliği sağlar.
|
||||
Yani, bu tip tanımıyla birlikte **FastAPI** size otomatik request "<dfn title="HTTP request'ten gelen string'i Python verisine dönüştürme">ayrıştırma</dfn>" sağlar.
|
||||
|
||||
///
|
||||
|
||||
## Veri Doğrulama
|
||||
## Veri Doğrulama { #data-validation }
|
||||
|
||||
Eğer tarayıcınızda <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> sayfasını açarsanız, şuna benzer güzel bir HTTP hatası ile karşılaşırsınız:
|
||||
Ancak tarayıcınızda <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> adresine giderseniz, şuna benzer güzel bir HTTP hatası görürsünüz:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -62,141 +62,135 @@ Eğer tarayıcınızda <a href="http://127.0.0.1:8000/items/foo" class="external
|
||||
}
|
||||
```
|
||||
|
||||
Çünkü burada `item_id` yol parametresi `int` tipinde bir değer beklerken `"foo"` yani `string` tipinde bir değer almıştı.
|
||||
çünkü path parametresi `item_id`, `int` olmayan `"foo"` değerine sahipti.
|
||||
|
||||
Aynı hata <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a> sayfasında olduğu gibi `int` yerine `float` bir değer verseydik de ortaya çıkardı.
|
||||
Aynı hata, şu örnekte olduğu gibi `int` yerine `float` verirseniz de ortaya çıkar: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Böylece, aynı Python tip tanımlaması ile birlikte, **FastAPI** veri doğrulama özelliği sağlar.
|
||||
Yani, aynı Python tip tanımıyla birlikte **FastAPI** size veri doğrulama sağlar.
|
||||
|
||||
Dikkatinizi çekerim ki, karşılaştığınız hata, doğrulamanın geçersiz olduğu mutlak noktayı da açık bir şekilde belirtiyor.
|
||||
Dikkat edin: hata ayrıca doğrulamanın geçmediği noktayı da açıkça belirtir.
|
||||
|
||||
Bu özellik, API'ınızla iletişime geçen kodu geliştirirken ve ayıklarken inanılmaz derecede yararlı olacaktır.
|
||||
Bu, API'ınızla etkileşime giren kodu geliştirirken ve debug ederken inanılmaz derecede faydalıdır.
|
||||
|
||||
///
|
||||
|
||||
## Dokümantasyon
|
||||
## Dokümantasyon { #documentation }
|
||||
|
||||
Ayrıca, tarayıcınızı <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresinde açarsanız, aşağıdaki gibi otomatik ve interaktif bir API dökümantasyonu ile karşılaşırsınız:
|
||||
Tarayıcınızı <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresinde açtığınızda, aşağıdaki gibi otomatik ve interaktif bir API dokümantasyonu görürsünüz:
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | Ek bilgi
|
||||
|
||||
Üstelik, sadece aynı Python tip tanımlaması ile, **FastAPI** size otomatik ve interaktif (Swagger UI ile entegre) bir dokümantasyon sağlar.
|
||||
Yine, sadece aynı Python tip tanımıyla **FastAPI** size otomatik ve interaktif dokümantasyon (Swagger UI entegrasyonuyla) sağlar.
|
||||
|
||||
Dikkatinizi çekerim ki, yol parametresi integer olarak tanımlanmıştır.
|
||||
Dikkat edin: path parametresi integer olarak tanımlanmıştır.
|
||||
|
||||
///
|
||||
|
||||
## Standartlara Dayalı Avantajlar, Alternatif Dokümantasyon
|
||||
## Standartlara Dayalı Avantajlar, Alternatif Dokümantasyon { #standards-based-benefits-alternative-documentation }
|
||||
|
||||
Oluşturulan şema <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> standardına uygun olduğu için birçok uyumlu araç mevcuttur.
|
||||
Üretilen şema <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> standardından geldiği için birçok uyumlu araç vardır.
|
||||
|
||||
Bu sayede, **FastAPI**'ın bizzat kendisi <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> sayfasından erişebileceğiniz alternatif (ReDoc kullanan) bir API dokümantasyonu sağlar:
|
||||
Bu nedenle **FastAPI**'ın kendisi, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresinden erişebileceğiniz alternatif bir API dokümantasyonu (ReDoc kullanarak) sağlar:
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
Aynı şekilde, farklı diller için kod türetme araçları da dahil olmak üzere çok sayıda uyumlu araç bulunur.
|
||||
Aynı şekilde, birçok uyumlu araç vardır. Birçok dil için kod üretme araçları da buna dahildir.
|
||||
|
||||
## Pydantic
|
||||
## Pydantic { #pydantic }
|
||||
|
||||
Tüm veri doğrulamaları <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> tarafından arka planda gerçekleştirilir, bu sayede tüm avantajlardan faydalanabilirsiniz. Böylece, emin ellerde olduğunuzu hissedebilirsiniz.
|
||||
Tüm veri doğrulamaları, arka planda <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> tarafından gerçekleştirilir; böylece onun tüm avantajlarından faydalanırsınız. Ve emin ellerde olduğunuzu bilirsiniz.
|
||||
|
||||
Aynı tip tanımlamalarını `str`, `float`, `bool` ve diğer karmaşık veri tipleri ile kullanma imkanınız vardır.
|
||||
Aynı tip tanımlarını `str`, `float`, `bool` ve daha birçok karmaşık veri tipiyle kullanabilirsiniz.
|
||||
|
||||
Bunlardan birkaçı, bu eğitimin ileriki bölümlerinde irdelenmiştir.
|
||||
Bunların birkaçı, eğitimin sonraki bölümlerinde ele alınacaktır.
|
||||
|
||||
## Sıralama Önem Arz Eder
|
||||
## Sıralama Önemlidir { #order-matters }
|
||||
|
||||
*Yol operasyonları* tasarlarken sabit yol barındıran durumlar ile karşılaşabilirsiniz.
|
||||
*Path operation*'lar oluştururken sabit bir path'e sahip olduğunuz durumlarla karşılaşabilirsiniz.
|
||||
|
||||
Farz edelim ki `/users/me` yolu geçerli kullanıcı hakkında bilgi almak için kullanılıyor olsun.
|
||||
Örneğin `/users/me`'nin, geçerli kullanıcı hakkında veri almak için kullanıldığını varsayalım.
|
||||
|
||||
Benzer şekilde `/users/{user_id}` gibi tanımlanmış ve belirli bir kullanıcı hakkında veri almak için kullanıcının ID bilgisini kullanan bir yolunuz da mevcut olabilir.
|
||||
Sonra belirli bir kullanıcı hakkında, kullanıcı ID'si ile veri almak için `/users/{user_id}` şeklinde bir path'iniz de olabilir.
|
||||
|
||||
*Yol operasyonları* sıralı bir şekilde gözden geçirildiğinden dolayı `/users/me` yolunun `/users/{user_id}` yolundan önce tanımlanmış olmasından emin olmanız gerekmektedir:
|
||||
*Path operation*'lar sırayla değerlendirildiği için, `/users/me` için olan path'in `/users/{user_id}` olandan önce tanımlandığından emin olmanız gerekir:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
|
||||
{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
|
||||
|
||||
Aksi halde, `/users/{user_id}` yolu `"me"` değerinin `user_id` parametresi için gönderildiğini "düşünerek" `/users/me` ile de eşleşir.
|
||||
Aksi halde, `/users/{user_id}` için olan path, `"me"` değerini `user_id` parametresi olarak aldığını "düşünerek" `/users/me` için de eşleşir.
|
||||
|
||||
Benzer şekilde, bir yol operasyonunu yeniden tanımlamanız mümkün değildir:
|
||||
Benzer şekilde, bir path operation'ı yeniden tanımlayamazsınız:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
|
||||
{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
|
||||
|
||||
Yol, ilk kısım ile eşleştiğinden dolayı her koşulda ilk yol operasyonu kullanılacaktır.
|
||||
Path önce eşleştiği için her zaman ilk olan kullanılır.
|
||||
|
||||
## Ön Tanımlı Değerler
|
||||
## Ön Tanımlı Değerler { #predefined-values }
|
||||
|
||||
Eğer *yol parametresi* alan bir *yol operasyonunuz* varsa ve alabileceği *yol parametresi* değerlerinin ön tanımlı olmasını istiyorsanız, standart Python <abbr title="Enumeration">`Enum`</abbr> tipini kullanabilirsiniz.
|
||||
Bir *path operation*'ınız *path parameter* alıyorsa ama olası geçerli *path parameter* değerlerinin önceden tanımlı olmasını istiyorsanız, standart bir Python <abbr title="Enumeration">`Enum`</abbr> kullanabilirsiniz.
|
||||
|
||||
### Bir `Enum` Sınıfı Oluşturalım
|
||||
### Bir `Enum` Sınıfı Oluşturalım { #create-an-enum-class }
|
||||
|
||||
`Enum` sınıfını projemize dahil edip `str` ile `Enum` sınıflarını miras alan bir alt sınıf yaratalım.
|
||||
`Enum`'u import edin ve `str` ile `Enum`'dan miras alan bir alt sınıf oluşturun.
|
||||
|
||||
`str` sınıfı miras alındığından dolayı, API dokümanı, değerlerin `string` tipinde olması gerektiğini anlayabilecek ve doğru bir şekilde işlenecektir.
|
||||
`str`'den miras aldığınızda API dokümanları değerlerin `string` tipinde olması gerektiğini anlayabilir ve doğru şekilde render edebilir.
|
||||
|
||||
Sonrasında, sınıf içerisinde, mevcut ve geçerli değerler olacak olan sabit değerli özelliklerini oluşturalım:
|
||||
Sonra, kullanılabilir geçerli değerler olacak sabit değerli class attribute'ları oluşturun:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
3.4 sürümünden beri <a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">enumerationlar (ya da enumlar) Python'da mevcuttur</a>.
|
||||
|
||||
///
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Merak ediyorsanız söyleyeyim, "AlexNet", "ResNet" ve "LeNet" isimleri Makine Öğrenmesi <abbr title="Teknik olarak, Derin Öğrenme model mimarileri">modellerini</abbr> temsil eder.
|
||||
Merak ediyorsanız: "AlexNet", "ResNet" ve "LeNet", Makine Öğrenmesi <dfn title="Teknik olarak, Derin Öğrenme model mimarileri">modelleri</dfn>nin sadece isimleridir.
|
||||
|
||||
///
|
||||
|
||||
### Bir *Yol Parametresi* Tanımlayalım
|
||||
### Bir *Path Parameter* Tanımlayalım { #declare-a-path-parameter }
|
||||
|
||||
Sonrasında, yarattığımız enum sınıfını (`ModelName`) kullanarak tip belirteci aracılığıyla bir *yol parametresi* oluşturalım:
|
||||
Ardından oluşturduğunuz enum sınıfını (`ModelName`) kullanarak tip belirteciyle bir *path parameter* oluşturun:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
|
||||
|
||||
### Dokümana Göz Atalım
|
||||
### Dokümana Göz Atalım { #check-the-docs }
|
||||
|
||||
*Yol parametresi* için mevcut değerler ön tanımlı olduğundan dolayı, interaktif döküman onları güzel bir şekilde gösterebilir:
|
||||
*Path parameter* için kullanılabilir değerler ön tanımlı olduğu için, interaktif dokümanlar bunları güzelce gösterebilir:
|
||||
|
||||
<img src="/img/tutorial/path-params/image03.png">
|
||||
|
||||
### Python *Enumerationları* ile Çalışmak
|
||||
### Python *Enumeration*'ları ile Çalışmak { #working-with-python-enumerations }
|
||||
|
||||
*Yol parametresinin* değeri bir *enumeration üyesi* olacaktır.
|
||||
*Path parameter*'ın değeri bir *enumeration member* olacaktır.
|
||||
|
||||
#### *Enumeration Üyelerini* Karşılaştıralım
|
||||
#### *Enumeration Member*'ları Karşılaştıralım { #compare-enumeration-members }
|
||||
|
||||
Parametreyi, yarattığınız enum olan `ModelName` içerisindeki *enumeration üyesi* ile karşılaştırabilirsiniz:
|
||||
Bunu, oluşturduğunuz enum `ModelName` içindeki *enumeration member* ile karşılaştırabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
|
||||
|
||||
#### *Enumeration Değerini* Edinelim
|
||||
#### *Enumeration Value*'yu Alalım { #get-the-enumeration-value }
|
||||
|
||||
`model_name.value` veya genel olarak `your_enum_member.value` tanımlarını kullanarak (bu durumda bir `str` olan) gerçek değere ulaşabilirsiniz:
|
||||
Gerçek değeri (bu durumda bir `str`) `model_name.value` ile veya genel olarak `your_enum_member.value` ile alabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[20] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
`"lenet"` değerine `ModelName.lenet.value` tanımı ile de ulaşabilirsiniz.
|
||||
`"lenet"` değerine `ModelName.lenet.value` ile de erişebilirsiniz.
|
||||
|
||||
///
|
||||
|
||||
#### *Enumeration Üyelerini* Döndürelim
|
||||
#### *Enumeration Member*'ları Döndürelim { #return-enumeration-members }
|
||||
|
||||
JSON gövdesine (örneğin bir `dict`) gömülü olsalar bile *yol operasyonundaki* *enum üyelerini* döndürebilirsiniz.
|
||||
*Path operation*'ınızdan, bir JSON body'nin içine gömülü olsalar bile (ör. bir `dict`) *enum member*'ları döndürebilirsiniz.
|
||||
|
||||
Bu üyeler istemciye iletilmeden önce kendilerine karşılık gelen değerlerine (bu durumda string) dönüştürüleceklerdir:
|
||||
İstemciye dönmeden önce, karşılık gelen değerlerine (bu durumda string) dönüştürülürler:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
|
||||
|
||||
İstemci tarafında şuna benzer bir JSON yanıtı ile karşılaşırsınız:
|
||||
İstemcinizde şöyle bir JSON response alırsınız:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -205,53 +199,53 @@ Bu üyeler istemciye iletilmeden önce kendilerine karşılık gelen değerlerin
|
||||
}
|
||||
```
|
||||
|
||||
## Yol İçeren Yol Parametreleri
|
||||
## Path İçeren Path Parametreleri { #path-parameters-containing-paths }
|
||||
|
||||
Farz edelim ki elinizde `/files/{file_path}` isminde bir *yol operasyonu* var.
|
||||
Diyelim ki `/files/{file_path}` path'ine sahip bir *path operation*'ınız var.
|
||||
|
||||
Fakat `file_path` değerinin `home/johndoe/myfile.txt` gibi bir *yol* barındırmasını istiyorsunuz.
|
||||
Ama `file_path`'in kendisinin `home/johndoe/myfile.txt` gibi bir *path* içermesi gerekiyor.
|
||||
|
||||
Sonuç olarak, oluşturmak istediğin URL `/files/home/johndoe/myfile.txt` gibi bir şey olacaktır.
|
||||
Böylece, o dosyanın URL'si şu şekilde olur: `/files/home/johndoe/myfile.txt`.
|
||||
|
||||
### OpenAPI Desteği
|
||||
### OpenAPI Desteği { #openapi-support }
|
||||
|
||||
Test etmesi ve tanımlaması zor senaryolara sebebiyet vereceğinden dolayı OpenAPI, *yol* barındıran *yol parametrelerini* tanımlayacak bir çözüm sunmuyor.
|
||||
OpenAPI, içinde bir *path* barındıracak bir *path parameter* tanımlamak için bir yöntem desteklemez; çünkü bu, test etmesi ve tanımlaması zor senaryolara yol açabilir.
|
||||
|
||||
Ancak bunu, Starlette kütüphanesinin dahili araçlarından birini kullanarak **FastAPI**'da gerçekleştirebilirsiniz.
|
||||
Yine de, Starlette'in dahili araçlarından birini kullanarak bunu **FastAPI**'da yapabilirsiniz.
|
||||
|
||||
Parametrenin bir yol içermesi gerektiğini belirten herhangi bir doküman eklemememize rağmen dokümanlar yine de çalışacaktır.
|
||||
Ve dokümanlar, parametrenin bir path içermesi gerektiğini söyleyen herhangi bir dokümantasyon eklemese bile çalışmaya devam eder.
|
||||
|
||||
### Yol Dönüştürücü
|
||||
### Path Dönüştürücü { #path-convertor }
|
||||
|
||||
Direkt olarak Starlette kütüphanesinden gelen bir opsiyon sayesinde aşağıdaki gibi *yol* içeren bir *yol parametresi* bağlantısı tanımlayabilirsiniz:
|
||||
Starlette'ten doğrudan gelen bir seçenekle, *path* içeren bir *path parameter*'ı şu URL ile tanımlayabilirsiniz:
|
||||
|
||||
```
|
||||
/files/{file_path:path}
|
||||
```
|
||||
|
||||
Bu durumda, parametrenin adı `file_path` olacaktır ve son kısım olan `:path` kısmı, parametrenin herhangi bir *yol* ile eşleşmesi gerektiğini belirtecektir.
|
||||
Bu durumda parametrenin adı `file_path`'tir ve son kısım olan `:path`, parametrenin herhangi bir *path* ile eşleşmesi gerektiğini söyler.
|
||||
|
||||
Böylece şunun gibi bir kullanım yapabilirsiniz:
|
||||
Yani şununla kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
|
||||
{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Parametrenin başında `/home/johndoe/myfile.txt` yolunda olduğu gibi (`/`) işareti ile birlikte kullanmanız gerektiği durumlar olabilir.
|
||||
Parametrenin başında `/home/johndoe/myfile.txt` örneğinde olduğu gibi bir eğik çizgi (`/`) ile başlaması gerekebilir.
|
||||
|
||||
Bu durumda, URL, `files` ile `home` arasında iki eğik çizgiye (`//`) sahip olup `/files//home/johndoe/myfile.txt` gibi gözükecektir.
|
||||
Bu durumda URL, `files` ile `home` arasında çift eğik çizgi (`//`) olacak şekilde `/files//home/johndoe/myfile.txt` olur.
|
||||
|
||||
///
|
||||
|
||||
## Özet
|
||||
## Özet { #recap }
|
||||
|
||||
**FastAPI** ile kısa, sezgisel ve standart Python tip tanımlamaları kullanarak şunları elde edersiniz:
|
||||
**FastAPI** ile kısa, sezgisel ve standart Python tip tanımlarını kullanarak şunları elde edersiniz:
|
||||
|
||||
* Editör desteği: hata denetimi, otomatik tamamlama, vb.
|
||||
* Veri "<abbr title="HTTP isteği ile birlikte gelen string'i Python verisine dönüştürme">dönüştürme</abbr>"
|
||||
* Editör desteği: hata denetimleri, otomatik tamamlama vb.
|
||||
* Veri "<dfn title="HTTP request'ten gelen string'i Python verisine dönüştürme">ayrıştırma</dfn>"
|
||||
* Veri doğrulama
|
||||
* API tanımlamaları ve otomatik dokümantasyon
|
||||
* API annotation ve otomatik dokümantasyon
|
||||
|
||||
Ve sadece, bunları bir kez tanımlamanız yeterli.
|
||||
Ve bunları sadece bir kez tanımlamanız yeterlidir.
|
||||
|
||||
Diğer frameworkler ile karşılaştırıldığında (ham performans dışında), üstte anlatılan durum muhtemelen **FastAPI**'ın göze çarpan başlıca avantajıdır.
|
||||
Bu, (ham performans dışında) **FastAPI**'ın alternatif framework'lere kıyasla muhtemelen en görünür ana avantajıdır.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Query Parameter Modelleri { #query-parameter-models }
|
||||
|
||||
Birbirleriyle ilişkili bir **query parameter** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz.
|
||||
|
||||
Böylece **modeli yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation (doğrulama) ile metadata’yı tek seferde tanımlayabilirsiniz. 😎
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Pydantic Model ile Query Parameters { #query-parameters-with-a-pydantic-model }
|
||||
|
||||
İhtiyacınız olan **query parameter**’ları bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Query` olarak belirtin:
|
||||
|
||||
{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
|
||||
|
||||
**FastAPI**, request’teki **query parameter**’lardan **her field** için veriyi **extract** eder ve tanımladığınız Pydantic model’i size verir.
|
||||
|
||||
## Dokümanları Kontrol Edin { #check-the-docs }
|
||||
|
||||
Query parameter’ları `/docs` altındaki dokümantasyon arayüzünde görebilirsiniz:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/query-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
## Ek Query Parameter'ları Yasaklayın { #forbid-extra-query-parameters }
|
||||
|
||||
Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), almak istediğiniz query parameter’ları **kısıtlamak** isteyebilirsiniz.
|
||||
|
||||
Pydantic’in model konfigürasyonunu kullanarak `extra` field’ları `forbid` edebilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
Bir client, **query parameter**’larda **ek (extra)** veri göndermeye çalışırsa, **error** response alır.
|
||||
|
||||
Örneğin client, değeri `plumbus` olan bir `tool` query parameter’ı göndermeye çalışırsa:
|
||||
|
||||
```http
|
||||
https://example.com/items/?limit=10&tool=plumbus
|
||||
```
|
||||
|
||||
`tool` query parameter’ına izin verilmediğini söyleyen bir **error** response alır:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "extra_forbidden",
|
||||
"loc": ["query", "tool"],
|
||||
"msg": "Extra inputs are not permitted",
|
||||
"input": "plumbus"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Özet { #summary }
|
||||
|
||||
**FastAPI** içinde **query parameter**’ları tanımlamak için **Pydantic model**’leri kullanabilirsiniz. 😎
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Spoiler: cookie ve header’ları tanımlamak için de Pydantic model’leri kullanabilirsiniz; ancak bunu tutorial’ın ilerleyen bölümlerinde göreceksiniz. 🤫
|
||||
|
||||
///
|
||||
@@ -0,0 +1,450 @@
|
||||
# Query Parametreleri ve String Doğrulamaları { #query-parameters-and-string-validations }
|
||||
|
||||
**FastAPI**, parametreleriniz için ek bilgi ve doğrulamalar (validation) tanımlamanıza izin verir.
|
||||
|
||||
Örnek olarak şu uygulamayı ele alalım:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||||
|
||||
Query parametresi `q`, `str | None` tipindedir. Yani tipi `str`’dir ama `None` da olabilir. Nitekim varsayılan değer `None` olduğu için FastAPI bunun zorunlu olmadığını anlar.
|
||||
|
||||
/// note | Not
|
||||
|
||||
FastAPI, `q`’nun zorunlu olmadığını `= None` varsayılan değerinden anlar.
|
||||
|
||||
`str | None` kullanmak, editörünüzün daha iyi destek vermesini ve hataları yakalamasını sağlar.
|
||||
|
||||
///
|
||||
|
||||
## Ek Doğrulama { #additional-validation }
|
||||
|
||||
`q` opsiyonel olsa bile, verildiği durumda **uzunluğunun 50 karakteri geçmemesini** zorlayacağız.
|
||||
|
||||
### `Query` ve `Annotated` import edin { #import-query-and-annotated }
|
||||
|
||||
Bunu yapmak için önce şunları import edin:
|
||||
|
||||
* `fastapi` içinden `Query`
|
||||
* `typing` içinden `Annotated`
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
FastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve önermeye başladı).
|
||||
|
||||
Daha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalışırken hata alırsınız.
|
||||
|
||||
`Annotated` kullanmadan önce FastAPI sürümünü en az 0.95.1’e yükseltmek için [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## `q` parametresinin tipinde `Annotated` kullanın { #use-annotated-in-the-type-for-the-q-parameter }
|
||||
|
||||
[Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} içinde `Annotated` ile parametrelerinize metadata ekleyebileceğinizi söylemiştim, hatırlıyor musunuz?
|
||||
|
||||
Şimdi bunu FastAPI ile kullanmanın zamanı. 🚀
|
||||
|
||||
Şu tip anotasyonuna sahiptik:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Şimdi bunu `Annotated` ile saracağız; şöyle olacak:
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None] = None
|
||||
```
|
||||
|
||||
Bu iki sürüm de aynı anlama gelir: `q`, `str` veya `None` olabilen bir parametredir ve varsayılan olarak `None`’dır.
|
||||
|
||||
Şimdi işin eğlenceli kısmına geçelim. 🎉
|
||||
|
||||
## `q` parametresindeki `Annotated` içine `Query` ekleyin { #add-query-to-annotated-in-the-q-parameter }
|
||||
|
||||
Artık ek bilgi (bu durumda ek doğrulama) koyabildiğimiz bir `Annotated`’ımız olduğuna göre, `Annotated` içine `Query` ekleyin ve `max_length` parametresini `50` olarak ayarlayın:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
|
||||
|
||||
Varsayılan değerin hâlâ `None` olduğuna dikkat edin; yani parametre hâlâ opsiyonel.
|
||||
|
||||
Ama şimdi `Annotated` içinde `Query(max_length=50)` kullanarak FastAPI’ye bu değer için **ek doğrulama** istediğimizi söylüyoruz: en fazla 50 karakter. 😎
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Burada `Query()` kullanıyoruz çünkü bu bir **query parametresi**. İleride `Path()`, `Body()`, `Header()` ve `Cookie()` gibi, `Query()` ile aynı argümanları kabul eden diğerlerini de göreceğiz.
|
||||
|
||||
///
|
||||
|
||||
FastAPI artık şunları yapacak:
|
||||
|
||||
* Verinin uzunluğunun en fazla 50 karakter olduğundan emin olacak şekilde **doğrulayacak**
|
||||
* Veri geçerli değilse client için **net bir hata** gösterecek
|
||||
* Parametreyi OpenAPI şemasındaki *path operation* içinde **dokümante edecek** (dolayısıyla **otomatik dokümantasyon arayüzünde** görünecek)
|
||||
|
||||
## Alternatif (eski): Varsayılan değer olarak `Query` { #alternative-old-query-as-the-default-value }
|
||||
|
||||
FastAPI’nin önceki sürümlerinde ( <dfn title="2023-03’ten önce">0.95.0</dfn> öncesi) `Query`’yi `Annotated` içine koymak yerine, parametrenizin varsayılan değeri olarak kullanmanız gerekiyordu. Etrafta bu şekilde yazılmış kod görme ihtimaliniz yüksek; bu yüzden açıklayalım.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Yeni kodlarda ve mümkün olduğunda, yukarıda anlatıldığı gibi `Annotated` kullanın. Birden fazla avantajı vardır (aşağıda anlatılıyor) ve dezavantajı yoktur. 🍰
|
||||
|
||||
///
|
||||
|
||||
Fonksiyon parametresinin varsayılan değeri olarak `Query()` kullanıp `max_length` parametresini 50 yapmak şöyle olurdu:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Bu senaryoda (`Annotated` kullanmadığımız için) fonksiyondaki `None` varsayılan değerini `Query()` ile değiştirmemiz gerekiyor. Bu durumda varsayılan değeri `Query(default=None)` ile vermeliyiz; bu, (en azından FastAPI açısından) aynı varsayılan değeri tanımlama amacına hizmet eder.
|
||||
|
||||
Yani:
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None)
|
||||
```
|
||||
|
||||
...parametreyi `None` varsayılan değeriyle opsiyonel yapar; şununla aynı:
|
||||
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Ancak `Query` sürümü bunun bir query parametresi olduğunu açıkça belirtir.
|
||||
|
||||
Sonrasında `Query`’ye daha fazla parametre geçebiliriz. Bu örnekte string’ler için geçerli olan `max_length`:
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Bu, veriyi doğrular, veri geçerli değilse net bir hata gösterir ve parametreyi OpenAPI şemasındaki *path operation* içinde dokümante eder.
|
||||
|
||||
### Varsayılan değer olarak `Query` veya `Annotated` içinde `Query` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
`Annotated` içinde `Query` kullanırken `Query` için `default` parametresini kullanamayacağınızı unutmayın.
|
||||
|
||||
Bunun yerine fonksiyon parametresinin gerçek varsayılan değerini kullanın. Aksi halde tutarsız olur.
|
||||
|
||||
Örneğin şu kullanım izinli değildir:
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query(default="rick")] = "morty"
|
||||
```
|
||||
|
||||
...çünkü varsayılan değerin `"rick"` mi `"morty"` mi olması gerektiği belli değildir.
|
||||
|
||||
Bu nedenle (tercihen) şöyle kullanırsınız:
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query()] = "rick"
|
||||
```
|
||||
|
||||
...veya eski kod tabanlarında şuna rastlarsınız:
|
||||
|
||||
```Python
|
||||
q: str = Query(default="rick")
|
||||
```
|
||||
|
||||
### `Annotated`’ın avantajları { #advantages-of-annotated }
|
||||
|
||||
Fonksiyon parametrelerindeki varsayılan değer stiline göre **`Annotated` kullanmanız önerilir**; birden fazla nedenle **daha iyidir**. 🤓
|
||||
|
||||
**Fonksiyon parametresinin** **varsayılan** değeri, **gerçek varsayılan** değerdir; bu genel olarak Python açısından daha sezgiseldir. 😌
|
||||
|
||||
Aynı fonksiyonu FastAPI olmadan **başka yerlerde** de **çağırabilirsiniz** ve **beklendiği gibi çalışır**. Eğer **zorunlu** bir parametre varsa (varsayılan değer yoksa) editörünüz hata ile bunu belirtir; ayrıca gerekli parametreyi vermeden çalıştırırsanız **Python** da şikayet eder.
|
||||
|
||||
`Annotated` kullanmayıp bunun yerine **(eski) varsayılan değer stilini** kullanırsanız, o fonksiyonu FastAPI olmadan **başka yerlerde** çağırdığınızda doğru çalışması için argümanları geçmeniz gerektiğini **hatırlamak** zorunda kalırsınız; yoksa değerler beklediğinizden farklı olur (ör. `QueryInfo` veya benzeri). Üstelik editörünüz de şikayet etmez ve Python da fonksiyonu çalıştırırken şikayet etmez; ancak içerideki operasyonlar hata verince ortaya çıkar.
|
||||
|
||||
`Annotated` birden fazla metadata anotasyonu alabildiği için, artık aynı fonksiyonu <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a> gibi başka araçlarla da kullanabilirsiniz. 🚀
|
||||
|
||||
## Daha fazla doğrulama ekleyin { #add-more-validations }
|
||||
|
||||
`min_length` parametresini de ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Regular expression ekleyin { #add-regular-expressions }
|
||||
|
||||
Parametrenin eşleşmesi gereken bir `pattern` <dfn title="String'ler için arama deseni tanımlayan karakter dizisi">düzenli ifade</dfn> tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
Bu özel regular expression pattern’i, gelen parametre değerinin şunları sağladığını kontrol eder:
|
||||
|
||||
* `^`: Aşağıdaki karakterlerle başlar; öncesinde karakter yoktur.
|
||||
* `fixedquery`: Tam olarak `fixedquery` değerine sahiptir.
|
||||
* `$`: Orada biter; `fixedquery` sonrasında başka karakter yoktur.
|
||||
|
||||
Bu **"regular expression"** konuları gözünüzü korkutuyorsa sorun değil. Birçok kişi için zor bir konudur. Regular expression’lara ihtiyaç duymadan da pek çok şey yapabilirsiniz.
|
||||
|
||||
Artık ihtiyaç duyduğunuzda **FastAPI** içinde kullanabileceğinizi biliyorsunuz.
|
||||
|
||||
## Varsayılan değerler { #default-values }
|
||||
|
||||
Elbette `None` dışında varsayılan değerler de kullanabilirsiniz.
|
||||
|
||||
Örneğin `q` query parametresi için `min_length` değerini `3` yapmak ve varsayılan değer olarak `"fixedquery"` vermek istediğinizi düşünelim:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
`None` dahil herhangi bir tipte varsayılan değere sahip olmak, parametreyi opsiyonel (zorunlu değil) yapar.
|
||||
|
||||
///
|
||||
|
||||
## Zorunlu parametreler { #required-parameters }
|
||||
|
||||
Daha fazla doğrulama veya metadata tanımlamamız gerekmiyorsa, `q` query parametresini yalnızca varsayılan değer tanımlamayarak zorunlu yapabiliriz:
|
||||
|
||||
```Python
|
||||
q: str
|
||||
```
|
||||
|
||||
şunun yerine:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Acak biz artık `Query` ile tanımlıyoruz; örneğin şöyle:
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None, Query(min_length=3)] = None
|
||||
```
|
||||
|
||||
Dolayısıyla `Query` kullanırken bir değeri zorunlu yapmak istediğinizde, varsayılan değer tanımlamamanız yeterlidir:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
|
||||
|
||||
### Zorunlu ama `None` olabilir { #required-can-be-none }
|
||||
|
||||
Bir parametrenin `None` kabul edebileceğini söyleyip yine de zorunlu olmasını sağlayabilirsiniz. Bu, client’ların değer göndermesini zorunlu kılar; değer `None` olsa bile.
|
||||
|
||||
Bunu yapmak için `None`’ı geçerli bir tip olarak tanımlayın ama varsayılan değer vermeyin:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||||
|
||||
## Query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values }
|
||||
|
||||
Bir query parametresini `Query` ile açıkça tanımladığınızda, bir değer listesi alacak şekilde (başka bir deyişle, birden fazla değer alacak şekilde) de tanımlayabilirsiniz.
|
||||
|
||||
Örneğin URL’de `q` query parametresinin birden fazla kez görünebilmesini istiyorsanız şöyle yazabilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
Sonra şu URL ile:
|
||||
|
||||
```
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
*path operation function* içinde, *function parameter* olan `q` parametresinde, birden fazla `q` *query parameters* değerini (`foo` ve `bar`) bir Python `list`’i olarak alırsınız.
|
||||
|
||||
Dolayısıyla bu URL’ye response şöyle olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"q": [
|
||||
"foo",
|
||||
"bar"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Yukarıdaki örnekte olduğu gibi tipi `list` olan bir query parametresi tanımlamak için `Query`’yi açıkça kullanmanız gerekir; aksi halde request body olarak yorumlanır.
|
||||
|
||||
///
|
||||
|
||||
Etkileşimli API dokümanları da buna göre güncellenir ve birden fazla değere izin verir:
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||
|
||||
### Varsayılanlarla query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values-with-defaults }
|
||||
|
||||
Hiç değer verilmezse varsayılan bir `list` de tanımlayabilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
|
||||
|
||||
Şu adrese giderseniz:
|
||||
|
||||
```
|
||||
http://localhost:8000/items/
|
||||
```
|
||||
|
||||
`q`’nun varsayılanı `["foo", "bar"]` olur ve response şöyle olur:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"q": [
|
||||
"foo",
|
||||
"bar"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Sadece `list` kullanmak { #using-just-list }
|
||||
|
||||
`list[str]` yerine doğrudan `list` de kullanabilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
|
||||
|
||||
/// note | Not
|
||||
|
||||
Bu durumda FastAPI, listenin içeriğini kontrol etmez.
|
||||
|
||||
Örneğin `list[int]`, listenin içeriğinin integer olduğunu kontrol eder (ve dokümante eder). Ancak tek başına `list` bunu yapmaz.
|
||||
|
||||
///
|
||||
|
||||
## Daha fazla metadata tanımlayın { #declare-more-metadata }
|
||||
|
||||
Parametre hakkında daha fazla bilgi ekleyebilirsiniz.
|
||||
|
||||
Bu bilgiler oluşturulan OpenAPI’a dahil edilir ve dokümantasyon arayüzleri ile harici araçlar tarafından kullanılır.
|
||||
|
||||
/// note | Not
|
||||
|
||||
Farklı araçların OpenAPI desteği farklı seviyelerde olabilir.
|
||||
|
||||
Bazıları tanımladığınız ek bilgilerin hepsini göstermeyebilir; ancak çoğu durumda eksik özellik geliştirme planındadır.
|
||||
|
||||
///
|
||||
|
||||
Bir `title` ekleyebilirsiniz:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
|
||||
|
||||
Ve bir `description`:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||||
|
||||
## Alias parametreleri { #alias-parameters }
|
||||
|
||||
Parametrenin adının `item-query` olmasını istediğinizi düşünün.
|
||||
|
||||
Örneğin:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
```
|
||||
|
||||
Ancak `item-query` geçerli bir Python değişken adı değildir.
|
||||
|
||||
En yakın seçenek `item_query` olur.
|
||||
|
||||
Ama sizin hâlâ tam olarak `item-query` olmasına ihtiyacınız var...
|
||||
|
||||
O zaman bir `alias` tanımlayabilirsiniz; bu alias, parametre değerini bulmak için kullanılacaktır:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
|
||||
|
||||
## Parametreleri deprecated yapmak { #deprecating-parameters }
|
||||
|
||||
Diyelim ki artık bu parametreyi istemiyorsunuz.
|
||||
|
||||
Bazı client’lar hâlâ kullandığı için bir süre tutmanız gerekiyor, ama dokümanların bunu açıkça <dfn title="kullanımdan kalkmış, kullanmamanız önerilir">deprecated</dfn> olarak göstermesini istiyorsunuz.
|
||||
|
||||
O zaman `Query`’ye `deprecated=True` parametresini geçin:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||||
|
||||
Dokümanlarda şöyle görünür:
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||||
|
||||
## Parametreleri OpenAPI’dan hariç tutun { #exclude-parameters-from-openapi }
|
||||
|
||||
Oluşturulan OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) bir query parametresini hariç tutmak için `Query`’nin `include_in_schema` parametresini `False` yapın:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
|
||||
|
||||
## Özel Doğrulama { #custom-validation }
|
||||
|
||||
Yukarıdaki parametrelerle yapılamayan bazı **özel doğrulama** ihtiyaçlarınız olabilir.
|
||||
|
||||
Bu durumlarda, normal doğrulamadan sonra (ör. değerin `str` olduğunun doğrulanmasından sonra) uygulanacak bir **custom validator function** kullanabilirsiniz.
|
||||
|
||||
Bunu, `Annotated` içinde <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic’in `AfterValidator`</a>’ını kullanarak yapabilirsiniz.
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Pydantic’te <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> ve başka validator’lar da vardır. 🤓
|
||||
|
||||
///
|
||||
|
||||
Örneğin bu custom validator, bir item ID’sinin <abbr title="International Standard Book Number - Uluslararası Standart Kitap Numarası">ISBN</abbr> kitap numarası için `isbn-` ile veya <abbr title="Internet Movie Database - İnternet Film Veritabanı: filmler hakkında bilgi içeren bir web sitesi">IMDB</abbr> film URL ID’si için `imdb-` ile başladığını kontrol eder:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info | Bilgi
|
||||
|
||||
Bu özellik Pydantic 2 ve üzeri sürümlerde mevcuttur. 😎
|
||||
|
||||
///
|
||||
|
||||
/// tip | İpucu
|
||||
|
||||
Veritabanı veya başka bir API gibi herhangi bir **harici bileşen** ile iletişim gerektiren bir doğrulama yapmanız gerekiyorsa, bunun yerine **FastAPI Dependencies** kullanmalısınız; onları ileride öğreneceksiniz.
|
||||
|
||||
Bu custom validator’lar, request’te sağlanan **yalnızca** **aynı veri** ile kontrol edilebilen şeyler içindir.
|
||||
|
||||
///
|
||||
|
||||
### O Kodu Anlamak { #understand-that-code }
|
||||
|
||||
Önemli nokta, **`Annotated` içinde bir fonksiyonla birlikte `AfterValidator` kullanmak**. İsterseniz bu kısmı atlayabilirsiniz. 🤸
|
||||
|
||||
---
|
||||
|
||||
Ama bu örnek kodun detaylarını merak ediyorsanız, birkaç ek bilgi:
|
||||
|
||||
#### `value.startswith()` ile String { #string-with-value-startswith }
|
||||
|
||||
Fark ettiniz mi? `value.startswith()` ile bir string, tuple alabilir ve tuple içindeki her değeri kontrol eder:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
|
||||
|
||||
#### Rastgele Bir Item { #a-random-item }
|
||||
|
||||
`data.items()` ile, her dictionary öğesi için key ve value içeren tuple’lardan oluşan bir <dfn title="for döngüsüyle üzerinde gezinebileceğimiz bir şey; list, set vb.">yinelemeli nesne</dfn> elde ederiz.
|
||||
|
||||
Bu yinelemeli nesneyi `list(data.items())` ile düzgün bir `list`’e çeviririz.
|
||||
|
||||
Ardından `random.choice()` ile list’ten **rastgele bir değer** alırız; yani `(id, name)` içeren bir tuple elde ederiz. Şuna benzer: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
Sonra tuple içindeki bu **iki değeri** `id` ve `name` değişkenlerine **atarız**.
|
||||
|
||||
Böylece kullanıcı bir item ID’si vermemiş olsa bile yine de rastgele bir öneri alır.
|
||||
|
||||
...bütün bunları **tek bir basit satırda** yapıyoruz. 🤯 Python’u sevmemek elde mi? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
## Özet { #recap }
|
||||
|
||||
Parametreleriniz için ek doğrulamalar ve metadata tanımlayabilirsiniz.
|
||||
|
||||
Genel doğrulamalar ve metadata:
|
||||
|
||||
* `alias`
|
||||
* `title`
|
||||
* `description`
|
||||
* `deprecated`
|
||||
|
||||
String’lere özel doğrulamalar:
|
||||
|
||||
* `min_length`
|
||||
* `max_length`
|
||||
* `pattern`
|
||||
|
||||
`AfterValidator` ile custom doğrulamalar.
|
||||
|
||||
Bu örneklerde `str` değerleri için doğrulamanın nasıl tanımlanacağını gördünüz.
|
||||
|
||||
Sayılar gibi diğer tipler için doğrulamaları nasıl tanımlayacağınızı öğrenmek için sonraki bölümlere geçin.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user