Compare commits

..

4 Commits

123 changed files with 1332 additions and 16615 deletions

1
.github/labeler.yml vendored
View File

@@ -31,7 +31,6 @@ internal:
- .pre-commit-config.yaml
- pdm_build.py
- requirements*.txt
- uv.lock
- docs/en/data/sponsors.yml
- docs/en/overrides/main.html
- all-globs-to-all-files:

View File

@@ -164,8 +164,6 @@ $ pip install "fastapi[standard]"
Create a file `main.py` with:
```Python
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@@ -177,7 +175,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}
```
@@ -186,9 +184,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
from typing import Union
```Python hl_lines="7 12"
from fastapi import FastAPI
app = FastAPI()
@@ -200,7 +196,7 @@ 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}
```
@@ -291,9 +287,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
```Python hl_lines="2 7-10 23-25"
from fastapi import FastAPI
from pydantic import BaseModel
@@ -303,7 +297,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Union[bool, None] = None
is_offer: bool | None = None
@app.get("/")
@@ -312,7 +306,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}

View File

@@ -145,8 +145,6 @@ There are other formats and tools to define and install package dependencies.
* Create a `main.py` file with:
```Python
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@@ -158,7 +156,7 @@ def read_root():
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
```

View File

@@ -161,8 +161,6 @@ $ pip install "fastapi[standard]"
Create a file `main.py` with:
```Python
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@@ -174,7 +172,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}
```
@@ -183,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
from typing import Union
```Python hl_lines="7 12"
from fastapi import FastAPI
app = FastAPI()
@@ -197,7 +193,7 @@ 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}
```
@@ -288,9 +284,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
```Python hl_lines="2 7-10 23-25"
from fastapi import FastAPI
from pydantic import BaseModel
@@ -300,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("/")
@@ -309,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}

View File

@@ -9,7 +9,6 @@ hide:
### Docs
* 📝 Fix minor typos in release notes. PR [#14780](https://github.com/fastapi/fastapi/pull/14780) by [@whyvineet](https://github.com/whyvineet).
* 🐛 Fix copy button in custom.js. PR [#14722](https://github.com/fastapi/fastapi/pull/14722) by [@fcharrier](https://github.com/fcharrier).
* 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs. PR [#14706](https://github.com/fastapi/fastapi/pull/14706) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs for management tasks. PR [#14705](https://github.com/fastapi/fastapi/pull/14705) by [@tiangolo](https://github.com/tiangolo).
@@ -19,9 +18,6 @@ hide:
### Translations
* 🌐 Update translations for tr (update-outdated). PR [#14745](https://github.com/fastapi/fastapi/pull/14745) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update `llm-prompt.md` for Korean language. PR [#14763](https://github.com/fastapi/fastapi/pull/14763) by [@seuthootDev](https://github.com/seuthootDev).
* 🌐 Update translations for ko (update outdated, found by fixer tool). PR [#14738](https://github.com/fastapi/fastapi/pull/14738) by [@YuriiMotov](https://github.com/YuriiMotov).
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
@@ -40,7 +36,6 @@ hide:
### Internal
* 🔧 Ensure that an edit to `uv.lock` gets the `internal` label. PR [#14759](https://github.com/fastapi/fastapi/pull/14759) by [@svlandeg](https://github.com/svlandeg).
* 🔧 Update sponsors: remove Requestly. PR [#14735](https://github.com/fastapi/fastapi/pull/14735) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsors, LambdaTest changes to TestMu AI. PR [#14734](https://github.com/fastapi/fastapi/pull/14734) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump actions/cache from 4 to 5. PR [#14511](https://github.com/fastapi/fastapi/pull/14511) by [@dependabot[bot]](https://github.com/apps/dependabot).
@@ -285,7 +280,7 @@ hide:
### Refactors
* 🔥 Remove dangling extra conditional no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
* 🔥 Remove dangling extra condiitonal no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
* ♻️ Refactor internals, update `is_coroutine` check to reuse internal supported variants (unwrap, check class). PR [#14434](https://github.com/fastapi/fastapi/pull/14434) by [@tiangolo](https://github.com/tiangolo).
### Translations
@@ -420,7 +415,7 @@ hide:
### Docs
* 📝 Update docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
* 📝 Upate docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
### Internal
@@ -2648,7 +2643,7 @@ Read more in the [advisory: Content-Type Header ReDoS](https://github.com/tiango
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/handling-errors.md`. PR [#1953](https://github.com/tiangolo/fastapi/pull/1953) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/response-status-code.md`. PR [#1942](https://github.com/tiangolo/fastapi/pull/1942) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/extra-models.md`. PR [#1941](https://github.com/tiangolo/fastapi/pull/1941) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese tranlsation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-nested-models.md`. PR [#1930](https://github.com/tiangolo/fastapi/pull/1930) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-fields.md`. PR [#1923](https://github.com/tiangolo/fastapi/pull/1923) by [@SwftAlpc](https://github.com/SwftAlpc).
* 🌐 Add German translation for `docs/de/docs/tutorial/index.md`. PR [#9502](https://github.com/tiangolo/fastapi/pull/9502) by [@fhabers21](https://github.com/fhabers21).
@@ -4024,7 +4019,7 @@ You hopefully updated to a supported version of Python a while ago. If you haven
### Fixes
* 🐛 Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen).
* 🐛 Fix empty response body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
### Docs

View File

@@ -102,15 +102,16 @@ Of course, you can also declare additional query parameters whenever you need, a
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
```Python
q: str | None = None
```
Or in Python 3.9:
```Python
q: Union[str, None] = None
```
Or in Python 3.10 and above:
```Python
q: str | None = None
```
For example:

View File

@@ -1,18 +1,18 @@
# 동시성과 async / await { #concurrency-and-async-await }
# 동시성과 async / await
*경로 처리 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
*경로 작동 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
## 바쁘신가요? { #in-a-hurry }
## 바쁘신 경우
<abbr title="too long; didn't read - 너무 길어서 읽지 않음"><strong>TL;DR:</strong></abbr>
<strong>요약</strong>
다음과 같이 `await`를 사용해 호출하라고 안내하는 제3 라이브러리를 사용하는 경우:
다음과 같이 `await`를 사용해 호출하는 제3 라이브러리를 사용하는 경우:
```Python
results = await some_library()
```
다음처럼 *경로 처리 함수*를 `async def`를 사용해 선언하십시오:
다음처럼 *경로 작동 함수*를 `async def`를 사용해 선언하십시오:
```Python hl_lines="2"
@app.get('/')
@@ -29,7 +29,7 @@ async def read_results():
---
데이터베이스, API, 파일시스템 등과 의사소통하는 제3 라이브러리를 사용하고, 그것이 `await` 사용을 지원하지 않는 경우(현재 대부분의 데이터베이스 라이브러리가 그러합니다), *경로 처리 함수*를 일반적인 `def`를 사용해 선언하십시오:
데이터베이스, API, 파일시스템 등과 의사소통하는 제3 라이브러리를 사용하고, 그것이 `await` 지원하지 않는 경우(현재 거의 모든 데이터베이스 라이브러리가 그러합니다), *경로 작동 함수*를 일반적인 `def`를 사용해 선언하십시오:
```Python hl_lines="2"
@app.get('/')
@@ -40,23 +40,23 @@ def results():
---
만약 여러분의 애플리케이션이 (어째서인지) 다른 어떤 것과도 통신하고 그 응답 기다릴 필요가 없다면, 내부에서 `await`를 사용할 필요가 없더라도 `async def`를 사용하세요.
만약 당신의 응용프로그램이 (어째서인지) 다른 무엇과 의사소통하고 그것이 응답하기를 기다릴 필요가 없다면 `async def`를 사용하십시오.
---
모르겠다면, 일반적인 `def`를 사용하세요.
모르겠다면, 그냥 `def`를 사용하십시오.
---
**참고**: *경로 처리 함수*에서 필요한 만큼 `def`와 `async def`를 혼용할 수 있으며, 각각에 대해 가장 알맞은 옵션을 선택해 정의하면 됩니다. FastAPI가 올바르게 처리합니다.
**참고**: *경로 작동 함수*에서 필요한만큼 `def`와 `async def`를 혼용할 수 있고, 가장 알맞은 을 선택해 정의할 수 있습니다. FastAPI가 자체적으로 알맞은 작업을 수행할 것입니다.
쨌든 위의 어떤 경우에서도 FastAPI는 여전히 비동기적으로 동작하며 매우 빠릅니다.
찌되었든, 상기 어떠한 경우라도, FastAPI는 여전히 비동기적으로 작동하고 매우 빠릅니다.
하지만 위의 단계를 따르면, 몇 가지 성능 최적화를 할 수 있습니다.
그러나 상기 작업을 수행함으로써 어느 정도의 성능 최적화가 가능합니다.
## 기술적 세부사항 { #technical-details }
## 기술적 세부사항
최신 파이썬 버전은 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 **`async` 및 `await`** 문법과 함께 지원합니다.
최신 파이썬 버전은 `async`와 `await` 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다:
@@ -64,283 +64,251 @@ def results():
* **`async`와 `await`**
* **코루틴**
## 비동기 코드 { #asynchronous-code }
## 비동기 코드
비동기 코드 언어 💬 가 코드의 어느 한 부분에서 컴퓨터/프로그램 🤖 에게, 어느 시점에는 어딘가에서 *다른 무언가*가 끝날 때까지 기다려야 한다고 말할 수 있는 방법이 있다는 의미입니다. *다른 무언가*를 "slow-file" 📝 이라고 해보겠습니다.
비동기 코드 언어 💬 가 코드의 어느 한 부분에서, 컴퓨터 / 프로그램🤖에게 *다른 무언가*가 어딘가에서 끝날 때까지 기다려야한다고 말하는 방식입니다. *다른 무언가*가 “느린-파일" 📝 이라고 불린다고 가정해봅시다.
따라서 그 시간 동안 컴퓨터는 "slow-file" 📝 이 끝나는 동안 다른 작업을 하러 갈 수 있습니다.
따라서 “느린-파일” 📝이 끝날때까지 컴퓨터는 다른 작업을 수행할 수 있습니다.
그 다음 컴퓨터/프로그램 🤖 은 다시 기다리는 중이기 때문에 기회가 있을 때마다 돌아오거나, 혹은 그 시점에 해야 할 작업을 모두 끝낼 때마다 돌아옵니다. 그리고 기다리던 작업 중 이미 끝난 것이 있는지 확인하면서, 해야 했던 작업을 수행합니다.
그 다음 컴퓨터 / 프로그램 🤖 은 다시 기다리고 있기 때문에 기회가 있을 때마다 다시 돌아오거나, 혹은 당시에 수행해야하는 작업들이 완료될 때마다 다시 돌아옵니다. 그리고 그것 🤖 은 기다리고 있던 작업 중 어느 것이 이미 완료되었는지, 그것 🤖 이 해야하는 모든 작업을 수행하면서 확인합니다.
다음으로, 완료 번째 작업(우리의 "slow-file" 📝 이라고 해보겠습니다)을 가져와서, 그에 대해 해야 했던 작업을 계속합니다.
다음으로, 그것 🤖 은 완료 첫번째 작업에 착수하고(우리의 "느린-파일" 📝 이라고 가정합시다) 그에 대해 수행해야하는 작업을 계속합니다.
"다른 무언가를 기다리는 것"은 일반적으로 프로세서와 RAM 메모리 속도에 비해 상대적으로 "느린" <abbr title="Input and Output - 입력/출력">I/O</abbr> 작업을 의미합니다. 예를 들 다음을 기다리는 것입니다:
"다른 무언가를 기다리는 것"은 일반적으로 비교적 "느린" (프로세서와 RAM 메모리 속도에 비해) <abbr title="Input and Output">I/O</abbr> 작업을 의미합니다. 예를 들 다음의 것들을 기다리는 것입니다:
* 네트워크를 통해 클라이언트가 데이터를 보내는 것
* 네트워크를 통해 클라이언트가 여러분의 프로그램이 보낸 데이터를 받는 것
* 시스템이 디스크의 파일 내용을 읽어서 프로그램에 전달하는 것
* 프로그램이 시스템에 전달한 내용을 디스크에 쓰는 것
* 네트워크를 통해 클라이언트로부터 전송되는 데이터
* 네트워크를 통해 클라이언트가 수신할, 당신의 프로그램으로부터 전송되는 데이터
* 시스템이 읽고 프로그램에 전달할 디스크 내의 파일 내용
* 당신의 프로그램이 시스템에 전달하는, 디스크에 작성될 내용
* 원격 API 작업
* 데이터베이스 작업이 완료되는 것
* 데이터베이스 쿼리가 결과를 반환하는 것
* 기타 등등
* 완료될 데이터베이스 작업
* 결과를 반환하는 데이터베이스 쿼리
* 기타
행 시간의 대부분이 <abbr title="Input and Output - 입력/출력">I/O</abbr> 작업을 기다리는 데 소되기 때문에, 이를 "I/O bound" 작업이라고 부릅니다.
행 시간의 대부분이 <abbr title="Input and Output">I/O</abbr> 작업을 기다리는데되기 때문에, "I/O에 묶인" 작업이라고 불립니다.
이것은 컴퓨터/프로그램이 느린 작업 "동기화"되어, 아무것도 하지 않은 채 그 작업이 끝나는 정확한 시점만 기다렸다가 결과를 가져와 일을 계속할 필요가 없기 때문에 "비동기"라고 불립니다.
이것은 "비동기"라고 불리는데 컴퓨터 / 프로그램이 작업 결과를 가지고 일을 수행할 수 있도록, 느린 작업 "동기화"되어 아무것도 하지 않으면서 작업이 완료될 정확한 시점만 기다릴 필요가 없기 때문입니다.
대신 "비동기" 시스템에서는, 작업이 끝나면 컴퓨터/프로그램이 하러 갔던 일을 마칠 때까지 잠시(몇 마이크로초) 줄에서 기다렸다가, 다시 돌아와 결과를 받아 이를 사용해 작업을 계속할 수 있습니다.
이 대신에, "비동기" 시스템에서는, 작업은 일단 완료되면, 컴퓨터 / 프로그램이 수행하고 있는 일을 완료하고 이후 다시 돌아와서 그것의 결과를 받아 이를 사용해 작업을 지속할 때까지 잠시 (몇 마이크로초) 대기할 수 있습니다.
"동기"(비동기의 반대)는 보통 "순차"라는 용어로도 불리는데, 컴퓨터/프로그램이 다른 작업으로 전환하기 전에 모든 단계를 순서대로 따르기 때문이며, 그 단계들에 기다림이 포함되어 있더라도 마찬가지입니다.
"동기"("비동기"의 반대)는 컴퓨터 / 프로그램이 상이한 작업들간 전환하기 전에 그것이 대기를 동반하게 될지라도 모든 순서를 따르기 때문에 "순차"라는 용어로도 흔히 불립니다.
### 동시성과 버거 { #concurrency-and-burgers }
### 동시성과 버거
위에서 설명한 **비동기** 코드에 대한 개념은 때때로 **"동시성"**이라고도 불립니다. 이 **"병렬성"**과는 다릅니다.
위에서 설명한 **비동기** 코드에 대한 개념은 종종 **"동시성"**이라고도 불립니다. 이것은 **"병렬성"**과는 다릅니다.
**동시성**과 **병렬성**은 모두 "대략 같은 시간에 일어나는 서로 다른 일들"과 관련이 있습니다.
**동시성**과 **병렬성**은 모두 "동시에 일어나는 서로 다른 일들"과 관련이 있습니다.
하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다.
차이를 기 위해, 다음의 버거 이야기를 상상해보세요:
차이를 확인하기 위해, 다음의 버거에 대한 이야기를 상상해보십시오:
### 동시 버거 { #concurrent-burgers }
### 동시 버거
여러분은 짝사랑 상대와 패스트푸드를 먹으러 갔고, 점원이 여러분 앞 사람들의 주문을 받 동안 줄을 서서 기다니다. 😍
당신은 짝사랑 상대 😍 와 패스트푸드 🍔 를 먹으러 갔습니다. 당신은 점원 💁 이 당신 앞에 있는 사람들의 주문을 받 동안 줄을 서서 기다리고 있습니다.
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
이제 당신의 순서가 되어서, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
이제 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 햄버거 2개를 주문합니다. 🍔🍔
당신이 돈을 냅니다 💸.
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
점원 💁 은 주방 👨‍🍳 에 요리를 하라고 전달하고, 따라서 그들은 당신의 버거 🍔 를 준비해야한다는 사실을 알게됩니다(그들이 지금은 당신 앞 고객들의 주문을 준비하고 있을지라도 말입니다).
점원은 주방의 요리사에게 무언가를 말해, (지금은 앞선 손님들의 주문을 준비하고 있더라도) 여러분의 햄버거를 준비해야 한다는 것을 알게 합니다.
점원 💁 은 당신의 순서가 적힌 번호표를 줍니다.
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
기다리는 동안, 당신은 짝사랑 상대 😍 와 함께 테이블을 고르고, 자리에 앉아 오랫동안 (당신이 주문한 버거는 꽤나 고급스럽기 때문에 준비하는데 시간이 조금 걸립니다 ✨🍔✨) 대화를 나눕니다.
여러분이 돈을 냅니다. 💸
짝사랑 상대 😍 와 테이블에 앉아서 버거 🍔 를 기다리는 동안, 그 사람 😍 이 얼마나 멋지고, 사랑스럽고, 똑똑한지 감탄하며 시간냅니다 ✨😍✨.
점원은 여러분 차례 번호를 니다.
짝사랑 상대 😍 와 기다리면서 얘기하는 동안, 때때로, 당신은 당신의 차례가 되었는지 보기 위해 카운터의 번호를 확인합니다.
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
그러다 어느 순간, 당신의 차례가 됩니다. 카운터에 가서, 버거 🍔 를 받고, 테이블로 다시 돌아옵니다.
기다리는 동안, 여러분은 짝사랑 상대와 함께 자리를 고르고 앉아 오랫동안 대화를 나눕니다(여러분의 햄버거는 매우 고급스럽기 때문에 준비하는 데 시간이 좀 걸립니다).
짝사랑 상대와 테이블에 앉아 햄버거를 기다리는 동안, 그 사람이 얼마나 멋지고 귀엽고 똑똑한지 감탄하며 시간을 보낼 수 있습니다 ✨😍✨.
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
기다리며 대화하는 동안, 때때로 여러분은 카운터에 표시되는 번호를 확인해 여러분 차례인지 봅니다.
그러다 어느 순간 마침내 여러분 차례가 됩니다. 여러분은 카운터에 가서 햄버거를 받고, 테이블로 돌아옵니다.
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
여러분과 짝사랑 상대는 햄버거를 먹으며 좋은 시간을 보냅니다. ✨
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
/// info | 정보
아름다운 일러스트: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
///
당신과 짝사랑 상대 😍 는 버거 🍔 를 먹으며 좋은 시간을 보냅니다 ✨.
---
이 이야기에서 여러분이 컴퓨터/프로그램 🤖 이라고 상상해보세요.
당신이 이 이야기에서 컴퓨터 / 프로그램 🤖 이라고 상상해보십시오.
줄을 서는 동안, 여러분은 그냥 쉬고 😴, 차례를 기다리며, 그다지 "생산적인" 일 하지 않습니다. 하지만 점원은 주문만 받지(음식을 준비하) 때문에 줄이 빠르게 줄어들어 괜찮습니다.
줄을 서서 기다리는 동안, 당신은 아무것도 하지 않고 😴 당신의 차례를 기다리며, 어떠한 "생산적인" 일 하지 않습니다. 하지만 점원 💁 이 (음식을 준비하지는) 주문을 받기만 하기 때문에 줄이 빨리 줄어들어 괜찮습니다.
다음 여러분 차례가 면, 여러분은 실제로 "생산적인" 일을 합니다. 메뉴를 처리하고, 무엇을 먹을지 결정하고, 짝사랑 상대의 선택을 확인하고, 결제하고, 올바른 현금이나 카드를 냈는지 확인하고, 정확히 청구되었는지 확인하고, 주문에 올바른 항목들이 들어갔는지 확인하는 등등을 합니다.
그다음, 당신이 차례가 면, 당신은 실제로 "생산적인" 일 🤓 을 합니다. 당신은 메뉴를 고, 무엇을 먹을지 결정하고, 짝사랑 상대 😍 의 선택을 묻고, 돈을 내고 💸 , 맞는 카드를 냈는지 확인하고, 비용이 제대로 지불되었는지 확인하고, 주문이 제대로 들어갔는지 확인하는 작업 등등을 수행합니다.
하지만 그 다음에는, 아직 햄버거를 받지 못했더라도, 버거가 준비될 때까지 기다려야 🕙 하므로 점원과의 작업은 "일시정지" ⏸ 상태입니다.
하지만 이후에는, 버거 🍔 를 아직 받지 못했음에도, 버거가 준비될 때까지 기다려야 🕙 하기 때문에 점원 💁 과의 작업은 "일시정지" ⏸ 상태입니다.
하지만 번호를 고 카운터에서 벗어나 테이블에 앉으면, 여러분은 짝사랑 상대에게 관심을 전환 🔀 하고, 그에 대한 "작업" ⏯ 🤓 을 할 수 있습니다. 그러면 여러분은 다시 짝사랑 상대에게 작업을 거는 매우 "생산적인" 일을 하게 됩니다 😍.
하지만 번호고 카운터에서 나 테이블에 앉으면, 당신은 짝사랑 상대 😍 와 그 "작업" ⏯ 🤓 에 번갈아가며 🔀 집중합니다. 그러면 당신은 다시 짝사랑 상대 😍 에게 작업을 거는 매우 "생산적인" 일 🤓 을 합니다.
그 다음 점원 💁 이 카운터 화면에 여러분 번호를 띄워 "버거를 만들었어요"라고 말하지만, 표시된 번호가 여러분 차례로 바뀌었다고 해서 즉시 미친 듯이 뛰어가지는 않습니다. 여러분은 여러분 번호를 갖고 있고, 다른 사람들은 그들의 번호를 갖고 있으니, 아무도 여러분 햄버거를 훔쳐갈 수 없다는 을 알기 때문입니다.
점원 💁 이 카운터 화면에 당신의 번호를 표시함으로써 "버거 🍔 가 준비되었습니다"라고 해도, 당신은 즉시 뛰쳐나가지는 않을 것입니다. 당신은 당신의 번호를 갖고있고, 다른 사람들은 그들의 번호를 갖고있기 때문에, 아무도 당신의 버거 🍔 를 훔쳐가지 않는다는 사실을 알기 때문입니다.
그래서 여러분은 짝사랑 상대가 이야기를 끝낼 때까지 기다린 다음(현재 작업 ⏯ / 처리 중인 작업 🤓 을 끝내고), 부드럽게 미소 지으며 햄버거를 가지러 가겠다고 말합니다 ⏸.
그래서 당신은 짝사랑 상대 😍 가 이야기를 끝낼 때까지 기다린 (현재 작업 완료 ⏯ / 진행 중인 작업 처리 🤓 ), 정중하게 미소짓고 버거를 가지러 가겠다고 말합니다 ⏸.
다음 여러분은 카운터 가서 🔀, 이제 끝난 초기 작업 ⏯ 으로 돌아와 햄버거를 받고, 감사 인사를 하고, 테이블로 가져옵니다. 이로써 카운터와 상호작용하는 그 단계/작업이 끝납니다 ⏹. 그리고 이는 새로운 작업인 "햄버거 먹기" 🔀 ⏯ 를 만들지만, 이전 작업인 "햄버거 받기"는 끝났습니다 ⏹.
그다음 당신은 카운터 가서 🔀 , 초기 작업을 이제 완료하고 ⏯ , 버거 🍔 를 받고, 감사하다고 말하고 테이블로 가져옵니다. 이로써 카운터와 상호작용 단계 / 작업이 종료됩니다 ⏹.
### 병렬 햄버거 { #parallel-burgers }
이전 작업인 "버거 받기"가 종료되면 ⏹ "버거 먹기"라는 새로운 작업이 생성됩니다 🔀 ⏯.
이제 이것이 "동시 햄버거"가 아니라 "병렬 버거"라고 상상해봅시다.
### 병렬 버거
여러분은 짝사랑 상대와 함께 병렬 패스트푸드를 먹으러 갑니다.
이제 "동시 버거"가 아닌 "병렬 버거"를 상상해보십시오.
여러분은 여러 명(예: 8명)의 점원이 동시에 요리사이기도 하여 여러분 앞 사람들의 주문을 받는 동안 줄을 서 있습니다.
당신은 짝사랑 상대 😍 와 함께 병렬 패스트푸드 🍔 를 먹으러 갔습니다.
여러분 앞의 모든 사람들은, 8명의 점원 각각이 다음 주문을 받기 전에 바로 햄버거를 준비하러 가기 때문에, 카운터를 떠나지 않고 햄버거가 준비될 때까지 기다립니다.
당신은 여러명(8명이라고 가정합니다)의 점원이 당신 앞 사람들의 주문을 받으며 동시에 요리 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 도 하는 동안 줄을 서서 기다립니다.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
당신 앞 모든 사람들이 버거가 준비될 때까지 카운터에서 떠나지 않고 기다립니다 🕙 . 왜냐하면 8명의 직원들이 다음 주문을 받기 전에 버거를 준비하러 가기 때문입니다.
마침내 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 버거 2개를 주문합니다.
마침내 당신의 차례가 왔고, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
여러분이 돈을 냅니다 💸.
당신이 비용을 지불합니다 💸 .
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
점원이 주방에 갑니다 👨‍🍳 .
점원은 주방으로 갑니다.
당신은 번호표가 없기 때문에 누구도 당신의 버거 🍔 를 대신 가져갈 수 없도록 카운터에 서서 기다립니다 🕙 .
여러분은 번호표가 없으므로, 다른 사람이 여러분보다 먼저 햄버거를 가져가지 못하도록 카운터 앞에 서서 기다립니다 🕙.
당신과 짝사랑 상대 😍 는 다른 사람이 새치기해서 버거를 가져가지 못하게 하느라 바쁘기 때문에 🕙 , 짝사랑 상대에게 주의를 기울일 수 없습니다 😞 .
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
이것은 "동기" 작업이고, 당신은 점원/요리사 👨‍🍳 와 "동기화" 되었습니다. 당신은 기다리고 🕙 , 점원/요리사 👨‍🍳 가 버거 🍔 준비를 완료한 후 당신에게 주거나, 누군가가 그것을 가져가는 그 순간에 그 곳에 있어야합니다.
여러분과 짝사랑 상대는 햄버거가 나오면 다른 사람이 끼어들어 가져가지 못하게 하느라 바쁘기 때문에, 짝사랑 상대에게 집중할 수 없습니다. 😞
카운터 앞에서 오랫동안 기다린 후에 🕙 , 점원/요리사 👨‍🍳 가 당신의 버거 🍔 를 가지고 돌아옵니다.
이것은 "동기" 작업이며, 여러분은 점원/요리사 👨‍🍳 와 "동기화"되어 있습니다. 점원/요리사 👨‍🍳 가 햄버거를 완성해 여러분에게 주는 정확한 순간에 그 자리에 있어야 하므로, 여러분은 기다려야 🕙 하고, 그렇지 않으면 다른 사람이 가져갈 수도 있습니다.
당신은 버거를 받고 짝사랑 상대와 함께 테이블로 돌아옵니다.
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
단지 먹기만 하다가, 다 먹었습니다 🍔 ⏹.
그러다 점원/요리사 👨‍🍳 가 카운터 앞에서 오랫동안 기다린 🕙 끝에 마침내 햄버거를 가지고 돌아옵니다.
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
여러분은 햄버거를 받아 짝사랑 상대와 테이블로 갑니다.
그냥 먹고, 끝입니다. ⏹
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
대부분의 시간을 카운터 앞에서 기다리는 데 🕙 썼기 때문에, 대화하거나 작업을 걸 시간은 많지 않았습니다. 😞
/// info | 정보
아름다운 일러스트: <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
///
카운터 앞에서 기다리면서 🕙 너무 많은 시간을 허비했기 때문에 대화를 하거나 작업을 걸 시간이 거의 없었습니다 😞 .
---
이 병렬 버거 시나리오에서, 여러분은 두 개의 프로세서(여러분과 짝사랑 상대)를 가진 컴퓨터/프로그램 🤖 이며, 둘 다 기다리고 🕙 오랫동안 "카운터에서 기다리기" 🕙 에 주의를 ⏯ 기울입니다.
이 병렬 버거 시나리오에서, 당신은 기다리고 🕙 , 오랜 시간동안 "카운터에서 기다리는" 🕙 데에 주의를 기울이는 ⏯ 두 개의 프로세서(당신과 짝사랑 상대😍)를 가진 컴퓨터 / 프로그램 🤖 입니다.
패스트푸드점에는 8개의 프로세서(점원/요리사)가 있습니다. 동시 버거 가게는 2개(점원 1명, 요리사 1명)만 있었을 것입니다.
패스트푸드점에는 8개의 프로세서(점원/요리사) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 가 있습니다. 동시 버거는 단 두 개(한 명의 직원과 한 명의 요리사) 💁 👨‍🍳 만을 가지고 있었습니다.
하지만 여전히 최종 경험은 그다지 좋지 않습니다. 😞
하지만 여전히, 병렬 버거 예시가 최선은 아닙니다 😞 .
---
것이 햄버거의 병렬 버전에 해당하는 이야기입니다. 🍔
예시는 버거🍔 이야기와 결이 같습니다.
더 "현실적인" 예시로, 은행을 상상해보세요.
더 "현실적인" 예시로, 은행을 상상해보십시오.
최근까지 대부분의 은행에는 여러 은행원 👨‍💼👨‍💼👨‍💼👨‍💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다.
최근까지,다수의 은행에는 다수의 은행원 👨‍💼👨‍💼👨‍💼👨‍💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다.
모든 은행원고객씩 순서대로 모든 일을 처리합니다 👨‍💼⏯.
모든 은행원들은명 한 명의 고객들을 차례로 상대합니다 👨‍💼⏯ .
그리고 여러분은 오랫동안 줄에서 기다려야 🕙 하며, 그렇지 않으면 차례를 잃니다.
그리고 당신은 오랫동안 줄에서 기다려야하고 🕙 , 그렇지 않으면 당신의 차례를 잃게 됩니다.
아마 은행 🏦 업무를 보러 갈 때 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
아마 당신은 은행 🏦 심부름에 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
### 버거 예시의 결론 { #burger-conclusion }
### 버거 예시의 결론
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서 기다림 🕙 이 기 때문에, 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 훨씬 더 합리적입니다.
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서, 오랜 기다림 🕙 이 기 때문에 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 더 합리적입니다.
부분의 웹 애플리케이션이 그렇습니다.
다수의 웹 응용프로그램의 경우가 그러합니다.
매우 많은 사용자들이 있고, 서버는 그들의 좋지 않은 연결을 통해 요청이 전송되기를 기다립니다 🕙.
매우 많은 수의 유저가 있지만, 서버는 그들의 요청을 전송하기 위해 그닥-좋지-않은 연결을 기다려야 합니다 🕙 .
그리고 응답이 돌아오기를 다시 기다니다 🕙.
그리고 응답이 돌아올 때까지 다시 기다려야 합니다 🕙 .
이 "기다림" 🕙 은 마이크로초 단위로 측정되지만, 모두 합치면 결국 꽤 많은 대기 시간이 됩니다.
이 "기다림" 🕙 은 마이크로초 단위지만, 모두 더해지면, 결국에는 매우 긴 대기시간이 됩니다.
그래서 웹 API에는 비동기 ⏸🔀⏯ 코드를 사용하는 것이 매우 합리적입니다.
따라서 웹 API를 위해 비동기 ⏸🔀⏯ 코드를 사용하는 것이 합리적입니다.
이러한 종류의 비동기성은 NodeJS가 인기 있는 이유(비록 NodeJS가 병렬은 아니지만)이자, 프로그래밍 언어로서 Go의 강점입니다.
대부분의 존재하는 유명한 파이썬 프레임워크 (Flask와 Django 등)은 새로운 비동기 기능들이 파이썬에 존재하기 전에 만들어졌습니다. 그래서, 그들의 배포 방식은 병렬 실행과 새로운 기능만큼 강력하지는 않은 예전 버전의 비동기 실행을 지원합니다.
그리고 이것이 **FastAPI**로 얻는 것과 같은 수준의 성능입니다.
비동기 웹 파이썬(ASGI)에 대한 주요 명세가 웹소켓을 지원하기 위해 Django에서 개발 되었음에도 그렇습니다.
또한 병렬성과 비동기성을 동시에 사용할 수 있으므로, 대부분의 테스트된 NodeJS 프레임워크보다 더 높은 성능을 얻고, C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다 <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>.
이러한 종류의 비동기성은 (NodeJS는 병렬적이지 않음에도) NodeJS가 사랑받는 이유이고, 프로그래밍 언어로서의 Go의 강점입니다.
### 동시성이 병렬성보다 더 나은가요? { #is-concurrency-better-than-parallelism }
그리고 **FastAPI**를 사용함으로써 동일한 성능을 낼 수 있습니다.
아니요! 그게 이 이야기의 교훈은 아닙니다.
또한 병렬성과 비동기성을 동시에 사용할 수 있기 때문에, 대부분의 테스트가 완료된 NodeJS 프레임워크보다 더 높은 성능을 얻고 C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다<a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>.
동시성은 병렬성과 다릅니다. 그리고 많은 기다림이 포함되는 **특정한** 시나리오에서는 더 낫습니다. 그 때문에 웹 애플리케이션 개발에서는 일반적으로 병렬성보다 훨씬 더 낫습니다. 하지만 모든 것에 해당하진 않습니다.
### 동시성이 병렬성보다 더 나은가?
래서 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보세요:
렇지 않습니다! 그것이 이야기의 교훈은 아닙니다.
> 여러분은 크고 더러운 집을 청소해야 합니다.
동시성은 병렬성과 다릅니다. 그리고 그것은 많은 대기를 필요로하는 **특정한** 시나리오에서는 더 낫습니다. 이로 인해, 웹 응용프로그램 개발에서 동시성이 병렬성보다 일반적으로 훨씬 낫습니다. 하지만 모든 경우에 그런 것은 아닙니다.
따라서, 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보십시오:
> 당신은 크고, 더러운 집을 청소해야합니다.
*네, 이게 전부입니다*.
---
어디에도 기다림 🕙 없고, 집의 여러 장소에서 해야 할 일이 많을 뿐입니다.
어디에도 기 🕙 없고, 집안 곳곳에서 해야하는 많은 작업들만 있습니다.
버거 예시처럼 거실부터, 그 다음은 부엌처럼 순서를 정할 수도 있지만, 어떤 것도 기다리지 🕙 않고 계속 청소 하기 때문에, 순서는 아무런 영향을 지 않습니다.
버거 예시처럼 처음에는 거실, 그 다음은 부엌과 같은 식으로 순서를 정할 수도 있으나, 무엇도 기다리지 🕙 않고 계속해서 청소 작업만 수행하기 때문에, 순서는 아무런 영향을 미치지 않습니다.
순서가 있든 없든(동시성) 끝내는 데 걸리는 시간은 같고, 같은 양의 을 하게 니다.
순서가 있든 없든 동일한 시간이 소요될 것이고(동시성) 동일한 양의 작업을 하게 될 것입니다.
하지만 이 경우, 전(前) 점원/요리사이현(現) 청소부가 된 8명을 데려올 수 있고, 각자(그리고 여러분)가 집의 구역을 하나씩 맡아 청소한다면, 추가 도움과 함께 모든 일을 **병렬**로 수행하여 훨씬 더 빨리 끝낼 수 있습니다.
하지만 이 경우에서, 8명의 전(前)-점원/요리사이면서-현(現)-청소부 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 를 고용할 수 있고, 그들 각자(그리고 당신)가 집의 한 부분씩 맡아 청소한다면, 당신은 **병렬**작업을 수행할 수 있고, 조금의 도움이 있다면, 훨씬 더 빨리 끝낼 수 있습니다.
이 시나리오에서 (여러분을 포함한) 각 청소부 프로세서가 되어, 맡은 일을 수행합니다.
이 시나리오에서, (당신을 포함한) 각각의 청소부들은 프로세서가 될 것이고, 각자의 역할을 수행합니다.
그리고 실행 시간의 대부분이 기다림이 아니라 실제 작업에 쓰이고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit - 중앙 처리 장치">CPU</abbr>가 수행하므로, 이 문제를 "CPU bound"라고 부릅니다.
실행 시간의 대부분이 대기가 아닌 실제 작업에 소요되고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit">CPU</abbr>에서 이루어지므로, 이러한 문제를 "CPU에 묶였"다고 합니다.
---
CPU bound 작업의 흔한 예시는 복잡한 수학 처리 필요한 것들입니다.
CPU에 묶인 연산에 관한 흔한 예시는 복잡한 수학 처리 필요로 하는 경우입니다.
예를 들어:
* **오디오** 또는 **이미지** 처리
* **컴퓨터 비전**: 이미지는 수백개의 픽셀로 구성되, 각 픽셀은 3개의 값/색을 갖습니다. 보통 그 픽셀들에 대해 동시에 무언가를 계산해야 합니다.
* **머신러닝**: 보통 많은 "matrix"와 "vector" 곱셈이 필요합니다. 숫자가 있는 거대한 스프레드시트를 생각하고, 그 모든 수를 동시에 곱한다고 생각해보세요.
* **딥러닝**: 머신러닝의 하위 분야이므로 동일하게 적용됩니다. 다만 곱해야 할 숫자가 있는 스프레드시트가 하나가 아니라, 아주 큰 집합이며, 많은 경우 모델을 만들고/또는 사용하기 위해 특한 프로세서를 사용합니다.
* **오디오** 또는 **이미지** 처리.
* **컴퓨터 비전**: 하나의 이미지는 수백개의 픽셀로 구성되어있고, 각 픽셀은 3개의 값 / 색을 갖고 있으며, 일반적으로 해당 픽셀들에 대해 동시에 무언가를 계산해야하는 처리.
* **머신러닝**: 일반적으로 많은 "행렬"과 "벡터" 곱셈이 필요합니다. 거대한 스프레드 시트에 수들이 있고 그 수들을 동시에 곱해야 한다고 생각해보십시오.
* **딥러닝**: 머신러닝의 하위영역으로, 동일한 예시가 적용됩니다. 단지 이 경우에는 하나의 스프레드 시트에 곱해야할 수들이 있는 것이 아니라, 거대한 세트의 스프레드 시트들이 있고, 많은 경우에, 이 모델을 만들고 사용하기 위해 특한 프로세서를 사용합니다.
### 동시성 + 병렬성: 웹 + 머신러닝 { #concurrency-parallelism-web-machine-learning }
### 동시성 + 병렬성: 웹 + 머신러닝
**FastAPI**를 사용하면 웹 개발에서 매우 흔한 동시성의 이점을( NodeJS의 주 매력과 같은) 얻을 수 있습니다.
**FastAPI**를 사용하면 웹 개발에서 매우 흔한 동시성의 이점을 (NodeJS의 주 매력만큼) 얻을 수 있습니다.
또한 머신러닝 시스템처럼 **CPU bound** 워크로드에 대해 병렬성과 멀티프로세싱(여러 프로세스를 병렬로 실행)을 활용할 수도 있습니다.
뿐만 아니라 머신러닝 시스템과 같이 **CPU에 묶인** 작업을 위해 병렬성과 멀티프로세싱(다수의 프로세스를 병렬적으로 동작시키는 것)을 이용하는 것도 가능합니다.
이것은 파이썬이 **데이터 사이언스**, 머신러닝, 특히 딥러닝의 주 언어라는 단한 사실 더해, FastAPI를 데이터 사이언스/머신러닝 웹 API 및 애플리케이션(그 외에도 많은 것들)에 매우 잘 맞는 선택으로 만들어 줍니다.
파이썬이 **데이터 사이언스**, 머신러닝 특히 딥러닝의 주 언어라는 단한 사실 더해, 이것은 FastAPI를 데이터 사이언스 / 머신러닝 웹 API와 응용프로그램에 (다른 것들보다) 좋은 선택지가 되게 합니다.
프로덕션에서 이 병렬을 어떻게 달성하는지 보려면 [배포](deployment/index.md){.internal-link target=_blank} 섹션을 참고하세요.
배포시 병렬을 어떻게 가능하게 하는지 알고싶다면, [배포](deployment/index.md){.internal-link target=_blank}문서를 참고하십시오.
## `async`와 `await` { #async-and-await }
## `async`와 `await`
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이 방법은 이를 평범한 "순차" 코드처럼 보이게 하고, 적절한 순간에 여러분을 위해 "기다림"을 수행합니다.
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이는 이것을 평범한 "순차" 코드 보이게 하고, 적절한 순간에 당신을 위해 "대기"합니다.
결과를 기 전에 기다림이 필요한 작업이 있고, 이러한 새로운 파이썬 기능을 지원한다면, 다음과 같이 작성할 수 있습니다:
연산이 결과를 전달하기 전에 대기를 해야하고 새로운 파이썬 기능을 지원한다면, 이렇게 코드를 작성할 수 있습니다:
```Python
burgers = await get_burgers(2)
```
여기서 핵심은 `await`입니다. 이 파이썬에게 `get_burgers(2)`가 그 일을 끝낼 때까지 🕙 기다리도록 ⏸ 말하고, 그 결과를 `burgers`에 저장하기 전에 완료되기를 기다리라고 합니다. 이를 통해 파이썬은 그동안(예: 다른 요청을 받는 것처럼) 다른 일을 하러 갈 수 있다는 것 🔀 ⏯ 을 알게 됩니다.
여기서 핵심은 `await`입니다. 이것은 파이썬에게 `burgers` 결과를 저장하기 이전에 `get_burgers(2)`의 작업이 완료되기를 🕙 기다리라고 ⏸ 말합니다. 이로 인해, 파이썬은 그동안 (다른 요청을 받는 것과 같은) 다른 작업을 수행해도 된다는 것 🔀 ⏯ 알게될 것입니다.
`await`가 동작하려면, 이 비동기성을 지원하는 함수 내부에 있어야 합니다. 그러려면 `async def`로 선언하기만 하면 됩니다:
`await`가 동작하기 위해, 이것은 비동기 지원하는 함수 내부에 있어야 합니다. 이를 위해서 함수를 `async def`를 사용해 정의하기만 하면 됩니다:
```Python hl_lines="1"
async def get_burgers(number: int):
# 햄버거를 만들기 위한 비동기 처리를 수행
# Do some asynchronous stuff to create the burgers
return burgers
```
...`def` 대신:
...`def`를 사용하는 대신:
```Python hl_lines="2"
# 비동기가 아닙니다
# This is not asynchronous
def get_sequential_burgers(number: int):
# 햄버거를 만들기 위한 순차 처리를 수행
# Do some sequential stuff to create the burgers
return burgers
```
`async def`를 사용하면, 파이썬은 함수 내에서 `await` 표현에 주의해야 하며, 그 함수의 실행을 "일시정지"하고 다시 돌아오기 전 다른 일을 하러 갈 수 있다는 것 🔀 을 알게 됩니다.
`async def`를 사용하면, 파이썬은 해당 함수 내에서 `await` 표현에 주의해야한다는 사실과, 해당 함수의 실행을 "일시정지"하고 다시 돌아오기 전까지 다른 작업을 수행🔀할 수 있다는 것을 알게됩니다.
`async def` 함수를 호출하고자 할 때, 그 함수를 "await" 해야 합니다. 따라서 아래는 동작하지 않습니다:
`async def`f 함수를 호출하고자 할 때, "대기"해야합니다. 따라서, 아래는 동작하지 않습니다.
```Python
# 동작하지 않습니다. get_burgers는 async def로 정의되었습니다
# This won't work, because get_burgers was defined with: async def
burgers = get_burgers(2)
```
---
따라서, `await` 호출할 수 있다고 말하는 라이브러리를 사용한다면, 다음과 같이 그것을 사용하는 *경로 처리 함수*를 `async def`로 만들어야 합니다:
따라서, `await`f를 사용해서 호출할 수 있는 라이브러리를 사용한다면, 다음과 같이 `async def`를 사용하는 *경로 작동 함수*를 생성해야 합니다:
```Python hl_lines="2-3"
@app.get('/burgers')
@@ -349,96 +317,94 @@ async def read_burgers():
return burgers
```
### 더 세부적인 기술적 사항 { #more-technical-details }
### 더 세부적인 기술적 사항
`await` `async def`로 정의된 함수 내부에서만 사용할 수 있다는 것을 눈치채셨을 것입니다.
`await` `async def`를 사용하는 함수 내부에서만 사용이 가능하다는 것을 눈치채셨을 것입니다.
하지만 동시에, `async def`로 정의된 함수는 "await" 되어야 합니다. 따라서 `async def`를 가진 함수는 `async def`로 정의된 함수 내부에서만 호출될 수 있습니다.
하지만 동시에, `async def`로 정의된 함수들은 "대기"되어야 합니다. 따라서, `async def`를 사용한 함수들은 역시 `async def`를 사용한 함수 내부에서만 호출될 수 있습니다.
그렇다면, 닭이 먼저냐 달걀이 먼저냐처럼, 첫 번째 `async` 함수 어떻게 호출할 수 있을까요?
그렇다면 닭이 먼저냐, 달걀이 먼저냐, 첫 `async` 함수 어떻게 호출할 수 있겠습니까?
**FastAPI** 작업한다면 걱정할 필요가 없습니다. 그 "첫" 함수는 여러분의 *경로 처리 함수*가 될 것이고, FastAPI는 올바르게 처리하는 방법을 알고 있기 때문입니다.
**FastAPI**를 사용해 작업한다면 이것을 걱정하지 않아도 됩니다. 왜냐하면 그 "첫" 함수는 당신의 *경로 작동 함수*가 될 것이고, FastAPI는 어떻게 올바르게 처리할지 알고있기 때문입니다.
하지만 FastAPI 없이 `async` / `await`를 사용하고 싶다면, 그것도 가능합니다.
하지만 FastAPI를 사용하지 않고 `async` / `await`를 사용하고 싶다면, 이 역시 가능합니다.
### 여러분만의 async 코드 작성하기 { #write-your-own-async-code }
### 당신만의 비동기 코드 작성하기
Starlette(그리고 **FastAPI**)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고 있으며, 파이썬 표준 라이브러리 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> 모두와 호환됩니다.
Starlette(그리고 FastAPI)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고있고, 따라서 파이썬 표준 라이브러리 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>와 호환됩니다.
특히, 코드에서 고급 패턴이 필요한 고급 동시성 사용 사례에서는 직접 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다.
특히, 코드에서 고급 패턴이 필요한 고급 동시성 사용하는 경우 직접적으로 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다.
그리고 FastAPI를 사용하지 않더라도, 높은 호환성을 확보하고 그 이점(예: *structured concurrency*)을 기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>로 여러분만의 async 애플리케이션을 작성할 수 있습니다.
FastAPI를 사용하지 않더라도, 높은 호환성 및 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>의 이점(예: *구조화된 동시성*)을 취하기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용해 비동기 응용프로그램을 작성할 수 있습니다.
저는 AnyIO 위에 얇은 레이어로 또 다른 라이브러리를 만들었는데, 타입 어노테이션을 조금 개선하고 더 나은 **자동완성**, **인라인 오류** 등을 얻기 위한 것입니다. 또한 **이해**하고 **여러분만의 async 코드**를 작성하도록 돕는 친절한 소개와 튜토리얼도 제공합니다: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. 특히 **async 코드와 일반**(blocking/동기) 코드를 **결합**해야 한다면 아주 유용합니다.
### 비동기 코드의 다른 형태
### 비동기 코드의 다른 형태 { #other-forms-of-asynchronous-code }
파이썬에서 `async`와 `await`를 사용하게 된 것은 비교적 최근의 일입니다.
`async`와 `await`를 사용하는 이 스타일은 언어에서 비교적 최근에 추가되었습니다.
하지만 이로 인해 비동기 코드 작업이 훨씬 간단해졌습니다.
하지만 비동기 코드를 다루는 일을 훨씬 더 쉽게 만들어 줍니다.
같은 (또는 거의 유사한) 문법은 최신 버전의 자바스크립트(브라우저와 NodeJS)에도 추가되었습니다.
거의 동일한 문법이 최근 브라우저와 NodeJS의 최신 JavaScript에도 포함되었습니다.
하지만 그 이전에, 비동기 코드를 처리하는 것은 꽤 복잡하고 어려운 일이었습니다.
하지만 그 이전에는 비동기 코드를 처리하는 것이 훨씬 더 복잡하고 어려웠습니다.
파이썬의 예전 버전이라면, 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는게 훨씬 복잡합니다.
전 버전의 파이썬에서는 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있었을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는 것이 훨씬 더 복잡합니다.
전 버전의 NodeJS / 브라우저 자바스크립트라면, "콜백 함수"를 사용했을 것입니다. 그리고 이로 인해 "콜백 지옥"에 빠지게 될 수 있습니다.
이전 버전의 NodeJS/브라우저 JavaScript에서는 "callback"을 사용했을 것입니다. 이는 "callback hell"로 이어집니다.
## 코루틴
## 코루틴 { #coroutines }
**코루틴**은 `async def` 함수가 반환하는 것을 칭하는 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 시작되고 어느 시점에서 완료되지만 내부에 `await`가 있을 때마다 내부적으로 일시정지⏸될 수도 있는 함수와 유사한 것이라는 사실을 알고있습니다.
**코루틴**은 `async def` 함수가 반환하는 것에 대한 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 함수와 비슷한 무언가로서 시작할 수 있고, 어느 시점에 끝나지만, 내부에 `await`가 있을 때마다 내부적으로도 일시정지 ⏸ 될 수 있다는 것을 알고 있습니다.
그러나 `async` 및 `await`께 비동기 코드를 사용하는 이 모든 기능들은 "코루틴"으로 간단히 요약됩니다. 이것은 Go의 주된 핵심 기능인 "고루틴"에 견줄 수 있습니다.
하지만 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능은 종종 "코루틴"을 사용한다고 요약됩니다. 이는 Go의 주요 핵심 기능인 "Goroutines"에 비견됩니다.
## 결론
## 결론 { #conclusion }
상기 문장을 다시 한 번 봅시다:
위의 같은 문장을 다시 봅시다:
> 최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
> 최신 파이썬 버전은 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 **`async` 및 `await`** 문법과 함께 지원합니다.
이제 이 말을 조금 더 이해할 수 있을 것입니다.
제 더 이해가 될 것입니다.
것이 (Starlette을 통해) FastAPI를 강하게 하면서 그것이 인상적인 성능을 낼 수 있게 합니다.
이 모든 것이 FastAPI(Starlette을 통해)를 구동하고, 인상적인 성능을 내게 하는 원동력입니다.
## 매우 세부적인 기술적 사항 { #very-technical-details }
## 매우 세부적인 기술적 사항
/// warning | 경고
이 부분은 아마 건너뛰어도 됩니다.
이 부분은 넘어가도 됩니다.
이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다.
(코루틴, 스레드, 블킹 등) 같은 기술 지식이 꽤 있고 FastAPI가 `async def`와 일반 `def`를 어떻게 처리하는지 궁금하다면, 계속 읽어보세요.
만약 기술적 지식(코루틴, 스레드, 블킹 등) 있고 FastAPI가 어떻게 `async def` vs `def`를 다루는지 궁금하다면, 계속하십시오.
///
### 경로 처리 함수 { #path-operation-functions }
### 경로 작동 함수
*경로 처리 함수*를 `async def` 대신 일반적인 `def`로 선언하, (서버를 블로킹할 수 있으므로 직접 호출하는 대신) 외부 스레드풀에서 실행되고 그 결과를 await 합니다.
경로 작동 함수를 `async def` 대신 일반적인 `def`로 선언하는 경우, (서버를 차단하는 것처럼) 그것을 직접 호출하는 대신 대기중인 외부 스레드풀에서 실행니다.
위에서 설명한 방식으로 동작하지 않는 다른 async 프레임워크를 사용해본 적이 있고, 아주 작은 성능 향상(약 100 나노초)을 위해 계산만 하는 사소한 *경로 처리 함수*를 일반 `def`로 정의하곤 했다면, **FastAPI**에서는 그 효과가 정반대가 될 수 있다의하세요. 이 경우에 *경로 처리 함수*에서 블로킹 <abbr title="Input/Output - 입력/출력: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr> 를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
만약 상기에 묘사된대로 동작하지 않는 비동기 프로그램을 사용해왔고 약간의 성능 향상 (약 100 나노초)을 위해 `def`를 사용해서 계산만을 위한 사소한 *경로 작동 함수*를 정의해왔다면, **FastAPI**는 이와는 반대라의하십시오. 이러한 경우에, *경로 작동 함수* 블로킹 <abbr title="Input/Output: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr>를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
그럼에도 두 경우 모두, **FastAPI**는 이전에 사용하던 프레임워크보다 [여전히 더 빠를](index.md#performance){.internal-link target=_blank} 가능성이 높습니다(또는 최소한 비슷합니다).
하지만 두 경우 모두, FastAPI가 당신이 전에 사용하던 프레임워크보다 [더 빠를](index.md#_11){.internal-link target=_blank} (최소한 비견될) 확률이 높습니다.
### 의존성 { #dependencies }
### 의존성
[의존성](tutorial/dependencies/index.md){.internal-link target=_blank}에도 동일하게 적용됩니다. 의존성이 `async def` 대신 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
의존성에도 동일하게 적용됩니다. 의존성이 `async def`가 아닌 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
### 하위 의존성 { #sub-dependencies }
### 하위-의존성
서로를 필요로 하는 여러 의존성과 [하위 의존성](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}을 함수 정의의 매개변수로 가질 수 있으며, 그중 일부는 `async def`로, 다른 일부는 일반 `def`로 생성되었을 수 있습니다. 그래도 정상 동작하, 일반 `def`로 생성된 것들은 "await"되는 대신 (스레드풀에서) 외부 스레드에서 호출됩니다.
함수 정의시 매개변수로 서로를 필요로하는 다수의 의존성과 하위-의존성 가질 수 있, 그 중 일부는 `async def`로, 다른 일부는 일반적인 `def`로 생성되었을 수 있습니다. 이것은 여전히 잘 동작하, 일반적인 `def`로 생성된 것들은 "대기"되는 대신 (스레드풀로부터) 외부 스레드에서 호출됩니다.
### 다른 유틸리티 함수 { #other-utility-functions }
### 다른 유틸리티 함수
직접 호출는 다른 모든 유틸리티 함수는 일반 `def`나 `async def`로 생성될 수 있으며, FastAPI는 호출 방식에 영향을 지 않습니다.
직접 호출는 다른 모든 유틸리티 함수는 일반적인 `def`나 `async def`로 생성될 수 있 FastAPI는 이를 호출하는 방식에 영향을 미치지 않습니다.
FastAPI가 여러분을 위해 호출하는 함수(즉, *경로 처리 함수*와 의존성)와 대비됩니다.
것은 FastAPI가 당신을 위해 호출하는 함수와는 반대입니다: *경로 작동 함수*와 의존성
유틸리티 함수가 `def`로 만든 일반 함수라면, 스레드풀 아니라 직접(코드에 작성한 대로) 호출됩니다. 그리고 `async def`로 생성된 함수라면, 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
만약 당신의 유틸리티 함수가 `def`를 사용한 일반적인 함수라면, 스레드풀에서가 아니라 직접 호출(당신이 코드에 작성한 대로)될 것이고, `async def`로 생성된 함수라면 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
---
다시 말하지만, 이것아마도 이를 찾고 있었던 경우에 유용 매우 세부적인 기술사항입니다.
다시 말하지만, 이것은 당신이 이것에 대해 찾고있던 경우에 한해 유용 매우 세부적인 기술사항입니다.
그렇지 않다면, 위 섹션의 가이드라인이면 충분합니다: <a href="#in-a-hurry">바쁘신가요?</a>.
그렇지 않은 경우, 상기의 가이드라인만으로도 충분할 것입니다: [바쁘신 경우](#_1).

View File

@@ -1,75 +1,83 @@
# FastAPI CLI { #fastapi-cli }
# FastAPI CLI
**FastAPI CLI**는 FastAPI 애플리케이션을 서빙하고, FastAPI 프로젝트를 관리하는 등 다양한 작업에 사용할 수 있는 커맨드 라인 프로그램입니다.
**FastAPI CLI**는 FastAPI 애플리케이션을 실행하고, 프로젝트를 관리하는 등 다양한 작업을 수행할 수 있는 커맨드 라인 프로그램입니다.
FastAPI를 설치할 때(예: `pip install "fastapi[standard]"`), `fastapi-cli`라는 패키지가 포함되며, 이 패키지는 터미널에서 `fastapi` 명령어를 제공합니다.
FastAPI를 설치할 때 (예: `pip install "fastapi[standard]"` 명령어를 사용할 경우), `fastapi-cli`라는 패키지가 포함됩니다. 이 패키지는 터미널에서 사용할 수 있는 `fastapi` 명령어를 제공합니다.
개발용으로 FastAPI 애플리케이션을 실행하려면 `fastapi dev` 명령어를 사용할 수 있습니다:
개발용으로 FastAPI 애플리케이션을 실행하려면 다음과 같이 `fastapi dev` 명령어를 사용할 수 있습니다:
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
│ │
│ 🐍 main.py │
│ │
╰──────────────────────╯
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>
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
<font color="#3465A4">INFO </font> Found importable FastAPI app
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
│ │
│ <span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span> │
│ │
╰──────────────────────────╯
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
following code:
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
<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:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ </font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"> │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
<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">&apos;/home/user/code/awesomeapp&apos;</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.
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: [&apos;/home/user/code/awesomeapp&apos;]
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
<font color="#4E9A06">INFO</font>: Waiting for application startup.
<font color="#4E9A06">INFO</font>: Application startup complete.
```
</div>
`fastapi`라고 불리는 커맨드 라인 프로그램은 **FastAPI CLI**입니다.
`fastapi`라고 불리는 명령어 프로그램은 **FastAPI CLI**입니다.
FastAPI CLI는 Python 프로그램의 경로(예: `main.py`)를 받아 `FastAPI` 인스턴스(일반적으로 `app`으로 이름을 붙임)를 자동으로 감지하고, 올바른 임포트 과정을 결정한 다음 서빙합니다.
FastAPI CLI는 Python 프로그램의 경로(예: `main.py`)를 인수로 받아, `FastAPI` 인스턴스(일반적으로 `app`으로 명명)를 자동으로 감지하고 올바른 임포트 과정을 결정한 후 이를 실행합니다.
프로덕션에서는 대신 `fastapi run` 사용합니다. 🚀
프로덕션 환경에서는 `fastapi run` 명령어를 사용합니다. 🚀
내부적으로 **FastAPI CLI**는 고성능의, 프로덕션에 적합한 ASGI 서버인 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>을 사용합니다. 😎
내부적으로, **FastAPI CLI**는 고성능의, 프로덕션에 적합한, ASGI 서버인 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>을 사용합니다. 😎
## `fastapi dev` { #fastapi-dev }
## `fastapi dev`
`fastapi dev` 실행하면 개발 모드가 시작됩니다.
`fastapi dev` 명령을 실행하면 개발 모드가 시작됩니다.
기본적으로 **auto-reload**가 활성화되어 코드에 변경이 생기면 서버를 자동으로 다시 로드합니다. 이는 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 개발 환경에서만 사용해야 합니다. 또한 컴퓨터가 자신과만 통신하기 위한(`localhost`) IP`127.0.0.1`에서 연결을 대기합니다.
기본적으로 **자동 재시작(auto-reload)** 기능이 활성화되어, 코드에 변경이 생기면 서버를 자동으로 다시 시작합니다. 하지만 이 기능은 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 따라서 개발 환경에서만 사용하는 것이 좋습니다. 또한, 서버는 컴퓨터가 자체적으로 통신할 수 있는 IP 주소(`localhost`)인 `127.0.0.1`에서 연결을 대기합니다.
## `fastapi run` { #fastapi-run }
## `fastapi run`
`fastapi run`을 실행하면 기본적으로 프로덕션 모드로 FastAPI가 시작됩니다.
`fastapi run` 명령을 실행하면 기본적으로 프로덕션 모드로 FastAPI가 시작됩니다.
기본적으로 **auto-reload**는 비활성화되어 있습니다. 또한 사용 가능한 모든 IP 주소를 의미하는 `0.0.0.0`에서 연결을 대기하므로, 해당 컴퓨터와 통신할 수 있는 누구에게나 공개적으로 접근 가능해집니다. 보통 프로덕션에서는 이렇게 실행하며, 예를 들어 컨테이너에서 이런 방식으로 실행합니다.
기본적으로 **자동 재시작(auto-reload)** 기능이 비활성화되어 있습니다. 또한, 사용 가능한 모든 IP 주소 `0.0.0.0`에서 연결을 대기하므로 해당 컴퓨터와 통신할 수 있는 모든 사람이 공개적으로 액세스할 수 있습니다. 이는 일반적으로 컨테이너와 같은 프로덕션 환경에서 실행하는 방법입니다.
대부분의 경우 위에 "termination proxy"를 두고 HTTPS를 처리하게(그리고 처리해야) 됩니다. 이는 애플리케이션을 배포하는 방식에 따라 달라지며, 제공자가 이 작업을 대신 처리해줄 수도 있고 직접 설정해야 할 수도 있습니다.
애플리케이션을 배포하는 방식에 따라 다르지만, 대부분 "종료 프록시(termination proxy)"를 활용해 HTTPS를 처리하는 것이 좋습니다. 배포 서비스 제공자가 이 작업을 대신 처리해줄 수도 있고, 직접 설정해야 할 수도 있습니다.
/// tip | 팁
/// tip
자세한 내용은 [배포 문서](deployment/index.md){.internal-link target=_blank}에서 확인할 수 있습니다.
자세한 내용은 [deployment documentation](deployment/index.md){.internal-link target=\_blank}에서 확인할 수 있습니다.
///

View File

@@ -1,43 +1,43 @@
# 기능 { #features }
# 기능
## FastAPI의 기능 { #fastapi-features }
## FastAPI의 기능
**FastAPI**는 다음과 같은 기능을 제공합니다:
### 개방형 표준을 기반으로 { #based-on-open-standards }
### 개방형 표준을 기반으로
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>: <abbr title="또한 다음으로도 불립니다: 엔드포인트, 라우트">path</abbr> <abbr title="HTTP 메소드(POST, GET, PUT, DELETE 등)로도 알려져 있습니다">operations</abbr>, 매개변수, 요청 본문, 보안 등의 선언을 포함하여 API를 생성합니다.
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a>를 사용한 자동 데이터 모델 문서화(OpenAPI 자체가 JSON Schema를 기반으로 하기 때문입니다).
* 단순히 떠올려서 덧붙인 레이어가 아니라, 세심한 검토를 거친 이러한 표준을 중심으로 설계되었습니다.
* 이는 또한 다양한 언어로 자동 **클라이언트 코드 생성**을 사용할 수 있게 해줍니다.
* <abbr title="엔드포인트, 라우트로도 알려져 있습니다">경로</abbr><abbr title="POST, GET, PUT, DELETE와 같은 HTTP 메소드로 알려져 있습니다">작동</abbr>, 매개변수, 본문 요청, 보안 그 외의 선언을 포함한 API 생성을 위한 <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (OpenAPI 자체가 JSON Schema를 기반으로 하고 있습니다)를 사용한 자동 데이터 모델 문서화.
* 단순히 떠올려서 덧붙인 기능이 아닙니다. 세심한 검토를 거친 후, 이러한 표준을 기반으로 설계되었습니다.
* 이는 또한 다양한 언어로 자동적인 **클라이언트 코드 생성**을 사용할 수 있게 지원합니다.
### 문서 자동화 { #automatic-docs }
### 문서 자동화
대화형 API 문서와 탐색용 웹 사용자 인터페이스를 제공합니다. 프레임워크가 OpenAPI를 기반으로 하기에 여러 옵션이 있으며, 기본으로 2가지가 포함됩니다.
대화형 API 문서와 웹 탐색 유저 인터페이스를 제공합니다. 프레임워크가 OpenAPI를 기반으로 하기에, 2가지 옵션이 기본으로 들어간 여러 옵션이 존재합니다.
* 대화형 탐색이 가능한 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a> 브라우저에서 직접 API를 호출하 테스트할 수 있습니다.
* 대화형 탐색 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>를 이용해, 브라우저에서 바로 여러분의 API를 호출하거나 테스트할 수 있습니다.
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>을 이용한 대체 API 문서화.
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>을 이용 API 문서화를 대체할 수 있습니다.
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### 그저 현대 파이썬 { #just-modern-python }
### 그저 현대 파이썬
( Pydantic 덕분에) 모든 것이 표준 **Python 타입** 선언 기반으로 합니다. 새로 배울 문법이 없습니다. 그저 표준적인 현대 파이썬입니다.
(Pydantic 덕분에) FastAPI는 표준 **파이썬 3.6 타입** 선언 기반하고 있습니다. 새로 배울 문법이 없습니다. 그저 표준적인 현대 파이썬입니다.
Python 타입을 어떻게 사용하는지 2분 정도 복습이 필요하다면(FastAPI를 사용하지 않더라도), 다음의 짧은 자습서를 확인하세요: [Python 타입](python-types.md){.internal-link target=_blank}.
만약 여러분이 파이썬 타입을 어떻게 사용하는지에 대한 2분 정도 복습이 필요하다면 (비록 여러분이 FastAPI를 사용하지 않는다 하더라도), 다음의 짧은 자습서를 확인하세요: [파이썬 타입](python-types.md){.internal-link target=\_blank}.
여러분은 타입이 있는 표준 Python을 다음과 같이 작성합니다:
여러분은 타입을 이용한 표준 파이썬을 다음과 같이 적을 수 있습니다:
```Python
from datetime import date
from pydantic import BaseModel
# 변수를 str로 선언합니다
# 그리고 함수 내부에서 편집기 지원을 받습니다
# 변수를 str로 선언
# 그 함수 에서 편집기 지원을 받으세요
def main(user_id: str):
return user_id
@@ -49,7 +49,7 @@ class User(BaseModel):
joined: date
```
그 다음 다음과 같이 사용 수 있습니다:
위의 코드는 다음과 같이 사용 수 있습니다:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
@@ -65,23 +65,23 @@ my_second_user: User = User(**second_user_data)
/// info | 정보
`**second_user_data`는 다음을 의미합니다:
`**second_user_data`가 뜻하는 것:
`second_user_data` `dict`의 키와 값을 키-값 인자로서 바로 넘겨주는 것으로, 다음과 동일합니다: `User(id=4, name="Mary", joined="2018-11-30")`
`second_user_data` 딕셔너리의 키와 값을 키-값 인자로서 바로 넘겨줍니다. 다음과 동일합니다: `User(id=4, name="Mary", joined="2018-11-30")`
///
### 편집기 지원 { #editor-support }
### 편집기 지원
프레임워크 전체는 사용하기 쉽고 직관적으로 설계되었으며, 최고의 개발 경험을 보장하기 위해 개발을 시작하기도 전에 모든 결정은 여러 편집기에서 테스트되었습니다.
모든 프레임워크는 사용하기 쉽고 직관적으로 설계되었으며, 좋은 개발 경험을 보장하기 위해 개발을 시작하기도 전에 모든 결정은 여러 편집기에서 테스트니다.
Python 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">가장 많이 사용되는 기능 중 하나가 "자동 완성"이라는 점</a>이 분명합니다.
최근 파이썬 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">"자동 완성"이 가장 많이 사용되는 기능</a>이라는 것이 밝혀졌습니다.
**FastAPI** 프레임워크 전체는 이를 족하기 위해 만들어졌습니다. 자동 완성은 어서나 작동합니다.
**FastAPI** 프레임워크의 모든 부분은 이를 족하기 위해 설계되었습니다. 자동완성은 어느 곳에서나 작동합니다.
문서로 다시 돌아올 일 거의 없을 것입니다.
여러분은 문서로 다시 돌아올 일 거의 없을 니다.
편집기가 여러분을 어떻게 도와줄 수 있는지 살펴보세요:
다음은 편집기가 어떻게 여러분을 도와주는지 보여줍니다:
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>에서:
@@ -91,111 +91,111 @@ Python 개발자 설문조사에서 <a href="https://www.jetbrains.com/research/
![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)
이전에 불가능하다고 생각했을 코드에서도 자동 완성을 받을 수 있니다. 예를 들어, 요청에서 전달되는(중첩될 수도 있는) JSON 본문 내부 `price` 같은 경우입니다.
여러분이 이전에 불가능하다고 고려했던 코드도 완성할 수 있을 겁니다. 예를 들어, 요청에서 전달되는 (중첩될 수도 있는)JSON 본문 내부에 있는 `price` 키입니다.
더 이상 잘못된 키 이름을 입력하거나, 문서 사이를 왔다 갔다 하거나, `username`을 썼는지 `user_name`는지 찾으려고 위아래로 스크롤할 필요가 없습니다.
잘못된 키 이름을 적을 일도, 문서를 왔다 갔다할 일도 없으며, 혹은 마지막으로 `username` 또는 `user_name`사용했는지 찾기 위해 위 아래로 스크롤할 일도 없습니다.
### 간결함 { #short }
### 토막 정보
선택적 구성을 어디서나 할 수 있도록 하면서도, 모든 것에 합리적인 **기본값**이 설정되어 있습니다. 모든 매개변수는 필요한 작업을 하거나 필요한 API를 정의하기 위해 미세하게 조정할 수 있습니다.
어느 곳에서나 선택적 구성이 가능한 모든 것에 합리적인 기본값이 설정되어 있습니다. 모든 매개변수는 여러분이 필요하거나, 원하는 API를 정의하기 위해 미세하게 조정할 수 있습니다.
하지만 기본적으로 모든 것이 **"그냥 작동합니다"**.
하지만 기본적으로 모든 것이 "그냥 작동합니다".
### 검증 { #validation }
### 검증
* 다음을 포함 대부분(혹은 전부?)의 Python **데이터 타입**에 대한 검증:
* 다음을 포함한, 대부분(혹은 모든?) 파이썬 **데이터 타입** 검증할 수 있습니다:
* JSON 객체 (`dict`).
* 아이템 타입을 정의하는 JSON 배열 (`list`).
* 최소/최대 길이를 정의하는 문자열(`str`) 필드.
*소/최대 값을 가지는 숫자(`int`, `float`).
* 최소 길이와 최대 길이를 정의하는 문자열 (`str`) 필드.
*솟값과 최댓값을 가지는 숫자 (`int`, `float`), 그 외.
* 다음과 같은 좀 더 이색적인 타입에 대 검증:
* 다음과 같 이색적인 타입에 대 검증할 수 있습니다:
* URL.
* Email.
* 이메일.
* UUID.
* ...그 외.
* ...다른 것들.
모든 검증은 잘 확립되어 있고 견고한 **Pydantic** 처리니다.
모든 검증은 견고하면서 잘 확립된 **Pydantic**에 의해 처리니다.
### 보안과 인증 { #security-and-authentication }
### 보안과 인증
보안과 인증이 통합되어 있습니다. 데이터베이스나 데이터 모델과 타협하지 않습니다.
보안과 인증이 통합되어 있습니다. 데이터베이스나 데이터 모델과 타협없이 사용할 수 있습니다.
다음을 포함해 OpenAPI에 정의된 모든 보안 스키마:
다음을 포함하는, 모든 보안 스키마가 OpenAPI에 정의되어 있습니다.
* HTTP Basic.
* **OAuth2**(**JWT tokens** 또한 포함). [JWT를 사용한 OAuth2](tutorial/security/oauth2-jwt.md){.internal-link target=_blank} 자습서를 확인해 보세요.
* **OAuth2** (**JWT tokens** 또한 포함). [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=\_blank}에 있는 자습서를 확인해 보세요.
* 다음에 들어 있는 API 키:
* 헤더.
* 쿼리 매개변수.
* 쿠키 .
* 매개변수.
* 쿠키 및 그 외.
추가로 Starlette의 모든 보안 기능(**세션 쿠키** 포함)도 제공합니다.
추가적으로 (**세션 쿠키** 포함한) 모든 보안 기능은 Starlette에 있습니다.
모두 재사용 가능한 도구와 컴포넌트로 만들어져 있어, 여러분의 시스템, 데이터 저장소, 관계형 및 NoSQL 데이터베이스 등과 쉽게 통합할 수 있습니다.
모두 재사용할 수 있는 도구와 컴포넌트로 만들어져 있어 여러분의 시스템, 데이터 저장소, 관계형 및 NoSQL 데이터베이스 등과 쉽게 통합할 수 있습니다.
### 의존성 주입 { #dependency-injection }
### 의존성 주입
FastAPI는 사용하기 매우 지만, 매우 강력한 <abbr title='또한 다음으로도 불립니다: "컴포넌트", "자원", "서비스", "제공자"'><strong>Dependency Injection</strong></abbr> 시스템을 포함하고 있습니다.
FastAPI는 사용하기 매우 간편하지만, 엄청난 <abbr title='"컴포넌트", "자원", "서비스", "제공자"로도 알려진'><strong>의존성 주입</strong></abbr>시스템을 포함하고 있습니다.
* 의존성 의존성을 가질 수 있어, 의존성의 계층 또는 **의존성의 "그래프"**를 성합니다.
* 모든 것이 프레임워크에 의해 **자동으로 처리됩니다**.
* 모든 의존성은 요청에서 데이터를 요구할 수 있으며, **경로 처리** 제약과 자동 문서화를 강화할 수 있습니다.
* 의존성에 정의된 *경로 처리* 매개변수에 대해서도 **자동 검증**을 합니다.
* 복잡한 사용자 인증 시스템, **데이터베이스 연결** 등을 지원합니다.
* 데이터베이스, 프론트엔드 등과 **타협하지 않니다**. 하지만 모두와 쉽게 통합할 수 있습니다.
* 의존성 의존성을 가질수 있어, 이를 통해 의존성의 계층이나 **의존성의 "그래프"**를 성합니다.
* 모든 것이 프레임워크에 의해 **자동으로 처리됩니다**.
* 모든 의존성은 요청에서 데이터를 요구하여 자동 문서화와 **경로 작동 제약을 강화할 수 있습니다**.
* 의존성에 정의된 _경로 작동_ 매개변수에 대해서도 **자동 검증**이 이루어 집니다.
* 복잡한 사용자 인증 시스템, **데이터베이스 연결**, 등등을 지원합니다.
* 데이터베이스, 프론트엔드 등과 관련되어 **타협하지 않아도 됩니다**. 하지만 그 모든 것과 쉽게 통합이 가능합니다.
### 제한 없는 "플러그인" { #unlimited-plug-ins }
### 제한 없는 "플러그인"
또 다른 방으로, 그것들 필요 없습니다. 필요한 코드 임포트해서 사용하면 됩니다.
다른 방으로, 그것들을 사용할 필요 없 필요한 코드 임포트할 수 있습니다.
통합이든(의존성과 함께) 사용하기 매우 간단하도록 설계되어 있어, *경로 처리*에 사용된 것과 동일한 구조와 문법을 사용 2줄의 코드로 애플리케이션용 "플러그인"을 만들 수 있습니다.
통합(의존성과 함께) 사용하기 쉽게 설계되어 있어, *경로 작동*에 사용된 것과 동일한 구조와 문법을 사용하여 2줄의 코드로 여러분의 어플리케이션에 사용할 "플러그인"을 만들 수 있습니다.
### 테스트됨 { #tested }
### 테스트 결과
* 100% <abbr title="자동으로 테스트되는 코드의 양">test coverage</abbr>.
* 100% <abbr title="Python 타입 어노테이션으로, 이를 통해 편집기와 외부 도구 더 나은 지원을 제공할 수 있습니다">type annotated</abbr> 코드 베이스.
* 프로덕션 애플리케이션에서 사용됩니다.
* 100% <abbr title="자동으로 테스트 코드의 양">테스트 범위</abbr>.
* 100% <abbr title="파이썬의 타입 어노테이션, 이를 통해 여러분의 편집기와 외부 도구는 여러분에게 더 나은 지원을 할 수 있습니다">타입이 명시된</abbr> 코드 베이스.
* 상용 어플리케이션에서 사용.
## Starlette 기능 { #starlette-features }
## Starlette 기능
**FastAPI**는 <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a>와 완전히 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Starlette 코드도 모두 동작합니다.
**FastAPI**는 <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a>를 기반으로 구축되었으며, 이와 완전히 호환됩니다. 따라서, 여러분이 보유하고 있는 어떤 추가적인 Starlette 코드도 작동할 것입니다.
`FastAPI`는 실제로 `Starlette`의 하위 클래스입니다. 그래서 Starlette을 이미 알고 있거나 사용하고 있면, 대부분의 기능이 같은 방식으로 작할 것입니다.
`FastAPI`는 실제로 `Starlette`의 하위 클래스입니다. 그래서, 여러분이 이미 Starlette을 알고 있거나 사용하고 있면, 대부분의 기능이 같은 방식으로 작할 것입니다.
**FastAPI**를 사용하면 **Starlette**의 모든 기능을 얻게 니다(FastAPI Starlette력한 기능을 더한 것입니다):
**FastAPI**를 사용하면 여러분은 **Starlette**의 기능 대부분을 얻게 될 것입니다(FastAPI가 단순히 Starlette화했기 때문입니다):
* 정말 인상적인 성능. <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">**NodeJS**와 **Go**에 버금가는, 사용 가능한 가장 빠른 Python 프레임워크 중 하나입니다</a>.
* 아주 인상적인 성능. 이는 <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">**NodeJS**와 **Go**와 동등하게 사용 가능한 가장 빠른 파이썬 프레임워크 중 하나입니다</a>.
* **WebSocket** 지원.
* 프로세스 내 백그라운드 작업.
* 시작 종료 이벤트.
* 프로세스 내 백그라운드 작업.
* 시작 종료 이벤트.
* HTTPX 기반 테스트 클라이언트.
* **CORS**, GZip, 정적 파일, 스트리밍 응답.
* **세션과 쿠키** 지원.
* 100% test coverage.
* 100% type annotated codebase.
* 100% 테스트 범위.
* 100% 타입이 명시된 코드 베이스.
## Pydantic 기능 { #pydantic-features }
## Pydantic 기능
**FastAPI**는 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>과 완벽하게 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Pydantic 코드도 모두 동작합니다.
**FastAPI**는 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>을 기반으로 하며 Pydantic과 완벽하게 호환됩니다. 그래서 어느 추가적인 Pydantic 코드를 여러분이 가지고 있든 작동할 것입니다.
데이터베이스를 위한 <abbr title="Object-Relational Mapper - 객체-관계 매퍼">ORM</abbr>, <abbr title="Object-Document Mapper - 객체-문서 매퍼">ODM</abbr>과 같은, Pydantic을 기반으로 하는 외부 라이브러리 포함합니다.
Pydantic을 기반으로 하는, 데이터베이스를 위한 <abbr title="Object-Relational Mapper">ORM</abbr>, <abbr title="Object-Document Mapper">ODM</abbr>을 포함한 외부 라이브러리 포함합니다.
이는 모든 것이 자동으로 검증되기 때문에, 많은 경우 요청에서 얻은 동일한 객체를 **직접 데이터베이스로** 넘겨줄 수 있다는 의미이기도 합니다.
이는 모든 것이 자동으로 검증되기 때문에, 많은 경우에서 요청을 통해 얻은 동일한 객체를, **직접 데이터베이스로** 넘겨줄 수 있니다.
반대로도 마찬가지이며, 많은 경우 데이터베이스에서 얻은 객체를 **직접 클라이언트로**대로 넘겨줄 수 있습니다.
반대로도 마찬가지이며, 많은 경우에서 여러분은 **직접 클라이언트로**저 객체를 넘겨줄 수 있습니다.
**FastAPI**를 사용하면(모든 데이터 처리를 위해 FastAPI가 Pydantic을 기반으로 하기에) **Pydantic**의 모든 기능을 얻게 됩니다:
**FastAPI**를 사용하면 (모든 데이터 처리를 위해 FastAPI가 Pydantic을 기반으로 하기 있기에) **Pydantic**의 모든 기능을 얻게 됩니다:
* **No brainfuck**:
* 새로운 스키마 정의 마이크로 언어를 배울 필요가 없습니다.
* Python 타입을 알고 있다면 Pydantic 사용법도 알고 있는 것입니다.
* 여러분의 **<abbr title="Integrated Development Environment - 통합 개발 환경: 코드 편집기와 비슷합니다">IDE</abbr>/<abbr title="코드 오류를 확인하는 프로그램">linter</abbr>/뇌**와 잘 어울립니다:
* pydantic 데이터 구조는 여러분이 정의한 클래스 인스턴스일 뿐이므로, 자동 완성, 린팅, mypy, 그리고 직관까지도 검증된 데이터와 함께 제대로 작동합니다.
* **어렵지 않은 언어**:
* 새로운 스키마 정의 마이크로 언어를 배우지 않아도 됩니다.
* 여러분이 파이썬 타입을 안다면, 여러분은 Pydantic을 어떻게 사용하는지 아는 겁니다.
* 여러분의 **<abbr title="통합 개발 환경, 코드 편집기와 비슷합니다">IDE</abbr>/<abbr title="코드 에러를 확인하는 프로그램">린터</abbr>/뇌**와 잘 어울립니다:
* Pydantic 데이터 구조는 단순 여러분이 정의한 클래스 인스턴스이기 때문에, 자동 완성, 린팅, mypy 그리고 여러분의 직관까지 여러분의 검증된 데이터와 올바르게 작동합니다.
* **복잡한 구조**를 검증합니다:
* 계층적인 Pydantic 모델, Python `typing``List``Dict` 등을 사용합니다.
* 그리고 validator는 복잡한 데이터 스키마를 명확하고 쉽게 정의하고, 검사하고, JSON Schema로 문서화할 수 있게 해줍니다.
* 깊게 **중첩된 JSON** 객체를 가질 수 있으며, 이 모두 검증하고 주석을 달 수 있습니다.
* **확장 가능**:
* Pydantic은 사용자 정의 데이터 타입을 정의할 수 있게 하거나, validator decorator가 붙은 모델 메서드로 검증을 확장할 수 있습니다.
* 100% test coverage.
* 계층적인 Pydantic 모델, 파이썬 `typing``List``Dict`, 그 외를 사용합니다.
* 그리고 검증자는 복잡한 데이터 스키마를 명확하고 쉽게 정의 및 확인하며 JSON 스키마로 문서화합니다.
* 여러분은 깊게 **중첩된 JSON** 객체를 가질 수 있으며, 이 객체 모두 검증하고 설명을 붙일 수 있습니다.
* **확장 가능**:
* Pydantic은 사용자 정의 데이터 타입을 정의할 수 있게 하거나, 검증자 데코레이터가 붙은 모델소드를 사용하여 검증을 확장할 수 있습니다.
* 100% 테스트 범위.

View File

@@ -1,4 +1,4 @@
# FastAPI 지원 - 도움 받기 { #help-fastapi-get-help }
# FastAPI 지원 - 도움 받기
**FastAPI** 가 마음에 드시나요?
@@ -10,9 +10,9 @@ FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
또한 도움을 받을 수 있는 방법도 몇 가지 있습니다.
## 뉴스레터 구독 { #subscribe-to-the-newsletter }
## 뉴스레터 구독
(자주 발송되지 않는) [**FastAPI and friends** 뉴스레터](newsletter.md){.internal-link target=_blank}를 구독하여 최신 정보를 유지할 수 있습니다:
[**FastAPI and friends** 뉴스레터](newsletter.md){.internal-link target=\_blank}를 구독하여 최신 정보를 유지할 수 있습니다:
* FastAPI and friends에 대한 뉴스 🚀
* 가이드 📝
@@ -20,65 +20,65 @@ FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
* 획기적인 변화 🚨
* 팁과 요령 ✅
## X(Twitter)에서 FastAPI 팔로우하기 { #follow-fastapi-on-x-twitter }
## 트위터에서 FastAPI 팔로우하기
<a href="https://x.com/fastapi" class="external-link" target="_blank">**X (Twitter)**의 @fastapi를 팔로우</a>하여 **FastAPI** 에 대한 최신 뉴스를 얻을 수 있습니다. 🐦
## GitHub에서 **FastAPI**에 Star 주기 { #star-fastapi-in-github }
## Star **FastAPI** in GitHub
GitHub에서 FastAPI에 "star"를 붙일 수 있습니다 (오른쪽 상단의 star 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
스타를 늘림으로써, 다른 사용자들이 좀 더 쉽게 찾을 수 있고, 많은 사람들에게 유용한 것임을 나타낼 수 있습니다.
## 릴리즈 확인을 위해 GitHub 저장소 보기 { #watch-the-github-repository-for-releases }
## GitHub 저장소에서 릴리즈 확인
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch" 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
여기서 "Releases only" 선택할 수 있습니다.
여기서 "Releases only" 선택할 수 있습니다.
이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 릴리즈(새 버전) 있을 때마다 (이메일) 통지를 받을 수 있습니다.
이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 자료 (최신 버전) 있을 때마다 (이메일) 통지를 받을 수 있습니다.
## 개발자와의 연결 { #connect-with-the-author }
## 개발자와의 연결
개발자(작성자)인 <a href="https://tiangolo.com" class="external-link" target="_blank">(Sebastián Ramírez / `tiangolo`)</a>와 연락을 취할 수 있습니다.
<a href="https://tiangolo.com" class="external-link" target="_blank">개발자(Sebastián Ramírez / `tiangolo`)</a>와 연락을 취할 수 있습니다.
여러분은 할 수 있습니다:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">**GitHub**에서 팔로우하기</a>.
* 여러분에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">**GitHub**에서 팔로우하기.</a>.
* 당신에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
* 새로운 오픈소스 프로젝트를 만들었을 때 확인하려면 팔로우 하십시오.
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">**X (Twitter)**</a> 또는 <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>에서 팔로우하기.
* FastAPI의 사용 용도를 알려주세요 (그것을 듣는 것을 좋아합니다).
* 발표나 새로운 툴 출시 소식을 받아보십시오.
* <a href="https://x.com/fastapi" class="external-link" target="_blank">X(Twitter)에서 @fastapi를 팔로우</a> (별도 계정에서) 할 수 있습니다.
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**LinkedIn**에서 팔로우하기</a>.
* 새로운 툴의 발표나 출시 소식을 받아보십시오 (단, X (Twitter)를 더 자주 사용합니다 🤷‍♂).
* <a href="https://x.com/fastapi" class="external-link" target="_blank">**X (Twitter)**의 @fastapi를 팔로우</a> (별도 계정에서) 할 수 있습니다.
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**LinkedIn**에서 팔로우하기.</a>.
* 새로운 툴의 발표나 출시 소식을 받아보십시오. (단, X (Twitter)를 더 자주 사용합니다 🤷‍♂).
* <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> 또는 <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>에서 제가 작성한 내용을 읽어 보십시오 (또는 팔로우).
* 다른 아이디어와 기사들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
* 새로운 내용을 게시할 때 읽기 위해 팔로우 하십시오.
* 다른 기사나 아이디어들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
* 새로운 기사를 읽기 위해 팔로우 하십시오.
## **FastAPI**에 대 트윗하기 { #tweet-about-fastapi }
## **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**에 대해 트윗</a> 하고 저와 다른 사람들에게 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**에 대해 트윗</a> 하고 FastAPI가 마음에 드는 이유를 알려주세요. 🎉
**FastAPI**가 어떻게 사용되고 있는지, 어떤 점이 마음에 들었는지, 어떤 프로젝트/회사에서 사용하고 있는지 등에 대해 듣고 싶습니다.
## FastAPI에 투표하기 { #vote-for-fastapi }
## FastAPI에 투표하기
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Slant에서 **FastAPI** 에 대해 투표하십시오</a>.
* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">AlternativeTo에서 **FastAPI** 에 대해 투표하십시오</a>.
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare에서 **FastAPI**를 사용한다고 표시하세요</a>.
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare에서 **FastAPI** 에 대해 투표하십시오</a>.
## GitHub에서 질문으로 다른 사람 돕기 { #help-others-with-questions-in-github }
## GitHub의 이슈로 다른사람 돕기
다른 사람들의 질문에 도움을 줄 수 있습니다:
* <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>
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub 디스커션</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 이슈</a>
많은 경우, 여러분은 이미 그 질문에 대한 답을 알고 있을 수도 있습니다. 🤓
만약 많은 사람들의 질문을 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 될 것입니다. 🎉
만약 많은 사람들의 문제를 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts){.internal-link target=\_blank} 가 될 것입니다. 🎉
가장 중요한 점은: 친절하려고 노력하는 것입니다. 사람들은 좌절감을 안고 오며, 많은 경우 최선의 방식으로 질문하지 않을 수도 있습니다. 하지만 최대한 친절하게 대하려고 노력하세요. 🤗
@@ -86,170 +86,183 @@ GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch"
---
다른 사람들의 질문(디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.
다른 사람들의 질문 (디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.
### 질문 이해하기 { #understand-the-question }
### 질문 이해하기
* 질문하는 사람이 가진 **목적**과 사용 사례를 이해할 수 있는지 확인하세요.
* 그런 다음 질문(대부분은 질문입니다)이 **명확**한지 확인하세요.
* 질문 (대부분은 질문입니다)이 **명확**한지 확인하세요.
* 많은 경우 사용자가 상상한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.
* 많은 경우, 사용자가 가정한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.
* 질문을 이해할 수 없다면, 더 **자세한 정보**를 요청하세요.
### 문제 재현하기 { #reproduce-the-problem }
### 문제 재현하기
대부분의 경우 그리고 대부분의 질문에서는 질문자의 **원본 코드**와 관련된 내용이 있습니다.
대부분의 경우, 질문은 질문자의 **원본 코드**와 관련이 있습니다.
많은 경우, 코드의 일부만 복사해서 올리지만, 그것만으로는 **문제를 재현**하기에 충분하지 않습니다.
* 질문자에게 <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">최소한의 재현 가능한 예제</a>를 제공해달라고 요청할 수 있습니다. 이렇게 하면 코드를 **복사-붙여넣기**하여 로컬에서 실행하고, 질문자가 보고 있는 것과 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.
* 질문자에게 <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">최소한의 재현 가능한 예제</a>를 제공해달라고 요청하세요. 이렇게 하면 코드를 **복사-붙여넣기**하여 직접 실행하고, 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.
* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 다만 이는 시간이 많이 걸릴 수 있으므로, 먼저 문제를 명확히 해달라고 요청하는 것이 더 나을 수 있다는 점을 기억하세요.
* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 하지만, 이는 시간이 많이 걸릴 수 있으므로, 먼저 질문을 명확히 해달라고 요청하는 것이 좋습니다.
### 해결책 제안하기 { #suggest-solutions }
### 해결책 제안하기
* 질문을 충분히 이해한 후에는 가능한 **답변**을 제공할 수 있습니다.
* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 더 좋습니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.
* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 중요합니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.
### 종료 요청하기 { #ask-to-close }
### 해결 요청하기
질문자가 답변을 하면, 여러분이 문제를 해결했을 가능성이 높습니다. 축하합니다, **여러분은 영웅입니다**! 🦸
질문자가 답변을 확인하고 나면, 당신이 문제를 해결했을 가능성이 높습니다. 축하합니다, **당신은 영웅입니다**! 🦸
* 이제 문제를 해결했다면, 질문자에게 다음을 요청할 수 있습니다.
* GitHub Discussions에서: 댓글을 **답변**으로 표시하도록 요청하세요.
* GitHub Issues에서: 이슈를 **닫아달라고** 요청하세요.
* GitHub 디스커션에서: 댓글을 **답변**으로 표시하도록 요청하세요.
* GitHub 이슈에서: 이슈를 **닫아달라고** 요청하세요.
## GitHub 저장소 보기 { #watch-the-github-repository }
## GitHub 저장소 보기
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 "watch" 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
"Releases only" 대신 "Watching"을 선택하면 누군가가 새 이슈나 질문을 만들 때 알림을 받게 됩니다. 또한 새 이슈, 디스커션, PR 등만 알림 받도록 정할 수도 있습니다.
"Releases only" 대신 "Watching"을 선택하면, 새로운 이슈나 질문이 생성될 때 알림을 받을 수 있습니다. 또한, 특정하게 새로운 이슈, 디스커션, PR 등만 알림 받도록 정할 수도 있습니다.
그런 다음 이런 질문들을 해결도록 도줄 수 있습니다.
그런 다음 이런 이슈들을 해결 할 수 있도록 도움을 줄 수 있습니다.
## 질문하기 { #ask-questions }
## 이슈 생성하기
GitHub 저장소에 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">새 질문을 생성</a>할 수 있습니다. 예를 들면 다음과 같습니다:
GitHub 저장소에 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">새로운 이슈 생성</a>할 수 있습니다, 예를들면 다음과 같습니다:
* **질문**을 하거나 **문제**에 대해 질문합니다.
* 새로운 **기능**을 제안 합니다.
**참고**: 만약 이렇게 한다면, 저는 여러분에게 다른 사람들 도와달라고 요청할 것입니다. 😉
**참고**: 만약 이슈를 생성한다면, 저는 여러분에게 다른 사람들 도와달라고 부탁할 것입니다. 😉
## Pull Request 리뷰하기 { #review-pull-requests }
## Pull Requests 리뷰하기
다른 사람들이 만든 pull request를 리뷰하는 데 저를 도와줄 수 있습니다.
다른 사람들 pull request를 리뷰하는 데 도움을 줄 수 있습니다.
다시 한번 말하지만, 최대한 친절하게 리뷰해 주세요. 🤗
---
Pull request를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:
Pull Rrquest를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:
### 문제 이해하기 { #understand-the-problem }
### 문제 이해하기
* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub Discussion 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.
* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub 디스커션 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.
* Pull request가 실제로 필요하지 않을 가능성도 니다. 문제가 **다른 방식**으로 해결 수 있기 때문입니다. 그런 경우 그 방법을 제안하거나 질문할 수 있습니다.
* Pull request가 필요하지 않을 가능성도 있습니다. **다른 방식**으로 문제를 해결 수 있다면, 그 방법을 제안하거나 질문할 수 있습니다.
### 스타일에 너무 신경 쓰지 않기 { #dont-worry-about-style }
### 스타일에 너무 신경 쓰지 않기
* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 마세요. 저는 커밋을 수동으로 조정해서 squash and merge를 할 것입니다.
* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 않아도 됩니다. 저는 직접 커밋을 수정하여 squash and merge를 수행할 것입니다.
* 코드 스타일 규칙도 걱정할 필요 없습니다. 이미 자동화된 도구들이 이를 검사하고 있습니다.
그리고 다른 스타일이나 일관성 관련 필요 사항이 있다면, 제가 직접 요청하거나 필요한 변경 사항을 위에 커밋으로 추가할 것입니다.
스타일이나 일관성 관련 요청이 필요한 경우, 제가 직접 요청하거나 필요한 변경 사항을 추가 커밋으로 수정할 것입니다.
### 코드 확인하기 { #check-the-code }
### 코드 확인하기
* 코드를 확인하고 읽어서 말이 되는지 보고, **로컬에서 실행**해 실제로 문제가 해결되는지 확인하세요.
* 코드를 읽고, **논리적으로 타당**한지 확인한 후 로컬에서 실행하여 문제가 해결되는지 확인하세요.
* 그런 다음 그렇게 했다고 **댓글** 남겨 주세요. 그래야 제가 정말로 확인했음을 알 수 있습니다.
* 그런 다음, 확인했다고 **댓글** 남겨 주세요. 그래야 제가 검토했음을 알 수 있습니다.
/// info | 정보
/// info
불행히도, 제가 단순히 여러 개의 승인만으로 PR을 신뢰할 수는 없습니다.
여러 번, 설명이 그럴듯해서인지 3개, 5개 이상의 승인이 달린 PR이 있었지만, 제가 확인해보면 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 있었습니다. 😅
3개, 5개 이상의 승인이 달린 PR이 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 여러 번 있었습니다. 😅
따라서, 정말로 코드를 읽고 실행한 뒤, 댓글로 확인 내용을 남겨 주는 것이 매우 중요합니다. 🤓
///
* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다(그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.
* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다 (그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.
### 테스트 { #tests }
### 테스트
* PR에 **테스트**가 포함되어 있는지 확인하는 데 도움을 주세요.
* PR 전에 테스트가 **실패**하는지 확인하세요. 🚨
* PR을 적용하기 전에 테스트가 **실패**하는지 확인하세요. 🚨
* 그런 다음 PR 후에는 테스트가 **통과**하는지 확인하세요. ✅
* PR을 적용한 후 테스트가 **통과**하는지 확인하세요. ✅
* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 가장 많이 드는 것들 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.
* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 많이 소요되는 부분 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.
* 그리고 시도한 내용을 댓글로 남겨주세요. 그러면 제가 확인했다는 걸 알 수 있습니다. 🤓
## Pull Request 만들기 { #create-a-pull-request }
## Pull Request드십시오
Pull Requests를 이용하여 소스 코드에 [기여](contributing.md){.internal-link target=_blank}할 수 있습니다. 예를 들면 다음과 같습니다:
Pull Requests를 이용하여 소스코드에 [컨트리뷰트](contributing.md){.internal-link target=\_blank} 할 수 있습니다. 예를 들면 다음과 같습니다:
* 문서에서 발견한 오타를 수정할 때.
* FastAPI에 대한 글, 비디오, 팟캐스트를 작성했거나 발견했다면 <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">이 파일을 편집</a>하여 공유할 때.
* FastAPI 관련 문서, 비디오 또는 팟캐스트를 작성했거나 발견하여 <a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">이 파일을 편집하여</a> 공유할 때.
* 해당 섹션의 시작 부분에 링크를 추가해야 합니다.
* 여러분의 언어로 [문서 번역](contributing.md#translations){.internal-link target=_blank} 도움을 줄 때.
* 당신의 언어로 [문서 번역하는데](contributing.md#translations){.internal-link target=\_blank} 기여할 때.
* 다른 사람이 작성한 번역을 검토하는 것도 도울 수 있습니다.
* 새로운 문서 섹션을 제안할 때.
* 기존 이슈/버그를 수정할 때.
* 새로운 문서 섹션을 제안할 때.
* 기존 문제/버그를 수정할 때.
* 테스트를 반드시 추가해야 합니다.
* 새로운 기능을 추가할 때.
* 새로운 feature를 추가할 때.
* 테스트를 반드시 추가해야 합니다.
* 관련 문서가 다면 반드시 추가해야 합니다.
* 관련 문서가 필요하다면 반드시 추가해야 합니다.
## FastAPI 유지 관리 돕기 { #help-maintain-fastapi }
## FastAPI 유지 관리에 도움 주기
**FastAPI** 유지를 도와주세요! 🤓
**FastAPI** 유지 관리를 도와주세요! 🤓
할 일이 많고, 그중 대부분은 **여러분**이 할 수 있습니다.
할 일이 많고, 그 중 대부분은 **여러분**이 할 수 있습니다.
지금 할 수 있는 주요 작업은:
* [GitHub에서 질문으로 다른 사람 돕기](#help-others-with-questions-in-github){.internal-link target=_blank} (위의 섹션을 참조하세요).
* [Pull Request 리뷰하기](#review-pull-requests){.internal-link target=_blank} (위의 섹션을 참조하세요).
* [GitHub에서 다른 사람들의 질문에 도움 주기](#github_1){.internal-link target=_blank} (위의 섹션을 참조하세요).
* [Pull Request 리뷰하기](#pull-requests){.internal-link target=_blank} (위의 섹션을 참조하세요).
이 두 작업이 **가장 많은 시간을 소모**니다. 것이 FastAPI 유지 관리하는 주요 작업입니다.
이 두 작업이 **가장 많은 시간을 소모**하는 일입니다. 것이 FastAPI 유지 관리 주요 작업입니다.
이 작업을 도와주신다면, **FastAPI 유지를 돕는 것**이며 FastAPI가 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀
이 작업을 도와주신다면, **FastAPI 유지 관리에 도움을 주는 것**이며 그것이 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀
## 채팅에 참여하기 { #join-the-chat }
## 채팅에 참여하십시오
👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord 채팅 서버</a> 👥 에 참여해서 FastAPI 커뮤니티 다른 사람들과 어울리세요.
👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">디스코드 채팅 서버</a> 👥 에 가입하고 FastAPI 커뮤니티에서 다른 사람들과 어울리세요.
/// tip | 팁
/// tip
질문 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>에서 하세요. [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank}로부터 도움을 받을 가능성이 훨씬 높습니다.
질문이 있는 경우, <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub 디스커션</a> 에서 질문하십시오, [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank} 도움을 받을 가능성이 높습니다.
채팅은 다른 일반적인 대화를 위해서만 사용하세요.
다른 일반적인 대화에서만 채팅을 사용하십시오.
///
### 질문을 위해 채팅을 사용하지 마세요 { #dont-use-the-chat-for-questions }
### 질문을 위해 채팅을 사용하지 마십시오
채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 답하기 어려운 질문을 쉽게 할 수 있 답변을 받지 못할 수 있다는 점을 기억하세요.
채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 답하기 어려운 질문을 쉽게 질문을 할 수 있으므로, 답변을 받지 못할 수 있습니다.
GitHub에서 템플릿 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나, 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 제가 항상 모든 것에 답하도록 보장할 수 있습니다. 채팅 시스템에서는 제가 개인적으로 그렇게 할 수 없습니다. 😅
GitHub 이슈에서 템플릿 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 항상 모든 것에 답할 수 있습니다. 채팅 시스템에서는 개인적으로 그렇게 할 수 없습니다. 😅
채팅 시스템에서의 대화 또한 GitHub만큼 쉽게 검색할 수 없기 때문에, 질문과 답변이 대화 속에서 사라질 수 있습니다. 그리고 GitHub에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 되는 것으로 인정되므로, GitHub에서 더 많은 관심을 받게 될 가능성이 큽니다.
채팅 시스템에서의 대화 또한 GitHub에서 처럼 쉽게 검색할 수 없기 때문에 대화 중에 질문과 답변이 손실될 수 있습니다. 그리고 GitHub 이슈에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 되는 것으로 간주되므로, GitHub 이슈에서 더 많은 관심을 받을 것입니다.
반면, 채팅 시스템에는 수천 명의 사용자가 있으므로, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
반면, 채팅 시스템에는 수천 명의 사용자가 있기 때문에, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
## 개발자 스폰서 되기 { #sponsor-the-author }
## 개발자 스폰서십시오
여러분의 **제품/회사**가 **FastAPI**에 의존하거나 관련되어 있고, FastAPI 사용자를 대상으로 알리고 싶다면 <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>를 통해 개발자(저)를 스폰서할 수 있습니다. 티어에 따라 문서에 배지 같은 추가 혜택을 받을 있습니다. 🎁
<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub 스폰서</a> 를 통해 개발자를 경제적으로 지원할 수 있습니다.
감사하다는 말로 커피를 ☕️ 한잔 사줄 수 있습니다. 😄
또한 FastAPI의 실버 또는 골드 스폰서가 될 수 있습니다. 🏅🎉
## FastAPI를 강화하는 도구의 스폰서가 되십시오
문서에서 보았듯이, FastAPI는 Starlette과 Pydantic 라는 거인의 어깨에 타고 있습니다.
다음의 스폰서가 될 수 있습니다
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
---

View File

@@ -1,79 +1,81 @@
# 역사, 디자인 그리고 미래 { #history-design-and-future }
# 역사, 디자인 그리고 미래
얼마 전, <a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">한 **FastAPI** 사용자가 이렇게 물었습니다</a>:
어느 날, [한 FastAPI 사용자](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920)가 이렇게 물었습니다:
> 이 프로젝트의 역사는 무엇인가요? 몇 주 만에 아무 데서도 갑자기 나타나 엄청나게 좋아진 것처럼 보이네요 [...]
> 이 프로젝트의 역사를 알려 주실 수 있나요? 몇 주 만에 멋진 결과를 낸 것 같아요. [...]
여기서 그 역사에 대해 간단히 설명하겠습니다.
## 대안 { #alternatives }
---
저는 여러 해 동안 복잡한 요구사항(머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 등)을 가진 API를 만들면서 여러 개발 팀을 이끌어 왔습니다.
## 대안
그 과정에서 많은 대안을 조사하고, 테스트하고, 사용해야 했습니다.
저는 여러 해 동안 머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 같은 복잡한 요구사항을 가진 API를 개발하며 여러 팀을 이끌어 왔습니다.
**FastAPI**의 역사는 상당 부분 그 이전에 있던 도구의 역사니다.
이 과정에서 많은 대안을 조사하고, 테스트하며, 사용해야 했습니다. **FastAPI**의 역사는 그 이전에 나왔던 여러 도구의 역사와 밀접하게 연관되어 있습니다.
[대안](alternatives.md){.internal-link target=_blank} 섹션에서 언급된 것처럼:
<blockquote markdown="1">
> **FastAPI**는 이전에 나왔던 많은 도구들의 노력 없이는 존재하지 않았을 것입니다.
>
> 이전에 개발된 여러 도구들이 이 프로젝트에 영감을 주었습니다.
>
> 저는 오랫동안 새로운 프레임워크를 만드는 것을 피하고자 했습니다. 처음에는 **FastAPI**가 제공하는 기능들을 다양한 프레임워크와 플러그인, 도구들을 조합해 해결하려 했습니다.
>
> 하지만 결국에는 이 모든 기능을 통합하는 도구가 필요해졌습니다. 이전 도구들로부터 최고의 아이디어들을 모으고, 이를 최적의 방식으로 조합해야만 했습니다. 이는 :term:Python 3.6+ 타입 힌트 <type hints>와 같은, 이전에는 사용할 수 없었던 언어 기능이 가능했기 때문입니다.
**FastAPI**는 다른 사람들이 이전에 해온 작업이 없었다면 존재하지 않았을 것입니다.
---
그 전에 만들어진 많은 도구들이 이것의 탄생에 영감을 주었습니다.
## 조사
저는 여러 해 동안 새로운 프레임워크를 만드는 것을 피하고 있었습니다. 처음에는 **FastAPI**가 다루는 모든 기능을 여러 다른 프레임워크, 플러그인, 도구들을 사용해 해결하려고 했습니다.
여러 대안을 사용해 보며 다양한 도구에서 배운 점들을 모아 저와 개발팀에게 가장 적합한 방식을 찾았습니다.
하지만 어느 시점에는, 이전 도구들의 최고의 아이디어를 가져와 가능한 한 최선의 방식으로 조합하고, 이전에는 존재하지 않았던 언어 기능(Python 3.6+ type hints)을 사용해 이 모든 기능을 제공하는 무언가를 만드는 것 외에는 다른 선택지가 없었습니다.
예를 들어, 표준 :term:Python 타입 힌트 <type hints>에 기반하는 것이 이상적이라는 점이 명확했습니다.
</blockquote>
또한, 이미 존재하는 표준을 활용하는 것이 가장 좋은 접근법이라 판단했습니다.
## 조사 { #investigation }
그래서 **FastAPI**의 코드를 작성하기 전에 몇 달 동안 OpenAPI, JSON Schema, OAuth2 명세를 연구하며 이들의 관계와 겹치는 부분, 차이점을 이해했습니다.
이전의 모든 대안을 사용해 보면서, 각 도구로부터 배울 기회를 얻었고, 아이디어를 가져와 제가 일해온 개발 팀들과 저 자신에게 가장 적합하다고 찾은 방식으로 조합할 수 있었습니다.
---
예를 들어, 이상적으로는 표준 Python 타입 힌트에 기반해야 한다는 점이 분명했습니다.
## 디자인
또한, 가장 좋은 접근법은 이미 존재하는 표준을 사용하는 것이었습니다.
그 후, **FastAPI** 사용자가 될 개발자로서 사용하고 싶은 개발자 "API"를 디자인했습니다.
그래서 **FastAPI**의 코딩을 시작하기도 전에, OpenAPI, JSON Schema, OAuth2 등과 같은 명세를 몇 달 동안 공부했습니다. 이들의 관계, 겹치는 부분, 차이점을 이해하기 위해서였습니다.
[Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)에 따르면 약 80%의 Python 개발자가 PyCharm, VS Code, Jedi 기반 편집기 등에서 개발합니다. 이 과정에서 여러 아이디어를 테스트했습니다.
## 디자인 { #design }
대부분의 다른 편집기도 유사하게 동작하기 때문에, **FastAPI**의 이점은 거의 모든 편집기에서 누릴 수 있습니다.
그 다음에는 (FastAPI를 사용하는 개발자로서) 사용자로서 갖고 싶었던 개발자 "API"를 디자인하는 데 시간을 썼습니다.
이 과정을 통해 코드 중복을 최소화하고, 모든 곳에서 자동 완성, 타입 검사, 에러 확인 기능이 제공되는 최적의 방식을 찾아냈습니다.
가장 인기 있는 Python 편집기들: PyCharm, VS Code, Jedi 기반 편집기에서 여러 아이디어를 테스트했습니다.
이 모든 것은 개발자들에게 최고의 개발 경험을 제공하기 위해 설계되었습니다.
약 80%의 사용자를 포함하는 최근 <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">Python Developer Survey</a>에 따르면 그렇습니다.
---
즉, **FastAPI**는 Python 개발자의 80%가 사용하는 편집기들로 특별히 테스트되었습니다. 그리고 대부분의 다른 편집기도 유사하게 동작하는 경향이 있으므로, 그 모든 이점은 사실상 모든 편집기에서 동작해야 합니다.
## 필요조건
그렇게 해서 코드 중복을 가능한 한 많이 줄이고, 어디서나 자동 완성, 타입 및 에러 검사 등을 제공하는 최선의 방법을 찾을 수 있었습니다.
여러 대안을 테스트한 후, [Pydantic](https://docs.pydantic.dev/)을 사용하기로 결정했습니다.
모든 개발자에게 최고의 개발 경험을 제공하는 방식으로 말입니다.
이후 저는 **Pydantic**이 JSON Schema와 완벽히 호환되도록 개선하고, 다양한 제약 조건 선언을 지원하며, 여러 편집기에서의 자동 완성과 타입 검사 기능을 향상하기 위해 기여했습니다.
## 필요조건 { #requirements }
또한, 또 다른 주요 필요조건이었던 [Starlette](https://www.starlette.dev/)에도 기여했습니다.
여러 대안을 테스트한 후, 장점 때문에 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a>을 사용하기로 결정했습니다.
---
그 후, JSON Schema를 완전히 준수하도록 하고, 제약 조건 선언을 정의하는 다양한 방식을 지원하며, 여러 편집기에서의 테스트를 바탕으로 편집기 지원(타입 검사, 자동 완성)을 개선하기 위해 기여했습니다.
## 개발
개발 과정에서, 또 다른 핵심 필요조건인 <a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>에도 기여했습니다.
**FastAPI**를 개발하기 시작할 즈음에는 대부분의 준비가 이미 완료된 상태였습니다. 설계가 정의되었고, 필요조건과 도구가 준비되었으며, 표준과 명세에 대한 지식도 충분했습니다.
## 개발 { #development }
---
**FastAPI** 자체를 만들기 시작했을 때쯤에는, 대부분의 조각들이 이미 갖춰져 있었고, 디자인은 정의되어 있었으며, 필요조건과 도구는 준비되어 있었고, 표준과 명세에 대한 지식도 명확하고 최신 상태였습니다.
## 미래
## 미래 { #future }
현시점에서 **FastAPI**가 많은 사람들에게 유용하다는 것이 명백해졌습니다.
이 시점에는, **FastAPI**가 그 아이디어와 함께 많은 사람들에게 유용하다는 것이 이미 분명합니다.
여러 용도에 더 적합한 도구로서 기존 대안보다 선호되고 있습니다.
이미 많은 개발자와 팀들이 **FastAPI**에 의존해 프로젝트를 진행 중입니다 (저와 제 팀도 마찬가지입니다).
많은 사용 사례에 더 잘 맞기 때문에 이전 대안들보다 선택되고 있습니다.
많은 개발자와 팀이 이미 자신의 프로젝트를 위해 **FastAPI**에 의존하고 있습니다(저와 제 팀도 포함해서요).
하지만 여전히, 앞으로 나올 개선 사항과 기능들이 많이 있습니다.
**FastAPI**의 미래는 밝습니다.
하지만 여전히 개선해야 할 점과 추가할 기능들이 많이 남아 있습니다.
**FastAPI**는 밝은 미래로 나아가고 있습니다.
그리고 [여러분의 도움](help-fastapi.md){.internal-link target=_blank}은 큰 힘이 됩니다.

View File

@@ -33,9 +33,6 @@ Use the following preferred translations when they apply in documentation prose:
- response (HTTP): 응답
- path operation: 경로 처리
- path operation function: 경로 처리 함수
- app: 애플리케이션
- command: 명령어
- burger: 햄버거 (NOT 버거)
### `///` admonitions

View File

@@ -1,503 +0,0 @@
# 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.
`script/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).
`script/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
Some text
///
/// note | Not
Some text
///
/// note | Teknik Detaylar
Some text
///
/// check | Ek bilgi
Some text
///
/// tip | İpucu
Some text
///
/// warning | Uyarı
Some text
///
/// danger | Tehlike
Some text
///
////
//// tab | Bilgi
Sekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir.
`script/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">External link</a>
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">Link to a style</a>
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">Link to a script</a>
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">Link to an image</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.
`script/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 - XML Web Token">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface - Paralel Sunucu Gateway Interface">PSGI</abbr>
### abbr bir açıklama verir { #the-abbr-gives-an-explanation }
* <abbr title="Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makinelerden oluşan bir grup.">cluster</abbr>
* <abbr 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 machine learning yöntemi">Deep Learning</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.
`script/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.
////
## 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.
`script/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.
////

View File

@@ -1,3 +1,3 @@
# Hakkında { #about }
# Hakkında
FastAPI, tasarımı, ilham kaynağı ve daha fazlası hakkında. 🤓

View File

@@ -1,247 +0,0 @@
# 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_py39.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_py39.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.

View File

@@ -1,41 +0,0 @@
# 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}.

View File

@@ -1,163 +0,0 @@
# 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_py39.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_py39.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_py39.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_py39.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, `yield` kullanan dependency'ler için `Depends(scope="function")` desteğini ekledi.
`Depends(scope="function")` kullanıldığında, `yield` sonrasındaki çıkış kodu, *path operation function* biter bitmez, response client'a geri gönderilmeden önce çalıştırılır.
`Depends(scope="request")` (varsayılan) kullanıldığında ise `yield` sonrasındaki çıkış kodu, response gönderildikten sonra çalıştırılır.
Daha fazlasını [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz.
### `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'ıı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'ıı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 Question</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 Handlers](../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.

View File

@@ -1,99 +0,0 @@
# 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_py39/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_py39/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_py39/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_py39/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.
///

View File

@@ -1,466 +0,0 @@
# 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_py39.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_py39.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",
// More stuff here
"servers": [
{
"url": "/api/v1"
}
],
"paths": {
// More stuff here
}
}
```
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_py39.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_py39.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_py39.py hl[4:7] *}
Şöyle bir OpenAPI şeması üretir:
```JSON hl_lines="5-7"
{
"openapi": "3.1.0",
// More stuff here
"servers": [
{
"url": "/api/v1"
},
{
"url": "https://stag.example.com",
"description": "Staging environment"
},
{
"url": "https://prod.example.com",
"description": "Production environment"
}
],
"paths": {
// More stuff here
}
}
```
/// 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_py39.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. ✨

View File

@@ -1,312 +0,0 @@
# Ö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 OpenAPInin 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 typea (`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 responseunuzun 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 responseu `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; tutorialda 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 FastAPInin 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_py39.py hl[2,7] *}
/// info | Bilgi
`response_class` parametresi, responseun "media type"ını tanımlamak için de kullanılır.
Bu durumda HTTP header `Content-Type`, `application/json` olarak ayarlanır.
Ve OpenAPIde de bu şekilde dokümante edilir.
///
/// tip | İpucu
`ORJSONResponse` yalnızca FastAPIde vardır, Starlettete 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_py39.py hl[2,7] *}
/// info | Bilgi
`response_class` parametresi, responseun "media type"ını tanımlamak için de kullanılır.
Bu durumda HTTP header `Content-Type`, `text/html` olarak ayarlanır.
Ve OpenAPIde 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 responseu override edebilirsiniz.
Yukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir:
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
/// warning | Uyarı
*path operation function*ınızın doğrudan döndürdüğü bir `Response`, OpenAPIde 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.
///
### OpenAPIde Dokümante Et ve `Response`u Override Et { #document-in-openapi-and-override-response }
Responseu fonksiyonun içinden override etmek ama aynı zamanda OpenAPIde "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_py39.py hl[7,21,23] *}
Bu örnekte `generate_html_response()` fonksiyonu, HTMLi 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 OpenAPIde 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 Starletteten 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` - Stringlerden 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_py39.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_py39.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-caseleri ele alma konusunda Pythonun built-in implementasyonu kadar dikkatli değildir.
///
{* ../../docs_src/custom_response/tutorial001_py39.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_py39.py hl[2,9] *}
---
Veya `response_class` parametresi içinde kullanabilirsiniz:
{* ../../docs_src/custom_response/tutorial006b_py39.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_py39.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
Bir async generator veya normal generator/iterator alır ve response bodyyi stream eder.
{* ../../docs_src/custom_response/tutorial007_py39.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 memoryye 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_py39.py hl[2,10:12,14] *}
1. Bu generator functiondı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 functiondan (`iterfile`) geliyormuş gibi yield eder.
Yani, içerdeki "üretme" (generating) işini başka bir şeye devreden bir generator functiondı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 headerlar; 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` headerlarını içerir.
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
`response_class` parametresini de kullanabilirsiniz:
{* ../../docs_src/custom_response/tutorial009b_py39.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, contenti `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır:
{* ../../docs_src/custom_response/tutorial009c_py39.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 JSONu 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_py39.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 }
OpenAPIde media typeı ve daha birçok detayı `responses` kullanarak da tanımlayabilirsiniz: [OpenAPIde Ek Response'lar](additional-responses.md){.internal-link target=_blank}.

View File

@@ -1,95 +0,0 @@
# 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 <abbr title="converting the data to a format that can be transmitted - veriyi aktarılabilir bir formata dönüştürme">serializing</abbr> etmeyi 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. 🔖

View File

@@ -1,165 +0,0 @@
# 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 requestleri 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 requestler arasında **paylaşılan** **resource**ları kurmak ve/veya sonrasında bunları **temizlemek** için çok faydalıdır. Örneğin bir veritabanı connection poolu 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.
Requestleri işlemek için kullanmak istediğiniz bazı **machine learning modelleriniz** olduğunu hayal edelim. 🤖
Aynı modeller requestler 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 requestler 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_py39.py hl[16,19] *}
Burada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionarye 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 **requestleri işlemeyi bitirdikten sonra**, *shutdown*dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resourceları 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 Dependenciese oldukça benzer.
{* ../../docs_src/events/tutorial003_py39.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_py39.py hl[1,13] *}
Pythonda **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 FastAPIye 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_py39.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 handlerları 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 handlerları (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"` eventi ile tanımlayın:
{* ../../docs_src/events/tutorial001_py39.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 handlerları tamamlanmadan uygulamanız request almaya başlamaz.
### `shutdown` eventi { #shutdown-event }
Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `"shutdown"` eventi ile tanımlayın:
{* ../../docs_src/events/tutorial002_py39.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 diske 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ı nerdler 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 Protocol</a>ün bir parçasıdır ve `startup` ile `shutdown` adında eventler tanımlar.
/// info | Bilgi
Starlette `lifespan` handlerları hakkında daha fazlasını <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette's Lifespan docs</a> içinde okuyabilirsiniz.
Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan statei nasıl yöneteceğinizi de kapsar.
///
## Alt Uygulamalar { #sub-applications }
🚨 Unutmayın: Bu lifespan eventleri (`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.

View File

@@ -1,208 +0,0 @@
# 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ıı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_py39.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_py39.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_py39.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_py39.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**. ✨

View File

@@ -1,21 +1,36 @@
# Gelişmiş Kullanıcı Rehberi { #advanced-user-guide }
# Gelişmiş Kullanıcı Rehberi
## Ek Özellikler { #additional-features }
## Ek Özellikler
Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası, **FastAPI**'ın tüm temel özelliklerini tanımanız için yeterli olmalıdır.
[Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası **FastAPI**'ın tüm ana özelliklerini tanıtmaya yetecektir.
Sonraki bölümlerde diğer seçenekleri, konfigürasyonları ve ek özellikleri göreceksiniz.
İlerleyen bölümlerde diğer seçenekler, konfigürasyonlar ve ek özellikleri göreceğiz.
/// tip | İpucu
Sonraki bölümler **mutlaka "gelişmiş" olmak zorunda değildir**.
Ve kullanım amacınıza bağlı olarak, çözüm bunlardan birinde olabilir.
Kullanım şeklinize bağlı olarak, çözümünüz bu bölümlerden birinde olabilir.
///
## Önce Tutorial'ı Okuyun { #read-the-tutorial-first }
## Önce Öğreticiyi Okuyun
Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nın çoğu özelliğini yine de kullanabilirsiniz.
[Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nın çoğu özelliğini kullanabilirsiniz.
Ve sonraki bölümler, onu zaten okuduğunuzu ve bu temel fikirleri bildiğinizi varsayar.
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>

View File

@@ -1,97 +0,0 @@
# İ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_py39.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_py39.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_py39.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.

View File

@@ -1,186 +0,0 @@
# 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">

View File

@@ -1,55 +0,0 @@
# 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_py39.py hl[9:13,36:53] *}
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">

View File

@@ -1,172 +0,0 @@
# 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_py39.py hl[6] *}
### operationId olarak *path operation function* adını kullanma { #using-the-path-operation-function-name-as-the-operationid }
APIlerinizin 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_py39.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.
///
## OpenAPIden 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_py39.py hl[6] *}
## Docstringden İleri Düzey Açıklama { #advanced-description-from-docstring }
OpenAPI için, bir *path operation function*ın docstringinden 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 responseu ile ilgili metadatayı tanımlar.
Ek responseları; modelleri, status codeları vb. ile birlikte ayrıca da tanımlayabilirsiniz.
Dokümantasyonda bununla ilgili ayrı bir bölüm var; [OpenAPIde 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 metadatayı 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 Object</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 responselar tanımlamanız gerekiyorsa, bunu yapmanın daha pratik yolu [OpenAPIde 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 Extensions](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_py39.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 OpenAPIyi (APInizde `/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 FastAPInin otomatik özelliklerini kullanmadan requesti kendi kodunuzla okuyup doğrulamaya karar verebilirsiniz; ancak yine de OpenAPI şemasında requesti tanımlamak isteyebilirsiniz.
Bunu `openapi_extra` ile yapabilirsiniz:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
Bu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak <abbr title="converted from some plain format, like bytes, into Python objects - bytes gibi düz bir formattan Python nesnelerine dönüştürme">parsed</abbr> bile edilmiyor; 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 Schemayı 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, FastAPInin 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_py39.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 Schemayı manuel üretmek üzere bir Pydantic model kullanmaya devam ediyoruz.
Ardından requesti doğrudan kullanıp bodyyi `bytes` olarak çıkarıyoruz. Bu da FastAPInin 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_py39.py hl[24:31] *}
/// tip | İpucu
Burada aynı Pydantic modeli tekrar kullanıyoruz.
Aynı şekilde, başka bir yöntemle de doğrulama yapabilirdik.
///

View File

@@ -1,31 +0,0 @@
# 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_py39.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.

View File

@@ -1,51 +0,0 @@
# 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_py39.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_py39.py hl[10:12] *}
/// tip | İpucu
`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.

View File

@@ -1,65 +0,0 @@
# 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 Compatible 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_py39.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 [Additional Responses in OpenAPI](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.

View File

@@ -1,41 +0,0 @@
# 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_py39.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_py39.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.

View File

@@ -1,107 +0,0 @@
# HTTP Basic Auth { #http-basic-auth }
En basit senaryolarda HTTP Basic Auth kullanabilirsiniz.
HTTP Basic Authta 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_py39.py hl[4,8,12] *}
URLyi 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 (İngilizcedeki 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_py39.py hl[1,12:24] *}
Bu, kabaca şuna benzer olurdu:
```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# Return some error
...
```
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 stringin 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 stringin 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" responseunu 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 }
Credentialları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_py39.py hl[26:30] *}

View File

@@ -1,6 +1,6 @@
# Gelişmiş Güvenlik { #advanced-security }
# Gelişmiş Güvenlik
## Ek Özellikler { #additional-features }
## Ek Özellikler
[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.
@@ -8,12 +8,12 @@
Sonraki bölümler **mutlaka "gelişmiş" olmak zorunda değildir**.
Ve kullanım durumunuza göre, çözüm bu bölümlerden birinde olabilir.
Kullanım şeklinize bağlı olarak, çözümünüz bu bölümlerden birinde olabilir.
///
## Önce Öğreticiyi Okuyun { #read-the-tutorial-first }
## Önce Öğreticiyi Okuyun
Sonraki bölümler, ana [Tutorial - User Guide: Security](../../tutorial/security/index.md){.internal-link target=_blank} sayfasını zaten okuduğunuzu varsayar.
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.
Hepsi aynı kavramlara dayanır, ancak bazı ek işlevselliklere izin verir.
Bu bölümler aynı kavramlara dayanır, ancak bazı ek işlevsellikler sağlar.

View File

@@ -1,274 +0,0 @@
# 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.
Ancak 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şık 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.

View File

@@ -1,302 +0,0 @@
# 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_py39.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_py39.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_py39/config.py *}
Ve ardından bunu `main.py` dosyasında kullanabilirsiniz:
{* ../../docs_src/settings/app01_py39/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_py39/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_py39/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_py39/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_py39/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_py39/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_py39/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.

View File

@@ -1,67 +0,0 @@
# 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 pathin 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_py39.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_py39.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` pathine mount edilecektir:
{* ../../docs_src/sub_applications/tutorial001_py39.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ıı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 pathini 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ı [Behind a Proxy](behind-a-proxy.md){.internal-link target=_blank} bölümünde öğreneceksiniz.

View File

@@ -1,126 +0,0 @@
# Ş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_py39.py hl[4,11,15:18] *}
/// note | Not
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 | İpucu
`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.

View File

@@ -1,53 +0,0 @@
# 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.
///

View File

@@ -1,12 +0,0 @@
# 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_py39.py hl[9:15,18,27:28,30:32,41:43] *}
Bu konuda daha fazla ayrıntıyı resmi Starlette dokümantasyon sitesindeki ["Running lifespan in tests in the official Starlette documentation site."](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_py39.py hl[9:12,20:24] *}

View File

@@ -1,13 +1,13 @@
# WebSockets'i Test Etmek { #testing-websockets }
# WebSockets'i Test Etmek
WebSockets'i test etmek için aynı `TestClient`'ı kullanabilirsiniz.
WebSockets testi yapmak için `TestClient`'ı kullanabilirsiniz.
Bunun için `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanırsınız:
Bu işlem için, `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanabilirsiniz:
{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
/// note | Not
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.
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.
///

View File

@@ -1,56 +0,0 @@
# 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_py39.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.
///

View File

@@ -1,186 +0,0 @@
# 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_py39.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_py39.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_py39.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_py39.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>.

View File

@@ -1,32 +1,32 @@
# WSGI'yi Dahil Etme - Flask, Django ve Diğerleri { #including-wsgi-flask-django-others }
# WSGI - Flask, Django ve Daha Fazlasını FastAPI ile Kullanma
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 mount edebilirsiniz.
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.
Bunun için `WSGIMiddleware`'ı kullanabilir ve bunu WSGI uygulamanızı (örneğin Flask, Django vb.) sarmalamak için kullanabilirsiniz.
Bunun için `WSGIMiddleware` ile Flask, Django vb. WSGI uygulamanızı sarmalayabilir ve FastAPI'ya bağlayabilirsiniz.
## `WSGIMiddleware` Kullanımı { #using-wsgimiddleware }
## `WSGIMiddleware` Kullanımı
`WSGIMiddleware`'ı import etmeniz gerekir.
`WSGIMiddleware`'ı projenize dahil edin.
Ardından WSGI (örn. Flask) uygulamasını middleware ile sarmalayın.
Ardından WSGI (örneğin Flask) uygulamanızı middleware ile sarmalayın.
Ve sonra bunu bir path'in altına mount edin.
Son olarak da bir yol altında bağlama işlemini gerçekleştirin.
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
## Kontrol Edelim { #check-it }
## Kontrol Edelim
Artık `/v1/` path'i altındaki her request Flask uygulaması tarafından işlenecektir.
Artık `/v1/` yolunun altındaki her istek 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 response'u 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 yanıtı göreceksiniz:
```txt
Hello, World from Flask!
```
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:
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:
```JSON
{

View File

@@ -1,34 +1,34 @@
# Kıyaslamalar { #benchmarks }
# Kıyaslamalar
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).
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. (*)
Fakat kıyaslamaları ve karşılaştırmaları incelerken şunları aklınızda bulundurmalısınız.
## Kıyaslamalar ve Hız { #benchmarks-and-speed }
## Kıyaslamalar ve Hız
Kıyaslamalara baktığınızda, farklı türlerdeki birk aracın eşdeğermiş gibi karşılaştırıldığını görmek yaygındır.
Kıyaslamaları incelediğinizde, farklı özelliklere sahip arların eşdeğer olarak karşılaştırıldığını yaygın bir şekilde görebilirsiniz.
Ö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, elde edeceği performans o kadar iyi olur. Ayrıca kıyaslamaların çoğu, aracın sağladığı ek özellikleri test etmez.
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.
Hiyerarşi şöyledir:
* **Uvicorn**: bir ASGI sunucusu
* **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'ü
* **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ü
* **Uvicorn**:
* 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.
* 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.
* **Starlette**:
* 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.
* 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.
* **FastAPI**:
* 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.
* 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.

View File

@@ -1,24 +1,13 @@
# Bulut Sağlayıcılar Üzerinde FastAPI Yayınlama { #deploy-fastapi-on-cloud-providers }
# FastAPI Uygulamasını Bulut Sağlayıcılar Üzerinde Yayınlama
FastAPI uygulamanızı yayınlamak için neredeyse **herhangi bir bulut sağlayıcıyı** kullanabilirsiniz.
FastAPI uygulamasını yayınlamak için hemen hemen **herhangi bir bulut sağlayıcıyı** kullanabilirsiniz.
Çoğu durumda, ana bulut sağlayıcıların FastAPI'yi onlarla birlikte yayınlamak için kılavuzları vardır.
Büyük bulut sağlayıcıların çoğu FastAPI uygulamasını yayınlamak için kılavuzlara sahiptir.
## FastAPI Cloud { #fastapi-cloud }
## Bulut Sağlayıcılar - Sponsorlar
**<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.
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.
Bir API'yi minimum çabayla **oluşturma**, **yayınlama** ve **erişme** sürecini kolaylaştırır.
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.
FastAPI ile uygulama geliştirirken elde edilen aynı **geliştirici deneyimini**, onları buluta **yayınlamaya** da taşır. 🎉
FastAPI Cloud, *FastAPI and friends*ı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>
Bu hizmetleri denemek ve kılavuzlarını incelemek isteyebilirsiniz.

View File

@@ -1,321 +0,0 @@
# 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.

View File

@@ -1,620 +0,0 @@
# 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.9
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 typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
### Dockerfile { #dockerfile }
Şimdi aynı proje dizininde `Dockerfile` adlı bir dosya oluşturun ve içine şunları yazın:
```{ .dockerfile .annotate }
# (1)!
FROM python:3.9
# (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">Why do my services take 10 seconds to recreate or stop?</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):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
## 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):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## 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.9
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 }
Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>'ınız varsa, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **cluster seviyesinde** ele almak istersiniz.
Kubernetes 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.9
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). 😎

View File

@@ -1,65 +0,0 @@
# 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*ı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. 🤓

View File

@@ -1,231 +0,0 @@
# HTTPS Hakkında { #about-https }
HTTPSin 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 **HTTPSin 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, **HTTPnin bir katman altıdır**.
* Dolayısıyla **sertifika ve şifreleme** işlemleri **HTTPden ö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, HTTPden ö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) serverdaki **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, serverda (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ı serverda ç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 clienta geri göndermek. Bu servera ç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 Encryptten ö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**.
Domainler 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 APInin 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 <abbr title="That doesn't change - Bu değişmez">fixed</abbr> 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ı HTTPSten ç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 serverları tarayıcıya belirli bir **IP adresini** kullanmasını söyler. Bu, DNS serverları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 }
Serverda, belirli bir **IP adresindeki** belirli bir **portu** dinleyen **yalnızca bir process** olabilir. Aynı IP adresinde başka portları dinleyen başka processler 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; TLSin 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 requesttir.
<img src="/img/deployment/https/https04.drawio.svg">
### Requestin Şifresini Çözme { #decrypt-the-request }
TLS Termination Proxy, üzerinde anlaşılan şifrelemeyi kullanarak **requestin şifresini çözer** ve **düz (şifresi çözülmüş) HTTP request**i uygulamayı çalıştıran processe iletir (ör. FastAPI uygulamasını çalıştıran Uvicorn processi).
<img src="/img/deployment/https/https05.drawio.svg">
### HTTP Response { #http-response }
Uygulama requesti işler ve TLS Termination Proxyye **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 responseu, 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ı responseun geçerli olduğunu ve doğru kriptografik anahtarla şifrelendiğini doğrular vb. Ardından **responseun şifresini çözer** ve işler.
<img src="/img/deployment/https/https07.drawio.svg">
Client (tarayıcı), responseun doğru serverdan geldiğini bilir; çünkü daha önce **HTTPS sertifikası** ile üzerinde anlaştıkları kriptografiyi kullanmaktadır.
### Birden Fazla Uygulama { #multiple-applications }
Aynı serverda (veya serverlarda) ö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/processler, 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 requestleri 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 domaini **"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 APIlerini desteklemesi gerekir. Dolayısıyla kullandığınız DNS providera 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 Proxynin sertifika yenileme sürecini de yönetmesinin neden çok faydalı olduğunun sebeplerinden biridir.
* Aksi halde TLS Termination Proxyyi 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 Proxyyi 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 HTTPSi yönetecek **ayrı bir sistem** istemenizin başlıca nedenlerinden biridir.
## Proxy Forwarded Headers { #proxy-forwarded-headers }
HTTPSi 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 requesti **application server**a iletmeden önce, requestin proxy tarafından **forward** edildiğini application servera bildirmek için bazı HTTP headerlarını anlık olarak ekler.
/// note | Teknik Detaylar
Proxy headerları ş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 headerlara güvenmez.
Ancak **application server**ı, **proxy**nin gönderdiği *forwarded* headerlarına güvenecek şekilde yapılandırabilirsiniz. FastAPI CLI kullanıyorsanız, hangi IPlerden gelen *forwarded* headerlara 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ığı IPden request alacağı için `--forwarded-allow-ips="*"` ayarlayıp gelen tüm IPlere güvenmesini sağlayabilirsiniz.
Bu sayede uygulama kendi public URLinin ne olduğunu, HTTPS kullanıp kullanmadığını, domaini vb. bilebilir.
Bu, örneğin redirectleri 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. 🔒

View File

@@ -1,23 +1,21 @@
# Deployment { #deployment }
# Deployment (Yayınlama)
**FastAPI** uygulamasını deploy etmek nispeten kolaydır.
**FastAPI** uygulamasını deploy etmek oldukça kolaydır.
## Deployment Ne Anlama Gelir? { #what-does-deployment-mean }
## Deployment Ne Anlama 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 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 **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.
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.
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.
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.
## Deployment Stratejileri { #deployment-strategies }
## Deployment Stratejileri
Kullanım durumunuza ve kullandığınız araçlara bağlı olarak bunu yapmanın birkaç yolu vardır.
Kullanım durumunuza ve kullandığınız araçlara bağlı olarak bir kaç farklı yol izleyebilirsiniz.
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.
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.
**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 bunu yapmaya yönelik bazı teknikleri göreceksiniz. ✨
Sonraki bölümlerde akılda tutulması gereken diğer ayrıntıları ve yayınlama tekniklerinden bazılarını göreceksiniz. ✨

View File

@@ -1,157 +0,0 @@
# 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">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 [virtual environment](../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
*ı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. 🚀

View File

@@ -1,139 +0,0 @@
# 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ıı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. ✨

View File

@@ -1,93 +0,0 @@
# 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
```

View File

@@ -1,298 +0,0 @@
# 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, Pythonun **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 }
Pythona 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>
////
## Pythonda env var Okuma { #read-env-vars-in-python }
Ortam değişkenlerini Pythonun **dışında** (terminalde veya başka bir yöntemle) oluşturup daha sonra **Pythonda 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">The Twelve-Factor App: 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ü Pythonun 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, Pythonda 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 stringdir; Linux ve macOSte dizinler iki nokta üst üste `:` ile, Windowsta 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 }
Pythonu kurarken, `PATH` ortam değişkenini güncellemek isteyip istemediğiniz sorulabilir.
//// tab | Linux, macOS
Diyelim ki Pythonu 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 Pythonu 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 Pythonda 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">Wikipedia for Environment Variable</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.

View File

@@ -1,75 +0,0 @@
# 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">&apos;/home/user/code/awesomeapp&apos;</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.
///

View File

@@ -1,256 +0,0 @@
# 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! 🚀

View File

@@ -1,17 +0,0 @@
# 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_py39.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.
///

View File

@@ -1,56 +0,0 @@
# 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_py39.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"
}
```

View File

@@ -1,70 +0,0 @@
# 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_py39.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_py39.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_py39.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.

View File

@@ -1,185 +0,0 @@
# Ö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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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.

View File

@@ -1,109 +0,0 @@
# Ö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] *}

View File

@@ -1,80 +0,0 @@
# 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_py39.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_py39.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_py39.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_py39.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_py39.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">

View File

@@ -1,39 +1,39 @@
# Genel - Nasıl Yapılır - Tarifler { #general-how-to-recipes }
# Genel - Nasıl Yapılır - Tarifler
Bu sayfada genel veya sık sorulan sorular için dokümantasyonun diğer bölümlerine çeşitli yönlendirmeler bulunmaktadır.
Bu sayfada genel ve sıkça sorulan sorular için dokümantasyonun diğer sayfalarına yönlendirmeler bulunmaktadır.
## Veri Filtreleme - Güvenlik { #filter-data-security }
## Veri Filtreleme - Güvenlik
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.
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.
## Dokümantasyon Etiketleri - OpenAPI { #documentation-tags-openapi }
## Dokümantasyon Etiketleri - OpenAPI
*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.
*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.
## Dokümantasyon Özeti ve Açıklaması - OpenAPI { #documentation-summary-and-description-openapi }
## Dokümantasyon Özeti ve Açıklaması - OpenAPI
*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.
*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.
## Dokümantasyon Yanıt Açıklaması - OpenAPI { #documentation-response-description-openapi }
## Yanıt Açıklaması Dokümantasyonu - OpenAPI
Dokümantasyon arayüzünde gösterilen responseı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.
Dokümantasyon arayüzünde yer alan yanıtı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ümantasyonda Bir *Path Operation*'ı Kullanımdan Kaldırma - OpenAPI { #documentation-deprecate-a-path-operation-openapi }
## *Yol Operasyonunu* Kullanımdan Kaldırma - OpenAPI
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.
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.
## Herhangi Bir Veriyi JSON Uyumlu Hale Getirme { #convert-any-data-to-json-compatible }
## Herhangi Bir Veriyi JSON Uyumlu Hale Getirme
Herhangi bir veriyi JSON uyumlu hale getirmek için, [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} dokümantasyonunu okuyun.
Herhangi bir veriyi JSON uyumlu hale getirmek için, [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} sayfasını okuyun.
## OpenAPI Meta Verileri - Dokümantasyon { #openapi-metadata-docs }
## OpenAPI Meta Verileri - Dokümantasyon
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 ş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.
## OpenAPI Özel URL { #openapi-custom-url }
## OpenAPI Bağlantı Özelleştirme
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 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 Dokümantasyon URL'leri { #openapi-docs-urls }
## OpenAPI Dokümantasyon Bağlantıları
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.
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.

View File

@@ -1,60 +0,0 @@
# 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_py39.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.

View File

@@ -1,13 +1,13 @@
# Nasıl Yapılır - Tarifler { #how-to-recipes }
# Nasıl Yapılır - Tarifler
Burada **çeşitli konular** hakkında farklı tarifler veya "nasıl yapılır" kılavuzları göreceksiniz.
Burada çeşitli konular hakkında farklı tarifler veya "nasıl yapılır" kılavuzları yer alıyor.
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.
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.
Projeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve inceleyin; aksi halde muhtemelen bunları atlayabilirsiniz.
Projeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve inceleyin, aksi halde bunları atlayabilirsiniz.
/// tip | İpucu
**FastAPI**'ı 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.
**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.
///

View File

@@ -1,135 +0,0 @@
# 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 v2nin içinden Pydantic v1e (`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 v2nin 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ı (separated)** 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. 🚶

View File

@@ -1,102 +0,0 @@
# 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>

View File

@@ -1,7 +0,0 @@
# 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. 😎

View File

@@ -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/tr"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
<a href="https://fastapi.tiangolo.com"><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 kolay, kodlaması hızlı, production'a hazır</em>
<em>FastAPI framework, yüksek performanslı, öğrenmesi oldukça kolay, kodlaması hızlı, kullanıma 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,65 +27,59 @@
---
**Dokümantasyon**: <a href="https://fastapi.tiangolo.com/tr" target="_blank">https://fastapi.tiangolo.com</a>
**Dokümantasyon**: <a href="https://fastapi.tiangolo.com" 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'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.
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.
Temel özellikleri şunlardı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. *
* **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. *
* **Daha az hata**: İnsan (geliştirici) kaynaklı hataları yaklaşık %40 azaltır. *
* **Sezgisel**: Harika bir editör desteği. Her yerde <abbr title="auto-complete, autocompletion, IntelliSense olarak da bilinir">Completion</abbr>. 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>.
* **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>.
<small>* tahmin, production uygulamalar geliştiren dahili bir geliştirme ekibinin yaptığı testlere dayanmaktadır.</small>
<small>* ilgili kanılar, dahili geliştirme ekibinin geliştirdikleri ürünlere yaptıkları testlere dayanmaktadır.</small>
## Sponsorlar { #sponsors }
## Sponsorlar
<!-- 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 }
{% if 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 { #opinions }
## Görüşler
"_[...] 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._"
"_[...] 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._"
<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>
---
"_**predictions** almak için sorgulanabilecek bir **REST** server oluşturmak amacıyla **FastAPI** kütüphanesini benimsedik. [Ludwig için]_"
"_**FastAPI**'ı **tahminlerimiz**'i sorgulanabilir hale getirecek bir **REST** sunucu oluşturmak in benimsedik/kullanmaya başladık._"
<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önetimi** orkestrasyon framework'ümüz: **Dispatch**'in open-source sürümünü duyurmaktan memnuniyet duyar! [**FastAPI** ile geliştirildi]_"
"_**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ı.]_"
<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>
@@ -97,68 +91,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="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>
<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>
---
"_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 [...]_"
"_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. [...]_"
"_**API**'larımız için **FastAPI**'a geçtik [...] Bence hoşunuza gidecek [...]_"
"_**API** servislerimizi **FastAPI**'a taşıdık [...] Sizin de beğeneceğinizi düşünüyoruz. [...]_"
<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>
---
"_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._"
"_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._"
<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>
---
## 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 }
## Komut Satırı Uygulamalarının FastAPI'ı: **Typer**
<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>
Web API yerine terminalde kullanılacak bir <abbr title="Command Line Interface">CLI</abbr> uygulaması geliştiriyorsanız <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>'a göz atın.
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.
**Typer**, FastAPI'ın küçük kardeşi. Ve hedefi CLI'ların **FastAPI'ı** olmak. ⌨️ 🚀
**Typer** kısaca FastAPI'ın küçük kardeşi. Ve hedefi komut satırı uygulamalarının **FastAPI'ı** olmak. ⌨️ 🚀
## Gereksinimler { #requirements }
## Gereksinimler
FastAPI iki devin omuzları üstünde duruyor:
* 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>.
* 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>.
## 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:
## Kurulum
<div class="termy">
```console
$ pip install "fastapi[standard]"
$ pip install fastapi
---> 100%
```
</div>
**Not**: Tüm terminallerde çalıştığından emin olmak için `"fastapi[standard]"` ifadesini tırnak içinde yazdığınızdan emin olun.
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.
## Örnek { #example }
<div class="termy">
### Oluşturalım { #create-it }
```console
$ pip install "uvicorn[standard]"
Şu içerikle `main.py` adında bir dosya oluşturalım:
---> 100%
```
</div>
## Örnek
### Kodu Oluşturalım
* `main.py` adında bir dosya oluşturup içine şu kodu yapıştıralım:
```Python
from typing import Union
@@ -179,9 +175,9 @@ def read_item(item_id: int, q: Union[str, None] = None):
```
<details markdown="1">
<summary>Ya da <code>async def</code> kullanalım...</summary>
<summary>Ya da <code>async def</code>...</summary>
Eğer kodunuz `async` / `await` kullanıyorsa, `async def` kullanın:
Eğer kodunuzda `async` / `await` varsa, `async def` kullanalım:
```Python hl_lines="9 14"
from typing import Union
@@ -203,35 +199,22 @@ async def read_item(item_id: int, q: Union[str, None] = None):
**Not**:
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.
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.
</details>
### Çalıştıralım { #run-it }
### Kodu Çalıştıralım
Sunucuyu şu komutla çalıştıralım:
Sunucuyu aşağıdaki komutla çalıştıralım:
<div class="termy">
```console
$ fastapi dev main.py
$ uvicorn main:app --reload
╭────────── FastAPI CLI - Development mode ───────────╮
│ │
│ Serving at: http://127.0.0.1:8000 │
│ │
│ API docs: http://127.0.0.1:8000/docs │
│ │
│ Running in development mode, for production use: │
│ │
│ fastapi run │
│ │
╰─────────────────────────────────────────────────────╯
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [2248755] using WatchFiles
INFO: Started server process [2248757]
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
@@ -239,54 +222,54 @@ INFO: Application startup complete.
</div>
<details markdown="1">
<summary><code>fastapi dev main.py</code> komutu hakkında...</summary>
<summary><code>uvicorn main:app --reload</code> komutuyla ilgili...</summary>
`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.
`uvicorn main:app` komutunu şu şekilde açıklayabiliriz:
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.
* `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.
</details>
### Kontrol Edelim { #check-it }
### Şimdi de Kontrol Edelim
Tarayıcınızda şu bağlantıyıı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>.
Tarayıcımızda şu bağlantıyı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>.
Şu JSON response'unu göreceksiniz:
Aşağıdaki gibi bir JSON yanıtıyla karşılaşacağız:
```JSON
{"item_id": 5, "q": "somequery"}
```
Artık şunları yapan bir API oluşturdunuz:
Az önce oluşturduğumuz API:
* `/` 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.
* `/` 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.
### Etkileşimli API dokümantasyonu { #interactive-api-docs }
### Etkileşimli API Dokümantasyonu
Ş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.
Ş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.
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):
<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:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternatif API dokümantasyonu { #alternative-api-docs }
### Alternatif API Dokümantasyonu
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.
Ş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.
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):
<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan otomatik dokümantasyonu göreceğiz:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Örneği Güncelleyelim { #example-upgrade }
## Örneği Güncelleyelim
Şimdi `main.py` dosyasını, `PUT` request'iyle gelen bir body alacak şekilde değiştirelim.
Şimdi `main.py` dosyasını, `PUT` isteğiyle birlikte bir gövde alacak şekilde değiştirelim.
Body'yi Pydantic sayesinde standart Python tiplerini kullanarak tanımlayalım.
<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
@@ -318,248 +301,174 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
`fastapi dev` server'ı otomatik olarak yeniden yüklemelidir.
Sunucu otomatik olarak yeniden başlamış olmalı (çünkü yukarıda `uvicorn` komutuyla birlikte `--reload` parametresini kullandık).
### Etkileşimli API dokümantasyonu güncellemesi { #interactive-api-docs-upgrade }
### Etkileşimli API Dokümantasyonundaki Değişimi Görelim
Ş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.
Ş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.
* Etkileşimli API dokümantasyonu, yeni body dahil olacak şekilde otomatik olarak güncellenecek:
* Etkileşimli API dokümantasyonu, yeni gövdede dahil olmak üzere otomatik olarak güncellenmiş olacak:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* "Try it out" butonuna tıklayın; parametreleri doldurmanıza ve API ile doğrudan etkileşime girmenize olanak sağlar:
* "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 gmemize imkan sağlayacak:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* 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:
* Ş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:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Alternatif API dokümantasyonu güncellemesi { #alternative-api-docs-upgrade }
### Alternatif API Dokümantasyonundaki Değişimi Görelim
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.
Ş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.
* Alternatif dokümantasyon da yeni query parameter ve body'yi yansıtacak:
* Alternatif dokümantasyonda yaptığımız değişiklikler ile birlikte yeni sorgu parametresi ve gövde bilgisi ile güncelemiş olacak:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Özet { #recap }
### Özet
Özetle, parametrelerin, body'nin vb. type'larını fonksiyon parametreleri olarak **bir kere** tanımlarsınız.
Özetlemek gerekirse, parametrelerin, gövdenin, vb. veri tiplerini fonksiyon parametreleri olarak **bir kere** tanımlıyoruz.
Bunu standart modern Python tipleriyle yaparsınız.
Bu işlemi standart modern Python tipleriyle yapıyoruz.
Yeni bir syntax, belirli bir kütüphanenin method'larını ya da class'larını vb. öğrenmeniz gerekmez.
Yeni bir sözdizimi yapısını, bir kütüphane özel metod veya sınıfları öğrenmeye gerek yoktur.
Sadece standart **Python**.
Hepsi sadece **Python** standartlarına dayalıdır.
Örneğin bir `int` için:
Örnek olarak, `int` tanımlamak için:
```Python
item_id: int
```
ya da daha karmaşık bir `Item` modeli için:
ya da daha kompleks herhangi bir python modelini tanımlayabiliriz, örneğin `Item` modeli için:
```Python
item: Item
```
...ve bu tek tanımla şunları elde edersiniz:
...ve sadece kısa bir parametre tipi belirterek elde ettiklerimiz:
* Ş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 <abbr title="serialization, parsing, marshalling olarak da bilinir">Dönüşümü</abbr>: network'ten gelen veriyi Python verisine ve type'larına çevirir. Şunlardan okur:
* 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ü</abbr> aşağıdaki veri tiplerini kullanarak gerçekleştirir:
* JSON.
* Path parameter'lar.
* Query parameter'lar.
* Cookie'ler.
* Header'lar.
* Form'lar.
* File'lar.
* Çıktı verisinin <abbr title="serialization, parsing, marshalling olarak da bilinir">Dönüşümü</abbr>: 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.
* Yol parametreleri.
* Sorgu parametreleri.
* Çerezler.
* Headers.
* Formlar.
* Dosyalar.
* Giden verinin <abbr title="Dönüşüm: serialization, parsing, marshalling olarak da biliniyor">dönüşümü</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.
* Veritabanı modelleri.
* ...ve daha fazlası.
* 2 alternatif kullanıcı arayüzü dahil otomatik etkileşimli API dokümantasyonu:
* ve çok daha fazlası...
* 2 alternatif kullanıcı arayüzü dahil olmak üzere, otomatik etkileşimli API dokümantasyonu sağlar:
* Swagger UI.
* ReDoc.
---
Önceki kod örneğine dönersek, **FastAPI** şunları yapacaktır:
Az önceki örneğe geri dönelim, **FastAPI**'ın yapacaklarına bir bakış atalım:
* `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:
* `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:
* Etkileşimli dokümantasyon sistemleri.
* Birçok dil için otomatik client kodu üretim sistemleri.
* 2 etkileşimli dokümantasyon web arayüzünü doğrudan sunar.
* Bir çok programlama dili için otomatik istemci kodu üretim sistemleri.
* İki ayrı etkileşimli dokümantasyon arayüzünü doğrudan sağlayacak.
---
Daha yolun başındayız, ama bunun nasıl çalıştığı hakkında fikri kaptınız.
Daha yeni başladık ama çalışma mantığını çoktan anlamış oldunuz.
Şu satırı değiştirmeyi deneyin:
Şimdi aşağıdaki satırı değiştirmeyi deneyin:
```Python
return {"item_name": item.name, "item_id": item_id}
```
...şundan:
...bundan:
```Python
... "item_name": item.name ...
```
...şuna:
...buna:
```Python
... "item_price": item.price ...
```
...ve editörünüzün alanları otomatik tamamladığını ve type'larını bildiğini görün:
...ve editörünün veri tiplerini bildiğini ve otomatik tamamladığını göreceksiniz:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
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.
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.
**Spoiler alert**: öğretici - kullanıcı rehberi şunları içerir:
**Spoiler**: Öğretici - Kullanıcı rehberi şunları içerir:
* **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 **<abbr title="components, resources, providers, services, injectables olarak da bilinir">Dependency Injection</abbr>** 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ıırı kolay testler
* **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ırı kolay testler.
* **CORS**
* **Cookie Sessions**
* ...ve daha fazlası.
### Uygulamanızı deploy edin (opsiyonel) { #deploy-your-app-optional }
## Performans
İ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. 🚀
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.
Zaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek bir komutla deploy edebilirsiniz.
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>.
Deploy etmeden önce, giriş yaptığınızdan emin olun:
## Opsiyonel Gereksinimler
<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:
Pydantic tarafında kullanılan:
* <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 <abbr title="HTTP request'inden gelen string'i Python verisine dönüştürme">"parsing"</abbr> 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[standard]"` yerine `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 kullanılacak ek type'lar 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.
Ek opsiyonel FastAPI bağımlılıkları:
Starlette tarafında kullanılan:
* <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.
* <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).
## Lisans { #license }
Hem FastAPI hem de Starlette tarafından kullanılan:
Bu proje MIT lisansı şartları altında lisanslanmıştır.
* <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.

View File

@@ -1,5 +1,5 @@
# Öğren { #learn }
# Öğren
**FastAPI** öğrenmek için giriş bölümleri ve öğreticiler burada yer alıyor.
Burayı, bir **kitap**, bir **kurs**, FastAPI öğrenmenin **resmi** ve önerilen yolu olarak düşünebilirsiniz. 😎
Burayı, bir **kitap**, bir **kurs**, ve FastAPI öğrenmenin **resmi** ve önerilen yolu olarak düşünülebilirsiniz. 😎

View File

@@ -1,28 +1,84 @@
# Full Stack FastAPI Şablonu { #full-stack-fastapi-template }
# Proje oluşturma - Şablonlar
Ş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. 🏁
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.
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.
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.
GitHub Repository: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
## Full Stack FastAPI PostgreSQL
## Full Stack FastAPI Şablonu - Teknoloji Yığını ve Özellikler { #full-stack-fastapi-template-technology-stack-and-features }
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>
- ⚡ 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).
### 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.

View File

@@ -1,74 +1,76 @@
# Python Tiplerine Giriş { #python-types-intro }
# Python Veri Tiplerine Giriş
Python, isteğe bağlı "type hints" (diğer adıyla "type annotations") desteğine sahiptir.
Python isteğe bağlı olarak "tip belirteçlerini" destekler.
Bu **"type hints"** veya annotations, bir değişkenin <abbr title="örneğin: str, int, float, bool">type</abbr>'ını bildirmeye yarayan özel bir sözdizimidir.
**"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.
Değişkenleriniz için type bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.
Değişkenlerin tiplerini belirterek editör ve araçlardan daha fazla destek alabilirsiniz.
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.
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.
**FastAPI** tamamen bu type hints üzerine kuruludur; bunlar ona birçok avantaj ve fayda sağlar.
**FastAPI' nin** tamamı bu tür tip belirteçleri ile donatılmıştır ve birçok avantaj sağlamaktadır.
Ancak hiç **FastAPI** kullanmasanız bile, bunlar hakkında biraz öğrenmeniz size fayda sağlayacaktır.
**FastAPI** kullanmayacak olsanız bile tür belirteçleri hakkında bilgi edinmenizde fayda var.
/// note | Not
Eğer bir Python uzmanıysanız ve type hints hakkında her şeyi zaten biliyorsanız, sonraki bölüme geçin.
Python uzmanıysanız ve tip belirteçleri ilgili her şeyi zaten biliyorsanız, sonraki bölüme geçin.
///
## Motivasyon { #motivation }
## Motivasyon
Basit bir örnekle başlayalım:
Basit bir örnek ile başlayalım:
{* ../../docs_src/python_types/tutorial001_py39.py *}
{* ../../docs_src/python_types/tutorial001.py *}
Bu programı çalıştırınca şu çıktıyı alırsınız:
Programın çıktısı:
```
John Doe
```
Fonksiyon şunları yapar:
Fonksiyon sırayla şunları yapar:
* `first_name` ve `last_name` değerlerini alır.
* `title()` ile her birinin ilk harfini büyük harfe çevirir.
* Ortada bir boşluk olacak şekilde <abbr title="Hepsini, tek bir bütün olacak şekilde bir araya koyar. İçerikler ardışık şekilde yer alır.">Concatenates</abbr> eder.
* `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>.
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
### Düzenleyelim { #edit-it }
### Düzenle
Bu çok basit bir program.
Ama şimdi bunu sıfırdan yazdığınızı hayal edin.
Ama şimdi sıfırdan yazdığınızı hayal edin.
Bir noktada fonksiyon tanımını yazmaya başlamış olacaktınız, parametreler hazır...
Bir noktada fonksiyonun tanımına başlayacaktınız, parametreleri hazır hale getirdiniz...
Ama sonra "ilk harfi büyük harfe çeviren method"u çağırmanız gerekiyor.
Ama sonra "ilk harfi büyük harfe dönüştüren yöntemi" çağırmanız gerekir.
`upper` mıydı? `uppercase` miydi? `first_uppercase`? `capitalize`?
`upper` mıydı ? Yoksa `uppercase`' mi? `first_uppercase`? `capitalize`?
Sonra eski programcı dostuyla denersiniz: editör autocomplete.
Ardından, programcıların en iyi arkadaşı olan otomatik tamamlama ile denediniz.
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.
'first_name', ardından bir nokta ('.') yazıp otomatik tamamlamayı tetiklemek için 'Ctrl+Space' tuşlarına bastınız.
Ama ne yazık ki, işe yarar bir şey göremezsiniz:
Ancak, ne yazık ki, yararlı hiçbir şey elde edemediniz:
<img src="/img/python-types/image01.png">
### Tipleri ekleyelim { #add-types }
### Tipleri ekle
Önceki sürümden tek bir satırı değiştirelim.
Önceki sürümden sadece bir satırı değiştirelim.
Fonksiyonun parametreleri olan şu parçayı:
Tam olarak bu parçayı, işlevin parametrelerini değiştireceğiz:
```Python
first_name, last_name
```
şuna çevireceğiz:
ve bu hale getireceğiz:
```Python
first_name: str, last_name: str
@@ -76,55 +78,58 @@ Fonksiyonun parametreleri olan şu parçayı:
Bu kadar.
Bunlar "type hints":
İşte bunlar "tip belirteçleri":
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
Bu, aşağıdaki gibi default değerler bildirmekle aynı şey değildir:
Bu, aşağıdaki gibi varsayılan değerleri bildirmekle aynı şey değildir:
```Python
first_name="john", last_name="doe"
```
Bu farklı bir şey.
Bu tamamen farklı birşey
Eşittir (`=`) değil, iki nokta (`:`) kullanıyoruz.
İki nokta üst üste (`:`) kullanıyoruz , eşittir (`=`) değil.
Ve type hints eklemek, normalde onlarsız ne oluyorsa onu değiştirmez.
Normalde tip belirteçleri eklemek, kod üzerinde olacakları değiştirmez.
Ama şimdi, type hints ile o fonksiyonu oluşturmanın ortasında olduğunuzu tekrar hayal edin.
Şimdi programı sıfırdan birdaha yazdığınızı hayal edin.
Aynı noktada, `Ctrl+Space` ile autocomplete'i tetiklemeye çalışırsınız ve şunu görürsünüz:
Aynı noktada, `Ctrl+Space` ile otomatik tamamlamayı tetiklediniz ve şunu görüyorsunuz:
<img src="/img/python-types/image02.png">
Bununla birlikte, seçenekleri görerek kaydırabilirsiniz; ta ki "tanıdık gelen" seçeneği bulana kadar:
Aradığınızı bulana kadar seçenekleri kaydırabilirsiniz:
<img src="/img/python-types/image03.png">
## Daha fazla motivasyon { #more-motivation }
## Daha fazla motivasyon
Şu fonksiyona bakın, zaten type hints içeriyor:
Bu fonksiyon, zaten tür belirteçlerine sahip:
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
Editör değişkenlerin tiplerini bildiği için, sadece completion değil, aynı zamanda hata kontrolleri de alırsınız:
Editör değişkenlerin tiplerini bildiğinden, yalnızca otomatik tamamlama değil, hata kontrolleri de sağlar:
<img src="/img/python-types/image04.png">
Artık bunu düzeltmeniz gerektiğini, `age`'i `str(age)` ile string'e çevirmeniz gerektiğini biliyorsunuz:
Artık `age` değişkenini `str(age)` olarak kullanmanız gerektiğini biliyorsunuz:
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
## Tipleri bildirmek { #declaring-types }
Type hints bildirmek için ana yeri az önce gördünüz: fonksiyon parametreleri.
## Tip bildirme
Bu, **FastAPI** ile kullanırken de onları en çok kullanacağınız yerdir.
Az önce tip belirteçlerinin en çok kullanıldığı yeri gördünüz.
### Basit tipler { #simple-types }
**FastAPI**ile çalışırken tip belirteçlerini en çok kullanacağımız yer yine fonksiyonlardır.
Sadece `str` değil, tüm standart Python tiplerini bildirebilirsiniz.
### Basit tipler
Yalnızca `str` değil, tüm standart Python tiplerinin bildirebilirsiniz.
Örneğin şunları kullanabilirsiniz:
@@ -133,332 +138,176 @@ Sadece `str` değil, tüm standart Python tiplerini bildirebilirsiniz.
* `bool`
* `bytes`
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
### Tip parametreleri ile Generic tipler { #generic-types-with-type-parameters }
`dict`, `list`, `set` ve `tuple` gibi, başka değerler içerebilen bazı veri yapıları vardır. Ve iç değerlerin kendi tipi de olabilir.
### Tip parametreleri ile Generic tipler
İç tipleri olan bu tiplere "**generic**" tipler denir. Ve bunları, iç tipleriyle birlikte bildirmek mümkündür.
"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.
Bu tipleri ve iç tipleri bildirmek için standart Python modülü `typing`'i kullanabilirsiniz. Bu modül, özellikle bu type hints desteği için vardır.
Bu tipleri ve dahili tpileri bildirmek için standart Python modülünü "typing" kullanabilirsiniz.
#### Python'un daha yeni sürümleri { #newer-versions-of-python }
Bu tür tip belirteçlerini desteklemek için özel olarak mevcuttur.
`typing` kullanan sözdizimi, Python 3.6'dan en yeni sürümlere kadar (Python 3.9, Python 3.10, vb. dahil) tüm sürümlerle **uyumludur**.
#### `List`
Python geliştikçe, **daha yeni sürümler** bu type annotations için daha iyi destekle gelir ve çoğu durumda type annotations bildirmek için `typing` modülünü import edip kullanmanız bile gerekmez.
Örneğin `str` değerlerden oluşan bir `list` tanımlayalım.
Projeniz için daha yeni bir Python sürümü seçebiliyorsanız, bu ek sadelikten yararlanabilirsiniz.
From `typing`, import `List` (büyük harf olan `L` ile):
Tüm dokümanlarda her Python sürümüyle uyumlu örnekler vardır (fark olduğunda).
{* ../../docs_src/python_types/tutorial006.py hl[1] *}
Örneğin "**Python 3.6+**", Python 3.6 veya üstüyle (3.7, 3.8, 3.9, 3.10, vb. dahil) uyumludur. "**Python 3.9+**" ise Python 3.9 veya üstüyle (3.10 vb. dahil) uyumludur.
Eğer **Python'un en güncel sürümlerini** kullanabiliyorsanız, en güncel sürüme ait örnekleri kullanın; bunlar **en iyi ve en basit sözdizimine** sahip olur, örneğin "**Python 3.10+**".
Değişkenin tipini yine iki nokta üstüste (`:`) ile belirleyin.
#### List { #list }
tip olarak `List` kullanın.
Örneğin, `str`'lerden oluşan bir `list` olan bir değişken tanımlayalım.
Liste, bazı dahili tipleri içeren bir tür olduğundan, bunları köşeli parantez içine alırsınız:
Değişkeni, aynı iki nokta (`:`) sözdizimiyle bildirin.
{* ../../docs_src/python_types/tutorial006.py hl[4] *}
Type olarak `list` yazın.
`list`, bazı iç tipleri barındıran bir tip olduğundan, bunları köşeli parantez içine yazarsınız:
/// tip | Ipucu
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
Köşeli parantez içindeki bu dahili tiplere "tip parametreleri" denir.
/// info | Bilgi
Köşeli parantez içindeki bu iç tiplere "type parameters" denir.
Bu durumda `str`, `list`'e verilen type parameter'dır.
Bu durumda `str`, `List`e iletilen tür parametresidir.
///
Bu şu demektir: "`items` değişkeni bir `list` ve bu listedeki her bir öğe `str`".
Bunun anlamı şudur: "`items` değişkeni bir `list`tir ve bu listedeki öğelerin her biri bir `str`dir".
Bunu yaparak, editörünüz listeden öğeleri işlerken bile destek sağlayabilir:
Bunu yaparak, düzenleyicinizin listedeki öğeleri işlerken bile destek sağlamasını sağlayabilirsiniz:
<img src="/img/python-types/image05.png">
Tipler olmadan, bunu başarmak neredeyse imkansızdır.
Tip belirteçleri olmadan, bunu başarmak neredeyse imkansızdır.
`item` değişkeninin, `items` listesindeki elemanlardan biri olduğuna dikkat edin.
`item` değişkeninin `items` listesindeki öğelerden biri olduğuna dikkat edin.
Ve yine de editör bunun bir `str` olduğunu bilir ve buna göre destek sağlar.
Ve yine, editör bunun bir `str` olduğunu biliyor ve bunun için destek sağlıyor.
#### Tuple ve Set { #tuple-and-set }
#### `Tuple` ve `Set`
`tuple`'ları ve `set`'leri bildirmek için de aynısını yaparsınız:
`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] *}
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
Bu şu anlama gelir:
* `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.
* `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).
#### Dict { #dict }
#### `Optional`
Bir `dict` tanımlamak için, virgülle ayrılmış 2 type parameter verirsiniz.
İlk type parameter, `dict`'in key'leri içindir.
İkinci type parameter, `dict`'in value'ları içindir:
{* ../../docs_src/python_types/tutorial008_py39.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`.
Python 3.6 ve üzeri sürümlerde (Python 3.10 dahil), `typing` içinden `Union` tipini kullanabilir ve köşeli parantez içine kabul edilecek olası tipleri yazabilirsiniz.
Python 3.10'da ayrıca, olası tipleri <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> ile ayırabildiğiniz **yeni bir sözdizimi** de vardır.
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
////
//// tab | Python 3.9+
`Optional` bir değişkenin `str`gibi bir tipi olabileceğini ama isteğe bağlı olarak tipinin `None` olabileceğini belirtir:
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
{!../../docs_src/python_types/tutorial009.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.
Her iki durumda da 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.
Python 3.6 ve üzeri sürümlerde (Python 3.10 dahil), `typing` modülünden `Optional` import edip kullanarak bunu bildirebilirsiniz.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009_py39.py!}
```
Sadece `str` yerine `Optional[str]` kullanmak, aslında değer `None` olabilecekken her zaman `str` olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olmasını sağlar.
`Optional[Something]`, aslında `Union[Something, None]` için bir kısayoldur; eşdeğerdirler.
Bu aynı zamanda Python 3.10'da `Something | None` kullanabileceğiniz anlamına gelir:
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial009_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009_py39.py!}
```
////
//// tab | Python 3.9+ alternatif
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
```
////
#### `Union` veya `Optional` kullanmak { #using-union-or-optional }
Python sürümünüz 3.10'un altındaysa, 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 eşdeğerdir ve altta aynı şeydir; ama ben `Optional` yerine `Union` önermeyi tercih ederim. Çünkü "**optional**" kelimesi değerin optional olduğunu ima ediyor gibi durur; ama gerçekte anlamı "değer `None` olabilir"dir. Değer optional olmasa ve hâlâ required olsa bile.
Bence `Union[SomeType, None]` ne anlama geldiğini daha açık şekilde ifade ediyor.
Bu, tamamen kelimeler ve isimlendirmelerle ilgili. Ancak bu kelimeler, sizin ve ekip arkadaşlarınızın kod hakkında nasıl düşündüğünü etkileyebilir.
Örnek olarak şu fonksiyonu ele alalım:
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
`name` parametresi `Optional[str]` olarak tanımlanmış, ama **optional değil**; parametre olmadan fonksiyonu çağıramazsınız:
```Python
say_hi() # Oh, no, this throws an error! 😱
```
`name` parametresi **hâlâ required**'dır (*optional* değildir) çünkü bir default değeri yoktur. Yine de `name`, değer olarak `None` kabul eder:
```Python
say_hi(name=None) # This works, None is valid 🎉
```
İyi haber şu ki, Python 3.10'a geçtiğinizde bununla uğraşmanız gerekmeyecek; çünkü tiplerin union'larını tanımlamak için doğrudan `|` kullanabileceksiniz:
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
Ve böylece `Optional` ve `Union` gibi isimlerle de uğraşmanız gerekmeyecek. 😎
#### Generic tipler { #generic-types }
Köşeli parantez içinde type parameter alan bu tiplere **Generic types** veya **Generics** denir, örneğin:
//// tab | Python 3.10+
Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içindeki tiplerle):
* `list`
* `tuple`
* `set`
* `dict`
Ve önceki Python sürümlerinde olduğu gibi `typing` modülünden:
* `Union`
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Optional`
* ...and others.
Python 3.10'da, `Union` ve `Optional` generics'lerini kullanmaya alternatif olarak, tip union'larını bildirmek için <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> kullanabilirsiniz; bu çok daha iyi ve daha basittir.
**Generic types** yada **Generics** olarak adlandırılır.
////
### Tip olarak Sınıflar
//// tab | Python 3.9+
Bir değişkenin tipini bir sınıf ile bildirebilirsiniz.
Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içindeki tiplerle):
Diyelim ki `name` değerine sahip `Person` sınıfınız var:
* `list`
* `tuple`
* `set`
* `dict`
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
Ve `typing` modülünden gelen generics:
* `Union`
* `Optional`
* ...and others.
Sonra bir değişkeni 'Person' tipinde tanımlayabilirsiniz:
////
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
### Tip olarak sınıflar { #classes-as-types }
Bir sınıfı da bir değişkenin tipi olarak bildirebilirsiniz.
Örneğin, adı olan bir `Person` sınıfınız olsun:
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
Sonra bir değişkeni `Person` tipinde olacak şekilde bildirebilirsiniz:
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
Ve sonra, yine tüm editör desteğini alırsınız:
Ve yine bütün editör desteğini alırsınız:
<img src="/img/python-types/image06.png">
Bunun "`one_person`, `Person` sınıfının bir **instance**'ıdır" anlamına geldiğine dikkat edin.
## Pydantic modelleri
"`one_person`, `Person` adlı **class**'tır" anlamına gelmez.
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> veri doğrulaması yapmak için bir Python kütüphanesidir.
## Pydantic modelleri { #pydantic-models }
Verilerin "biçimini" niteliklere sahip sınıflar olarak düzenlersiniz.
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, data validation yapmak için bir Python kütüphanesidir.
Ve her niteliğin bir türü vardır.
Verinin "shape"'ini attribute'lara sahip sınıflar olarak tanımlarsınız.
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.
Ve her attribute'un bir tipi vardır.
Ve ortaya çıkan nesne üzerindeki bütün editör desteğini alırsınız.
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.
Resmi Pydantic dokümanlarından alınmıştır:
Ve bu ortaya çıkan nesne ile tüm editör desteğini alırsınız.
{* ../../docs_src/python_types/tutorial011.py *}
Resmî Pydantic dokümanlarından bir örnek:
{* ../../docs_src/python_types/tutorial011_py310.py *}
/// info
/// 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>.
Daha fazla şey öğrenmek için <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic'i takip edin</a>.
///
**FastAPI** tamamen Pydantic üzerine kuruludur.
**FastAPI** tamamen Pydantic'e dayanmaktadır.
Bunların pratikte nasıl çalıştığını [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank} içinde çok daha fazla göreceksiniz.
Daha fazlasini görmek için [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
/// tip | İpucu
## **FastAPI** tip belirteçleri
Pydantic, default value olmadan `Optional` veya `Union[Something, None]` kullandığınızda özel bir davranışa sahiptir; bununla ilgili daha fazla bilgiyi Pydantic dokümanlarında <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a> bölümünde okuyabilirsiniz.
///
## Metadata Annotations ile Type Hints { #type-hints-with-metadata-annotations }
Python'da ayrıca, `Annotated` kullanarak bu type hints içine **ek <abbr title="Veri hakkında veri; bu durumda type hakkında bilgi, örneğin bir açıklama.">metadata</abbr>** koymayı sağlayan bir özellik de vardır.
Python 3.9'dan itibaren `Annotated`, standart kütüphanenin bir parçasıdır; bu yüzden `typing` içinden import edebilirsiniz.
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
Python'un kendisi bu `Annotated` ile bir şey yapmaz. Editörler ve diğer araçlar için tip hâlâ `str`'dir.
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.
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.
Şimdilik, sadece `Annotated`'ın var olduğunu ve bunun standart Python olduğunu bilmeniz yeterli. 😎
İleride bunun ne kadar **güçlü** olabildiğini göreceksiniz.
/// 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, 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ı [Tutorial - User Guide](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>.
**FastAPI** birkaç şey yapmak için bu tür tip belirteçlerinden faydalanır.
**FastAPI** ile parametre tiplerini bildirirsiniz ve şunları elde edersiniz:
* **Editor desteği**.
* **Tip kontrolü**.
...ve **FastAPI** aynı belirteçleri şunlar için de kullanıyor:
* **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.
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}.
Ö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.
/// info
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>.
///

View File

@@ -1,3 +1,3 @@
# Kaynaklar { #resources }
# Kaynaklar
Ek kaynaklar, dış bağlantılar ve daha fazlası. ✈️
Ek kaynaklar, dış bağlantılar, makaleler ve daha fazlası. ✈️

View File

@@ -1,84 +0,0 @@
# Arka Plan Görevleri { #background-tasks }
Response döndürüldükten *sonra* çalıştırılacak arka plan görevleri tanımlayabilirsiniz.
Bu, requestten sonra yapılması gereken; ancak clientın responseu 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 servera bağlanmak ve email göndermek genellikle "yavaş" olduğundan (birkaç saniye), responseu 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) responseu 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_py39.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_py39.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_py39.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 dependencyde (dependable), bir sub-dependencyde, 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.
Requestte bir query varsa, loga 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 FastAPInin 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.
FastAPIde `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">Starlettein 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 processte ve özellikle birden fazla serverda çalıştırmanıza olanak tanırlar.
Ancak aynı **FastAPI** appi 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 dependencylerde parametre olarak `BackgroundTasks`i import edip kullanın.

View File

@@ -1,504 +0,0 @@
# 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/` packagei içinde olduğundan bir submoduledür: `app.routers.items`.
* `app/routers/users.py` için de aynı şekilde, başka bir submoduledü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 submoduledü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 APIsinin 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_py39/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_py39/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 dependencylere ve bir diğer `APIRouter`a bakalım.
## Dependencies { #dependencies }
Uygulamanın birden fazla yerinde kullanılacak bazı dependencylere 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_py39/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 moduledeki 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` dependencysine ihtiyacı var.
Dolayısıyla bunları her *path operation*a tek tek eklemek yerine `APIRouter`a ekleyebiliriz.
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Her *path operation*ın pathi 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):
...
```
...prefixin 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 routerdaki 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 dependencylerde](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 pathleri 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 dependencyleri, sonra decoratordaki [`dependencies`](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, sonra da normal parametre dependencyleri çalışır.
* Ayrıca [`scopes` ile `Security` dependencyleri](../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. Dependencyleri 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 dependencyler için `..` ile relative import kullanıyoruz:
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Relative Import Nasıl Çalışır { #how-relative-imports-work }
/// tip | İpucu
Importları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 dependencylerimiz `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) packagee çı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 packagee çı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 packagee 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 importları kullanabilirsiniz. 🤓
### Özel `tags`, `responses` ve `dependencies` Ekleyin { #add-some-custom-tags-responses-and-dependencies }
`/items` prefixini 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_py39/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 modulelerinde 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 dependencylerle birleştirilecek [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank} bile tanımlayabilirsiniz:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
### `APIRouter` Import Edin { #import-the-apirouter }
Şimdi `APIRouter` içeren diğer submoduleleri import ediyoruz:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
`app/routers/users.py` ve `app/routers/items.py` dosyaları aynı Python packagei olan `app`in parçası olan submoduleler 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` subpackageini 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 submoduleleri doğrudan import ediyoruz:
{* ../../docs_src/bigger_applications/app_an_py39/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` submodulelerindeki `router`ları dahil edelim:
{* ../../docs_src/bigger_applications/app_an_py39/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 routelar 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
Routerları 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_py39/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_py39/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` prefixi.
* `admin` tagi.
* `get_token_header` dependencysi.
* `418` responseu. 🍵
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_py39/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 submodulelerdeki pathleri, doğru pathler (ve prefixler) ve doğru taglerle 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ı prefixler kullanarak birden fazla kez de dahil edebilirsiniz.
Örneğin aynı APIyi `/api/v1` ve `/api/latest` gibi farklı prefixler 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.

View File

@@ -1,60 +0,0 @@
# 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.

View File

@@ -1,175 +0,0 @@
# 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: Union[str, None] = None
```
Ya da Python 3.10 ve üzeri için:
```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.

View File

@@ -1,220 +0,0 @@
# 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 attributeu 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 listin elemanlarının tipini belirtmez.
## Tip parametresi olan list alanları { #list-fields-with-type-parameter }
Ancak Pythonda, iç tipleri olan listleri (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 attributeları için de aynı standart sözdizimini kullanın.
Dolayısıyla örneğimizde, `tags`i özel olarak bir "string listi" yapabiliriz:
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
## Set tipleri { #set-types }
Sonra bunu düşününce, taglerin tekrar etmemesi gerektiğini fark ederiz; büyük ihtimalle benzersiz stringler olmalıdır.
Pythonda benzersiz öğelerden oluşan kümeler için özel bir veri tipi vardır: `set`.
O zaman `tags`i stringlerden 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 sete 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 attributeunun 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 attributeun 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 Type Overview</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 Pydanticin `HttpUrl` tipinden bir instance olacak şekilde tanımlayabiliriz:
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
Stringin geçerli bir URL olup olmadığı kontrol edilir ve JSON Schema / OpenAPIde de buna göre dokümante edilir.
## Alt modellerden oluşan listlere sahip attributelar { #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` keyinin artık image objectlerinden 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` listi olduğuna, `Item`ların da opsiyonel bir `Image` listine sahip olduğuna dikkat edin.
///
## Sadece list olan bodyler { #bodies-of-pure-lists }
Beklediğiniz JSON bodynin en üst seviye değeri bir JSON `array` (Pythonda `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_py39.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 dictler otomatik olarak dönüştürülür ve outputunuz da otomatik olarak JSONa çevrilir.
## Rastgele `dict` bodyleri { #bodies-of-arbitrary-dicts }
Bodyyi, keyleri bir tipte ve valueları 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 keyleri almak istediğiniz durumlarda faydalıdır.
---
Bir diğer faydalı durum da keylerin başka bir tipte olmasını istediğiniz zamandır (ör. `int`).
Burada göreceğimiz şey de bu.
Bu durumda, `int` keylere ve `float` valuelara sahip olduğu sürece herhangi bir `dict` kabul edersiniz:
{* ../../docs_src/body_nested_models/tutorial009_py39.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 clientlarınız keyleri sadece string olarak gönderebilse bile, bu stringler saf tamsayı içeriyorsa Pydantic bunları dönüştürür ve doğrular.
Ve `weights` olarak aldığınız `dict`, gerçekte `int` keylere ve `float` valuelara 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

View File

@@ -1,100 +0,0 @@
# 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.
///

View File

@@ -1,166 +0,0 @@
# 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` (Python 3.10+) veya `Union[str, None]` (Python 3.9+) içindeki `Union`, 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.

View File

@@ -1,76 +0,0 @@
# Cookie Parameter Models { #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
Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir.
///
/// 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 Cookies'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 <abbr title="This is a joke, just in case. It has nothing to do with cookie consents, but it's funny that even the API can now reject the poor cookies. Have a cookie. 🍪">cookie consent</abbr>'ı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ı... <abbr title="This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕">API'nin bunu reddetmesi için</abbr>.
Örneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker` <abbr title="Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.">cookie is not allowed</abbr> 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 <abbr title="Have a last cookie before you go. 🍪">**cookies**</abbr> tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎

View File

@@ -1,45 +1,35 @@
# Çerez (Cookie) Parametreleri { #cookie-parameters }
# Çerez (Cookie) Parametreleri
`Query` ve `Path` parametrelerini tanımladığınız şekilde Cookie parametreleri tanımlayabilirsiniz.
`Query` (Sorgu) ve `Path` (Yol) parametrelerini tanımladığınız şekilde çerez parametreleri tanımlayabilirsiniz.
## `Cookie`'yi Import Edin { #import-cookie }
## Import `Cookie`
Öncelikle, `Cookie`'yi import edin:
Öncelikle, `Cookie`'yi projenize dahil edin:
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
## `Cookie` Parametrelerini Tanımlayın { #declare-cookie-parameters }
## `Cookie` Parametrelerini Tanımlayın
Ardından, `Path` ve `Query` ile aynı yapıyı kullanarak Cookie parametrelerini tanımlayın.
Çerez parametrelerini `Path` veya `Query` tanımlaması yapar gibi tanımlayın.
Varsayılan değeri ve tüm ekstra doğrulama veya annotation parametrelerini tanımlayabilirsiniz:
İlk değer varsayılan değerdir; tüm ekstra doğrulama veya belirteç parametrelerini kullanabilirsiniz:
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
/// note | Teknik Detaylar
`Cookie`, `Path` ve `Query`'nin "kardeş" sınıfıdır. O da aynı ortak `Param` sınıfından miras alır.
`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.
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.
Ancak `fastapi`'dan projenize dahil ettiğiniz `Query`, `Path`, `Cookie` ve diğerleri aslında özel sınıflar döndüren birer fonksiyondur.
///
/// info | Bilgi
Çerezleri tanımlamak için `Cookie` kullanmanız gerekir, aksi halde parametreler query parametreleri olarak yorumlanır.
Çerez tanımlamak için `Cookie` sınıfını kullanmanız gerekmektedir, aksi taktirde parametreler sorgu parametreleri olarak yorumlanır.
///
/// info | Bilgi
## Özet
**Tarayıcılar çerezleri** ö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 çerezlerin **dokümantasyonunu** görebilirsiniz.
Ancak **veriyi doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için çerezler 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, çerezleri `Cookie` ile tanımlayın.
Çerez tanımlamalarını `Cookie` sınıfını kullanarak `Query` ve `Path` tanımlar gibi tanımlayın.

View File

@@ -1,89 +0,0 @@
# 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 frontendin JavaScript kodunun bir backend ile iletişim kurduğu ve backendin frontendden farklı bir "origin"de olduğu durumları ifade eder.
## Origin { #origin }
Origin; protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`) ve portun (`80`, `443`, `8080`) birleşimidir.
Dolayısıyla şunların hepsi farklı originlerdir:
* `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 frontendiniz var ve JavaScripti, `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`-backende bir HTTP `OPTIONS` requesti gönderir. Eğer backend, bu farklı originden (`http://localhost:8080`) gelen iletişimi yetkilendiren uygun headerları gönderirse, `:8080`-tarayıcı frontenddeki JavaScriptin `:80`-backende request göndermesine izin verir.
Bunu sağlayabilmek için `:80`-backendin bir "allowed origins" listesi olmalıdır.
Bu örnekte `:8080`-frontendin 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: Cookieler, Bearer Tokenlarla kullanılanlar gibi Authorization headerları, vb.
Bu yüzden her şeyin düzgün çalışması için, izin verilen originleri 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 originlerden (string) oluşan bir liste oluşturun.
* Bunu **FastAPI** uygulamanıza bir "middleware" olarak ekleyin.
Ayrıca backendin şunlara izin verip vermediğini de belirtebilirsiniz:
* Credentials (Authorization headerları, Cookieler, vb).
* Belirli HTTP methodları (`POST`, `PUT`) veya wildcard `"*"` ile hepsini.
* Belirli HTTP headerları veya wildcard `"*"` ile hepsini.
{* ../../docs_src/cors/tutorial001_py39.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 originleri, methodları veya headerlarııkça etkinleştirmeniz gerekir.
Aşağıdaki argümanlar desteklenir:
* `allow_origins` - Cross-origin request yapmasına izin verilmesi gereken originlerin listesi. Örn. `['https://example.org', 'https://www.example.org']`. Herhangi bir origine izin vermek için `['*']` kullanabilirsiniz.
* `allow_origin_regex` - Cross-origin request yapmasına izin verilmesi gereken originlerle eşleşecek bir regex stringi. Örn. `'https://.*\.example\.org'`.
* `allow_methods` - Cross-origin requestlerde izin verilmesi gereken HTTP methodlarının listesi. Varsayılanı `['GET']`. Tüm standart methodlara izin vermek için `['*']` kullanabilirsiniz.
* `allow_headers` - Cross-origin requestlerde desteklenmesi gereken HTTP request headerlarının listesi. Varsayılanı `[]`. Tüm headerlara izin vermek için `['*']` kullanabilirsiniz. `Accept`, `Accept-Language`, `Content-Language` ve `Content-Type` headerları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 requestler 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 headerlarını belirtir. Varsayılanı `[]`.
* `max_age` - Tarayıcıların CORS responselarını cachelemesi 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` headerlarına sahip herhangi bir `OPTIONS` requestidir.
Bu durumda middleware gelen requesti intercept eder ve uygun CORS headerları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 requesti normal şekilde geçirir, ancak responsea uygun CORS headerlarını ekler.
## Daha Fazla Bilgi { #more-info }
<abbr title="Cross-Origin Resource Sharing">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ı middlewareler sağlar. Ancak mevcut middlewarelerin çoğu doğrudan Starletteten gelir.
///

View File

@@ -1,113 +0,0 @@
# 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_py39.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">

View File

@@ -1,288 +0,0 @@
# 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.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 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.9+
```Python
commons: Annotated[CommonQueryParams, ...
```
////
//// tab | Python 3.9+ 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.9+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 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.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 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.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 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.9+
```Python
commons: Annotated[CommonQueryParams, Depends()]
```
////
//// tab | Python 3.9+ 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.
///

View File

@@ -1,69 +0,0 @@
# 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_py39.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_py39.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_py39.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_py39.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.

View File

@@ -1,289 +0,0 @@
# `yield` ile Dependency'ler { #dependencies-with-yield }
FastAPI, işini bitirdikten sonra <abbr title='bazen "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code" vb. olarak da adlandırılır'>ek adımlar çalıştıran</abbr> 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_py39.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_py39.py hl[4] *}
Response'dan sonra `yield` satırını takip eden kod çalıştırılır:
{* ../../docs_src/dependencies/tutorial007_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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.
///

View File

@@ -1,16 +0,0 @@
# 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_py39.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.

View File

@@ -1,250 +0,0 @@
# Bağımlılıklar { #dependencies }
**FastAPI**, çok güçlü ama aynı zamanda sezgisel bir **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** 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.

View File

@@ -1,105 +0,0 @@
# 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 <abbr title="A utility/system to store computed/generated values, to reuse them instead of computing them again. - Hesaplanan/üretilen değerleri saklayıp, onları tekrar hesaplamak yerine yeniden kullanmayı sağlayan bir yardımcı araç/sistem.">"cache"</abbr> 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.9+
```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.9+ 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.
///

View File

@@ -1,35 +0,0 @@
# 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, Pythonun 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.
///

View File

@@ -1,62 +0,0 @@
# 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 ve response'larda `str` olarak temsil edilir.
* `datetime.datetime`:
* Python `datetime.datetime`.
* request 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 ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`.
* `datetime.time`:
* Python `datetime.time`.
* request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`.
* `datetime.timedelta`:
* Python `datetime.timedelta`.
* request 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 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 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 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] *}

View File

@@ -1,211 +0,0 @@
# 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
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
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
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 `typing.List`'i (ya da Python 3.9 ve üzeri için sadece `list`) kullanın:
{* ../../docs_src/extra_models/tutorial004_py39.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 `typing.Dict` (ya da Python 3.9 ve üzeri için sadece `dict`) kullanabilirsiniz:
{* ../../docs_src/extra_models/tutorial005_py39.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.

View File

@@ -1,118 +1,102 @@
# İlk Adımlar { #first-steps }
# İlk Adımlar
En sade FastAPI dosyası şu şekilde görünür:
{* ../../docs_src/first_steps/tutorial001_py39.py *}
{* ../../docs_src/first_steps/tutorial001.py *}
Yukarıdakini `main.py` adlı bir dosyaya kopyalayın.
Yukarıdaki içeriği bir `main.py` dosyasına kopyalayalım.
Canlı sunucuyu çalıştırın:
Uygulamayı çalıştıralım:
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
$ uvicorn main:app --reload
<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">&apos;/home/user/code/awesomeapp&apos;</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.
<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.
```
</div>
Çıktıda, şuna benzer bir satır göreceksiniz:
/// 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:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Bu satır, uygulamanızın yerel makinenizde hangi URL'de sunulduğunu gösterir.
Bu satır, yerel makinenizde uygulamanızın çalıştığı bağlantıyı gösterir.
### Kontrol Edelim { #check-it }
### Kontrol Edelim
Tarayıcınızııp <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresine gidin.
Tarayıcınızıı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.
Şu şekilde bir JSON response göreceksiniz:
Şu şekilde bir JSON yanıtı ile karşılaşacağız:
```JSON
{"message": "Hello World"}
```
### Etkileşimli API Dokümantasyonu { #interactive-api-docs }
### Etkileşimli API Dokümantasyonu
Ş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.
Ş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.
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:
<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:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternatif API Dokümantasyonu { #alternative-api-docs }
### Alternatif API Dokümantasyonu
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.
Ş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.
Alternatif otomatik dokümantasyonu ( <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan) göreceksiniz:
<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan otomatik dokümantasyonu göreceğiz:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### OpenAPI { #openapi }
### OpenAPI
**FastAPI**, API'ları tanımlamak için **OpenAPI** standardını kullanarak tüm API'nızın tamamını içeren bir "şema" üretir.
**FastAPI**, **OpenAPI** standardını kullanarak tüm API'ınızın tamamını tanımlayan bir "şema" oluşturur.
#### "Şema" { #schema }
#### "Şema"
"Şema", bir şeyin tanımı veya açıklamasıdır. Onu uygulayan kod değil, sadece soyut bir açıklamadır.
"Şema", bir şeyin tanımı veya açıklamasıdır. Geliştirilen koddan ziyade soyut bir açıklamadır.
#### API "şeması" { #api-schema }
#### API "Şeması"
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 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 şema tanımı, API path'leriniz, alabilecekleri olası parametreler vb. şeyleri içerir.
Bu şema tanımı, API yollarınızla birlikte yollarınızın aldığı olası parametreler gibi tanımlamaları içerir.
#### Veri "şeması" { #data-schema }
#### Veri "Şeması"
"Şema" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.
Bu durumda, JSON attribute'ları ve sahip oldukları veri türleri vb. anlamına gelir.
Bu durumda, JSON özellikleri ve sahip oldukları veri türleri gibi anlamlarına gelir.
#### OpenAPI ve JSON Schema { #openapi-and-json-schema }
#### OpenAPI ve JSON Şema
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, 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.json` Dosyasına Göz At { #check-the-openapi-json }
#### `openapi.json` Dosyasına Göz At
Ham OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nızın ıklamalarını içeren bir JSON (şema) üretir.
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.
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>.
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.
Şuna benzer bir şekilde başlayan bir JSON gösterecektir:
Aşağıdaki gibi başlayan bir JSON ile karşılaşacaksınız:
```JSON
{
@@ -135,87 +119,79 @@ Bunu doğrudan şuradan görebilirsiniz: <a href="http://127.0.0.1:8000/openapi.
...
```
#### OpenAPI Ne İşe Yarar? { #what-is-openapi-for }
#### OpenAPI Ne İşe Yarar?
OpenAPI şeması, dahil edilen iki etkileşimli dokümantasyon sistemine güç veren şeydir.
OpenAPI şeması, FastAPI projesinde bulunan iki etkileşimli dokümantasyon sistemine güç veren şeydir.
Ve OpenAPI tabanlı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
OpenAPI'ya dayalı düzinelerce alternatif etkileşimli dokümantasyon aracı mevcuttur. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
Ayrıca, API'nızla iletişim kuran istemciler için otomatik olarak kod üretmekte de kullanabilirsiniz. Örneğin frontend, mobil veya IoT uygulamaları.
Ayrıca, API'ınızla iletişim kuracak önyüz, mobil veya IoT uygulamaları gibi istemciler için otomatik olarak kod oluşturabilirsiniz.
### Uygulamanızı Yayınlayın (opsiyonel) { #deploy-your-app-optional }
## Adım Adım Özetleyelim
İ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. 🚀
### Adım 1: `FastAPI`yı Projemize Dahil Edelim
Zaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek komutla deploy edebilirsiniz.
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
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_py39.py hl[1] *}
`FastAPI`, API'nız için tüm işlevselliği sağlayan bir Python class'ıdır.
`FastAPI`, API'niz için tüm işlevselliği sağlayan bir Python sınıfıdır.
/// note | Teknik Detaylar
`FastAPI`, doğrudan `Starlette`'ten miras alan bir class'tır.
`FastAPI` doğrudan `Starlette`'i miras alan bir sınıftı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` "instance"ı oluşturun { #step-2-create-a-fastapi-instance }
### Adım 2: Bir `FastAPI` "Örneği" Oluşturalım
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
Burada `app` değişkeni `FastAPI` class'ının bir "instance"ı olacaktır.
Burada `app` değişkeni `FastAPI` sınıfının bir örneği olacaktır.
Bu, tüm API'nızı oluşturmak için ana etkileşim noktası olacaktır.
Bu, tüm API'yı oluşturmak için ana etkileşim noktası olacaktır.
### Adım 3: bir *path operation* oluşturun { #step-3-create-a-path-operation }
Bu `app` değişkeni, `uvicorn` komutunda atıfta bulunulan değişkenin ta kendisidir.
#### Path { #path }
<div class="termy">
Buradaki "Path", URL'in ilk `/` işaretinden başlayarak son kısmını ifade eder.
```console
$ uvicorn main:app --reload
Yani, şu şekilde bir URL'de:
<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:
```
https://example.com/items/foo
```
...path şöyle olur:
... yol şöyle olur:
```
/items/foo
@@ -223,77 +199,77 @@ https://example.com/items/foo
/// info | Bilgi
Bir "path" genellikle "endpoint" veya "route" olarak da adlandırılır.
"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 API oluştururken, "path", "concerns" ve "resources" ayrımını yapmanın ana yoludur.
Bir API oluştururken, "yol", "kaynaklar" ile "endişeleri" ayırmanın ana yöntemidir.
#### Operation { #operation }
#### Operasyonlar
Burada "Operation", HTTP "method"larından birini ifade eder.
Burada "operasyon" HTTP "metodlarından" birini ifade eder.
Şunlardan biri:
Bunlardan biri:
* `POST`
* `GET`
* `PUT`
* `DELETE`
...ve daha egzotik olanlar:
...veya daha az kullanılan diğerleri:
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
HTTP protokolünde, her bir path ile bu "method"lardan biri (veya birden fazlası) ile iletişim kurabilirsiniz.
HTTP protokolünde, bu "metodlardan" birini (veya daha fazlasını) kullanarak her bir yol ile iletişim kurabilirsiniz.
---
API oluştururken, normalde belirli bir aksiyon için bu spesifik HTTP method'larını kullanırsınız.
API oluştururkan, belirli bir amaca hizmet eden belirli HTTP metodlarını kullanırsınız.
Normalde şunları kullanırsınız:
Normalde kullanılan:
* `POST`: veri oluşturmak için.
* `GET`: veri okumak için.
* `PUT`: veriyi güncellemek için.
* `DELETE`: veriyi silmek için.
* `POST`: veri oluşturmak.
* `GET`: veri okumak.
* `PUT`: veriyi güncellemek.
* `DELETE`: veriyi silmek.
Bu nedenle, OpenAPI'da HTTP method'larının her birine "operation" denir.
Bu nedenle, OpenAPI'da HTTP metodlarından her birine "operasyon" denir.
Biz de bunlara "**operation**" diyeceğiz.
Biz de onları "**operasyonlar**" olarak adlandıracağız.
#### Bir *path operation decorator* tanımlayın { #define-a-path-operation-decorator }
#### Bir *Yol Operasyonu Dekoratörü* Tanımlayalım
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
`@app.get("/")`, **FastAPI**'a hemen altındaki fonksiyonun şuraya giden request'leri ele almakla sorumlu olduğunu söyler:
`@app.get("/")` dekoratörü, **FastAPI**'a hemen altındaki fonksiyonun aşağıdaki durumlardan sorumlu olduğunu söyler:
* path `/`
* <abbr title="bir HTTP GET method'u"><code>get</code> operation</abbr> kullanarak
* <abbr title="Bir HTTP GET metodu"><code>get</code> operasyonu</abbr> ile
* `/` yoluna gelen istekler
/// info | `@decorator` Bilgisi
Python'daki `@something` söz dizimi "decorator" olarak adlandırılır.
Python'da `@something` sözdizimi "<abbr title="Decorator">dekoratör</abbr>" olarak adlandırılır.
Onu bir fonksiyonun üstüne koyarsınız. Güzel, dekoratif bir şapka gibi (sanırım terim de buradan geliyor).
Dekoratörler, dekoratif bir şapka gibi (sanırım terim buradan geliyor) fonksiyonların üzerlerine yerleştirilirler.
Bir "decorator", altındaki fonksiyonu alır ve onunla bir şey yapar.
Bir "dekoratör" hemen altında bulunan fonksiyonu alır ve o fonksiyon ile bazı işlemler gerçekleştirir.
Bizim durumumuzda bu decorator, **FastAPI**'a altındaki fonksiyonun **path** `/` ile **operation** `get`'e karşılık geldiğini söyler.
Bizim durumumuzda, kullandığımız dekoratör, **FastAPI**'a altındaki fonksiyonun `/` yoluna gelen `get` metodlu isteklerden sorumlu olduğunu söyler.
Bu, "**path operation decorator**"dır.
Bu bir **yol operasyonu dekoratörüdür**.
///
Diğer operation'ları da kullanabilirsiniz:
Ayrıca diğer operasyonları da kullanabilirsiniz:
* `@app.post()`
* `@app.put()`
* `@app.delete()`
Ve daha egzotik olanları:
Daha az kullanılanları da kullanabilirsiniz:
* `@app.options()`
* `@app.head()`
@@ -302,79 +278,58 @@ Ve daha egzotik olanları:
/// tip | İpucu
Her bir operation'ı (HTTP method'unu) istediğiniz gibi kullanmakta özgürsünüz.
Her işlemi (HTTP metod) istediğiniz gibi kullanmakta özgürsünüz.
**FastAPI** herhangi bir özel anlamı zorunlu kılmaz.
**FastAPI** herhangi bir özel amacı veya anlamı olması konusunda ısrarcı olmaz.
Buradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.
Örneğin GraphQL kullanırken, normalde tüm aksiyonları yalnızca `POST` operation'ları kullanarak gerçekleştirirsiniz.
Mesela GraphQL kullanırkan genelde tüm işlemleri yalnızca `POST` operasyonunu kullanarak gerçekleştirirsiniz.
///
### Adım 4: **path operation function**'ı tanımlayın { #step-4-define-the-path-operation-function }
### Adım 4: **Yol Operasyonu Fonksiyonunu** Tanımlayın
Bu bizim "**path operation function**"ımız:
Aşağıdaki, bizim **yol operasyonu fonksiyonumuzdur**:
* **path**: `/`.
* **operation**: `get`.
* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")`'in altındaki).
* **yol**: `/`
* **operasyon**: `get`
* **fonksiyon**: "dekoratör"ün (`@app.get("/")`'in) altındaki fonksiyondur.
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
Bu bir Python fonksiyonudur.
**FastAPI**, "`/`" URL'ine `GET` operation kullanarak bir request aldığında bu fonksiyonu çağıracaktır.
Bu fonksiyon bir `GET` işlemi kullanılarak "`/`" bağlantısına bir istek geldiğinde **FastAPI** tarafından çağrılır.
Bu durumda, bu bir `async` fonksiyondur.
Bu durumda bu fonksiyon bir `async` fonksiyondur.
---
Bunu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz:
Bu fonksiyonu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz.
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Not
Eğer farkı bilmiyorsanız, [Async: *"Aceleniz mi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} sayfasına bakın.
Eğer farkı bilmiyorsanız, [Async: *"Aceleniz mi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} sayfasını kontrol edebilirsiniz.
///
### Adım 5: içeriği döndürün { #step-5-return-the-content }
### Adım 5: İçeriği Geri Döndürün
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Bir `dict`, `list`, `str`, `int` vb. tekil değerler döndürebilirsiniz.
Bir `dict`, `list` veya `str`, `int` gibi tekil değerler döndürebilirsiniz.
Ayrıca Pydantic modelleri de döndürebilirsiniz (bununla ilgili daha fazlasını ileride göreceksiniz).
Ayrıca, Pydantic modelleri de döndürebilirsiniz (bu konu ileriki aşamalarda irdelenecektir).
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.
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.
### Adım 6: Deploy edin { #step-6-deploy-it }
## Özet
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.
* `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.

View File

@@ -1,244 +0,0 @@
# Hataları Yönetme { #handling-errors }
APInizi kullanan bir clienta hata bildirmek zorunda olduğunuz pek çok durum vardır.
Bu client; frontendi olan bir tarayıcı, başka birinin yazdığı bir kod, bir IoT cihazı vb. olabilir.
Clienta ş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 codelarına (200 ile 299 arası) benzer. Bu "200" status codeları, requestin bir şekilde "başarılı" olduğunu ifade eder.
400 aralığındaki status codelar 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 }
Clienta hata içeren HTTP responseları döndürmek için `HTTPException` kullanırsınız.
### `HTTPException`ı Import Etme { #import-httpexception }
{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
### Kodunuzda Bir `HTTPException` Raise Etme { #raise-an-httpexception-in-your-code }
`HTTPException`, APIlerle 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; requesti hemen sonlandırır ve `HTTPException` içindeki HTTP hatasını clienta 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 codeu ile bir exception raise edelim:
{* ../../docs_src/handling_errors/tutorial001_py39.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 responseu 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 responseu alır:
```JSON
{
"detail": "Item not found"
}
```
/// tip | İpucu
Bir `HTTPException` raise ederken, `detail` parametresine sadece `str` değil, JSONa 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 JSONa dönüştürülür.
///
## Özel Headerlar Eklemek { #add-custom-headers }
Bazı durumlarda HTTP hata responseuna özel headerlar 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 headerlar ekleyebilirsiniz:
{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
## Özel Exception Handlerları Kurmak { #install-custom-exception-handlers }
<a href="https://www.starlette.dev/exceptions/" class="external-link" target="_blank">Starlettein aynı exception yardımcı araçlarıyla</a> özel exception handlerlar 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_py39.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 codeu `418` olan, JSON içeriği şu şekilde temiz bir hata responseu 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 responseların çoğu doğrudan Starletteten gelir. `Request` için de aynısı geçerlidir.
///
## Varsayılan Exception Handlerları Override Etmek { #override-the-default-exception-handlers }
**FastAPI** bazı varsayılan exception handlerlara sahiptir.
Bu handlerlar, `HTTPException` `raise` ettiğinizde ve request geçersiz veri içerdiğinde varsayılan JSON responseları döndürmekten sorumludur.
Bu exception handlerları kendi handlerlarınızla override edebilirsiniz.
### Request Validation Exceptionları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_py39.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_py39.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 responseların çoğu doğrudan Starletteten gelir.
///
/// warning | Uyarı
`RequestValidationError`, validation hatasının gerçekleştiği dosya adı ve satır bilgilerini içerir; isterseniz bunu loglarınıza ilgili bilgilerle birlikte yazdırabilirsiniz.
Ancak bu, eğer sadece stringe ç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` Bodysini Kullanmak { #use-the-requestvalidationerror-body }
`RequestValidationError`, geçersiz veriyle aldığı `body`yi içerir.
Uygulamanızı geliştirirken bodyyi loglamak, debug etmek, kullanıcıya döndürmek vb. için bunu kullanabilirsiniz.
{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
Şimdi şu gibi geçersiz bir item göndermeyi deneyin:
```JSON
{
"title": "towel",
"size": "XL"
}
```
Aldığınız bodyyi 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"
}
}
```
#### FastAPInin `HTTPException`ı vs Starlettein `HTTPException`ı { #fastapis-httpexception-vs-starlettes-httpexception }
**FastAPI**nin kendi `HTTPException`ı vardır.
Ve **FastAPI**nin `HTTPException` hata sınıfı, Starlettein `HTTPException` hata sınıfından kalıtım alır (inherit).
Tek fark şudur: **FastAPI**nin `HTTPException`ı `detail` alanı için JSONa çevrilebilir herhangi bir veri kabul ederken, Starlettein `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 Starlettein `HTTPException`ı için register etmelisiniz.
Böylece Starlettein internal kodunun herhangi bir bölümü ya da bir Starlette extension/plug-ini Starlette `HTTPException` raise ederse, handlerınız bunu yakalayıp (catch) handle edebilir.
Bu örnekte, iki `HTTPException`ı da aynı kodda kullanabilmek için Starlettein exceptionı `StarletteHTTPException` olarak yeniden adlandırılıyor:
```Python
from starlette.exceptions import HTTPException as StarletteHTTPException
```
### **FastAPI**nin Exception Handlerlarını Yeniden Kullanmak { #reuse-fastapis-exception-handlers }
Exceptionı, **FastAPI**nin aynı varsayılan exception handlerlarıyla birlikte kullanmak isterseniz, varsayılan exception handlerları `fastapi.exception_handlers` içinden import edip yeniden kullanabilirsiniz:
{* ../../docs_src/handling_errors/tutorial006_py39.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 handlerları olduğu gibi yeniden kullanabilirsiniz.

View File

@@ -1,72 +0,0 @@
# 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. 😎

View File

@@ -1,91 +0,0 @@
# 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.

View File

@@ -1,95 +0,0 @@
# 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">&apos;/home/user/code/awesomeapp&apos;</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 [virtual environment](../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.

View File

@@ -1,120 +0,0 @@
# 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_py39.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_py39.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_py39.py hl[3:16,18] *}
ı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_py39.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_py39.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_py39.py hl[3] *}

Some files were not shown because too many files have changed in this diff Show More