name: de - Deutsch
- link: /es/
name: es - español
+ - link: /ko/
+ name: ko - 한국어
- link: /pt/
name: pt - português
- link: /ru/
-# 소개
+# 소개 { #about }
-FastAPI에 대한 디자인, 영감 등에 대해 🤓
+FastAPI, 그 디자인, 영감 등에 대해 🤓
-# 추가 상태 코드
+# 추가 상태 코드 { #additional-status-codes }
기본적으로 **FastAPI**는 응답을 `JSONResponse`를 사용하여 반환하며, *경로 작업(path operation)*에서 반환한 내용을 해당 `JSONResponse` 안에 넣어 반환합니다.
기본 상태 코드 또는 *경로 작업*에서 설정한 상태 코드를 사용합니다.
-## 추가 상태 코드
+## 추가 상태 코드 { #additional-status-codes_1 }
기본 상태 코드와 별도로 추가 상태 코드를 반환하려면 `JSONResponse`와 같이 `Response`를 직접 반환하고 추가 상태 코드를 직접 설정할 수 있습니다.
예를 들어 항목을 업데이트할 수 있는 *경로 작업*이 있고 성공 시 200 “OK”의 HTTP 상태 코드를 반환한다고 가정해 보겠습니다.
-하지만 새로운 항목을 허용하기를 원할 것입니다. 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 "Created"를 반환합니다.
+하지만 새로운 항목을 허용하기를 원할 것입니다. 그리고 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 "Created"를 반환합니다.
이를 위해서는 `JSONResponse`를 가져와서 원하는 `status_code`를 설정하여 콘텐츠를 직접 반환합니다:
///
-/// note | 기술적 세부 정보
+/// note | 기술 세부사항
`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
///
-## OpenAPI 및 API 문서
+## OpenAPI 및 API 문서 { #openapi-and-api-docs }
추가 상태 코드와 응답을 직접 반환하는 경우, FastAPI는 반환할 내용을 미리 알 수 있는 방법이 없기 때문에 OpenAPI 스키마(API 문서)에 포함되지 않습니다.
-# 고급 의존성
+# 고급 의존성 { #advanced-dependencies }
-## 매개변수화된 의존성
+## 매개변수화된 의존성 { #parameterized-dependencies }
지금까지 본 모든 의존성은 고정된 함수 또는 클래스입니다.
이때 해당 고정된 내용을 매개변수화할 수 있길 바랍니다.
-## "호출 가능한" 인스턴스
+## "호출 가능한" 인스턴스 { #a-callable-instance }
Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법이 있습니다.
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
이 경우, **FastAPI**는 추가 매개변수와 하위 의존성을 확인하기 위해 `__call__`을 사용하게 되며,
-ë\82\98ì¤\91ì\97\90 *ê²½ë¡\9c ì\97°ì\82° 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.
+ë\82\98ì¤\91ì\97\90 *ê²½ë¡\9c ì²\98리 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.
-## 인스턴스 매개변수화하기
+## 인스턴스 매개변수화하기 { #parameterize-the-instance }
이제 `__init__`을 사용하여 의존성을 "매개변수화"할 수 있는 인스턴스의 매개변수를 선언할 수 있습니다:
이 경우, **FastAPI**는 `__init__`에 전혀 관여하지 않으며, 우리는 이 메서드를 코드에서 직접 사용하게 됩니다.
-## 인스턴스 생성하기
+## 인스턴스 생성하기 { #create-an-instance }
다음과 같이 이 클래스의 인스턴스를 생성할 수 있습니다:
이렇게 하면 `checker.fixed_content` 속성에 `"bar"`라는 값을 담아 의존성을 "매개변수화"할 수 있습니다.
-## 인스턴스를 의존성으로 사용하기
+## 인스턴스를 의존성으로 사용하기 { #use-the-instance-as-a-dependency }
-그런 다음, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있으며,
-클래스 자체가 아닌 인스턴스 `checker`가 의존성이 됩니다.
+그런 다음, 클래스 자체가 아닌 인스턴스 `checker`가 의존성이 되므로, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있습니다.
의존성을 해결할 때 **FastAPI**는 이 `checker`를 다음과 같이 호출합니다:
checker(q="somequery")
```
-...ê·¸ë¦¬ê³ ì\9d´ë\95\8c ë°\98í\99\98ë\90\98ë\8a\94 ê°\92ì\9d\84 *ê²½ë¡\9c ì\97°ì\82° í\95¨ì\88\98*ì\9d\98 `fixed_content_included` 매ê°\9cë³\80ì\88\98ë¡\9c 전달합니다:
+...ê·¸ë¦¬ê³ ì\9d´ë\95\8c ë°\98í\99\98ë\90\98ë\8a\94 ê°\92ì\9d\84 *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ì\9d\98 ì\9d\98ì¡´ì\84± ê°\92ì\9c¼ë¡\9c, `fixed_content_included` 매ê°\9cë³\80ì\88\98ì\97\90 전달합니다:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
-/// tip | 참고
+/// tip | 팁
이 모든 과정이 복잡하게 느껴질 수 있습니다. 그리고 지금은 이 방법이 얼마나 유용한지 명확하지 않을 수도 있습니다.
이 예시는 의도적으로 간단하게 만들었지만, 전체 구조가 어떻게 작동하는지 보여줍니다.
-보안 관련 장에서는 이와 같은 방식으로 구현된 편의 함수들이 있습니다.
+보안 관련 장에서는 이와 같은 방식으로 구현된 유틸리티 함수들이 있습니다.
-이 모든 과정을 이해했다면, 이러한 보안 도구들이 내부적으로 어떻게 작동하는지 이미 파악한 것입니다.
+이 모든 과정을 이해했다면, 이러한 보안용 유틸리티 도구들이 내부적으로 어떻게 작동하는지 이미 파악한 것입니다.
///
+
+## `yield`, `HTTPException`, `except`, 백그라운드 태스크가 있는 의존성 { #dependencies-with-yield-httpexception-except-and-background-tasks }
+
+/// warning | 경고
+
+대부분의 경우 이러한 기술 세부사항이 필요하지 않을 것입니다.
+
+이 세부사항은 주로 0.121.0 이전의 FastAPI 애플리케이션이 있고 `yield`가 있는 의존성에서 문제가 발생하는 경우에 유용합니다.
+
+///
+
+`yield`가 있는 의존성은 여러 사용 사례를 수용하고 일부 문제를 해결하기 위해 시간이 지나며 발전해 왔습니다. 다음은 변경된 내용의 요약입니다.
+
+### `yield`와 `scope`가 있는 의존성 { #dependencies-with-yield-and-scope }
+
+0.121.0 버전에서 FastAPI는 `yield`가 있는 의존성에 대해 `Depends(scope="function")` 지원을 추가했습니다.
+
+`Depends(scope="function")`를 사용하면, `yield` 이후의 종료 코드는 *경로 처리 함수*가 끝난 직후(클라이언트에 응답이 반환되기 전)에 실행됩니다.
+
+그리고 `Depends(scope="request")`(기본값)를 사용하면, `yield` 이후의 종료 코드는 응답이 전송된 후에 실행됩니다.
+
+자세한 내용은 [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 문서를 참고하세요.
+
+### `yield`가 있는 의존성과 `StreamingResponse`, 기술 세부사항 { #dependencies-with-yield-and-streamingresponse-technical-details }
+
+FastAPI 0.118.0 이전에는 `yield`가 있는 의존성을 사용하면, *경로 처리 함수*가 반환된 뒤 응답을 보내기 직전에 `yield` 이후의 종료 코드가 실행되었습니다.
+
+의도는 응답이 네트워크를 통해 전달되기를 기다리면서 필요한 것보다 더 오래 리소스를 점유하지 않도록 하는 것이었습니다.
+
+이 변경은 `StreamingResponse`를 반환하는 경우에도 `yield`가 있는 의존성의 종료 코드가 이미 실행된다는 의미이기도 했습니다.
+
+예를 들어, `yield`가 있는 의존성에 데이터베이스 세션이 있다면, `StreamingResponse`는 데이터를 스트리밍하는 동안 해당 세션을 사용할 수 없게 됩니다. `yield` 이후의 종료 코드에서 세션이 이미 닫혔기 때문입니다.
+
+이 동작은 0.118.0에서 되돌려져, `yield` 이후의 종료 코드가 응답이 전송된 뒤 실행되도록 변경되었습니다.
+
+/// info | 정보
+
+아래에서 보시겠지만, 이는 0.106.0 버전 이전의 동작과 매우 비슷하지만, 여러 개선 사항과 코너 케이스에 대한 버그 수정이 포함되어 있습니다.
+
+///
+
+#### 종료 코드를 조기에 실행하는 사용 사례 { #use-cases-with-early-exit-code }
+
+특정 조건의 일부 사용 사례에서는 응답을 보내기 전에 `yield`가 있는 의존성의 종료 코드를 실행하던 예전 동작이 도움이 될 수 있습니다.
+
+예를 들어, `yield`가 있는 의존성에서 데이터베이스 세션을 사용해 사용자를 검증만 하고, *경로 처리 함수*에서는 그 데이터베이스 세션을 다시는 사용하지 않으며(의존성에서만 사용), **그리고** 응답을 전송하는 데 오랜 시간이 걸리는 경우를 생각해 봅시다. 예를 들어 데이터를 천천히 보내는 `StreamingResponse`인데, 어떤 이유로든 데이터베이스를 사용하지는 않는 경우입니다.
+
+이 경우 데이터베이스 세션은 응답 전송이 끝날 때까지 유지되지만, 사용하지 않는다면 굳이 유지할 필요가 없습니다.
+
+다음과 같이 보일 수 있습니다:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
+
+다음에서 `Session`을 자동으로 닫는 종료 코드는:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
+
+...응답이 느린 데이터 전송을 마친 뒤에 실행됩니다:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
+
+하지만 `generate_stream()`는 데이터베이스 세션을 사용하지 않으므로, 응답을 전송하는 동안 세션을 열린 채로 유지할 필요는 없습니다.
+
+SQLModel(또는 SQLAlchemy)을 사용하면서 이런 특정 사용 사례가 있다면, 더 이상 필요하지 않을 때 세션을 명시적으로 닫을 수 있습니다:
+
+{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
+
+그러면 세션이 데이터베이스 연결을 해제하여, 다른 요청들이 이를 사용할 수 있게 됩니다.
+
+`yield`가 있는 의존성에서 조기 종료가 필요한 다른 사용 사례가 있다면, 여러분의 구체적인 사용 사례와 `yield`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Question</a>을 생성해 주세요.
+
+`yield`가 있는 의존성에서 조기 종료에 대한 설득력 있는 사용 사례가 있다면, 조기 종료를 선택적으로 활성화할 수 있는 새로운 방법을 추가하는 것을 고려하겠습니다.
+
+### `yield`가 있는 의존성과 `except`, 기술 세부사항 { #dependencies-with-yield-and-except-technical-details }
+
+FastAPI 0.110.0 이전에는 `yield`가 있는 의존성을 사용한 다음 그 의존성에서 `except`로 예외를 잡고, 예외를 다시 발생시키지 않으면, 예외가 자동으로 어떤 예외 핸들러 또는 내부 서버 오류 핸들러로 raise/forward 되었습니다.
+
+이는 핸들러 없이 전달된 예외(내부 서버 오류)로 인해 처리되지 않은 메모리 사용이 발생하는 문제를 수정하고, 일반적인 Python 코드의 동작과 일관되게 하기 위해 0.110.0 버전에서 변경되었습니다.
+
+### 백그라운드 태스크와 `yield`가 있는 의존성, 기술 세부사항 { #background-tasks-and-dependencies-with-yield-technical-details }
+
+FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성의 종료 코드는 응답이 전송된 *후에* 실행되었기 때문에, [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 뒤였습니다.
+
+이는 주로 백그라운드 태스크 안에서 의존성이 "yield"한 동일한 객체들을 사용할 수 있게 하기 위한 설계였습니다. 백그라운드 태스크가 끝난 뒤에 종료 코드가 실행되었기 때문입니다.
+
+이는 응답이 네트워크를 통해 전달되기를 기다리는 동안 리소스를 점유하지 않기 위한 의도로 FastAPI 0.106.0에서 변경되었습니다.
+
+/// tip | 팁
+
+추가로, 백그라운드 태스크는 보통 별도의 리소스(예: 자체 데이터베이스 연결)를 가지고 따로 처리되어야 하는 독립적인 로직 집합입니다.
+
+따라서 이 방식이 코드를 더 깔끔하게 만들어줄 가능성이 큽니다.
+
+///
+
+이 동작에 의존하던 경우라면, 이제는 백그라운드 태스크를 위한 리소스를 백그라운드 태스크 내부에서 생성하고, 내부적으로는 `yield`가 있는 의존성의 리소스에 의존하지 않는 데이터만 사용해야 합니다.
+
+예를 들어, 동일한 데이터베이스 세션을 사용하는 대신, 백그라운드 태스크 내부에서 새 데이터베이스 세션을 생성하고, 이 새 세션을 사용해 데이터베이스에서 객체를 가져오면 됩니다. 그리고 데이터베이스에서 가져온 객체를 백그라운드 태스크 함수의 매개변수로 전달하는 대신, 해당 객체의 ID를 전달한 다음 백그라운드 태스크 함수 내부에서 객체를 다시 가져오면 됩니다.
-# 비동기 테스트 코드 작성
+# 비동기 테스트 { #async-tests }
-이전 장에서 `TestClient` 를 이용해 **FastAPI** 어플리케이션 테스트를 작성하는 법을 배우셨을텐데요.
-지금까지는 `async` 키워드 사용없이 동기 함수의 테스트 코드를 작성하는 법만 익혔습니다.
+제공된 `TestClient`를 사용하여 **FastAPI** 애플리케이션을 테스트하는 방법을 이미 살펴보았습니다. 지금까지는 `async` 함수를 사용하지 않고, 동기 테스트를 작성하는 방법만 보았습니다.
-하지만 비동기 함수를 사용하여 테스트 코드를 작성하는 것은 매우 유용할 수 있습니다.
-예를 들면 데이터베이스에 비동기로 쿼리하는 경우를 생각해봅시다.
-FastAPI 애플리케이션에 요청을 보내고, 비동기 데이터베이스 라이브러리를 사용하여 백엔드가 데이터베이스에 올바르게 데이터를 기록했는지 확인하고 싶을 때가 있을 겁니다.
+테스트에서 비동기 함수를 사용할 수 있으면 유용할 수 있습니다. 예를 들어 데이터베이스를 비동기로 쿼리하는 경우를 생각해 보세요. FastAPI 애플리케이션에 요청을 보낸 다음, async 데이터베이스 라이브러리를 사용하면서 백엔드가 데이터베이스에 올바른 데이터를 성공적으로 기록했는지 검증하고 싶을 수 있습니다.
-ì\9d´ë\9f° ê²½ì\9a°ì\9d\98 í\85\8cì\8a¤í\8a¸ ì½\94ë\93\9c를 ì\96´ë\96»ê²\8c ë¹\84ë\8f\99기ë¡\9c ì\9e\91ì\84±í\95\98ë\8a\94ì§\80 ì\95\8cì\95\84ë´\85ì\8b\9c다.
+ì\96´ë\96»ê²\8c ë\8f\99ì\9e\91í\95\98ê²\8c ë§\8cë\93¤ ì\88\98 ì\9e\88ë\8a\94ì§\80 ì\82´í\8e´ë³´ê² ì\8aµë\8b\88다.
-## pytest.mark.anyio
+## pytest.mark.anyio { #pytest-mark-anyio }
-앞에서 작성한 테스트 함수에서 비동기 함수를 호출하고 싶다면, 테스트 코드도 비동기 함수여야합니다.
-AnyIO는 특정 테스트 함수를 비동기 함수로 호출 할 수 있는 깔끔한 플러그인을 제공합니다.
+테스트에서 비동기 함수를 호출하려면, 테스트 함수도 비동기여야 합니다. AnyIO는 이를 위한 깔끔한 플러그인을 제공하며, 일부 테스트 함수를 비동기로 호출하도록 지정할 수 있습니다.
+## HTTPX { #httpx }
-## HTTPX
+**FastAPI** 애플리케이션이 `async def` 대신 일반 `def` 함수를 사용하더라도, 내부적으로는 여전히 `async` 애플리케이션입니다.
-**FastAPI** 애플리케이션이 `async def` 대신 `def` 키워드로 선언된 함수를 사용하더라도, 내부적으로는 여전히 `비동기` 애플리케이션입니다.
+`TestClient`는 표준 pytest를 사용하여, 일반 `def` 테스트 함수 안에서 비동기 FastAPI 애플리케이션을 호출하도록 내부에서 마법 같은 처리를 합니다. 하지만 비동기 함수 안에서 이를 사용하면 그 마법은 더 이상 동작하지 않습니다. 테스트를 비동기로 실행하면, 테스트 함수 안에서 `TestClient`를 더 이상 사용할 수 없습니다.
-`TestClient`는 pytest 표준을 사용하여 비동기 FastAPI 애플리케이션을 일반적인 `def` 테스트 함수 내에서 호출할 수 있도록 내부에서 마술을 부립니다. 하지만 이 마술은 비동기 함수 내부에서 사용할 때는 더 이상 작동하지 않습니다. 테스트를 비동기로 실행하면, 더 이상 테스트 함수 내부에서 `TestClient`를 사용할 수 없습니다.
+`TestClient`는 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>를 기반으로 하며, 다행히 HTTPX를 직접 사용해 API를 테스트할 수 있습니다.
-`TestClient`는 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>를 기반으로 하고 있으며, 다행히 이를 직접 사용하여 API를 테스트할 수 있습니다.
+## 예시 { #example }
-## 예시
-
-간단한 예시를 위해 [더 큰 어플리케이션 만들기](../ko/tutorial/bigger-applications.md){.internal-link target=_blank} 와 [테스트](../ko/tutorial/testing.md){.internal-link target=_blank}:에서 다룬 파일 구조와 비슷한 형태를 확인해봅시다:
+간단한 예시로, [더 큰 애플리케이션](../tutorial/bigger-applications.md){.internal-link target=_blank}과 [테스트](../tutorial/testing.md){.internal-link target=_blank}에서 설명한 것과 비슷한 파일 구조를 살펴보겠습니다:
```
.
│ └── test_main.py
```
- `main.py`는 아래와 같아야 합니다:
+`main.py` 파일은 다음과 같습니다:
-{* ../../docs_src/async_tests/main.py *}
+{* ../../docs_src/async_tests/app_a_py39/main.py *}
-`test_main.py` í\8c\8cì\9d¼ì\9d\80 `main.py`ì\97\90 ë\8c\80í\95\9c í\85\8cì\8a¤í\8a¸ê°\80 ì\9e\88ì\9d\84 í\85\90ë\8d°, ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\84 수 있습니다:
+`test_main.py` í\8c\8cì\9d¼ì\97\90ë\8a\94 `main.py`ì\97\90 ë\8c\80í\95\9c í\85\8cì\8a¤í\8a¸ê°\80 ì\9e\88ì\9c¼ë©°, ì\9d´ì \9c ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d´ ë³´ì\9d¼ 수 있습니다:
-{* ../../docs_src/async_tests/test_main.py *}
+{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
-## 실행하기
+## 실행하기 { #run-it }
-아래의 명령어로 테스트 코드를 실행합니다:
+다음과 같이 평소처럼 테스트를 실행할 수 있습니다:
<div class="termy">
</div>
-## 자세히 보기
+## 자세히 보기 { #in-detail }
-`@pytest.mark.anyio` ë§\88커ë\8a\94 pytestì\97\90ê²\8c ì\9d´ í\85\8cì\8a¤í\8a¸ í\95¨ì\88\98ê°\80 ë¹\84ë\8f\99기ë¡\9c í\98¸ì¶\9cë\90\98ì\96´ì\95¼ í\95¨ì\9d\84 알려줍니다:
+`@pytest.mark.anyio` ë§\88커ë\8a\94 pytestì\97\90ê²\8c ì\9d´ í\85\8cì\8a¤í\8a¸ í\95¨ì\88\98ê°\80 ë¹\84ë\8f\99기ë¡\9c í\98¸ì¶\9cë\90\98ì\96´ì\95¼ í\95\9cë\8b¤ê³ 알려줍니다:
-{* ../../docs_src/async_tests/test_main.py hl[7] *}
+{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
/// tip | 팁
-테스트 함수가 이제 `TestClient`를 사용할 때처럼 단순히 `def`가 아니라 `async def`로 작성된 점에 주목해주세요.
+`TestClient`를 사용할 때처럼 단순히 `def`가 아니라, 이제 테스트 함수가 `async def`라는 점에 주목하세요.
///
-그 다음에 `AsyncClient` 로 앱을 만들고 비동기 요청을 `await` 키워드로 보낼 수 있습니다:
+그 다음 앱으로 `AsyncClient`를 만들고, `await`를 사용해 비동기 요청을 보낼 수 있습니다.
-{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
+{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
-ì\9c\84ì\9d\98 ì½\94ë\93\9cë\8a\94:
+ì\9d´ë\8a\94 ë\8b¤ì\9d\8cê³¼ ë\8f\99ë\93±í\95©ë\8b\88ë\8b¤:
```Python
response = client.get('/')
```
-`TestClient` 에 요청을 보내던 것과 동일합니다.
+`TestClient`로 요청을 보내기 위해 사용하던 코드입니다.
/// tip | 팁
-새로운 `AsyncClient`를 사용할 때 async/await를 사용하고 있다는 점에 주목하세요. 이 요청은 비동기적으로 처리됩니다.
+새 `AsyncClient`와 함께 async/await를 사용하고 있다는 점에 주목하세요. 요청은 비동기입니다.
///
/// warning | 경고
-만약의 어플리케이션이 Lifespan 이벤트에 의존성을 갖고 있다면 `AsyncClient` 가 이러한 이벤트를 실행시키지 않습니다.
-`AsyncClient` 가 테스트를 실행시켰다는 것을 확인하기 위해
-`LifespanManager` from <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a>.확인해주세요.
-
+애플리케이션이 lifespan 이벤트에 의존한다면, `AsyncClient`는 이러한 이벤트를 트리거하지 않습니다. 이벤트가 트리거되도록 하려면 <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a>의 `LifespanManager`를 사용하세요.
///
-## ê·¸ ì\99¸ì\9d\98 ë¹\84ë\8f\99기 í\95¨ì\88\98 í\98¸ì¶\9c
+## 기í\83\80 ë¹\84ë\8f\99기 í\95¨ì\88\98 í\98¸ì¶\9c { #other-asynchronous-function-calls }
-테스트 함수가 이제 비동기 함수이므로, FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 호출하고 `await` 키워드를 사용 할 수 있습니다.
+테스트 함수가 이제 비동기이므로, 테스트에서 FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 코드의 다른 곳에서 호출하듯이 동일하게 호출하고 (`await`) 사용할 수도 있습니다.
/// tip | 팁
-테스트에 비동기 함수 호출을 통합할 때 (예: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB의 MotorClient</a>를 사용할 때) `RuntimeError: Task attached to a different loop` 오류가 발생한다면, 이벤트 루프가 필요한 객체는 반드시 비동기 함수 내에서만 인스턴스화해야 한다는 점을 주의하세요!
-예를 들어 `@app.on_event("startup")` 콜백 내에서 인스턴스화하는 것이 좋습니다.
+테스트에 비동기 함수 호출을 통합할 때(예: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB의 MotorClient</a>를 사용할 때) `RuntimeError: Task attached to a different loop`를 마주친다면, 이벤트 루프가 필요한 객체는 async 함수 안에서만 인스턴스화해야 한다는 점을 기억하세요. 예를 들어 `@app.on_event("startup")` 콜백에서 인스턴스화할 수 있습니다.
///
-# 사용자 정의 응답 - HTML, Stream, 파일, 기타
+# 사용자 정의 응답 - HTML, Stream, 파일, 기타 { #custom-response-html-stream-file-others }
기본적으로, **FastAPI** 응답을 `JSONResponse`를 사용하여 반환합니다.
그러나 `Response` (또는 `JSONResponse`와 같은 하위 클래스)를 직접 반환하면, 데이터가 자동으로 변환되지 않으며 (심지어 `response_model`을 선언했더라도), 문서화가 자동으로 생성되지 않습니다(예를 들어, 생성된 OpenAPI의 일부로 HTTP 헤더 `Content-Type`에 특정 "미디어 타입"을 포함하는 경우).
-í\95\98ì§\80ë§\8c *ê²½ë¡\9c ì\9e\91ì\97\85 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다.
+í\95\98ì§\80ë§\8c *ê²½ë¡\9c ì²\98리 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다.
-*ê²½ë¡\9c ì\9e\91ì\97\85 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다.
+*ê²½ë¡\9c ì²\98리 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다.
-ê·¸ë¦¬ê³ ë§\8cì\95½ ê·¸ `Response`ê°\80 `JSONResponse`ì\99\80 `UJSONResponse`ì\9d\98 ê²½ì\9a° ì²\98ë\9f¼ JSON 미ë\94\94ì\96´ í\83\80ì\9e\85(`application/json`)ì\9d\84 ê°\80ì§\80ê³ ì\9e\88ë\8b¤ë©´, *ê²½ë¡\9c ì\9e\91ì\97\85 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다.
+ê·¸ë¦¬ê³ ë§\8cì\95½ ê·¸ `Response`ê°\80 `JSONResponse`ì\99\80 `UJSONResponse`ì\9d\98 ê²½ì\9a° ì²\98ë\9f¼ JSON 미ë\94\94ì\96´ í\83\80ì\9e\85(`application/json`)ì\9d\84 ê°\80ì§\80ê³ ì\9e\88ë\8b¤ë©´, *ê²½ë¡\9c ì²\98리 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다.
/// note | 참고
///
-## `ORJSONResponse` 사용하기
+## `ORJSONResponse` 사용하기 { #use-orjsonresponse }
-예를 들어, 성능을 극대화하려는 경우, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">orjson</a>을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다.
+예를 들어, 성능을 극대화하려는 경우, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다.
-사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, **경로 작업 데코레이터*에서 선언하세요.
+사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, *경로 처리 데코레이터*에서 선언하세요.
대규모 응답의 경우, 딕셔너리를 반환하는 것보다 `Response`를 반환하는 것이 훨씬 빠릅니다.
하지만 반환하는 내용이 **JSON으로 직렬화 가능**하다고 확신하는 경우, 해당 내용을 응답 클래스에 직접 전달할 수 있으며, FastAPI가 반환 내용을 `jsonable_encoder`를 통해 처리한 뒤 응답 클래스에 전달하는 오버헤드를 피할 수 있습니다.
-{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
/// info | 정보
///
-## HTML 응답
+## HTML 응답 { #html-response }
**FastAPI**에서 HTML 응답을 직접 반환하려면 `HTMLResponse`를 사용하세요.
* `HTMLResponse`를 임포트 합니다.
-* *ê²½ë¡\9c ì\9e\91ì\97\85 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.
+* *ê²½ë¡\9c ì²\98리 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.
-{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
/// info | 정보
///
-### `Response` 반환하기
+### `Response` 반환하기 { #return-a-response }
-[ì\9d\91ë\8bµì\9d\84 ì§\81ì \91 ë°\98í\99\98í\95\98기](response-directly.md){.internal-link target=_blank}ì\97\90ì\84\9c 본 ê²\83 ì²\98ë\9f¼, *ê²½ë¡\9c ì\9e\91ì\97\85*에서 응답을 직접 반환하여 재정의할 수도 있습니다.
+[ì\9d\91ë\8bµì\9d\84 ì§\81ì \91 ë°\98í\99\98í\95\98기](response-directly.md){.internal-link target=_blank}ì\97\90ì\84\9c 본 ê²\83 ì²\98ë\9f¼, *ê²½ë¡\9c ì²\98리*에서 응답을 직접 반환하여 재정의할 수도 있습니다.
위의 예제와 동일하게 `HTMLResponse`를 반환하는 코드는 다음과 같을 수 있습니다:
-{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
+{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
/// warning | 경고
-*ê²½ë¡\9c ì\9e\91ì\97\85 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다.
+*ê²½ë¡\9c ì²\98리 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다.
///
///
-### OpenAPI에 문서화하고 `Response` 재정의 하기
+### OpenAPI에 문서화하고 `Response` 재정의 하기 { #document-in-openapi-and-override-response }
함수 내부에서 응답을 재정의하면서 동시에 OpenAPI에서 "미디어 타입"을 문서화하고 싶다면, `response_class` 매게변수를 사용하면서 `Response` 객체를 반환할 수 있습니다.
-ì\9d´ ê²½ì\9a° `response_class`ë\8a\94 OpenAPI *ê²½ë¡\9c ì\9e\91ì\97\85*ì\9d\84 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.
+ì\9d´ ê²½ì\9a° `response_class`ë\8a\94 OpenAPI *ê²½ë¡\9c ì²\98리*를 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.
-### `HTMLResponse`직접 반환하기
+#### `HTMLResponse`직접 반환하기 { #return-an-htmlresponse-directly }
예를 들어, 다음과 같이 작성할 수 있습니다:
-{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
+{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
이 예제에서, `generate_html_response()` 함수는 HTML을 `str`로 반환하는 대신 이미 `Response`를 생성하고 반환합니다.
`generate_html_response()`를 호출한 결과를 반환함으로써, 기본적인 **FastAPI** 기본 동작을 재정의 하는 `Response`를 이미 반환하고 있습니다.
-하지만 `response_class`에 `HTMLResponse`를 함께 전달했기 때문에, FastAPI는 이를 OpenAPI 및 대화형 문서에서 `text/html`로 HTML을 문서화 하는 방법을 알 수 있습니다.
+하지만 `response_class`에 `HTMLResponse`를 함께 전달했기 때문에, **FastAPI**는 이를 OpenAPI 및 대화형 문서에서 `text/html`로 HTML을 문서화 하는 방법을 알 수 있습니다.
<img src="/img/tutorial/custom-response/image01.png">
-## 사용 가능한 응답들
+## 사용 가능한 응답들 { #available-responses }
다음은 사용할 수 있는 몇가지 응답들 입니다.
///
-### `Response`
+### `Response` { #response }
기본 `Response` 클래스는 다른 모든 응답 클래스의 부모 클래스 입니다.
* `headers` - 문자열로 이루어진 `dict`.
* `media_type` - 미디어 타입을 나타내는 `str` 예: `"text/html"`.
-FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 `Content-Type` 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가 합니다.
+FastAPI (실제로는 Starlette)가 자동으로 Content-Length 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 Content-Type 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가 합니다.
-{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
-### `HTMLResponse`
+### `HTMLResponse` { #htmlresponse }
텍스트 또는 바이트를 받아 HTML 응답을 반환합니다. 위에서 설명한 내용과 같습니다.
-### `PlainTextResponse`
+### `PlainTextResponse` { #plaintextresponse }
텍스트 또는 바이트를 받아 일반 텍스트 응답을 반환합니다.
-{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
-### `JSONResponse`
+### `JSONResponse` { #jsonresponse }
데이터를 받아 `application/json`으로 인코딩된 응답을 반환합니다.
이는 위에서 설명했듯이 **FastAPI**에서 기본적으로 사용되는 응답 형식입니다.
-### `ORJSONResponse`
+### `ORJSONResponse` { #orjsonresponse }
<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 사용하여 빠른 JSON 응답을 제공하는 대안입니다. 위에서 설명한 내용과 같습니다.
///
-### `UJSONResponse`
+### `UJSONResponse` { #ujsonresponse }
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>을 사용한 또 다른 JSON 응답 형식입니다.
/// info | 정보
-이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: 'pip install ujson`.
+이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: `pip install ujson`.
///
///
-{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
/// tip | 팁
///
-### `RedirectResponse`
+### `RedirectResponse` { #redirectresponse }
HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 307(임시 리디렉션)으로 설정됩니다.
`RedirectResponse`를 직접 반환할 수 있습니다.
-{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
+{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
---
또는 `response_class` 매개변수에서 사용할 수도 있습니다:
-{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
-ì\9d´ ê²½ì\9a°, *ê²½ë¡\9c ì\9e\91ì\97\85* 함수에서 URL을 직접 반환할 수 있습니다.
+ì\9d´ ê²½ì\9a°, *ê²½ë¡\9c ì²\98리* 함수에서 URL을 직접 반환할 수 있습니다.
이 경우, 사용되는 `status_code`는 `RedirectResponse`의 기본값인 `307` 입니다.
`status_code` 매개변수를 `response_class` 매개변수와 함께 사용할 수도 있습니다:
-{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
-### `StreamingResponse`
+### `StreamingResponse` { #streamingresponse }
비동기 제너레이터 또는 일반 제너레이터/이터레이터를 받아 응답 본문을 스트리밍 합니다.
-{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
+{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
-#### 파일과 같은 객체를 사용한 `StreamingResponse`
+#### 파일과 같은 객체를 사용한 `StreamingResponse` { #using-streamingresponse-with-file-like-objects }
-파일과 같은 객체(예: `open()`으로 반환된 객체)가 있는 경우, 해당 파일과 같은 객체를 반복(iterate)하는 제너레이터 함수를 만들 수 있습니다.
+<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> 객체(예: `open()`으로 반환된 객체)가 있는 경우, 해당 file-like 객체를 반복(iterate)하는 제너레이터 함수를 만들 수 있습니다.
이 방식으로, 파일 전체를 메모리에 먼저 읽어들일 필요 없이, 제너레이터 함수를 `StreamingResponse`에 전달하여 반환할 수 있습니다.
이 방식은 클라우드 스토리지, 비디오 처리 등의 다양한 라이브러리와 함께 사용할 수 있습니다.
-{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
+{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
1. 이것이 제너레이터 함수입니다. `yield` 문을 포함하고 있으므로 "제너레이터 함수"입니다.
2. `with` 블록을 사용함으로써, 제너레이터 함수가 완료된 후 파일과 같은 객체가 닫히도록 합니다. 즉, 응답 전송이 끝난 후 닫힙니다.
이렇게 하면 "생성(generating)" 작업을 내부적으로 다른 무언가에 위임하는 제너레이터 함수가 됩니다.
- 이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다.
+ 이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다.
/// tip | 팁
-ì\97¬ê¸°ì\84\9c í\91\9cì¤\80 `open()`ì\9d\84 ì\82¬ì\9a©í\95\98ê³ ì\9e\88기 ë\95\8c문ì\97\90 `async`ì\99\80 `await`를 ì§\80ì\9b\90í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. ë\94°ë\9d¼ì\84\9c ê²½ë¡\9c ì\9e\91ì\97\85ì\9d\80 일반 `def`로 선언합니다.
+ì\97¬ê¸°ì\84\9c í\91\9cì¤\80 `open()`ì\9d\84 ì\82¬ì\9a©í\95\98ê³ ì\9e\88기 ë\95\8c문ì\97\90 `async`ì\99\80 `await`를 ì§\80ì\9b\90í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. ë\94°ë\9d¼ì\84\9c ê²½ë¡\9c ì²\98리ë\8a\94 일반 `def`로 선언합니다.
///
-### `FileResponse`
+### `FileResponse` { #fileresponse }
파일을 비동기로 스트리밍하여 응답합니다.
파일 응답에는 적절한 `Content-Length`, `Last-Modified`, 및 `ETag` 헤더가 포함됩니다.
-{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
+{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
또한 `response_class` 매개변수를 사용할 수도 있습니다:
-{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}
+{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
-ì\9d´ ê²½ì\9a°, ê²½ë¡\9c ì\9e\91ì\97\85 함수에서 파일 경로를 직접 반환할 수 있습니다.
+ì\9d´ ê²½ì\9a°, ê²½ë¡\9c ì²\98리 함수에서 파일 경로를 직접 반환할 수 있습니다.
-## 사용자 정의 응답 클래스
+## 사용자 정의 응답 클래스 { #custom-response-class }
`Response`를 상속받아 사용자 정의 응답 클래스를 생성하고 사용할 수 있습니다.
-예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">orjson</a>을 사용하고 싶다고 가정해봅시다.
+예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 사용하고 싶다고 가정해봅시다.
만약 들여쓰기 및 포맷된 JSON을 반환하고 싶다면, `orjson.OPT_INDENT_2` 옵션을 사용할 수 있습니다.
`CustomORJSONResponse`를 생성할 수 있습니다. 여기서 핵심은 `Response.render(content)` 메서드를 생성하여 내용을 `bytes`로 반환하는 것입니다:
-{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}
+{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
이제 다음 대신:
{"message": "Hello World"}
```
-이 응답은 이렇게 반환됩니다:
+...이 응답은 이렇게 반환됩니다:
```json
{
물론 JSON 포맷팅보다 더 유용하게 활용할 방법을 찾을 수 있을 것입니다. 😉
-## 기본 응답 클래스
+## 기본 응답 클래스 { #default-response-class }
**FastAPI** 클래스 객체 또는 `APIRouter`를 생성할 때 기본적으로 사용할 응답 클래스를 지정할 수 있습니다.
이를 정의하는 매개변수는 `default_response_class`입니다.
-아래 예제에서 **FastAPI**는 모든 경로 작업에서 기본적으로 `JSONResponse` 대신 `ORJSONResponse`를 사용합니다.
+아래 예제에서 **FastAPI**는 모든 *경로 처리*에서 기본적으로 `JSONResponse` 대신 `ORJSONResponse`를 사용합니다.
-{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
+{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
/// tip | 팁
-ì\97¬ì \84í\9e\88 ì\9d´ì \84ì²\98ë\9f¼ *ê²½ë¡\9c ì\9e\91ì\97\85*에서 `response_class`를 재정의할 수 있습니다.
+ì\97¬ì \84í\9e\88 ì\9d´ì \84ì²\98ë\9f¼ *ê²½ë¡\9c ì²\98리*에서 `response_class`를 재정의할 수 있습니다.
///
-## 추가 문서화
+## 추가 문서화 { #additional-documentation }
OpenAPI에서 `responses`를 사용하여 미디어 타입 및 기타 세부 정보를 선언할 수도 있습니다: [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}.
-# Lifespan 이벤트
+# Lifespan 이벤트 { #lifespan-events }
-애플리케이션 **시작 전**에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, **애플리케이션이 요청을 받기 시작하기 전**에 실행된다는 의미입니다.
+애플리케이션이 **시작**하기 전에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, 애플리케이션이 **요청을 받기 시작하기 전**에 실행된다는 의미입니다.
-마찬가지로, 애플리케이션이 **종료될 때** 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.
+마찬가지로, 애플리케이션이 **종료**될 때 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.
-이 코드가 애플리케이션이 **요청을 받기 시작하기 전에** 실행되고, 요청 처리가 끝난 후 **종료 직전에** 실행되기 때문에 전체 애플리케이션의 **수명(Lifespan)**을 다룹니다. (잠시 후 "수명"이라는 단어가 중요해집니다 😉)
+이 코드는 애플리케이션이 요청을 받기 **시작**하기 전에 실행되고, 요청 처리를 **끝낸 직후**에 실행되기 때문에 전체 애플리케이션의 **수명(lifespan)**을 다룹니다(잠시 후 "lifespan"이라는 단어가 중요해집니다 😉).
-이 방법은 전체 애플리케이션에서 사용해야 하는 **자원**을 설정하거나 요청 간에 **공유되는** 자원을 설정하고, 또는 그 후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유되는 머신러닝 모델을 로드하는 경우입니다.
+이는 전체 앱에서 사용해야 하는 **자원**을 설정하고, 요청 간에 **공유되는** 자원을 설정하고, 그리고/또는 이후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유 머신러닝 모델을 로드하는 경우입니다.
+## 사용 사례 { #use-case }
-## 사용 사례
+먼저 **사용 사례** 예시로 시작한 다음, 이를 어떻게 해결할지 살펴보겠습니다.
-먼저 **사용 사례**를 예로 들어보고, 이를 어떻게 해결할 수 있는지 살펴보겠습니다.
+요청을 처리하는 데 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖
-우리가 요청을 처리하기 위해 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖
+동일한 모델이 요청 간에 공유되므로, 요청마다 모델이 하나씩 있거나 사용자마다 하나씩 있는 등의 방식이 아닙니다.
-이 모델들은 요청 간에 공유되므로, 요청마다 모델이 하나씩 있는 것이 아니라, 여러 요청에서 동일한 모델을 사용합니다.
+모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 그래서 모든 요청마다 이를 수행하고 싶지는 않습니다.
-모ë\8d¸ì\9d\84 ë¡\9cë\93\9cí\95\98ë\8a\94 ë\8d° **ì\83\81ë\8b¹í\95\9c ì\8b\9cê°\84ì\9d´ 걸린ë\8b¤ê³ ì\83\81ì\83\81í\95´ ë´\85ì\8b\9cë\8b¤**, ì\99\9cë\83\90í\95\98ë©´ 모ë\8d¸ì\9d´ **ë\94\94ì\8a¤í\81¬ì\97\90ì\84\9c ë§\8eì\9d\80 ë\8d°ì\9d´í\84°ë¥¼ ì\9d½ì\96´ì\95¼** í\95\98기 ë\95\8c문ì\9e\85ë\8b\88ë\8b¤. ë\94°ë\9d¼ì\84\9c 모ë\93 ì\9a\94ì²ì\97\90 ë\8c\80í\95´ 모ë\8d¸ì\9d\84 매ë²\88 ë¡\9cë\93\9cí\95\98ê³ ì\8b¶ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
+모ë\93\88/í\8c\8cì\9d¼ì\9d\98 ìµ\9cì\83\81ì\9c\84ì\97\90ì\84\9c ë¡\9cë\93\9cí\95 ì\88\98ë\8f\84 ì\9e\88ì§\80ë§\8c, ê·¸ë\9f¬ë©´ ë\8b¨ì\88\9cí\95\9c ì\9e\90ë\8f\99í\99\94ë\90\9c í\85\8cì\8a¤í\8a¸ë¥¼ ì\8b¤í\96\89í\95\98ë\8a\94 ê²½ì\9a°ì\97\90ë\8f\84 **모ë\8d¸ì\9d\84 ë¡\9cë\93\9c**í\95\98ê²\8c ë\90\98ê³ , í\85\8cì\8a¤í\8a¸ê°\80 ì½\94ë\93\9cì\9d\98 ë\8f\85립ì \81ì\9d¸ ë¶\80ë¶\84ì\9d\84 ì\8b¤í\96\89í\95\98기 ì \84ì\97\90 모ë\8d¸ì\9d´ ë¡\9cë\93\9cë\90 ë\95\8cê¹\8cì§\80 기ë\8b¤ë ¤ì\95¼ í\95\98ë¯\80ë¡\9c **ë\8a\90ë ¤ì§\91ë\8b\88ë\8b¤**.
-모듈/파일의 최상위에서 모델을 로드할 수도 있지만, 그러면 **모델을 로드하는데** 시간이 걸리기 때문에, 단순한 자동화된 테스트를 실행할 때도 모델이 로드될 때까지 기다려야 해서 **테스트 속도가 느려집니다**.
+이것이 우리가 해결할 문제입니다. 요청을 처리하기 전에 모델을 로드하되, 코드가 로드되는 동안이 아니라 애플리케이션이 요청을 받기 시작하기 직전에만 로드하겠습니다.
-이 문제를 해결하려고 하는 것입니다. 요청을 처리하기 전에 모델을 로드하되, 애플리케이션이 요청을 받기 시작하기 직전에만 로드하고, 코드가 로드되는 동안은 로드하지 않도록 하겠습니다.
+## Lifespan { #lifespan }
-## Lifespan
+`FastAPI` 앱의 `lifespan` 매개변수와 "컨텍스트 매니저"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다(컨텍스트 매니저가 무엇인지 잠시 후에 보여드리겠습니다).
-`FastAPI` 애플리케이션의 `lifespan` 매개변수와 "컨텍스트 매니저"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다. (컨텍스트 매니저가 무엇인지 잠시 후에 설명드리겠습니다.)
+예제로 시작한 다음 자세히 살펴보겠습니다.
-예제를 통해 시작하고, 그 후에 자세히 살펴보겠습니다.
+`yield`를 사용해 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:
-우리는 `yield`를 사용하여 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:
+{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
-{* ../../docs_src/events/tutorial003.py hl[16,19] *}
+여기서는 `yield` 이전에 (가짜) 모델 함수를 머신러닝 모델이 들어 있는 딕셔너리에 넣어 모델을 로드하는 비용이 큰 *시작* 작업을 시뮬레이션합니다. 이 코드는 애플리케이션이 **요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.
-여기서 우리는 모델을 로드하는 비싼 *시작* 작업을 시뮬레이션하고 있습니다. `yield` 앞에서 (가짜) 모델 함수를 머신러닝 모델이 담긴 딕셔너리에 넣습니다. 이 코드는 **애플리케이션이 요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.
-
-그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 **애플리케이션이 요청 처리 완료 후**, *종료* 직전에 실행됩니다. 예를 들어, 메모리나 GPU와 같은 자원을 해제하는 작업을 할 수 있습니다.
+그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 애플리케이션이 **요청 처리를 마친 후**, *종료* 직전에 실행됩니다. 예를 들어 메모리나 GPU 같은 자원을 해제할 수 있습니다.
/// tip | 팁
-`shutdown`ì\9d\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 **ì¢\85ë£\8c**할 때 발생합니다.
+`shutdown`ì\9d\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 **ì¤\91ì§\80**할 때 발생합니다.
-새로운 버전을 시작해야 하거나, 그냥 실행을 멈추고 싶을 수도 있습니다. 🤷
+새 버전을 시작해야 할 수도 있고, 그냥 실행하는 게 지겨워졌을 수도 있습니다. 🤷
///
-### Lifespan 함수
+### Lifespan 함수 { #lifespan-function }
-먼저 주목할 점은, `yield`를 사용하여 비동기 함수(async function)를 정의하고 있다는 것입니다. 이는 `yield`를 사용한 의존성과 매우 유사합니다.
+먼저 주목할 점은 `yield`를 사용하여 비동기 함수를 정의하고 있다는 것입니다. 이는 `yield`를 사용하는 의존성과 매우 유사합니다.
-{* ../../docs_src/events/tutorial003.py hl[14:19] *}
+{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
함수의 첫 번째 부분, 즉 `yield` 이전의 코드는 애플리케이션이 시작되기 **전에** 실행됩니다.
-ê·¸ë¦¬ê³ `yield` ì\9d´í\9b\84ì\9d\98 ë¶\80ë¶\84ì\9d\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì\99\84ë£\8cë\90\9c í\9b\84 **ë\82\98ì¤\91에** 실행됩니다.
+ê·¸ë¦¬ê³ `yield` ì\9d´í\9b\84ì\9d\98 ë¶\80ë¶\84ì\9d\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì¢\85ë£\8cë\90\9c **í\9b\84에** 실행됩니다.
-### 비동기 컨텍스트 매니저
+### 비동기 컨텍스트 매니저 { #async-context-manager }
-í\95¨ì\88\98를 í\99\95ì\9d¸í\95´ë³´ë©´, `@asynccontextmanager`ë¡\9c ì\9e¥ì\8b\9d되어 있습니다.
+í\99\95ì\9d¸í\95´ ë³´ë©´, í\95¨ì\88\98ë\8a\94 `@asynccontextmanager`ë¡\9c ë\8d°ì½\94ë \88ì\9d´ì\85\98되어 있습니다.
-이것은 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환시킵니다.
+이는 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환합니다.
-{* ../../docs_src/events/tutorial003.py hl[1,13] *}
+{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
파이썬에서 **컨텍스트 매니저**는 `with` 문에서 사용할 수 있는 것입니다. 예를 들어, `open()`은 컨텍스트 매니저로 사용할 수 있습니다:
with open("file.txt") as file:
file.read()
```
-최근 버전의 파이썬에서는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:
+
+최근 버전의 파이썬에는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:
```Python
async with lifespan(app):
await do_stuff()
```
-컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80ë\82\98 ì\9c\84ì\99\80 ê°\99ì\9d\80 ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80를 ë§\8cë\93¤ë©´, `with` ë¸\94ë¡\9dì\97\90 ë\93¤ì\96´ê°\80기 ì \84ì\97\90 `yield` ì\9d´ì \84ì\9d\98 ì½\94ë\93\9cê°\80 ì\8b¤í\96\89ë\90\98ê³ , `with` ë¸\94ë¡\9dì\9d\84 ë²\97ì\96´ë\82\9c í\9b\84ì\97\90ë\8a\94 `yield` ì\9d´í\9b\84ì\9d\98 ì½\94ë\93\9cê°\80 ì\8b¤í\96\89ë\90©ë\8b\88ë\8b¤.
+ì\9c\84ì\99\80 ê°\99ì\9d\80 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80 ë\98\90ë\8a\94 ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80를 ë§\8cë\93¤ë©´, `with` ë¸\94ë¡\9dì\97\90 ë\93¤ì\96´ê°\80기 ì \84ì\97\90 `yield` ì\9d´ì \84ì\9d\98 ì½\94ë\93\9c를 ì\8b¤í\96\89í\95\98ê³ , `with` ë¸\94ë¡\9dì\9d\84 ë²\97ì\96´ë\82\9c í\9b\84ì\97\90ë\8a\94 `yield` ì\9d´í\9b\84ì\9d\98 ì½\94ë\93\9c를 ì\8b¤í\96\89í\95©ë\8b\88ë\8b¤.
-위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 사용하도록 합니다.
+위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 FastAPI가 이를 사용하도록 합니다.
-`FastAPI` ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 `lifespan` 매ê°\9cë³\80ì\88\98ë\8a\94 **ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80**를 ë°\9b기 ë\95\8c문ì\97\90, ì\83\88ë¡\9cì\9a´ `lifespan` ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80를 FastAPIì\97\90 전달할 수 있습니다.
+`FastAPI` ì\95±ì\9d\98 `lifespan` 매ê°\9cë³\80ì\88\98ë\8a\94 **ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80**를 ë°\9bì\9c¼ë¯\80ë¡\9c, ì\83\88 `lifespan` ë¹\84ë\8f\99기 컨í\85\8dì\8a¤í\8a¸ 매ë\8b\88ì \80를 전달할 수 있습니다.
-{* ../../docs_src/events/tutorial003.py hl[22] *}
+{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
-## 대체 이벤트 (사용 중단)
+## 대체 이벤트(사용 중단) { #alternative-events-deprecated }
/// warning | 경고
-*ì\8b\9cì\9e\91*ê³¼ *ì¢\85ë£\8c*를 ì²\98리í\95\98ë\8a\94 ê¶\8cì\9e¥ ë°©ë²\95ì\9d\80 ì\9c\84ì\97\90ì\84\9c ì\84¤ëª\85í\95\9c ë\8c\80ë¡\9c `FastAPI` ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 `lifespan` 매ê°\9cë³\80ì\88\98를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ì\9e\85ë\8b\88ë\8b¤. `lifespan` 매ê°\9cë³\80ì\88\98를 ì \9cê³µí\95\98ë©´ `startup`ê³¼ `shutdown` ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ë\8a\94 ë\8d\94 ì\9d´ì\83\81 í\98¸ì¶\9cë\90\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. `lifespan`ì\9d\84 ì\82¬ì\9a©í\95 ì§\80, 모ë\93 ì\9d´ë²¤í\8a¸ë¥¼ ì\82¬ì\9a©í\95 ì§\80 ì\84 í\83\9dí\95´ì\95¼ í\95\98ë©° ë\91\98 ë\8b¤ ì\82¬ì\9a©í\95 ì\88\98ë\8a\94 ì\97\86ì\8aµ니다.
+*ì\8b\9cì\9e\91*ê³¼ *ì¢\85ë£\8c*를 ì²\98리í\95\98ë\8a\94 ê¶\8cì\9e¥ ë°©ë²\95ì\9d\80 ì\9c\84ì\97\90ì\84\9c ì\84¤ëª\85í\95\9c ë\8c\80ë¡\9c `FastAPI` ì\95±ì\9d\98 `lifespan` 매ê°\9cë³\80ì\88\98를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ì\9e\85ë\8b\88ë\8b¤. `lifespan` 매ê°\9cë³\80ì\88\98를 ì \9cê³µí\95\98ë©´ `startup`ê³¼ `shutdown` ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ë\8a\94 ë\8d\94 ì\9d´ì\83\81 í\98¸ì¶\9cë\90\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. `lifespan`ë§\8c ì\93°ê±°ë\82\98 ì\9d´ë²¤í\8a¸ë§\8c ì\93°ê±°ë\82\98 ë\91\98 ì¤\91 í\95\98ë\82\98ì\9d´ì§\80, ë\91\98 ë\8b¤ë\8a\94 ì\95\84ë\8b\99니다.
-이 부분은 건너뛰셔도 좋습니다.
+이 부분은 아마 건너뛰셔도 됩니다.
///
*시작*과 *종료* 동안 실행될 이 로직을 정의하는 대체 방법이 있습니다.
-ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì\8b\9cì\9e\91ë\90\98기 ì \84ì\97\90 ë\98\90ë\8a\94 ì¢\85ë£\8cë\90 ë\95\8c ì\8b¤í\96\89í\95´ì\95¼ í\95\98ë\8a\94 ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬(í\95¨ì\88\98)를 ì \95ì\9d\98í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì\8b\9cì\9e\91ë\90\98기 ì \84ì\97\90 ë\98\90ë\8a\94 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì¢\85ë£\8cë\90 ë\95\8c ì\8b¤í\96\89ë\90\98ì\96´ì\95¼ í\95\98ë\8a\94 ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬(í\95¨ì\88\98)를 ì \95ì\9d\98í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
이 함수들은 `async def` 또는 일반 `def`로 선언할 수 있습니다.
-### `startup` 이벤트
+### `startup` 이벤트 { #startup-event }
애플리케이션이 시작되기 전에 실행되어야 하는 함수를 추가하려면, `"startup"` 이벤트로 선언합니다:
-{* ../../docs_src/events/tutorial001.py hl[8] *}
+{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
-이 경우, `startup` 이벤트 핸들러 함수는 "database"라는 항목(단지 `dict`)을 일부 값으로 초기화합니다.
+이 경우, `startup` 이벤트 핸들러 함수는 "database"(그냥 `dict`) 항목을 일부 값으로 초기화합니다.
여러 개의 이벤트 핸들러 함수를 추가할 수 있습니다.
-ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\80 모ë\93 `startup` ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ê°\80 ì\99\84ë£\8cë\90 ë\95\8cê¹\8cì§\80 ì\9a\94ì²ì\9d\84 ë°\9b기 ì\8b\9cì\9e\91í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
+ê·¸ë¦¬ê³ ëª¨ë\93 `startup` ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ê°\80 ì\99\84ë£\8cë\90 ë\95\8cê¹\8cì§\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\80 ì\9a\94ì²ì\9d\84 ë°\9b기 ì\8b\9cì\9e\91í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
-### `shutdown` 이벤트
+### `shutdown` 이벤트 { #shutdown-event }
애플리케이션이 종료될 때 실행되어야 하는 함수를 추가하려면, `"shutdown"` 이벤트로 선언합니다:
-{* ../../docs_src/events/tutorial002.py hl[6] *}
+{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
-여기서, `shutdown` 이벤트 핸들러 함수는 `"Application shutdown"`이라는 텍스트를 `log.txt` 파일에 기록합니다.
+여기서 `shutdown` 이벤트 핸들러 함수는 텍스트 한 줄 `"Application shutdown"`을 `log.txt` 파일에 기록합니다.
/// info | 정보
-`open()` 함수에서 `mode="a"`는 "추가"를 의미하므로, 파일에 있는 기존 내용은 덮어쓰지 않고 새로운 줄이 추가됩니다.
+`open()` 함수에서 `mode="a"`는 "append"(추가)를 의미하므로, 기존 내용을 덮어쓰지 않고 파일에 있던 내용 뒤에 줄이 추가됩니다.
///
/// tip | 팁
-이 경우, 우리는 표준 파이썬 `open()` 함수를 사용하여 파일과 상호작용하고 있습니다.
+이 경우에는 파일과 상호작용하는 표준 파이썬 `open()` 함수를 사용하고 있습니다.
-따라서 I/O(입출력) 작업이 포함되어 있어 디스크에 기록되는 것을 "기다리는" 과정이 필요합니다.
+따라서 I/O(input/output)가 포함되어 있어 디스크에 기록되는 것을 "기다리는" 과정이 필요합니다.
하지만 `open()`은 `async`와 `await`를 사용하지 않습니다.
-ê·¸ë\9e\98ì\84\9c ì\9a°ë¦¬ë\8a\94 ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ í\95¨ì\88\98를 `async def` ë\8c\80ì\8b ì\9d¼ë°\98 `def`로 선언합니다.
+ê·¸ë\9e\98ì\84\9c ì\9d´ë²¤í\8a¸ í\95¸ë\93¤ë\9f¬ í\95¨ì\88\98ë\8a\94 `async def` ë\8c\80ì\8b í\91\9cì¤\80 `def`로 선언합니다.
///
-### `startup`과 `shutdown`을 함께 사용
+### `startup`과 `shutdown`을 함께 { #startup-and-shutdown-together }
-*ì\8b\9cì\9e\91*ê³¼ *ì¢\85ë£\8c* ë¡\9cì§\81ì\9d´ ì\97°ê²°ë\90 ê°\80ë\8a¥ì\84±ì\9d´ ë\86\92ì\8aµë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´, 무ì\96¸ê°\80를 ì\8b\9cì\9e\91í\95\9c í\9b\84 ë\81\9dë\82´ê±°ë\82\98, ì\9e\90ì\9b\90ì\9d\84 í\9a\8dë\93\9dí\95\9c í\9b\84 í\95´ì \9cí\95\98ë\8a\94 ë\93±ì\9d\98 ì\9e\91ì\97\85ì\9d\84 할 수 있습니다.
+*ì\8b\9cì\9e\91*ê³¼ *ì¢\85ë£\8c* ë¡\9cì§\81ì\9d\80 ì\97°ê²°ë\90\98ì\96´ ì\9e\88ì\9d\84 ê°\80ë\8a¥ì\84±ì\9d´ ë\86\92ì\8aµë\8b\88ë\8b¤. 무ì\96¸ê°\80를 ì\8b\9cì\9e\91í\96\88ë\8b¤ê°\80 ë\81\9dë\82´ê±°ë\82\98, ì\9e\90ì\9b\90ì\9d\84 í\9a\8dë\93\9dí\96\88ë\8b¤ê°\80 í\95´ì \9cí\95\98ë\8a\94 ë\93±ì\9d\98 ì\9e\91ì\97\85ì\9d´ í\95\84ì\9a\94할 수 있습니다.
-이러한 작업을 별도의 함수로 처리하면 서로 로직이나 변수를 공유하지 않기 때문에 더 어려워집니다. 값들을 전역 변수에 저장하거나 비슷한 트릭을 사용해야 할 수 있습니다.
+로직이나 변수를 함께 공유하지 않는 분리된 함수에서 이를 처리하면, 전역 변수에 값을 저장하거나 비슷한 트릭이 필요해져 더 어렵습니다.
-그렇기 때문에 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.
+그 때문에, 이제는 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.
-## 기술적 세부사항
+## 기술적 세부사항 { #technical-details }
호기심 많은 분들을 위한 기술적인 세부사항입니다. 🤓
-ASGI 기술 사양에 따르면, 이는 <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다.
+내부적으로 ASGI 기술 사양에서는 이것이 <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다.
/// info | 정보
-Starlette의 `lifespan` 핸들러에 대해 더 읽고 싶다면 <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette의 Lifespan 문서</a>에서 확인할 수 있습니다.
+Starlette `lifespan` 핸들러에 대해서는 <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette의 Lifespan 문서</a>에서 더 읽어볼 수 있습니다.
-이 문서에는 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.
+또한 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.
///
-## 서브 애플리케이션
+## 서브 애플리케이션 { #sub-applications }
-🚨 이 lifespan 이벤트(`startup`과 `shutdown`)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md){.internal-link target=_blank}에는 실행되지 않음을 유의하세요.
+🚨 이 lifespan 이벤트(startup 및 shutdown)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md){.internal-link target=_blank}에는 실행되지 않음을 유의하세요.
-# 심화 사용자 안내서 - 도입부
+# 심화 사용자 안내서 - 도입부 { #advanced-user-guide }
-## 추가 기능
+## 추가 기능 { #additional-features }
메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}는 여러분이 **FastAPI**의 모든 주요 기능을 둘러보시기에 충분할 것입니다.
///
-## 자습서를 먼저 읽으십시오
+## 자습서를 먼저 읽으십시오 { #read-the-tutorial-first }
여러분은 메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}의 지식으로 **FastAPI**의 대부분의 기능을 사용하실 수 있습니다.
이어지는 장들은 여러분이 메인 자습서 - 사용자 안내서를 이미 읽으셨으며 주요 아이디어를 알고 계신다고 가정합니다.
-
-## TestDriven.io 강좌
-
-여러분이 문서의 이 부분을 보완하시기 위해 심화-기초 강좌 수강을 희망하신다면 다음을 참고 하시기를 바랍니다: **TestDriven.io**의 <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">FastAPI와 Docker를 사용한 테스트 주도 개발</a>.
-
-그들은 현재 전체 수익의 10퍼센트를 **FastAPI** 개발에 기부하고 있습니다. 🎉 😄
-# 응답 - 상태 코드 변경
+# 응답 - 상태 코드 변경 { #response-change-status-code }
기본 [응답 상태 코드 설정](../tutorial/response-status-code.md){.internal-link target=_blank}이 가능하다는 걸 이미 알고 계실 겁니다.
하지만 경우에 따라 기본 설정과 다른 상태 코드를 반환해야 할 때가 있습니다.
-## 사용 예
+## 사용 예 { #use-case }
예를 들어 기본적으로 HTTP 상태 코드 "OK" `200`을 반환하고 싶다고 가정해 봅시다.
하지만 데이터가 존재하지 않으면 이를 새로 생성하고, HTTP 상태 코드 "CREATED" `201`을 반환하고자 할 때가 있을 수 있습니다.
-이때도 여전히 `response_model`을 사용하여 반환하는 데이터를 필터링하고 변환하고 싶을 수 있습니다.
+하지만 여전히 `response_model`을 사용하여 반환하는 데이터를 필터링하고 변환할 수 있기를 원합니다.
이런 경우에는 `Response` 파라미터를 사용할 수 있습니다.
-## `Response` 파라미터 사용하기
+## `Response` 파라미터 사용하기 { #use-a-response-parameter }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게)
+*ê²½ë¡\9c ì²\98리 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게)
그리고 이 *임시* 응답 객체에서 `status_code`를 설정할 수 있습니다.
-{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
+{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
-그리고 평소처럼 원하는 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
+그리고 평소처럼 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).
`response_model`을 선언했다면 반환된 객체는 여전히 필터링되고 변환됩니다.
-**FastAPI**는 이 *임시* 응답 객체에서 상태 코드(쿠키와 헤더 포함)를 추출하여, `response_model`로 필터링된 반환 값을 최종 응답에 넣습니다.
+**FastAPI**는 이 *임시* 응답 객체에서 상태 코드(쿠키와 헤더 포함)를 추출하여, `response_model`로 필터링된 반환 값을 포함하는 최종 응답에 넣습니다.
또한, 의존성에서도 `Response` 파라미터를 선언하고 그 안에서 상태 코드를 설정할 수 있습니다. 단, 마지막으로 설정된 상태 코드가 우선 적용된다는 점을 유의하세요.
-# 응답 쿠키
+# 응답 쿠키 { #response-cookies }
-## `Response` 매개변수 사용하기
+## `Response` 매개변수 사용하기 { #use-a-response-parameter }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다.
+*ê²½ë¡\9c ì²\98리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다.
그런 다음 해당 *임시* 응답 객체에서 쿠키를 설정할 수 있습니다.
-{* ../../docs_src/response_cookies/tutorial002.py hl[1,8:9] *}
+{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
-그런 다음 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
+그런 다음 일반적으로 하듯이 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).
그리고 `response_model`을 선언했다면 반환한 객체를 거르고 변환하는 데 여전히 사용됩니다.
-**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, 반환된 값이 포함된 최종 응답에 이를 넣습니다. 이 값은 `response_model`로 걸러지게 됩니다.
+**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, `response_model`로 필터링된 반환 값이 포함된 최종 응답에 이를 넣습니다.
또한 의존관계에서 `Response` 매개변수를 선언하고, 해당 의존성에서 쿠키(및 헤더)를 설정할 수도 있습니다.
-## `Response`를 직접 반환하기
+## `Response`를 직접 반환하기 { #return-a-response-directly }
코드에서 `Response`를 직접 반환할 때도 쿠키를 생성할 수 있습니다.
이를 위해 [Response를 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성할 수 있습니다.
그런 다음 쿠키를 설정하고 반환하면 됩니다:
-{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
-/// tip
+
+{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
+
+/// tip | 팁
`Response` 매개변수를 사용하지 않고 응답을 직접 반환하는 경우, FastAPI는 이를 직접 반환한다는 점에 유의하세요.
따라서 데이터가 올바른 유형인지 확인해야 합니다. 예: `JSONResponse`를 반환하는 경우, JSON과 호환되는지 확인하세요.
-또한 `response_model`로 걸러져야 할 데이터가 전달되지 않도록 확인하세요.
+또한 `response_model`로 필터링되어야 했던 데이터를 전송하지 않도록 하세요.
///
-### 추가 정보
+### 추가 정보 { #more-info }
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
`from starlette.responses import Response` 또는 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
-**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 그러나 대부분의 응답은 Starlette에서 직접 제공됩니다.
+**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 제공됩니다.
또한 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용되므로, **FastAPI**는 이를 `fastapi.Response`로도 제공합니다.
///
-사용 가능한 모든 매개변수와 옵션은 <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette 문서</a>에서 확인할 수 있습니다.
+사용 가능한 모든 매개변수와 옵션은 <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette의 문서</a>에서 확인할 수 있습니다.
-# 응답을 직접 반환하기
+# 응답을 직접 반환하기 { #return-a-response-directly }
-**FastAPI**ì\97\90ì\84\9c *ê²½ë¡\9c ì\9e\91ì\97\85(path operation)*ì\9d\84 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다.
+**FastAPI**ì\97\90ì\84\9c *ê²½ë¡\9c ì²\98리(path operation)*를 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다.
-기본적으로 **FastAPI**는 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}에 설명된 `jsonable_encoder`를 사용해 해당 반환 값을 자동으로 `JSON`으로 변환합니다.
+기본적으로 **FastAPI**는 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}에 설명된 `jsonable_encoder`를 사용해 해당 반환 값을 자동으로 JSON으로 변환합니다.
-그런 다음, JSON í\98¸í\99\98 ë\8d°ì\9d´í\84°(ì\98\88: `dict`)를 `JSONResponse`ì\97\90 ë\84£ì\96´ ì\82¬ì\9a©ì\9e\90ì\9d\98 ì\9d\91ë\8bµì\9d\84 ì \84ì\86¡í\95\98ë\8a\94 ë°©ì\8b\9dì\9c¼ë¡\9c ì²\98리ë\90©ë\8b\88ë\8b¤.
+그런 다음, ë\82´ë¶\80ì \81ì\9c¼ë¡\9cë\8a\94 JSON í\98¸í\99\98 ë\8d°ì\9d´í\84°(ì\98\88: `dict`)를 `JSONResponse`ì\97\90 ë\84£ì\96´ í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ë¡\9c ì\9d\91ë\8bµì\9d\84 ì \84ì\86¡í\95\98ë\8a\94 ë\8d° ì\82¬ì\9a©í\95©ë\8b\88ë\8b¤.
-그러나 *경로 작업*에서 `JSONResponse`를 직접 반환할 수도 있습니다.
+하지만 *경로 처리*에서 `JSONResponse`를 직접 반환할 수도 있습니다.
예를 들어, 사용자 정의 헤더나 쿠키를 반환해야 하는 경우에 유용할 수 있습니다.
-## `Response` 반환하기
+## `Response` 반환하기 { #return-a-response }
사실, `Response` 또는 그 하위 클래스를 반환할 수 있습니다.
-/// tip
+/// tip | 팁
`JSONResponse` 자체도 `Response`의 하위 클래스입니다.
이로 인해 많은 유연성을 얻을 수 있습니다. 어떤 데이터 유형이든 반환할 수 있고, 데이터 선언이나 유효성 검사를 재정의할 수 있습니다.
-## `Response`에서 `jsonable_encoder` 사용하기
+## `Response`에서 `jsonable_encoder` 사용하기 { #using-the-jsonable-encoder-in-a-response }
-**FastAPI**는 반환하는 `Response`에 아무런 변í\99\98ì\9d\84 í\95\98ì§\80 ì\95\8aì\9c¼ë¯\80ë¡\9c, ê·¸ ë\82´ì\9a©ì\9d´ ì¤\80ë¹\84ë\90\98ì\96´ ì\9e\88ì\96´ì\95¼ í\95©ë\8b\88ë\8b¤.
+**FastAPI**는 반환하는 `Response`에 아무런 변ê²½ë\8f\84 í\95\98ì§\80 ì\95\8aì\9c¼ë¯\80ë¡\9c, ê·¸ ë\82´ì\9a©ì\9d´ ì¤\80ë¹\84ë\90\98ì\96´ ì\9e\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95´ì\95¼ í\95©ë\8b\88ë\8b¤.
-예를 들어, Pydantic 모델을 `dict`로 변환해 `JSONResponse`에 넣지 않으면 JSON 호환 유형으로 변환된 데이터 유형(예: `datetime`, `UUID` 등)이 사용되지 않습니다.
+예를 들어, Pydantic 모델을 먼저 `dict`로 변환하고 `datetime`, `UUID` 등의 모든 데이터 타입을 JSON 호환 타입으로 변환하지 않으면 Pydantic 모델을 `JSONResponse`에 넣을 수 없습니다.
이러한 경우, 데이터를 응답에 전달하기 전에 `jsonable_encoder`를 사용하여 변환할 수 있습니다:
-{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
+{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
-/// note | 기술적 세부 사항
+/// note | 기술 세부사항
`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
-**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 제공합니다. 그러나 대부분의 가능한 응답은 Starlette에서 직접 제공합니다.
+**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 제공합니다.
///
-## 사용자 정의 `Response` 반환하기
-위 예제는 필요한 모든 부분을 보여주지만, 아직 유용하지는 않습니다. 사실 데이터를 직접 반환하면 **FastAPI**가 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등 모든 작업을 자동으로 처리합니다.
+## 사용자 정의 `Response` 반환하기 { #returning-a-custom-response }
-ì\9d´ì \9c, ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 ì\9d\91ë\8bµì\9d\84 ë°\98í\99\98í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ì\95\8cì\95\84ë³´ê² ì\8aµ니다.
+ì\9c\84 ì\98\88ì \9cë\8a\94 í\95\84ì\9a\94í\95\9c 모ë\93 ë¶\80ë¶\84ì\9d\84 ë³´ì\97¬ì£¼ì§\80ë§\8c, ì\95\84ì§\81ì\9d\80 ê·¸ë\8b¤ì§\80 ì\9c ì\9a©í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. `item`ì\9d\84 ê·¸ë\83¥ ì§\81ì \91 ë°\98í\99\98í\96\88ì\96´ë\8f\84 **FastAPI**ê°\80 기본ì\9c¼ë¡\9c ì\9d´ë¥¼ `JSONResponse`ì\97\90 ë\84£ê³ `dict`ë¡\9c ë³\80í\99\98í\95\98ë\8a\94 ë\93±ì\9d\98 ì\9e\91ì\97\85ì\9d\84 모ë\91\90 ì\88\98í\96\89í\95´ 주ì\97\88ì\9d\84 ê²\83ì\9d´ê¸° ë\95\8c문ì\9e\85니다.
-예를 들어 <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> 응답을 반환하고 싶다고 가정해보겠습니다.
+이제, 이를 사용해 사용자 정의 응답을 반환하는 방법을 알아보겠습니다.
+
+예를 들어 <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> 응답을 반환하고 싶다고 가정해 보겠습니다.
XML 내용을 문자열에 넣고, 이를 `Response`에 넣어 반환할 수 있습니다:
-{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+
+## 참고 사항 { #notes }
-## 참고 사항
`Response`를 직접 반환할 때, 그 데이터는 자동으로 유효성 검사되거나, 변환(직렬화)되거나, 문서화되지 않습니다.
그러나 [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}에서 설명된 대로 문서화할 수 있습니다.
-이후 단락에서 자동 데이터 변환, 문서화 등을 사용하면서 사용자 정의 `Response`를 선언하는 방법을 확인할 수 있습니다.
+이후 섹션에서 자동 데이터 변환, 문서화 등을 계속 사용하면서 이러한 사용자 정의 `Response`를 사용하는/선언하는 방법을 확인할 수 있습니다.
-# 응답 헤더
+# 응답 헤더 { #response-headers }
-## `Response` 매개변수 사용하기
+## `Response` 매개변수 사용하기 { #use-a-response-parameter }
-ì\97¬ë\9f¬ë¶\84ì\9d\80 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다).
+ì\97¬ë\9f¬ë¶\84ì\9d\80 *ê²½ë¡\9c ì²\98리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다).
그런 다음, 여러분은 해당 *임시* 응답 객체에서 헤더를 설정할 수 있습니다.
-{* ../../docs_src/response_headers/tutorial002.py hl[1,7:8] *}
+{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
그 후, 일반적으로 사용하듯이 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
또한, 종속성에서 `Response` 매개변수를 선언하고 그 안에서 헤더(및 쿠키)를 설정할 수 있습니다.
-## `Response` 직접 반환하기
+## `Response` 직접 반환하기 { #return-a-response-directly }
`Response`를 직접 반환할 때에도 헤더를 추가할 수 있습니다.
[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성하고, 헤더를 추가 매개변수로 전달하세요.
-{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *}
+{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
`from starlette.responses import Response`나 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
-**FastAPI**는 `starlette.responses`를 `fastapi.responses`로 개발자의 편의를 위해 직접 제공하지만, 대부분의 응답은 Starlette에서 직접 제공됩니다.
+**FastAPI**는 해당 *임시* 응답에서 헤더(쿠키와 상태 코드도 포함)를 추출하여, 여러분이 반환한 값을 포함하는 최종 응답에 `response_model`로 필터링된 값을 넣습니다.
그리고 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용될 수 있으므로, **FastAPI**는 `fastapi.Response`로도 이를 제공합니다.
///
-## 커스텀 헤더
+## 커스텀 헤더 { #custom-headers }
-<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">‘X-’ 접두어를 사용하여</a> 커스텀 사설 헤더를 추가할 수 있습니다.
+<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` 접두어를 사용하여</a> 커스텀 사설 헤더를 추가할 수 있다는 점을 기억하세요.
-하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). `expose_headers` 매개변수를 사용하여 <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette의 CORS 설명서</a>에 문서화된 대로 설정할 수 있습니다.
+하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette의 CORS 문서</a>에 문서화된 `expose_headers` 매개변수를 사용하세요.
-# 하위 응용프로그램 - 마운트
+# 하위 응용프로그램 - 마운트 { #sub-applications-mounts }
-만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)을 “마운트"해서 사용할 수 있습니다.
+각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 애플리케이션이 필요하다면, 메인 앱을 두고 하나(또는 그 이상)의 하위 응용프로그램을 "마운트"할 수 있습니다.
-## **FastAPI** ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ ë§\88ì\9a´í\8a¸
+## **FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98 ë§\88ì\9a´í\8a¸ { #mounting-a-fastapi-application }
-“마운트"이란 완전히 “독립적인" 응용프로그램을 특정 경로에 추가하여 해당 하위 응용프로그램에서 선언된 *경로 동작*을 통해 해당 경로 아래에 있는 모든 작업들을 처리할 수 있도록 하는 것을 의미합니다.
+"마운트"란 완전히 "독립적인" 애플리케이션을 특정 경로에 추가하고, 그 하위 응용프로그램에 선언된 _경로 처리_로 해당 경로 아래의 모든 것을 처리하도록 하는 것을 의미합니다.
-### 최상단 응용프로그램
+### 최상위 애플리케이션 { #top-level-application }
-먼저, 메인, 최상단의 **FastAPI** 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+먼저, 메인 최상위 **FastAPI** 애플리케이션과 그 *경로 처리*를 생성합니다:
-{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *}
+{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
-### 하위 응용프로그램
+### 하위 응용프로그램 { #sub-application }
-다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+그 다음, 하위 응용프로그램과 그 *경로 처리*를 생성합니다.
-ì\9d´ í\95\98ì\9c\84 ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 ë\98\90 ë\8b¤ë¥¸ í\91\9cì¤\80 FastAPI ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9e\85ë\8b\88ë\8b¤. ë\8b¤ë§\8c ì\9d´ê²\83ì\9d\80 â\80\9cë§\88ì\9a´í\8a¸â\80\9dë\90 ê²\83입니다:
+ì\9d´ í\95\98ì\9c\84 ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 ë\98\90 ë\8b¤ë¥¸ í\91\9cì¤\80 FastAPI ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ì§\80ë§\8c, "ë§\88ì\9a´í\8a¸"ë\90 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98입니다:
-{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *}
+{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
-### 하위 응용프로그램 마운트
+### 하위 응용프로그램 마운트 { #mount-the-sub-application }
-최상단 응용프로그램, `app`에 하위 응용프로그램, `subapi`를 마운트합니다.
+최상위 애플리케이션 `app`에서 하위 응용프로그램 `subapi`를 마운트합니다.
-이 예시에서, 하위 응용프로그램션은 `/subapi` 경로에 마운트 될 것입니다:
+이 경우 `/subapi` 경로에 마운트됩니다:
-{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *}
+{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
-### 자동으로 생성된 API 문서 확인
+### 자동 API 문서 확인 { #check-the-automatic-api-docs }
-이제, `uvicorn`으로 메인 응용프로그램을 실행하십시오. 당신의 파일이 `main.py`라면, 이렇게 실행합니다:
+이제 파일과 함께 `fastapi` 명령을 실행하세요:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ 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>
-ê·¸ë¦¬ê³ <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>ì\97\90ì\84\9c 문ì\84\9c를 ì\97¬ì\8bì\8b\9cì\98¤.
+ê·¸ë¦¬ê³ <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>ì\97\90ì\84\9c 문ì\84\9c를 ì\97¬ì\84¸ì\9a\94.
-ë©\94ì\9d¸ ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 *ê²½ë¡\9c ë\8f\99ì\9e\91*ë§\8cì\9d\84 í\8f¬í\95¨í\95\98ë\8a\94, ë©\94ì\9d¸ ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\97\90 ë\8c\80í\95\9c ì\9e\90ë\8f\99 API 문ì\84\9c를 í\99\95ì\9d¸í\95 ì\88\98 ì\9e\88ì\8aµ니다:
+ë©\94ì\9d¸ ì\95±ì\9d\98 ì\9e\90ë\8f\99 API 문ì\84\9c를 ë³´ê²\8c ë\90 ê²\83ì\9d´ë©°, ë©\94ì\9d¸ ì\95± ì\9e\90ì²´ì\9d\98 _ê²½ë¡\9c ì²\98리_ë§\8c í\8f¬í\95¨ë\90©니다:
-<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image01.png">
+<img src="/img/tutorial/sub-applications/image01.png">
-다음으로, <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>에서 하위 응용프로그램의 문서를 여십시오.
+그 다음, <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>에서 하위 응용프로그램의 문서를 여세요.
-하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
+하위 응용프로그램의 자동 API 문서를 보게 될 것이며, 하위 경로 접두사 `/subapi` 아래에 올바르게 포함된 하위 응용프로그램 자체의 _경로 처리_만 포함됩니다:
-<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image02.png">
+<img src="/img/tutorial/sub-applications/image02.png">
-두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저는 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다.
+두 사용자 인터페이스 중 어느 것과 상호작용을 시도하더라도 올바르게 동작할 것입니다. 브라우저가 각 특정 앱 또는 하위 앱과 통신할 수 있기 때문입니다.
-### 기술적 세부사항: `root_path`
+### 기술적 세부사항: `root_path` { #technical-details-root-path }
-위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다.
+위에서 설명한 대로 하위 응용프로그램을 마운트하면, FastAPI는 ASGI 명세의 메커니즘인 `root_path`를 사용해 하위 응용프로그램에 대한 마운트 경로를 전달하는 작업을 처리합니다.
-ì\9d´ë¥¼ í\86µí\95´, í\95\98ì\9c\84 ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 문ì\84\9c UI를 ì\9c\84í\95´ ê²½ë¡\9c ì \91ë\91\90ì\82¬ë¥¼ ì\82¬ì\9a©í\95´ì\95¼ í\95\9cë\8b¤ë\8a\94 ì\82¬ì\8b¤ì\9d\84 ì\9d¸ì§\80í\95©ë\8b\88ë\8b¤.
+ì\9d´ë \87ê²\8c í\95\98ë©´ í\95\98ì\9c\84 ì\9d\91ì\9a©í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 문ì\84\9c UI를 ì\9c\84í\95´ í\95´ë\8b¹ ê²½ë¡\9c ì \91ë\91\90ì\82¬ë¥¼ ì\82¬ì\9a©í\95´ì\95¼ í\95\9cë\8b¤ë\8a\94 ê²\83ì\9d\84 ì\95\8cê²\8c ë\90©ë\8b\88ë\8b¤.
-하위 응용프로그램에도 역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 FastAPI가 모든 `root_path` 들을 자동적으로 처리하기 때문에 모든 것은 올바르게 동작할 것입니다.
+또한 하위 응용프로그램도 자체적으로 하위 앱을 마운트할 수 있으며, FastAPI가 이 모든 `root_path`를 자동으로 처리하기 때문에 모든 것이 올바르게 동작합니다.
-`root_path`와 이것을 사용하는 방법에 대해서는 [프록시의 뒷단](./behind-a-proxy.md){.internal-link target=_blank} 섹션에서 배울 수 있습니다.
+`root_path`와 이를 명시적으로 사용하는 방법에 대해서는 [프록시 뒤](behind-a-proxy.md){.internal-link target=_blank} 섹션에서 더 알아볼 수 있습니다.
-# 템플릿
+# 템플릿 { #templates }
**FastAPI**와 함께 원하는 어떤 템플릿 엔진도 사용할 수 있습니다.
설정을 쉽게 할 수 있는 유틸리티가 있으며, 이를 **FastAPI** 애플리케이션에서 직접 사용할 수 있습니다(Starlette 제공).
-## 의존성 설치
-
-가상 환경을 생성하고(virtual environment{.internal-link target=_blank}), 활성화한 후 jinja2를 설치해야 합니다:
+## 의존성 설치 { #install-dependencies }
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 후 `jinja2`를 설치해야 합니다:
<div class="termy">
</div>
-## 사용하기 `Jinja2Templates`
+## `Jinja2Templates` 사용하기 { #using-jinja2templates }
* `Jinja2Templates`를 가져옵니다.
* 나중에 재사용할 수 있는 `templates` 객체를 생성합니다.
-* 템플릿을 반환할 경로 작업에 `Request` 매개변수를 선언합니다.
+* 템플릿을 반환할 *경로 처리*에 `Request` 매개변수를 선언합니다.
* 생성한 `templates`를 사용하여 `TemplateResponse`를 렌더링하고 반환합니다. 템플릿의 이름, 요청 객체 및 Jinja2 템플릿 내에서 사용될 키-값 쌍이 포함된 "컨텍스트" 딕셔너리도 전달합니다.
-
-```Python hl_lines="4 11 15-18"
-{!../../docs_src/templates/tutorial001.py!}
-```
+{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
/// note | 참고
-FastAPI 0.108.0 이전과 Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.
+FastAPI 0.108.0 이전, Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.
-또한 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.
+또한 그 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.
///
/// tip | 팁
-`response_class=HTMLResponse`를 선언하면 문서 UI 응답이 HTML임을 알 수 있습니다.
+`response_class=HTMLResponse`를 선언하면 문서 UI가 응답이 HTML임을 알 수 있습니다.
///
-/// note | 기술 세부 사항
+/// note | 기술 세부사항
+
`from starlette.templating import Jinja2Templates`를 사용할 수도 있습니다.
-**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating` 대신 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request` 및 `StaticFiles`도 마찬가지입니다.
+**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating`과 동일하게 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request` 및 `StaticFiles`도 마찬가지입니다.
+
///
-## 템플릿 작성하기
+## 템플릿 작성하기 { #writing-templates }
그런 다음 `templates/item.html`에 템플릿을 작성할 수 있습니다. 예를 들면:
{!../../docs_src/templates/templates/item.html!}
```
-### 템플릿 컨텍스트 값
+### 템플릿 컨텍스트 값 { #template-context-values }
다음과 같은 HTML에서:
Item ID: 42
```
-### 템플릿 `url_for` 인수
+### 템플릿 `url_for` 인수 { #template-url-for-arguments }
-í\85\9cí\94\8c릿 ë\82´ì\97\90ì\84\9c `url_for()`를 ì\82¬ì\9a©í\95 ì\88\98ë\8f\84 ì\9e\88ì\9c¼ë©°, ì\9d´ë\8a\94 *ê²½ë¡\9c ì\9e\91ì\97\85 함수*에서 사용될 인수와 동일한 인수를 받습니다.
+í\85\9cí\94\8c릿 ë\82´ì\97\90ì\84\9c `url_for()`를 ì\82¬ì\9a©í\95 ì\88\98ë\8f\84 ì\9e\88ì\9c¼ë©°, ì\9d´ë\8a\94 *ê²½ë¡\9c ì²\98리 함수*에서 사용될 인수와 동일한 인수를 받습니다.
따라서 다음과 같은 부분에서:
{% endraw %}
-...ì\9d´ë\8a\94 *ê²½ë¡\9c ì\9e\91ì\97\85 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.
+...ì\9d´ë\8a\94 *ê²½ë¡\9c ì²\98리 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.
예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:
+
```html
<a href="/items/42">
```
-## 템플릿과 정적 파일
+## 템플릿과 정적 파일 { #templates-and-static-files }
템플릿 내에서 `url_for()`를 사용할 수 있으며, 예를 들어 `name="static"`으로 마운트한 `StaticFiles`와 함께 사용할 수 있습니다.
{!../../docs_src/templates/templates/item.html!}
```
-이 예제에서는 `static/styles.css`에 있는 CSS 파일에 연결될 것입니다:
+이 예제에서는 다음을 통해 `static/styles.css`에 있는 CSS 파일에 링크합니다:
```CSS hl_lines="4"
{!../../docs_src/templates/static/styles.css!}
그리고 `StaticFiles`를 사용하고 있으므로, 해당 CSS 파일은 **FastAPI** 애플리케이션에서 `/static/styles.css` URL로 자동 제공됩니다.
-## 더 많은 세부 사항
+## 더 많은 세부 사항 { #more-details }
템플릿 테스트를 포함한 더 많은 세부 사항은 <a href="https://www.starlette.dev/templates/" class="external-link" target="_blank">Starlette의 템플릿 문서</a>를 확인하세요.
-# 테스트 의존성 오버라이드
+# 오버라이드로 의존성 테스트하기 { #testing-dependencies-with-overrides }
-## 테스트 중 의존성 오버라이드하기
+## 테스트 중 의존성 오버라이드하기 { #overriding-dependencies-during-testing }
-테스트를 진행하다 보면 의존성을 오버라이드해야 하는 경우가 있습니다.
+테스트를 진행하다 보면 테스트 중에 의존성을 오버라이드해야 하는 경우가 있습니다.
원래 의존성을 실행하고 싶지 않을 수도 있습니다(또는 그 의존성이 가지고 있는 하위 의존성까지도 실행되지 않길 원할 수 있습니다).
대신, 테스트 동안(특정 테스트에서만) 사용될 다른 의존성을 제공하고, 원래 의존성이 사용되던 곳에서 사용할 수 있는 값을 제공하기를 원할 수 있습니다.
-### 사용 사례: 외부 서비스
+### 사용 사례: 외부 서비스 { #use-cases-external-service }
예를 들어, 외부 인증 제공자를 호출해야 하는 경우를 생각해봅시다.
외부 제공자를 한 번만 테스트하고 싶을 수도 있지만 테스트를 실행할 때마다 반드시 호출할 필요는 없습니다.
-ì\9d´ ê²½ì\9a° í\95´ë\8b¹ ê³µê¸\89ì\9e\90를 í\98¸ì¶\9cí\95\98ë\8a\94 ì¢\85ì\86\8dì\84±ì\9d\84 ì\98¤ë²\84ë\9d¼ì\9d´ë\93\9cí\95\98ê³ í\85\8cì\8a¤í\8a¸ì\97\90 ë\8c\80í\95´ì\84\9cë§\8c 모ì\9d\98 ì\82¬ì\9a©ì\9e\90를 ë°\98í\99\98í\95\98ë\8a\94 ì\82¬ì\9a©ì\9e\90 ì§\80ì \95 ì¢\85ì\86\8d성을 사용할 수 있습니다.
+ì\9d´ ê²½ì\9a° í\95´ë\8b¹ ê³µê¸\89ì\9e\90를 í\98¸ì¶\9cí\95\98ë\8a\94 ì\9d\98ì¡´ì\84±ì\9d\84 ì\98¤ë²\84ë\9d¼ì\9d´ë\93\9cí\95\98ê³ í\85\8cì\8a¤í\8a¸ì\97\90 ë\8c\80í\95´ì\84\9cë§\8c 모ì\9d\98 ì\82¬ì\9a©ì\9e\90를 ë°\98í\99\98í\95\98ë\8a\94 ì\82¬ì\9a©ì\9e\90 ì§\80ì \95 ì\9d\98ì¡´성을 사용할 수 있습니다.
-### `app.dependency_overrides` 속성 사용하기
+### `app.dependency_overrides` 속성 사용하기 { #use-the-app-dependency-overrides-attribute }
-ì\9d´ë\9f° ê²½ì\9a°ë¥¼ ì\9c\84í\95´ **FastAPI** ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.
+ì\9d´ë\9f° ê²½ì\9a°ë¥¼ ì\9c\84í\95´ **FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.
테스트를 위해 의존성을 오버라이드하려면, 원래 의존성(함수)을 키로 설정하고 오버라이드할 의존성(다른 함수)을 값으로 설정합니다.
**FastAPI** 애플리케이션 어디에서든 사용된 의존성에 대해 오버라이드를 설정할 수 있습니다.
-원래 의존성은 *경로 동작 함수*, *경로 동작 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.
+원래 의존성은 *경로 처리 함수*, *경로 처리 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.
FastAPI는 여전히 이를 오버라이드할 수 있습니다.
그런 다음, `app.dependency_overrides`를 빈 `dict`로 설정하여 오버라이드를 재설정(제거)할 수 있습니다:
-```python
+```Python
app.dependency_overrides = {}
```
-# 이벤트 테스트: 시작 - 종료
+# 이벤트 테스트: 라이프스팬 및 시작 - 종료 { #testing-events-lifespan-and-startup-shutdown }
-테스트에서 이벤트 핸들러(`startup` 및 `shutdown`)를 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다.
+테스트에서 `lifespan`을 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다:
-{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *}
+{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
+
+
+["공식 Starlette 문서 사이트에서 테스트에서 라이프스팬 실행하기."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)에 대한 자세한 내용을 더 읽을 수 있습니다.
+
+더 이상 권장되지 않는 `startup` 및 `shutdown` 이벤트의 경우, 다음과 같이 `TestClient`를 사용할 수 있습니다:
+
+{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
-# WebSocket 테스트하기
+# WebSocket 테스트하기 { #testing-websockets }
-`TestClient`를 사용하여 WebSocket을 테스트할 수 있습니다.
+같은 `TestClient`를 사용하여 WebSocket을 테스트할 수 있습니다.
이를 위해 `with` 문에서 `TestClient`를 사용하여 WebSocket에 연결합니다:
-{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
+{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
/// note | 참고
-자세한 내용은 Starlette의 <a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank"> WebSocket 테스트</a>에 관한 설명서를 참고하시길 바랍니다.
+자세한 내용은 Starlette의 <a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank">testing WebSockets</a> 문서를 확인하세요.
///
-# `Request` 직접 사용하기
+# `Request` 직접 사용하기 { #using-the-request-directly }
지금까지 요청에서 필요한 부분을 각 타입으로 선언하여 사용해 왔습니다.
다음과 같은 곳에서 데이터를 가져왔습니다:
-* 경로의 파라미터로부터.
+* 경로를 매개변수로.
* 헤더.
* 쿠키.
* 기타 등등.
하지만 `Request` 객체에 직접 접근해야 하는 상황이 있을 수 있습니다.
-## `Request` 객체에 대한 세부 사항
+## `Request` 객체에 대한 세부 사항 { #details-about-the-request-object }
**FastAPI**는 실제로 내부에 **Starlette**을 사용하며, 그 위에 여러 도구를 덧붙인 구조입니다. 따라서 여러분이 필요할 때 Starlette의 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">`Request`</a> 객체를 직접 사용할 수 있습니다.
-`Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기)에는 FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 문서 자동화(로 생성된) API 사용자 인터페이스)도 되지 않습니다.
+또한 이는 `Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기) FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 자동 API 사용자 인터페이스용)도 되지 않는다는 의미이기도 합니다.
그러나 다른 매개변수(예: Pydantic 모델을 사용한 본문)는 여전히 검증, 변환, 주석 추가 등이 이루어집니다.
-하지만 특정한 경우에는 `Request` 객체에 직접 접근하는 것이 유용할 수 있습니다.
+하지만 특정한 경우에는 `Request` 객체를 가져오는 것이 유용할 수 있습니다.
-## `Request` 객체를 직접 사용하기
+## `Request` 객체를 직접 사용하기 { #use-the-request-object-directly }
-ì\97¬ë\9f¬ë¶\84ì\9d´ í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ì\9d\98 IP 주ì\86\8c/í\98¸ì\8a¤í\8a¸ ì \95보를 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수* 내부에서 가져와야 한다고 가정해 보겠습니다.
+ì\97¬ë\9f¬ë¶\84ì\9d´ í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ì\9d\98 IP 주ì\86\8c/í\98¸ì\8a¤í\8a¸ ì \95보를 *ê²½ë¡\9c ì²\98리 함수* 내부에서 가져와야 한다고 가정해 보겠습니다.
이를 위해서는 요청에 직접 접근해야 합니다.
-{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *}
+{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
-*ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98* 매ê°\9cë³\80ì\88\98를 `Request` í\83\80ì\9e\85ì\9c¼ë¡\9c ì\84 ì\96¸í\95\98ë©´ **FastAPI**ê°\80 í\95´ë\8b¹ 매ê°\9cë³\80ì\88\98ì\97\90 `Request` ê°\9dì²´를 전달하는 것을 알게 됩니다.
+*ê²½ë¡\9c ì²\98리 í\95¨ì\88\98* 매ê°\9cë³\80ì\88\98를 `Request` í\83\80ì\9e\85ì\9c¼ë¡\9c ì\84 ì\96¸í\95\98ë©´ **FastAPI**ê°\80 í\95´ë\8b¹ 매ê°\9cë³\80ì\88\98ì\97\90 `Request`를 전달하는 것을 알게 됩니다.
/// tip | 팁
-이 경우, 요청 매개변수와 함께 경로 매개변수를 선언한 것을 볼 수 있습니다.
+이 경우, 요청 매개변수 옆에 경로 매개변수를 선언하고 있다는 점을 참고하세요.
따라서, 경로 매개변수는 추출되고 검증되며 지정된 타입으로 변환되고 OpenAPI로 주석이 추가됩니다.
///
-## `Request` 설명서
+## `Request` 설명서 { #request-documentation }
-여러분은 `Request` 객체에 대한 더 자세한 내용을 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">공식 Starlette 설명서 사이트</a>에서 읽어볼 수 있습니다.
+여러분은 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">공식 Starlette 설명서 사이트의 `Request` 객체</a>에 대한 더 자세한 내용을 읽어볼 수 있습니다.
/// note | 기술 세부사항
`from starlette.requests import Request`를 사용할 수도 있습니다.
-**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, 실제로는 Starlette에서 가져온 것입니다.
+**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, Starlette에서 직접 가져온 것입니다.
///
-# WebSockets
+# WebSockets { #websockets }
여러분은 **FastAPI**에서 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a>를 사용할 수 있습니다.
-## `WebSockets` 설치
+## `websockets` 설치 { #install-websockets }
-[가상 환경](../virtual-environments.md){.internal-link target=_blank)를 생성하고 활성화한 다음, `websockets`를 설치하세요:
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `websockets`("WebSocket" 프로토콜을 쉽게 사용할 수 있게 해주는 Python 라이브러리)를 설치하세요:
<div class="termy">
</div>
-## WebSockets 클라이언트
+## WebSockets 클라이언트 { #websockets-client }
-### 프로덕션 환경에서
+### 프로덕션 환경에서 { #in-production }
여러분의 프로덕션 시스템에서는 React, Vue.js 또는 Angular와 같은 최신 프레임워크로 생성된 프런트엔드를 사용하고 있을 가능성이 높습니다.
-백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.
+그리고 백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.
또는 네이티브 코드로 WebSocket 백엔드와 직접 통신하는 네이티브 모바일 응용 프로그램을 가질 수도 있습니다.
---
-하지만 이번 예제에서는 일부 자바스크립트를 포함한 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.
+하지만 이번 예제에서는 일부 자바스크립트를 포함한 매우 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.
물론, 이는 최적의 방법이 아니며 프로덕션 환경에서는 사용하지 않을 것입니다.
-í\94\84ë¡\9cë\8d\95ì\85\98 í\99\98ê²½ì\97\90ì\84\9cë\8a\94 ì\9c\84ì\97\90ì\84\9c ì\84¤ëª\85í\95\9c ì\98µì\85\98 ì¤\91 í\95\98ë\82\98를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ì\9d´ ì¢\8bì\8aµ니다.
+í\94\84ë¡\9cë\8d\95ì\85\98 í\99\98ê²½ì\97\90ì\84\9cë\8a\94 ì\9c\84ì\97\90ì\84\9c ì\84¤ëª\85í\95\9c ì\98µì\85\98 ì¤\91 í\95\98ë\82\98를 ì\82¬ì\9a©í\95 ê²\83ì\9e\85니다.
그러나 이는 WebSockets의 서버 측에 집중하고 동작하는 예제를 제공하는 가장 간단한 방법입니다:
-{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
+{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
-## `websocket` 생성하기
+## `websocket` 생성하기 { #create-a-websocket }
**FastAPI** 응용 프로그램에서 `websocket`을 생성합니다:
-{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
+{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
`from starlette.websockets import WebSocket`을 사용할 수도 있습니다.
///
-## 메시지를 대기하고 전송하기
+## 메시지를 대기하고 전송하기 { #await-for-messages-and-send-messages }
WebSocket 경로에서 메시지를 대기(`await`)하고 전송할 수 있습니다.
-{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
+{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
여러분은 이진 데이터, 텍스트, JSON 데이터를 받을 수 있고 전송할 수 있습니다.
-## 시도해보기
+## 시도해보기 { #try-it }
-파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
+파일 이름이 `main.py`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
<div class="termy">
</div>
-ë¸\8cë\9d¼ì\9a°ì \80ì\97\90ì\84\9c <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>ì\9d\84 ì\97´ì\96´ë³´세요.
+ë¸\8cë\9d¼ì\9a°ì \80ì\97\90ì\84\9c <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>ì\9d\84 ì\97¬세요.
간단한 페이지가 나타날 것입니다:
<img src="/img/tutorial/websockets/image02.png">
-**FastAPI** WebSocket 응용 프로그램이 응답을 돌려줄 것입니다:
+그리고 WebSockets가 포함된 **FastAPI** 응용 프로그램이 응답을 돌려줄 것입니다:
<img src="/img/tutorial/websockets/image03.png">
<img src="/img/tutorial/websockets/image04.png">
-모든 메시지는 동일한 WebSocket 연결을 사용합니다.
+그리고 모든 메시지는 동일한 WebSocket 연결을 사용합니다.
-## `Depends` 및 기타 사용하기
+## `Depends` 및 기타 사용하기 { #using-depends-and-others }
WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 수 있습니다:
* `Path`
* `Query`
-ì\9d´ë\93¤ì\9d\80 ë\8b¤ë¥¸ FastAPI ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸/*ê²½ë¡\9c ì\9e\91ë\8f\99*ê³¼ 동일하게 동작합니다:
+ì\9d´ë\93¤ì\9d\80 ë\8b¤ë¥¸ FastAPI ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸/*ê²½ë¡\9c ì²\98리*ì\99\80 동일하게 동작합니다:
{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
/// info | 정보
-WebSocketì\97\90ì\84\9cë\8a\94 `HTTPException`ì\9d\84 ë°\9cì\83\9dì\8b\9cí\82¤ë\8a\94 ê²\83ì\9d´ ì \81í\95©하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.
+WebSocketì\9d´ê¸° ë\95\8c문ì\97\90 `HTTPException`ì\9d\84 ë°\9cì\83\9dì\8b\9cí\82¤ë\8a\94 ê²\83ì\9d\80 ì \81ì \88하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.
명세서에 정의된 <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">유효한 코드</a>를 사용하여 종료 코드를 설정할 수 있습니다.
///
-### 종속성을 가진 WebSockets 테스트
+### 종속성을 가진 WebSockets 시도해보기 { #try-the-websockets-with-dependencies }
-파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
+파일 이름이 `main.py`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
<div class="termy">
</div>
-ë¸\8cë\9d¼ì\9a°ì \80ì\97\90ì\84\9c <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>ì\9d\84 ì\97´ì\96´ë³´세요.
+ë¸\8cë\9d¼ì\9a°ì \80ì\97\90ì\84\9c <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>ì\9d\84 ì\97¬세요.
-다음과 같은 값을 설정할 수 있습니다:
+여기에서 다음을 설정할 수 있습니다:
* 경로에 사용된 "Item ID".
* 쿼리 매개변수로 사용된 "Token".
///
-이제 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:
+이렇게 하면 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:
<img src="/img/tutorial/websockets/image05.png">
-## 연결 해제 및 다중 클라이언트 처리
+## 연결 해제 및 다중 클라이언트 처리 { #handling-disconnections-and-multiple-clients }
-WebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDisconnect` 예외를 발생시킵니다. 이를 잡아 처리할 수 있습니다:
+WebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDisconnect` 예외를 발생시킵니다. 그러면 이 예제처럼 이를 잡아 처리할 수 있습니다.
{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
* 여러 브라우저 탭에서 앱을 엽니다.
* 각 탭에서 메시지를 작성합니다.
-* 한 탭을 닫아보세요.
+* 그런 다음 탭 중 하나를 닫아보세요.
`WebSocketDisconnect` 예외가 발생하며, 다른 모든 클라이언트가 다음과 같은 메시지를 수신합니다:
/// tip | 팁
-ì\9c\84 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 ì\97¬ë\9f¬ WebSocket ì\97°ê²°ì\97\90 ë©\94ì\8b\9cì§\80를 ë¸\8cë¡\9cë\93\9cìº\90ì\8a¤í\8a¸í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ë³´ì\97¬ì£¼ë\8a\94 간단한 예제입니다.
+ì\9c\84 ì\95±ì\9d\80 ì\97¬ë\9f¬ WebSocket ì\97°ê²°ì\97\90 ë©\94ì\8b\9cì§\80를 ì²\98리í\95\98ê³ ë¸\8cë¡\9cë\93\9cìº\90ì\8a¤í\8a¸í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ë³´ì\97¬ì£¼ë\8a\94 ìµ\9cì\86\8cí\95\9cì\9d\98 간단한 예제입니다.
-그러나 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동합니다.
+하지만 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동한다는 점을 기억하세요.
-FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구를 찾고 있다면, <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>를 확인하세요.
+FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구가 필요하다면, <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>를 확인하세요.
///
-## 추가 정보
+## 추가 정보 { #more-info }
-ë\8b¤ì\9d\8c ì\98µì\85\98ì\97\90 ë\8c\80í\95\9c ì\9e\90ì\84¸í\95\9c ë\82´ì\9a©ì\9d\84 보려면 Starlette의 문서를 확인하세요:
+ë\8b¤ì\9d\8c ì\98µì\85\98ì\97\90 ë\8c\80í\95´ ë\8d\94 ì\95\8cì\95\84보려면 Starlette의 문서를 확인하세요:
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">`WebSocket` 클래스</a>.
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">클래스 기반 WebSocket 처리</a>.
-# WSGI 포함하기 - Flask, Django 그 외
+# WSGI 포함하기 - Flask, Django 그 외 { #including-wsgi-flask-django-others }
-[ì\84\9cë¸\8c ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ - ë§\88ì\9a´í\8a¸](sub-applications.md){.internal-link target=_blank}, [í\94\84ë¡\9dì\8b\9c ë\92¤í\8e¸ì\97\90ì\84\9c](behind-a-proxy.md){.internal-link target=_blank}ì\97\90ì\84\9c ë³´ì\95\98ë\93¯ì\9d´ WSGI ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ë\93¤ì\9d\84 ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d´ ë§\88ì\9a´í\8a¸ í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 마운트 할 수 있습니다.
-`WSGIMiddleware`를 사용하여 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
+이를 위해 `WSGIMiddleware`를 사용해 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
-## `WSGIMiddleware` 사용하기
+## `WSGIMiddleware` 사용하기 { #using-wsgimiddleware }
`WSGIMiddleware`를 불러와야 합니다.
그 후, 해당 경로에 마운트합니다.
-{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
+{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
-## 확인하기
+## 확인하기 { #check-it }
이제 `/v1/` 경로에 있는 모든 요청은 Flask 응용 프로그램에서 처리됩니다.
Hello, World from Flask!
```
-그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> Flask의 응답을 볼 수 있습니다:
+그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> **FastAPI**의 응답을 볼 수 있습니다:
```JSON
{
-# 벤치마크
+# 벤치마크 { #benchmarks }
-독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 <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">가장 빠른 Python 프레임워크 중 하나</a>로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다.
+독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 <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">사용 가능한 가장 빠른 Python 프레임워크 중 하나</a>로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다.
그러나 벤치마크와 비교를 확인할 때 다음 사항을 염두에 두어야 합니다.
-## 벤치마크와 속도
+## 벤치마크와 속도 { #benchmarks-and-speed }
벤치마크를 확인할 때, 일반적으로 여러 가지 유형의 도구가 동등한 것으로 비교되는 것을 볼 수 있습니다.
* **Uvicorn**: ASGI 서버
* **Starlette**: (Uvicorn 사용) 웹 마이크로 프레임워크
- * **FastAPI**: (Starlette 사용) API 구축을 위한 데이터 검증 등 여러 추가 기능이 포함된 API 마이크로 프레임워크
+ * **FastAPI**: (Starlette 사용) 데이터 검증 등 API를 구축하기 위한 여러 추가 기능이 포함된 API 마이크로 프레임워크
* **Uvicorn**:
* 서버 자체 외에는 많은 추가 코드가 없기 때문에 최고의 성능을 발휘합니다.
* **FastAPI**:
* Starlette가 Uvicorn을 사용하므로 Uvicorn보다 빨라질 수 없는 것과 마찬가지로, **FastAPI**는 Starlette를 사용하므로 더 빠를 수 없습니다.
* FastAPI는 Starlette에 추가적으로 더 많은 기능을 제공합니다. API를 구축할 때 거의 항상 필요한 데이터 검증 및 직렬화와 같은 기능들이 포함되어 있습니다. 그리고 이를 사용하면 문서 자동화 기능도 제공됩니다(문서 자동화는 응용 프로그램 실행 시 오버헤드를 추가하지 않고 시작 시 생성됩니다).
- * FastAPI를 사용하지 않고 직접 Starlette(또는 Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다.
- * ë\94°ë\9d¼ì\84\9c FastAPI를 ì\82¬ì\9a©í\95¨ì\9c¼ë¡\9cì\8d¨ ê°\9cë°\9c ì\8b\9cê°\84, ë²\84ê·¸, ì½\94ë\93\9c ë\9d¼ì\9d¸ì\9d\84 ì¤\84ì\9d¼ ì\88\98 ì\9e\88ì\9c¼ë©°, FastAPI를 ì\82¬ì\9a©í\95\98ì§\80 ì\95\8aì\95\98ì\9d\84 ë\95\8cì\99\80 ë\8f\99ì\9d¼í\95\98ê±°ë\82\98 ë\8d\94 ë\82\98ì\9d\80 ì\84±ë\8a¥ì\9d\84 ì\96»ì\9d\84 ì\88\98 ì\9e\88ì\8aµ니다(코드에서 모두 구현해야 하기 때문에).
- * FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화가 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 웹 응용 프로그램 프레임워크(또는 도구 집합)와 비교하세요.
+ * FastAPI를 사용하지 않고 직접 Starlette(또는 다른 도구, 예: Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다.
+ * ë\94°ë\9d¼ì\84\9c FastAPI를 ì\82¬ì\9a©í\95¨ì\9c¼ë¡\9cì\8d¨ ê°\9cë°\9c ì\8b\9cê°\84, ë²\84ê·¸, ì½\94ë\93\9c ë\9d¼ì\9d¸ì\9d\84 ì¤\84ì\9d¼ ì\88\98 ì\9e\88ì\9c¼ë©°, FastAPI를 ì\82¬ì\9a©í\95\98ì§\80 ì\95\8aì\95\98ì\9d\84 ë\95\8cì\99\80 ë\8f\99ì\9d¼í\95\9c ì\84±ë\8a¥(ë\98\90ë\8a\94 ë\8d\94 ë\82\98ì\9d\80 ì\84±ë\8a¥)ì\9d\84 ì\96»ì\9d\84 ì\88\98 ì\9e\88ì\9d\84 ê²\83ì\9e\85니다(코드에서 모두 구현해야 하기 때문에).
+ * FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화를 제공하는 웹 애플리케이션 프레임워크(또는 도구 집합)와 비교하세요. 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 프레임워크입니다.
-# FastAPI를 클라우드 제공업체에서 배포하기
+# 클라우드 제공업체에서 FastAPI 배포하기 { #deploy-fastapi-on-cloud-providers }
사실상 거의 **모든 클라우드 제공업체**를 사용하여 여러분의 FastAPI 애플리케이션을 배포할 수 있습니다.
대부분의 경우, 주요 클라우드 제공업체에서는 FastAPI를 배포할 수 있도록 가이드를 제공합니다.
-## 클라우드 제공업체 - 후원자들
+## FastAPI Cloud { #fastapi-cloud }
-ëª\87ëª\87 í\81´ë\9d¼ì\9a°ë\93\9c ì \9cê³µì\97\85ì²´ë\93¤ì\9d\80 [**FastAPI를 í\9b\84ì\9b\90í\95\98ë©°**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} â\9c¨, ì\9d´ë¥¼ í\86µí\95´ FastAPIì\99\80 FastAPI **ì\83\9dí\83\9cê³\84**ê°\80 ì§\80ì\86\8dì \81ì\9d´ê³ ê±´ì \84í\95\9c **ë°\9cì \84**ì\9d\84 í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**ë\8a\94 **FastAPI**를 ë§\8cë\93 ë\8f\99ì\9d¼í\95\9c ì\9e\91ì\84±ì\9e\90ì\99\80 í\8c\80ì\9d´ 구ì¶\95í\96\88ì\8aµë\8b\88ë\8b¤.
-ì\9d´ë\8a\94 FastAPIì\99\80 **커뮤ë\8b\88í\8b°** (ì\97¬ë\9f¬ë¶\84)ì\97\90 ë\8c\80í\95\9c ì§\84ì \95í\95\9c í\97\8cì\8b ì\9d\84 ë³´ì\97¬ì¤\8dë\8b\88ë\8b¤. ê·¸ë\93¤ì\9d\80 ì\97¬ë\9f¬ë¶\84ì\97\90ê²\8c **ì¢\8bì\9d\80 ì\84\9cë¹\84ì\8a¤**를 ì \9cê³µí\95 ë¿\90 ë§\8cì\9d´ ì\95\84ë\8b\88ë\9d¼ ì\97¬ë\9f¬ë¶\84ì\9d´ **í\9b\8cë¥í\95\98ê³ ê±´ê°\95í\95\9c í\94\84ë \88ì\9e\84ì\9b\8cí\81¬ì\9d¸** FastAPI 를 ì\82¬ì\9a©í\95\98길 ì\9b\90í\95\98기 ë\95\8c문ì\9e\85ë\8b\88ë\8b¤. ð\9f\99\87
+ìµ\9cì\86\8cí\95\9cì\9d\98 ë\85¸ë ¥ì\9c¼ë¡\9c API를 **구ì¶\95**, **ë°°í\8f¬**, **ì \91ê·¼**í\95\98ë\8a\94 ê³¼ì \95ì\9d\84 ê°\84ì\86\8cí\99\94í\95©ë\8b\88ë\8b¤.
-아래와 같은 서비스를 사용해보고 각 서비스의 가이드를 따를 수도 있습니다.
+FastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데에도 제공합니다. 🎉
+
+FastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 후원자이자 자금 제공자입니다. ✨
+
+## 클라우드 제공업체 - 후원자들 { #cloud-providers-sponsors }
+
+다른 몇몇 클라우드 제공업체들도 ✨ [**FastAPI를 후원합니다**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨. 🙇
+
+가이드를 따라 하고 서비스를 사용해보기 위해 이들도 고려해볼 수 있습니다:
+
+* <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>
-# 컨테이너의 FastAPI - 도커
+# 컨테이너의 FastAPI - 도커 { #fastapi-in-containers-docker }
-FastAPI ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ë°°í\8f¬í\95 ë\95\8c ì\9d¼ë°\98ì \81ì\9d¸ ì \91ê·¼ ë°©ë²\95ì\9d\80 **리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80**를 ì\83\9dì\84±í\95\98ë\8a\94 ê²\83ì\9e\85ë\8b\88ë\8b¤. ì\9d´ ë°©ë²\95ì\9d\80 주ë¡\9c <a href="https://www.docker.com/" class="external-link" target="_blank">**ë\8f\84커**</a>를 ì\82¬ì\9a©í\95´ ì\9d´ë£¨ì\96´ì§\91ë\8b\88ë\8b¤. ê·¸ë\9f° ë\8b¤ì\9d\8c í\95´ë\8b¹ 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ëª\87ê°\80ì§\80 ë°©ë²\95ì\9c¼로 배포할 수 있습니다.
+FastAPI ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ë°°í\8f¬í\95 ë\95\8c ì\9d¼ë°\98ì \81ì\9d¸ ì \91ê·¼ ë°©ë²\95ì\9d\80 **리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80**를 ë¹\8cë\93\9cí\95\98ë\8a\94 ê²\83ì\9e\85ë\8b\88ë\8b¤. ë³´í\86µ <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>를 ì\82¬ì\9a©í\95´ ì\88\98í\96\89í\95©ë\8b\88ë\8b¤. ê·¸ë\9f° ë\8b¤ì\9d\8c í\95´ë\8b¹ 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ëª\87 ê°\80ì§\80 ê°\80ë\8a¥í\95\9c ë°©ë²\95 ì¤\91 í\95\98ë\82\98로 배포할 수 있습니다.
-리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88를 ì\82¬ì\9a©í\95\98ë\8a\94 ë\8d°ì\97\90ë\8a\94 **ë³´ì\95\88**, **ë°\98ë³µ ê°\80ë\8a¥ì\84±**, **ë\8b¨ì\88\9cí\95¨** ë\93±ì\9d\98 장점이 있습니다.
+리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88를 ì\82¬ì\9a©í\95\98ë©´ **ë³´ì\95\88**, **ì\9e¬í\98\84 ê°\80ë\8a¥ì\84±**, **ë\8b¨ì\88\9cí\95¨** ë\93± ì\97¬ë\9f¬ 장점이 있습니다.
/// tip | 팁
-ì\8b\9cê°\84ì\97\90 ì«\93ê¸°ê³ ì\9e\88ê³ ì\9d´ë¯¸ ì\9d´ë\9f°ê²\83ë\93¤ì\9d\84 ì\95\8cê³ ì\9e\88ë\8b¤ë©´ [`Dockerfile`ð\9f\91\87](#build-a-docker-image-for-fastapi)ë¡\9c ì \90í\94\84í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\8b\9cê°\84ì\9d´ ì\97\86ê³ ì\9d´ë¯¸ ì\9d´ë\9f° ë\82´ì\9a©ë\93¤ì\9d\84 ì\95\8cê³ ê³\84ì\8b ê°\80ì\9a\94? ì\95\84ë\9e\98ì\9d\98 [`Dockerfile` ð\9f\91\87](#build-a-docker-image-for-fastapi)ë¡\9c ì\9d´ë\8f\99í\95\98ì\84¸ì\9a\94.
///
<details>
-<summary>도커파일 미리보기 👀</summary>
+<summary>Dockerfile Preview 👀</summary>
```Dockerfile
FROM python:3.9
COPY ./app /code/app
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
# If running behind a proxy like Nginx or Traefik add --proxy-headers
-# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
+# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
```
</details>
-## 컨테이너란
+## 컨테이너란 { #what-is-a-container }
-컨테이너(주로 리눅스 컨테이너)는 어플리케이션의 의존성과 필요한 파일들을 모두 패키징하는 매우 **가벼운** 방법입니다. 컨테이너는 같은 시스템에 있는 다른 컨테이너(다른 어플리케이션이나 요소들)와 독립적으로 유지됩니다.
+컨테이너(주로 리눅스 컨테이너)는 모든 의존성과 필요한 파일을 포함해 애플리케이션을 패키징하면서, 같은 시스템의 다른 컨테이너(다른 애플리케이션이나 컴포넌트)와는 분리된 상태로 유지할 수 있는 매우 **가벼운** 방법입니다.
-리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88ë\8a\94 í\98¸ì\8a¤í\8a¸(머ì\8b , ê°\80ì\83\81 머ì\8b , í\81´ë\9d¼ì\9a°ë\93\9c ì\84\9cë²\84 ë\93±)ì\99\80 ê°\99ì\9d\80 리ë\88\85ì\8a¤ 커ë\84\90ì\9d\84 ì\82¬ì\9a©í\95´ ì\8b¤í\96\89ë\90©ë\8b\88ë\8b¤. ì\9d´ë§\90ì\9d\80 리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88ê°\80 (ì \84ì²´ ì\9a´ì\98\81ì²´ì \9c를 모방í\95\98ë\8a\94 ë\8b¤ë¥¸ ê°\80ì\83\81 머ì\8b ê³¼ ë¹\84êµ\90í\96\88ì\9d\84 ë\95\8c) 매ì\9a° ê°\80ë³\8dë\8b¤ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95©니다.
+리ë\88\85ì\8a¤ 컨í\85\8cì\9d´ë\84\88ë\8a\94 í\98¸ì\8a¤í\8a¸(머ì\8b , ê°\80ì\83\81 머ì\8b , í\81´ë\9d¼ì\9a°ë\93\9c ì\84\9cë²\84 ë\93±)ì\99\80 ê°\99ì\9d\80 리ë\88\85ì\8a¤ 커ë\84\90ì\9d\84 ì\82¬ì\9a©í\95´ ì\8b¤í\96\89ë\90©ë\8b\88ë\8b¤. ì¦\89, ì \84ì²´ ì\9a´ì\98\81ì²´ì \9c를 ì\97\90뮬ë \88ì\9d´ì\85\98í\95\98ë\8a\94 ì\99\84ì \84í\95\9c ê°\80ì\83\81 머ì\8b ì\97\90 ë¹\84í\95´ 매ì\9a° ê°\80ë³\8dì\8aµ니다.
-이 방법을 통해, 컨테이너는 직접 프로세스를 실행하는 것과 비슷한 정도의 **적은 자원**을 소비합니다 (가상 머신은 훨씬 많은 자원을 소비할 것입니다).
+이 방식으로 컨테이너는 프로세스를 직접 실행하는 것과 비슷한 수준의 **적은 자원**을 소비합니다(가상 머신은 훨씬 더 많은 자원을 소비합니다).
-컨테이너는 또한 그들만의 **독립된** 실행 프로세스 (일반적으로 하나의 프로세스로 충분합니다), 파일 시스템, 그리고 네트워크를 가지므로 배포, 보안, 개발 및 기타 과정을 단순화 합니다.
+또한 컨테이너는 자체적인 **격리된** 실행 프로세스(보통 하나의 프로세스), 파일 시스템, 네트워크를 가지므로 배포, 보안, 개발 등을 단순화합니다.
-## 컨테이너 이미지란
+## 컨테이너 이미지란 { #what-is-a-container-image }
-**컨테이너**는 **컨테이너 이미지**를 실행한 것 입니다.
+**컨테이너**는 **컨테이너 이미지**에서 실행됩니다.
-컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80ë\9e\80 컨í\85\8cì\9d´ë\84\88ì\97\90 í\95\84ì\9a\94í\95\9c 모ë\93 í\8c\8cì\9d¼, í\99\98ê²½ ë³\80ì\88\98 ê·¸ë¦¬ê³ ë\94\94í\8f´í\8a¸ ëª\85ë ¹/í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 **ì \95ì \81** ë²\84ì \84ì\9e\85ë\8b\88ë\8b¤. ì\97¬ê¸°ì\84\9c **ì \95ì \81**ì\9d´ë\9e\80 ë§\90ì\9d\80 컨í\85\8cì\9d´ë\84\88 **ì\9d´ë¯¸ì§\80**ê°\80 ì\9e\91ë\8f\99ë\90\98ê±°ë\82\98 ì\8b¤í\96\89ë\90\98ì§\80 ì\95\8aì\9c¼ë©°, ë\8b¨ì§\80 í\8c¨í\82¤ì§\80 í\8c\8cì\9d¼ê³¼ ë©\94í\83\80 ë\8d°ì\9d´í\84°ë\9d¼ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95©니다.
+컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80ë\8a\94 컨í\85\8cì\9d´ë\84\88ì\97\90 ì\9e\88ì\96´ì\95¼ í\95\98ë\8a\94 모ë\93 í\8c\8cì\9d¼, í\99\98ê²½ ë³\80ì\88\98, 기본 ëª\85ë ¹/í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 **ì \95ì \81** ë²\84ì \84ì\9e\85ë\8b\88ë\8b¤. ì\97¬ê¸°ì\84\9c **ì \95ì \81**ì\9d´ë\9d¼ë\8a\94 ê²\83ì\9d\80 컨í\85\8cì\9d´ë\84\88 **ì\9d´ë¯¸ì§\80**ê°\80 ì\8b¤í\96\89 ì¤\91ì\9d´ê±°ë\82\98 ì\88\98í\96\89ë\90\98ë\8a\94 ê²\83ì\9d´ ì\95\84ë\8b\88ë\9d¼, í\8c¨í\82¤ì§\95ë\90\9c í\8c\8cì\9d¼ê³¼ ë©\94í\83\80ë\8d°ì\9d´í\84°ì\9d¼ ë¿\90ì\9d´ë\9d¼ë\8a\94 ë\9c»ì\9e\85니다.
-ì \80ì\9e¥ë\90\9c ì \95ì \81 컨í\85\90ì¸ ì\9d¸ **컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80**ì\99\80 ë\8c\80ì¡°ë\90\98ê²\8c, **컨í\85\8cì\9d´ë\84\88**ë\9e\80 ë³´í\86µ ì\8b¤í\96\89ë\90 ì\88\98 ì\9e\88ë\8a\94 ì\9e\91ë\8f\99 ì\9d¸ì\8a¤í\84´ì\8a¤ë¥¼ 의미합니다.
+ì \80ì\9e¥ë\90\9c ì \95ì \81 ì½\98í\85\90ì¸ ì\9d¸ "**컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80**"ì\99\80 ë\8b¬ë¦¬, "**컨í\85\8cì\9d´ë\84\88**"ë\8a\94 ë³´í\86µ ì\8b¤í\96\89 ì¤\91ì\9d¸ ì\9d¸ì\8a¤í\84´ì\8a¤, ì¦\89 **ì\8b¤í\96\89ë\90\98ë\8a\94** ë\8c\80ì\83\81ì\9d\84 의미합니다.
-**컨테이너**가 (**컨테이너 이미지**로 부터) 시작되고 실행되면, 컨테이너는 파일이나 환경 변수를 생성하거나 변경할 수 있습니다. 이러한 변화는 오직 컨테이너에서만 존재하며, 그 기반이 되는 컨테이너 이미지에는 지속되지 않습니다 (즉 디스크에는 저장되지 않습니다).
+**컨테이너**가 시작되어 실행 중이면(**컨테이너 이미지**로부터 시작됨) 파일, 환경 변수 등을 생성하거나 변경할 수 있습니다. 이러한 변경은 해당 컨테이너에만 존재하며, 기반이 되는 컨테이너 이미지에는 지속되지 않습니다(디스크에 저장되지 않습니다).
-컨테이너 이미지는 **프로그램** 파일과 컨텐츠, 즉 `python`과 어떤 파일 `main.py`에 비교할 수 있습니다.
+컨테이너 이미지는 **프로그램** 파일과 그 콘텐츠, 예를 들어 `python`과 어떤 파일 `main.py`에 비유할 수 있습니다.
-그리고 (**컨테이너 이미지**와 대비해서) **컨테이너**는 이미지의 실제 실행 인스턴스로 **프로세스**에 비교할 수 있습니다. 사실, 컨테이너는 **프로세스 러닝**이 있을 때만 실행됩니다 (그리고 보통 하나의 프로세스 입니다). 컨테이너는 내부에서 실행되는 프로세스가 없으면 종료됩니다.
+그리고 **컨테이너** 자체는(**컨테이너 이미지**와 달리) 이미지의 실제 실행 인스턴스로서 **프로세스**에 비유할 수 있습니다. 실제로 컨테이너는 **실행 중인 프로세스**가 있을 때만 실행됩니다(보통 단일 프로세스입니다). 컨테이너 내부에 실행 중인 프로세스가 없으면 컨테이너는 중지됩니다.
-## 컨테이너 이미지
+## 컨테이너 이미지 { #container-images }
-도커는 **컨테이너 이미지**와 **컨테이너**를 생성하고 관리하는데 주요 도구 중 하나가 되어왔습니다.
+Docker는 **컨테이너 이미지**와 **컨테이너**를 생성하고 관리하는 주요 도구 중 하나입니다.
-그리고 <a href="https://hub.docker.com/" class="external-link" target="_blank">도커 허브</a>에 다양한 도구, 환경, 데이터베이스, 그리고 어플리케이션에 대해 미리 만들어진 **공식 컨테이너 이미지**가 공개되어 있습니다.
+또한 <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>에는 다양한 도구, 환경, 데이터베이스, 애플리케이션을 위한 미리 만들어진 **공식 컨테이너 이미지**가 공개되어 있습니다.
-예를 들어, 공식 <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">파이썬 이미지</a>가 있습니다.
+예를 들어, 공식 <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Python Image</a>가 있습니다.
-또한 다른 대상, 예를 들면 데이터베이스를 위한 이미지들도 있습니다:
+그리고 데이터베이스 등 다양한 용도의 다른 이미지도 많이 있습니다. 예를 들면:
* <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> 등
-미리 ë§\8cë\93¤ì\96´ì§\84 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ì\82¬ì\9a©í\95\98ë©´ ì\84\9cë¡\9c ë\8b¤ë¥¸ ë\8f\84구ë\93¤ì\9d\84 **ê²°í\95©**í\95\98기 ì\89½ì\8aµë\8b\88ë\8b¤. ë\8c\80ë¶\80ë¶\84ì\9d\98 ê²½ì\9a°ì\97\90, **ê³µì\8b\9d ì\9d´ë¯¸ì§\80ë\93¤**ì\9d\84 ì\82¬ì\9a©í\95\98ê³ í\99\98ê²½ ë³\80ì\88\98를 í\86µí\95´ ì\84¤ì \95í\95 ì\88\98 ì\9e\88ì\8aµ니다.
+미리 ë§\8cë\93¤ì\96´ì§\84 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ì\82¬ì\9a©í\95\98ë©´ ì\84\9cë¡\9c ë\8b¤ë¥¸ ë\8f\84구를 **ê²°í\95©**í\95\98ê³ ì\82¬ì\9a©í\95\98기ê°\80 매ì\9a° ì\89½ì\8aµë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´ ì\83\88ë¡\9cì\9a´ ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ë¥¼ ì\8b\9cí\97\98í\95´ ë³¼ ë\95\8cë\8f\84 ê·¸ë \87ì\8aµë\8b\88ë\8b¤. ë\8c\80ë¶\80ë¶\84ì\9d\98 ê²½ì\9a° **ê³µì\8b\9d ì\9d´ë¯¸ì§\80**를 ì\82¬ì\9a©í\95\98ê³ , í\99\98ê²½ ë³\80ì\88\98ë¡\9c ì\84¤ì \95ë§\8c í\95\98ë©´ ë\90©니다.
-ì\9d´ë\9f° ë°©ë²\95ì\9c¼ë¡\9c ë\8c\80ë¶\80ë¶\84ì\9d\98 ê²½ì\9a°ì\97\90 컨í\85\8cì\9d´ë\84\88ì\99\80 ë\8f\84커ì\97\90 ë\8c\80í\95´ ë°°ì\9a¸ ì\88\98 ì\9e\88ì\9c¼ë©° ë\8b¤ì\96\91í\95\9c ë\8f\84구ì\99\80 ì\9a\94ì\86\8cë\93¤ì\97\90 ë\8c\80í\95\9c ì§\80ì\8b\9dì\9d\84 재사용할 수 있습니다.
+ì\9d´ë \87ê²\8c í\95\98ë©´ ë§\8eì\9d\80 ê²½ì\9a° 컨í\85\8cì\9d´ë\84\88ì\99\80 Docker를 í\95\99ì\8aµí\95\98ê³ , ê·¸ ì§\80ì\8b\9dì\9d\84 ì\97¬ë\9f¬ ë\8b¤ë¥¸ ë\8f\84구ì\99\80 ì»´í\8f¬ë\84\8cí\8a¸ì\97\90 재사용할 수 있습니다.
-따라서, 서로 다른 **다중 컨테이너**를 생성한 다음 이들을 연결할 수 있습니다. 예를 들어 데이터베이스, 파이썬 어플리케이션, 리액트 프론트엔드 어플리케이션을 사용하는 웹 서버에 대한 컨테이너를 만들어 이들의 내부 네트워크로 각 컨테이너를 연결할 수 있습니다.
+따라서 데이터베이스, Python 애플리케이션, React 프론트엔드 애플리케이션이 있는 웹 서버 등 서로 다른 것들을 담은 **여러 컨테이너**를 실행하고 내부 네트워크를 통해 연결할 수 있습니다.
-모든 컨테이너 관리 시스템(도커나 쿠버네티스)은 이러한 네트워킹 특성을 포함하고 있습니다.
+Docker나 Kubernetes 같은 모든 컨테이너 관리 시스템에는 이러한 네트워킹 기능이 통합되어 있습니다.
-## 컨테이너와 프로세스
+## 컨테이너와 프로세스 { #containers-and-processes }
-**컨테이너 이미지**는 보통 **컨테이너**를 시작하기 위해 필요한 메타데이터와 디폴트 커맨드/프로그램과 그 프로그램에 전달하기 위한 파라미터들을 포함합니다. 이는 커맨드 라인에서 프로그램을 실행할 때 필요한 값들과 유사합니다.
+**컨테이너 이미지**는 보통 **컨테이너**가 시작될 때 실행되어야 하는 기본 프로그램/명령과 해당 프로그램에 전달할 매개변수를 메타데이터에 포함합니다. 커맨드 라인에서 실행할 때와 매우 유사합니다.
-**컨테이너**가 시작되면, 해당 커맨드/프로그램이 실행됩니다 (그러나 다른 커맨드/프로그램을 실행하도록 오버라이드 할 수 있습니다).
+**컨테이너**가 시작되면 해당 명령/프로그램을 실행합니다(다만 오버라이드하여 다른 명령/프로그램을 실행하게 할 수도 있습니다).
-컨테이너는 **메인 프로세스**(커맨드 또는 프로그램)이 실행되는 동안 실행됩니다.
+컨테이너는 **메인 프로세스**(명령 또는 프로그램)가 실행되는 동안 실행됩니다.
-컨테이너는 일반적으로 **단일 프로세스**를 가지고 있지만, 메인 프로세스의 서브 프로세스를 시작하는 것도 가능하며, 이 방법으로 하나의 컨테이너에 **다중 프로세스**를 가질 수 있습니다.
+컨테이너는 보통 **단일 프로세스**를 가지지만, 메인 프로세스에서 서브프로세스를 시작할 수도 있으며, 그러면 같은 컨테이너에 **여러 프로세스**가 존재하게 됩니다.
-그러나 **최소한 하나의 실행중인 프로세스**를 가지지 않고서는 실행중인 컨테이너를 가질 수 없습니다. 만약 메인 프로세스가 중단되면, 컨테이너도 중단됩니다.
+하지만 **최소 하나의 실행 중인 프로세스** 없이 실행 중인 컨테이너를 가질 수는 없습니다. 메인 프로세스가 중지되면 컨테이너도 중지됩니다.
-## FastAPI를 위한 도커 이미지 빌드하기
+## FastAPI를 위한 도커 이미지 빌드하기 { #build-a-docker-image-for-fastapi }
-이제 무언가를 만들어 봅시다! 🚀
+ì¢\8bì\8aµë\8b\88ë\8b¤, ì\9d´ì \9c 무ì\96¸ê°\80를 ë§\8cë\93¤ì\96´ ë´\85ì\8b\9cë\8b¤! ð\9f\9a\80
-**공식 파이썬** 이미지에 기반하여, FastAPI를 위한 **도커 이미지**를 **맨 처음부터** 생성하는 방법을 보이겠습니다.
+**공식 Python** 이미지에 기반하여 FastAPI용 **Docker 이미지**를 **처음부터** 빌드하는 방법을 보여드리겠습니다.
-**대부분의 경우**에 다음과 같은 것들을 하게 됩니다. 예를 들면:
+이는 **대부분의 경우**에 하고 싶은 방식입니다. 예를 들면:
-* **쿠버네티스** 또는 유사한 도구 사용하기
-* **라즈베리 파이**로 실행하기
-* 컨테이너 이미지를 실행할 클라우드 서비스 사용하기 등
+* **Kubernetes** 또는 유사한 도구를 사용할 때
+* **Raspberry Pi**에서 실행할 때
+* 컨테이너 이미지를 대신 실행해주는 클라우드 서비스를 사용할 때 등
-### 요구 패키지
+### 패키지 요구사항 { #package-requirements }
-일반적으로는 어플리케이션의 특정 파일을 위한 **패키지 요구 조건**이 있을 것입니다.
+보통 애플리케이션의 **패키지 요구사항**을 어떤 파일에 적어 둡니다.
-그 요구 조건을 **설치**하는 방법은 여러분이 사용하는 도구에 따라 다를 것입니다.
+이는 주로 그 요구사항을 **설치**하는 데 사용하는 도구에 따라 달라집니다.
-ê°\80ì\9e¥ ì\9d¼ë°\98ì \81ì\9d¸ ë°©ë²\95ì\9d\80 í\8c¨í\82¤ì§\80 ì\9d´ë¦\84ê³¼ ë²\84ì \84ì\9d´ ì¤\84 ë³\84ë¡\9c 기ë¡\9dë\90\9c `requirements.txt` í\8c\8cì\9d¼ì\9d\84 ë§\8cë\93\9c는 것입니다.
+ê°\80ì\9e¥ ì\9d¼ë°\98ì \81ì\9d¸ ë°©ë²\95ì\9d\80 í\8c¨í\82¤ì§\80 ì\9d´ë¦\84ê³¼ ë²\84ì \84ì\9d\84 í\95\9c ì¤\84ì\97\90 í\95\98ë\82\98ì\94© ì \81ì\96´ ë\91\94 `requirements.txt` í\8c\8cì\9d¼ì\9d\84 ì\82¬ì\9a©í\95\98는 것입니다.
-버전ì\9d\98 ë²\94ì\9c\84를 ì\84¤ì \95í\95\98기 ì\9c\84í\95´ì\84\9cë\8a\94 [FastAPI ë²\84ì \84ë\93¤ì\97\90 ë\8c\80í\95\98ì\97¬](versions.md){.internal-link target=_blank}ì\97\90 ì\93°ì\97¬ì§\84 ê²\83ê³¼ ê°\99ì\9d\80 ì\95\84ì\9d´ë\94\94ì\96´ë¥¼ ì\82¬ì\9a©í\95©ë\8b\88ë\8b¤.
+버전 ë²\94ì\9c\84를 ì\84¤ì \95í\95 ë\95\8cë\8a\94 [FastAPI ë²\84ì \84ë\93¤ì\97\90 ë\8c\80í\95\98ì\97¬](versions.md){.internal-link target=_blank}ì\97\90ì\84\9c ì\9d½ì\9d\80 ê²\83ê³¼ ê°\99ì\9d\80 ì\95\84ì\9d´ë\94\94ì\96´ë¥¼ ì\82¬ì\9a©í\95\98ë©´ ë\90©ë\8b\88ë\8b¤.
-예를 들어, `requirements.txt` 파일은 다음과 같을 수 있습니다:
+예를 들어 `requirements.txt`는 다음과 같을 수 있습니다:
```
-fastapi>=0.68.0,<0.69.0
-pydantic>=1.8.0,<2.0.0
-uvicorn>=0.15.0,<0.16.0
+fastapi[standard]>=0.113.0,<0.114.0
+pydantic>=2.7.0,<3.0.0
```
-그리고 ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c í\8c¨í\82¤ì§\80 ì¢\85ì\86\8dì\84±ì\9d\80 `pip`ë¡\9c ì\84¤ì¹\98í\95©ë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´:
+그리고 ë³´í\86µ `pip`ë¡\9c í\8c¨í\82¤ì§\80 ì\9d\98ì¡´ì\84±ì\9d\84 ì\84¤ì¹\98í\95©ë\8b\88ë\8b¤. ì\98\88를 ë\93¤ë©´:
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
-Successfully installed fastapi pydantic uvicorn
+Successfully installed fastapi pydantic
```
</div>
/// info | 정보
-패키지 종속성을 정의하고 설치하기 위한 방법과 도구는 다양합니다.
-
-나중에 아래 세션에서 Poetry를 사용한 예시를 보이겠습니다. 👇
+패키지 의존성을 정의하고 설치하는 다른 형식과 도구도 있습니다.
///
-### **FastAPI** 코드 생성하기
+### **FastAPI** 코드 생성하기 { #create-the-fastapi-code }
-* `app` 디렉터리를 생성하고 이동합니다.
-* 빈 파일 `__init__.py`을 생성합니다.
-* 다음과 같은 `main.py`을 생성합니다:
+* `app` 디렉터리를 만들고 들어갑니다.
+* 빈 파일 `__init__.py`를 만듭니다.
+* 다음 내용으로 `main.py` 파일을 만듭니다:
```Python
from typing import Union
return {"item_id": item_id, "q": q}
```
-### 도커파일
+### Dockerfile { #dockerfile }
-이제 같은 프로젝트 디렉터리에 다음과 같은 파일 `Dockerfile`을 생성합니다:
+이제 같은 프로젝트 디렉터리에 다음 내용으로 `Dockerfile` 파일을 만듭니다:
```{ .dockerfile .annotate }
-# (1)
+# (1)!
FROM python:3.9
-# (2)
+# (2)!
WORKDIR /code
-# (3)
+# (3)!
COPY ./requirements.txt /code/requirements.txt
-# (4)
+# (4)!
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-# (5)
+# (5)!
COPY ./app /code/app
-# (6)
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+# (6)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```
-1. 공식 파이썬 베이스 이미지에서 시작합니다.
+1. 공식 Python 베이스 이미지에서 시작합니다.
-2. í\98\84ì\9e¬ ì\9b\8cí\82¹ 디렉터리를 `/code`로 설정합니다.
+2. í\98\84ì\9e¬ ì\9e\91ì\97\85 디렉터리를 `/code`로 설정합니다.
- 여기에 `requirements.txt` 파일과 `app` 디렉터리를 위치시킬 것입니다.
+ 여기에 `requirements.txt` 파일과 `app` 디렉터리를 둘 것입니다.
-3. 요구 조건과 파일을 `/code` 디렉터리로 복사합니다.
+3. 요구사항 파일을 `/code` 디렉터리로 복사합니다.
- 처음에는 **오직** 요구 조건이 필요한 파일만 복사하고, 이외의 코드는 그대로 둡니다.
+ 처음에는 요구사항 파일만 **단독으로** 복사하고, 나머지 코드는 복사하지 않습니다.
- ì\9d´ í\8c\8cì\9d¼ì\9d´ **ì\9e\90주 ë°\94ë\80\8cì§\80 ì\95\8a기 ë\95\8c문ì\97\90**, ë\8f\84커ë\8a\94 í\8c\8cì\9d¼ì\9d\84 í\83\90ì§\80í\95\98ì\97¬ ì\9d´ ë\8b¨ê³\84ì\9d\98 **ìº\90ì\8b\9c**를 ì\82¬ì\9a©í\95\98ì\97¬ ë\8b¤ì\9d\8c ë\8b¨ê³\84ì\97\90ì\84\9cë\8f\84 ìº\90ì\8b\9c를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d í\95©니다.
+ ì\9d´ í\8c\8cì\9d¼ì\9d\80 **ì\9e\90주 ë°\94ë\80\8cì§\80 ì\95\8a기** ë\95\8c문ì\97\90 Dockerë\8a\94 ì\9d´ë¥¼ ê°\90ì§\80í\95\98ì\97¬ ì\9d´ ë\8b¨ê³\84ì\97\90ì\84\9c **ìº\90ì\8b\9c**를 ì\82¬ì\9a©í\95\98ê³ , ë\8b¤ì\9d\8c ë\8b¨ê³\84ì\97\90ì\84\9cë\8f\84 ìº\90ì\8b\9c를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ê²\8c í\95´ì¤\8d니다.
-4. 요구 조건 파일에 있는 패키지 종속성을 설치합니다.
+4. 요구사항 파일에 있는 패키지 의존성을 설치합니다.
- `--no-cache-dir` 옵션은 `pip`에게 다운로드한 패키지들을 로컬 환경에 저장하지 않도록 전달합니다. 이는 마치 같은 패키지를 설치하기 위해 오직 `pip`만 다시 실행하면 될 것 같지만, 컨테이너로 작업하는 경우 그렇지는 않습니다.
+ `--no-cache-dir` 옵션은 `pip`가 다운로드한 패키지를 로컬에 저장하지 않도록 합니다. 이는 `pip`가 같은 패키지를 설치하기 위해 다시 실행될 때만 의미가 있지만, 컨테이너 작업에서는 그렇지 않기 때문입니다.
- /// note | 노트
+ /// note | 참고
- `--no-cache-dir` 는 오직 `pip`와 관련되어 있으며, 도커나 컨테이너와는 무관합니다.
+ `--no-cache-dir`는 `pip`에만 관련되어 있으며 Docker나 컨테이너와는 관련이 없습니다.
///
- `--upgrade` 옵션은 `pip`에게 설치된 패키지들을 업데이트하도록 합니다.
-
- 이전 단계에서 파일을 복사한 것이 **도커 캐시**에 의해 탐지되기 때문에, 이 단계에서도 가능한 한 **도커 캐시**를 사용하게 됩니다.
+ `--upgrade` 옵션은 이미 설치된 패키지가 있다면 `pip`가 이를 업그레이드하도록 합니다.
- 이 단계에서 캐시를 사용하면 **매번** 모든 종속성을 다운로드 받고 설치할 필요가 없어, 개발 과정에서 이미지를 지속적으로 생성하는 데에 드는 **시간**을 많이 **절약**할 수 있습니다.
+ 이전 단계에서 파일을 복사한 것이 **Docker 캐시**에 의해 감지될 수 있으므로, 이 단계에서도 가능하면 **Docker 캐시를 사용**합니다.
-5. `/code` 디렉터리에 `./app` 디렉터리를 복사합니다.
+ 이 단계에서 캐시를 사용하면 개발 중에 이미지를 반복해서 빌드할 때, 의존성을 **매번 다운로드하고 설치하는** 대신 많은 **시간**을 **절약**할 수 있습니다.
- **자주 변경되는** 모든 코드를 포함하고 있기 때문에, 도커 **캐시**는 이 단계나 **이후의 단계에서** 잘 사용되지 않습니다.
+5. `./app` 디렉터리를 `/code` 디렉터리 안으로 복사합니다.
- 그러므로 컨테이너 이미지 빌드 시간을 최적화하기 위해 `Dockerfile`의 **거의 끝 부분**에 입력하는 것이 중요합니다.
+ 이 디렉터리에는 **가장 자주 변경되는** 코드가 모두 포함되어 있으므로, Docker **캐시**는 이 단계나 **이후 단계들**에서는 쉽게 사용되지 않습니다.
-6. `uvicorn` 서버를 실행하기 위해 **커맨드**를 설정합니다.
+ 따라서 컨테이너 이미지 빌드 시간을 최적화하려면 `Dockerfile`의 **끝부분 근처**에 두는 것이 중요합니다.
- `CMD`는 문자열 리스트를 입력받고, 각 문자열은 커맨드 라인의 각 줄에 입력할 문자열입니다.
+6. 내부적으로 Uvicorn을 사용하는 `fastapi run`을 사용하도록 **명령**을 설정합니다.
- 이 커맨드는 **현재 워킹 디렉터리**에서 실행되며, 이는 위에서 `WORKDIR /code`로 설정한 `/code` 디렉터리와 같습니다.
+ `CMD`는 문자열 리스트를 받으며, 각 문자열은 커맨드 라인에서 공백으로 구분해 입력하는 항목들입니다.
- 프로그램이 `/code`에서 시작하고 그 속에 `./app` 디렉터리가 여러분의 코드와 함께 들어있기 때문에, **Uvicorn**은 이를 보고 `app`을 `app.main`으로부터 **불러 올** 것입니다.
+ 이 명령은 **현재 작업 디렉터리**에서 실행되며, 이는 위에서 `WORKDIR /code`로 설정한 `/code` 디렉터리와 같습니다.
/// tip | 팁
-각 코드 라인을 코드의 숫자 버블을 클릭하여 리뷰할 수 있습니다. 👆
+코드의 각 숫자 버블을 클릭해 각 줄이 하는 일을 확인하세요. 👆
+
+///
+
+/// warning | 경고
+
+아래에서 설명하는 것처럼 `CMD` 지시어는 **항상** **exec form**을 사용해야 합니다.
///
-이제 여러분은 다음과 같은 디렉터리 구조를 가지고 있을 것입니다:
+#### `CMD` 사용하기 - Exec Form { #use-cmd-exec-form }
+
+Docker 지시어 <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a>는 두 가지 형식으로 작성할 수 있습니다:
+
+✅ **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가 정상적으로 종료(graceful shutdown)되고 [lifespan 이벤트](../advanced/events.md){.internal-link target=_blank}가 트리거되도록 하려면, 항상 **exec** form을 사용하세요.
+
+자세한 내용은 <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">shell and exec form에 대한 Docker 문서</a>를 참고하세요.
+
+이는 `docker compose`를 사용할 때 꽤 눈에 띌 수 있습니다. 좀 더 기술적인 상세 내용은 Docker Compose FAQ 섹션을 참고하세요: <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>.
+
+#### 디렉터리 구조 { #directory-structure }
+
+이제 다음과 같은 디렉터리 구조가 되어야 합니다:
```
.
└── requirements.txt
```
-#### TLS 종료 프록시의 배후
+#### TLS 종료 프록시의 배후 { #behind-a-tls-termination-proxy }
-만약 여러분이 컨테이너를 Nginx 또는 Traefik과 같은 TLS 종료 프록시 (로드 밸런서) 뒤에서 실행하고 있다면, `--proxy-headers` 옵션을 더하는 것이 좋습니다. 이 옵션은 Uvicorn에게 어플리케이션이 HTTPS 등의 뒤에서 실행되고 있으므로 프록시에서 전송된 헤더를 신뢰할 수 있다고 알립니다.
+Nginx나 Traefik 같은 TLS 종료 프록시(로드 밸런서) 뒤에서 컨테이너를 실행하고 있다면 `--proxy-headers` 옵션을 추가하세요. 이 옵션은 (FastAPI CLI를 통해) Uvicorn에게 해당 프록시가 보낸 헤더를 신뢰하도록 하여, 애플리케이션이 HTTPS 뒤에서 실행 중임을 알게 합니다.
```Dockerfile
-CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
```
-#### 도커 캐시
+#### 도커 캐시 { #docker-cache }
-이 `Dockerfile`에는 중요한 트릭이 있는데, 처음에는 **의존성이 있는 파일만** 복사하고, 나머지 코드는 그대로 둡니다. 왜 이런 방법을 써야하는지 설명하겠습니다.
+이 `Dockerfile`에는 중요한 트릭이 있습니다. 먼저 **의존성 파일만** 복사하고, 나머지 코드는 복사하지 않는 것입니다. 왜 그런지 설명하겠습니다.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
-도커와 다른 도구들은 컨테이너 이미지를 **증가하는 방식으로 빌드**합니다. `Dockerfile`의 맨 윗 부분부터 시작해, 레이어 위에 새로운 레이어를 더하는 방식으로, `Dockerfile`의 각 지시 사항으로 부터 생성된 어떤 파일이든 더해갑니다.
+Docker와 다른 도구들은 `Dockerfile`의 위에서부터 시작해, 각 지시어가 만든 파일을 포함하며 **레이어를 하나씩 위에 쌓는 방식으로** 컨테이너 이미지를 **점진적으로** 빌드합니다.
-도커 그리고 이와 유사한 도구들은 이미지 생성 시에 **내부 캐시**를 사용합니다. 만약 어떤 파일이 마지막으로 컨테이너 이미지를 빌드한 때로부터 바뀌지 않았다면, 파일을 다시 복사하여 새로운 레이어를 처음부터 생성하는 것이 아니라, 마지막에 생성했던 **같은 레이어를 재사용**합니다.
+Docker와 유사한 도구들은 이미지를 빌드할 때 **내부 캐시**도 사용합니다. 어떤 파일이 마지막으로 컨테이너 이미지를 빌드했을 때부터 바뀌지 않았다면, 파일을 다시 복사하고 새 레이어를 처음부터 만드는 대신, 이전에 만든 **같은 레이어를 재사용**합니다.
-ë\8b¨ì§\80 í\8c\8cì\9d¼ ë³µì\82¬ë¥¼ ì§\80ì\96\91í\95\98ë\8a\94 ê²\83ì\9c¼ë¡\9c í\9a¨ì\9c¨ì\9d´ ë§\8eì\9d´ í\96¥ì\83\81ë\90\98ë\8a\94 ê²\83ì\9d\80 ì\95\84ë\8b\88ì§\80ë§\8c, ê·¸ ë\8b¨ê³\84ì\97\90ì\84\9c ìº\90ì\8b\9c를 ì\82¬ì\9a©í\96\88기 ë\95\8c문ì\97\90, **ë\8b¤ì\9d\8c ë\8b¨ê³\84ì\97\90ì\84\9cë\8f\84 ë§\88ì°¬ê°\80ì§\80ë¡\9c ìº\90ì\8b\9c를 ì\82¬ì\9a©**í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´, ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\80 ì\9d\98ì¡´ì\84±ì\9d\84 ì\84¤ì¹\98í\95\98ë\8a\94 ì§\80ì\8b\9c ì\82¬í\95ì\9d\84 ì\9c\84í\95\9c ìº\90ì\8b\9c를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
+í\8c\8cì\9d¼ ë³µì\82¬ë¥¼ í\94¼í\95\98ë\8a\94 ê²\83ë§\8cì\9c¼ë¡\9c í\81° ê°\9cì\84 ì\9d´ ì\83\9d기ì§\80ë\8a\94 ì\95\8aì\9d\84 ì\88\98 ì\9e\88ì§\80ë§\8c, í\95´ë\8b¹ ë\8b¨ê³\84ì\97\90ì\84\9c ìº\90ì\8b\9c를 ì\82¬ì\9a©í\96\88기 ë\95\8c문ì\97\90 **ë\8b¤ì\9d\8c ë\8b¨ê³\84ì\97\90ì\84\9cë\8f\84 ìº\90ì\8b\9c를 ì\82¬ì\9a©í\95 ì\88\98** ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´ ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d´ ì\9d\98ì¡´ì\84±ì\9d\84 ì\84¤ì¹\98í\95\98ë\8a\94 ì§\80ì\8b\9cì\96´ì\97\90ì\84\9c ìº\90ì\8b\9c를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
-패키지를 포함하는 파일은 **자주 변경되지 않습니다**. 따라서 해당 파일만 복사하므로서, 도커는 그 단계의 **캐시를 사용**할 수 있습니다.
+패키지 요구사항 파일은 **자주 변경되지 않습니다**. 따라서 그 파일만 복사하면 Docker는 그 단계에서 **캐시를 사용할 수** 있습니다.
-그 다음으로, 도커는 **다음 단계에서** 의존성을 다운로드하고 설치하는 **캐시를 사용**할 수 있게 됩니다. 바로 이 과정에서 우리는 **많은 시간을 절약**하게 됩니다. ✨ ...그리고 기다리는 지루함도 피할 수 있습니다. 😪😆
+그리고 Docker는 그 다음 단계에서 의존성을 다운로드하고 설치할 때도 **캐시를 사용할 수** 있습니다. 바로 여기에서 **많은 시간을 절약**하게 됩니다. ✨ ...그리고 기다리며 지루해지는 것도 피할 수 있습니다. 😪😆
-패키지 의존성을 다운로드 받고 설치하는 데이는 **수 분이 걸릴 수 있지만**, **캐시**를 사용하면 최대 **수 초만에** 끝낼 수 있습니다.
+패키지 의존성을 다운로드하고 설치하는 데에는 **몇 분**이 걸릴 수 있지만, **캐시**를 사용하면 많아야 **몇 초**면 끝납니다.
-또한 여러분이 개발 과정에서 코드의 변경 사항이 반영되었는지 확인하기 위해 컨테이너 이미지를 계속해서 빌드하면, 절약된 시간은 축적되어 더욱 커질 것입니다.
+또한 개발 중에 코드 변경 사항이 동작하는지 확인하기 위해 컨테이너 이미지를 계속 빌드하게 되므로, 이렇게 절약되는 시간은 누적되어 상당히 커집니다.
-그리고 나서 `Dockerfile`의 거의 끝 부분에서, 모든 코드를 복사합니다. 이것이 **가장 빈번하게 변경**되는 부분이며, 대부분의 경우에 이 다음 단계에서는 캐시를 사용할 수 없기 때문에 가장 마지막에 둡니다.
+그 다음 `Dockerfile`의 끝부분 근처에서 모든 코드를 복사합니다. 이 부분은 **가장 자주 변경되는** 부분이므로, 거의 항상 이 단계 이후에는 캐시를 사용할 수 없기 때문에 끝부분에 둡니다.
```Dockerfile
COPY ./app /code/app
```
-### 도커 이미지 생성하기
+### 도커 이미지 생성하기 { #build-the-docker-image }
-이제 모든 파일이 제자리에 있으니, 컨테이너 이미지를 빌드합니다.
+이제 모든 파일이 제자리에 있으니 컨테이너 이미지를 빌드해봅시다.
-* (여러분의 `Dockerfile`과 `app` 디렉터리가 위치한) 프로젝트 디렉터리로 이동합니다.
+* 프로젝트 디렉터리로 이동합니다(`Dockerfile`이 있고 `app` 디렉터리를 포함하는 위치).
* FastAPI 이미지를 빌드합니다:
<div class="termy">
/// tip | 팁
-맨 ë\81\9dì\97\90 ì\9e\88ë\8a\94 `.` ì\97\90 주목í\95©ì\8b\9cë\8b¤. ì\9d´ë\8a\94 `./`ì\99\80 ë\8f\99ë\93±í\95\98ë©°, ë\8f\84커ì\97\90ê²\8c 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ë¹\8cë\93\9cí\95\98기 ì\9c\84í\95\9c 디렉터리를 알려줍니다.
+ë\81\9dì\97\90 ì\9e\88ë\8a\94 `.`ì\97\90 주목í\95\98ì\84¸ì\9a\94. ì\9d´ë\8a\94 `./`ì\99\80 ë\8f\99ì\9d¼í\95\98ë©°, Dockerì\97\90ê²\8c 컨í\85\8cì\9d´ë\84\88 ì\9d´ë¯¸ì§\80를 ë¹\8cë\93\9cí\95 ë\95\8c ì\82¬ì\9a©í\95 디렉터리를 알려줍니다.
-이 경우에는 현재 디렉터리(`.`)와 같습니다.
+이 경우 현재 디렉터리(`.`)입니다.
///
-### 도커 컨테이너 시작하기
+### 도커 컨테이너 시작하기 { #start-the-docker-container }
* 여러분의 이미지에 기반하여 컨테이너를 실행합니다:
</div>
-## 체크하기
+## 확인하기 { #check-it }
-여러분의 도커 컨테이너 URL에서 실행 사항을 체크할 수 있습니다. 예를 들어: <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> 또는 <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> (또는 동일하게, 여러분의 도커 호스트를 이용해서 체크할 수도 있습니다).
+Docker 컨테이너의 URL에서 확인할 수 있어야 합니다. 예를 들어: <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> 또는 <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>(또는 Docker 호스트를 사용해 동등하게 확인할 수 있습니다).
-아래와 비슷한 것을 보게 될 것입니다:
+아래와 같은 것을 보게 될 것입니다:
```JSON
{"item_id": 5, "q": "somequery"}
```
-## 인터랙티브 API 문서
+## 인터랙티브 API 문서 { #interactive-api-docs }
-이제 여러분은 <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> 또는 <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a>로 이동할 수 있습니다(또는, 여러분의 도커 호스트를 이용할 수 있습니다).
+이제 <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> 또는 <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a>(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수 있습니다.
-ì\97¬ë\9f¬ë¶\84ì\9d\80 ì\9e\90ë\8f\99ì\9c¼ë¡\9c ì\83\9dì\84±ë\90\9c ì\9d¸í\84°ë\9e\99í\8b°ë¸\8c API(<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>ì\97\90ì\84\9c ì \9cê³µë\90\9c)를 볼 수 있습니다:
+ì\9e\90ë\8f\99ì\9c¼ë¡\9c ì\83\9dì\84±ë\90\9c ì\9d¸í\84°ë\9e\99í\8b°ë¸\8c API 문ì\84\9c(<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> ì \9cê³µ)를 볼 수 있습니다:

-## 대안 API 문서
+## 대안 API 문서 { #alternative-api-docs }
-또한 여러분은 <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> 또는 <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a>으로 이동할 수 있습니다(또는, 여러분의 도커 호스트를 이용할 수 있습니다).
+또한 <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> 또는 <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a>(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수도 있습니다.
-여러분은 자동으로 생성된 대안 문서(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>에서 제공된)를 볼 수 있습니다:
+대안 자동 문서(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> 제공)를 볼 수 있습니다:

-## 단일 파일 FastAPI로 도커 이미지 생성하기
+## 단일 파일 FastAPI로 도커 이미지 빌드하기 { #build-a-docker-image-with-a-single-file-fastapi }
-만약 여러분의 FastAPI가 하나의 파일이라면, 예를 들어 `./app` 디렉터리 없이 `main.py` 파일만으로 이루어져 있다면, 파일 구조는 다음과 유사할 것입니다:
+FastAPI가 단일 파일(예: `./app` 디렉터리 없이 `main.py`만 있는 경우)이라면, 파일 구조는 다음과 같을 수 있습니다:
```
.
└── requirements.txt
```
-ê·¸ë\9f¬ë©´ ì\97¬ë\9f¬ë¶\84ë\93¤ì\9d\80 `Dockerfile` ë\82´ì\97\90 ì\9e\88ë\8a\94 í\8c\8cì\9d¼ì\9d\84 ë³µì\82¬í\95\98기 ì\9c\84í\95´ ê·¸ì \80 ì\83\81ì\9d\91í\95\98ë\8a\94 ê²½ë¡\9c를 ë°\94꾸기ë§\8c 하면 됩니다:
+ê·¸ë\9f° ë\8b¤ì\9d\8c `Dockerfile`ì\97\90ì\84\9c í\95´ë\8b¹ í\8c\8cì\9d¼ì\9d\84 ë³µì\82¬í\95\98ë\8f\84ë¡\9d ê²½ë¡\9cë§\8c ë§\9eê²\8c ë³\80ê²½하면 됩니다:
```{ .dockerfile .annotate hl_lines="10 13" }
FROM python:3.9
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-# (1)
+# (1)!
COPY ./main.py /code/
-# (2)
-CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
+# (2)!
+CMD ["fastapi", "run", "main.py", "--port", "80"]
```
-1. `main.py` 파일을 `/code` 디렉터리로 곧바로 복사합니다(`./app` 디렉터리는 고려하지 않습니다).
+1. `main.py` 파일을 `/code` 디렉터리로 직접 복사합니다(`./app` 디렉터리 없이).
-2. Uvicorn을 실행해 `app` 객체를 (`app.main` 대신) `main`으로 부터 불러오도록 합니다.
+2. 단일 파일 `main.py`에 있는 애플리케이션을 제공(serve)하기 위해 `fastapi run`을 사용합니다.
-그 다음 Uvicorn 커맨드를 조정해서 FastAPI 객체를 불러오는데 `app.main` 대신에 새로운 모듈 `main`을 사용하도록 합니다.
+`fastapi run`에 파일을 전달하면, 이것이 패키지의 일부가 아닌 단일 파일이라는 것을 자동으로 감지하고, 어떻게 임포트해서 FastAPI 앱을 제공할지 알아냅니다. 😎
-## 배포 개념
+## 배포 개념 { #deployment-concepts }
-ì\9d´ì \9c 컨í\85\8cì\9d´ë\84\88ì\9d\98 측면ì\97\90ì\84\9c [ë°°í\8f¬ ê°\9cë\85\90](concepts.md){.internal-link target=_blank}ì\97\90ì\84\9c ë\8b¤ë£¨ì\97\88ë\8d\98 ê²\83ê³¼ ê°\99ì\9d\80 ë°°í\8f¬ ê°\9cë\85\90ì\97\90 ë\8c\80í\95´ ì\9d´ì\95¼ê¸°í\95´ ë³´ê² ì\8aµë\8b\88다.
+컨í\85\8cì\9d´ë\84\88 ê´\80ì \90ì\97\90ì\84\9c ê°\99ì\9d\80 [ë°°í\8f¬ ê°\9cë\85\90](concepts.md){.internal-link target=_blank}ë\93¤ì\9d\84 ë\8b¤ì\8b\9c ì\9d´ì\95¼ê¸°í\95´ ë´\85ì\8b\9c다.
-컨í\85\8cì\9d´ë\84\88ë\8a\94 주ë¡\9c ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ë¹\8cë\93\9cí\95\98ê³ ë°°í\8f¬í\95\98기 ì\9c\84í\95\9c ê³¼ì \95ì\9d\84 ë\8b¨ì\88\9cí\99\94í\95\98ë\8a\94 ë\8f\84구ì\9d´ì§\80ë§\8c, **ë°°í\8f¬ ê°\9cë\85\90**ì\97\90 ë\8c\80í\95\9c í\8a¹ì \95í\95\9c ì \91ê·¼ë²\95ì\9d\84 ê°\95ì\9a\94í\95\98ì§\80 ì\95\8a기 ë\95\8c문ì\97\90 ê°\80ë\8a¥í\95\9c ë°°í\8f¬ ì \84ë\9eµì\97\90ë\8a\94 ì\97¬ë\9f¬ê°\80ì§\80ê°\80 ì\9e\88ì\8aµ니다.
+컨í\85\8cì\9d´ë\84\88ë\8a\94 주ë¡\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 **ë¹\8cë\93\9c ë°\8f ë°°í\8f¬** ê³¼ì \95ì\9d\84 ë\8b¨ì\88\9cí\99\94í\95\98ë\8a\94 ë\8f\84구ì\9d´ì§\80ë§\8c, ì\9d´ë\9f¬í\95\9c **ë°°í\8f¬ ê°\9cë\85\90**ì\9d\84 ì²\98리í\95\98ë\8a\94 í\8a¹ì \95 ì \91ê·¼ ë°©ì\8b\9dì\9d\84 ê°\95ì \9cí\95\98ì§\80ë\8a\94 ì\95\8aì\9c¼ë©°, ê°\80ë\8a¥í\95\9c ì \84ë\9eµì\9d\80 ì\97¬ë\9f¬ ê°\80ì§\80ì\9e\85니다.
-**좋은 소식**은 서로 다른 전략들을 포괄하는 배포 개념이 있다는 점입니다. 🎉
+**좋은 소식**은 각 전략마다 모든 배포 개념을 다룰 수 있는 방법이 있다는 점입니다. 🎉
-컨테이너 측면에서 **배포 개념**을 리뷰해 보겠습니다:
+컨테이너 관점에서 이 **배포 개념**들을 살펴봅시다:
* HTTPS
-* 구동하기
+* 시작 시 자동 실행
* 재시작
-* 복제 (실행 중인 프로세스 개수)
+* 복제(실행 중인 프로세스 수)
* 메모리
-* 시작하기 전 단계들
+* 시작 전 사전 단계
-## HTTPS
+## HTTPS { #https }
-만약 우리가 FastAPI 어플리케이션을 위한 **컨테이너 이미지**에만 집중한다면 (그리고 나중에 실행될 **컨테이너**에), HTTPS는 일반적으로 다른 도구에 의해 **외부적으로** 다루어질 것 입니다.
+FastAPI 애플리케이션의 **컨테이너 이미지**(그리고 나중에 실행 중인 **컨테이너**)에만 집중한다면, HTTPS는 보통 다른 도구에 의해 **외부적으로** 처리됩니다.
-**HTTPS**와 **인증서**의 **자동** 취득을 다루는 것은 다른 컨테이너가 될 수 있는데, 예를 들어 <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>을 사용하는 것입니다.
+예를 들어 <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>을 사용하는 다른 컨테이너가 **HTTPS**와 **인증서**의 **자동** 획득을 처리할 수 있습니다.
/// tip | 팁
-Traefik은 도커, 쿠버네티스, 그리고 다른 도구와 통합되어 있어 여러분의 컨테이너를 포함하는 HTTPS를 셋업하고 설정하는 것이 매우 쉽습니다.
+Traefik은 Docker, Kubernetes 등과 통합되어 있어, 이를 사용해 컨테이너에 HTTPS를 설정하고 구성하기가 매우 쉽습니다.
///
-ë\8c\80ì\95\88ì \81ì\9c¼ë¡\9c, HTTPSë\8a\94 í\81´ë\9d¼ì\9a°ë\93\9c ì \9cê³µì\9e\90ì\97\90 ì\9d\98í\95´ ì\84\9cë¹\84ì\8a¤ì\9d\98 ì\9d¼í\99\98ì\9c¼ë¡\9c ë\8b¤ë£¨ì\96´ì§\88 ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤ (ì\9d´ë\95\8cë\8f\84 ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\80 ì\97¬ì \84í\9e\88 컨í\85\8cì\9d´ë\84\88ì\97\90ì\84\9c ì\8b¤í\96\89ë\90 ê²\83ì\9e\85니다).
+ë\98\90ë\8a\94 HTTPS를 í\81´ë\9d¼ì\9a°ë\93\9c ì \9cê³µì\9e\90ê°\80 ì\84\9cë¹\84ì\8a¤ì\9d\98 ì\9d¼ë¶\80ë¡\9c ì²\98리í\95 ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤(ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\80 ì\97¬ì \84í\9e\88 컨í\85\8cì\9d´ë\84\88ì\97\90ì\84\9c ì\8b¤í\96\89ë\90©니다).
-## 구동과 재시작
+## 시작 시 자동 실행과 재시작 { #running-on-startup-and-restarts }
-여러분의 컨테이너를 **시작하고 실행하는** 데에 일반적으로 사용되는 도구는 따로 있습니다.
+보통 컨테이너를 **시작하고 실행**하는 역할을 담당하는 다른 도구가 있습니다.
-ì\9d´ë\8a\94 **ë\8f\84커** ì\9e\90ì²´ì\9d¼ ì\88\98ë\8f\84 ì\9e\88ê³ , **ë\8f\84커 ì»´í\8f¬ì¦\88**, **ì¿ ë²\84ë\84¤í\8b°ì\8a¤**, **í\81´ë\9d¼ì\9a°ë\93\9c ì\84\9cë¹\84ì\8a¤** ë\93±ì\9d´ ë\90 ì\88\98 있습니다.
+ì§\81ì \91 **Docker**ì\9d¼ ì\88\98ë\8f\84 ì\9e\88ê³ , **Docker Compose**, **Kubernetes**, **í\81´ë\9d¼ì\9a°ë\93\9c ì\84\9cë¹\84ì\8a¤** ë\93±ì\9d¼ ì\88\98ë\8f\84 있습니다.
-대부분 (또는 전체) 경우에, 컨테이너를 구동하거나 고장시에 재시작하도록 하는 간단한 옵션이 있습니다. 예를 들어, 도커에서는, 커맨드 라인 옵션 `--restart` 입니다.
+대부분(또는 전부)의 경우, 시작 시 컨테이너를 실행하고 실패 시 재시작을 활성화하는 간단한 옵션이 있습니다. 예를 들어 Docker에서는 커맨드 라인 옵션 `--restart`입니다.
-컨테이너를 사용하지 않고서는, 어플리케이션을 구동하고 재시작하는 것이 매우 번거롭고 어려울 수 있습니다. 하지만 **컨테이너를 사용한다면** 대부분의 경우에 이런 기능은 기본적으로 포함되어 있습니다. ✨
+컨테이너를 사용하지 않으면 애플리케이션을 시작 시 자동 실행하고 재시작까지 구성하는 것이 번거롭고 어렵습니다. 하지만 **컨테이너로 작업할 때**는 대부분의 경우 그 기능이 기본으로 포함되어 있습니다. ✨
-## 복제 - 프로세스 개수
+## 복제 - 프로세스 개수 { #replication-number-of-processes }
-만약 여러분이 **쿠버네티스**와 머신 <abbr title="A group of machines that are configured to be connected and work together in some way.">클러스터</abbr>, 도커 스왐 모드, 노마드, 또는 다른 여러 머신 위에 분산 컨테이너를 관리하는 복잡한 시스템을 다루고 있다면, 여러분은 각 컨테이너에서 (워커와 함께 사용하는 Gunicorn 같은) **프로세스 매니저** 대신 **클러스터 레벨**에서 **복제를 다루**고 싶을 것입니다.
+**Kubernetes**, Docker Swarm Mode, Nomad 등의 복잡한 시스템으로 여러 머신에 분산된 컨테이너를 관리하는 <abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>를 사용한다면, 각 컨테이너에서(**워커를 사용하는 Uvicorn** 같은) **프로세스 매니저**를 쓰는 대신, **클러스터 레벨**에서 **복제를 처리**하고 싶을 가능성이 큽니다.
-쿠버네티스와 같은 분산 컨테이너 관리 시스템 중 일부는 일반적으로 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서 **컨테이너 복제**를 다루는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서 말이죠.
+Kubernetes 같은 분산 컨테이너 관리 시스템은 보통 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서도, **컨테이너 복제**를 처리하는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서요.
-이런 경우에, 여러분은 [위에서 묘사된 것](#dockerfile)처럼 **처음부터 도커 이미지를** 빌드해서, 의존성을 설치하고, Uvicorn 워커를 관리하는 Gunicorn 대신 **단일 Uvicorn 프로세스**를 실행하고 싶을 것입니다.
+그런 경우에는 [위에서 설명한 대로](#dockerfile) 의존성을 설치하고, 여러 Uvicorn 워커를 사용하는 대신 **단일 Uvicorn 프로세스**를 실행하는 **처음부터 만든 Docker 이미지**를 사용하는 것이 좋을 것입니다.
-### 로드 밸런서
+### 로드 밸런서 { #load-balancer }
-컨í\85\8cì\9d´ë\84\88ë¡\9c ì\9e\91ì\97\85í\95 ë\95\8c, ì\97¬ë\9f¬ë¶\84ì\9d\80 ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c **ë©\94ì\9d¸ í\8f¬í\8a¸ì\9d\98 ì\83\81í\99©ì\9d\84 ê°\90ì§\80í\95\98ë\8a\94** ì\9a\94ì\86\8c를 ê°\80ì§\80ê³ ì\9e\88ì\9d\84 ê²\83ì\9e\85ë\8b\88ë\8b¤. ì\9d´ë\8a\94 **HTTPS**를 ë\8b¤ë£¨ë\8a\94 **TLS ì¢\85ë£\8c í\94\84ë¡\9dì\8b\9c**ì\99\80 ê°\99ì\9d\80 ë\8b¤ë¥¸ 컨í\85\8cì\9d´ë\84\88ì\9d¼ ì\88\98ë\8f\84 ì\9e\88ê³ , ì\9c ì\82¬í\95\9c ë\8b¤ë¥¸ 도구일 수도 있습니다.
+컨í\85\8cì\9d´ë\84\88를 ì\82¬ì\9a©í\95 ë\95\8cë\8a\94 ë³´í\86µ **ë©\94ì\9d¸ í\8f¬í\8a¸ì\97\90ì\84\9c ë\8c\80기(listening)í\95\98ë\8a\94** ì»´í\8f¬ë\84\8cí\8a¸ê°\80 ì\9e\88ì\8aµë\8b\88ë\8b¤. **HTTPS**를 ì²\98리í\95\98기 ì\9c\84í\95\9c **TLS ì¢\85ë£\8c í\94\84ë¡\9dì\8b\9c** ì\97í\95 ì\9d\84 í\95\98ë\8a\94 ë\8b¤ë¥¸ 컨í\85\8cì\9d´ë\84\88ì\9d¼ ì\88\98ë\8f\84 ì\9e\88ê³ , ì\9c ì\82¬í\95\9c 도구일 수도 있습니다.
-ì\9d´ ì\9a\94ì\86\8cê°\80 ì\9a\94ì²ë\93¤ì\9d\98 **ë¡\9cë\93\9c**를 ì\9d½ì\96´ë\93¤ì\9d´ê³ ê°\81 ì\9b\8c커ì\97\90ê²\8c (ë°\94ë\9d¼ê±´ë\8c\80) **ê· í\98\95ì \81ì\9c¼ë¡\9c** ë¶\84ë°°í\95\9cë\8b¤ë©´, ì\9d´ ì\9a\94ì\86\8cë\8a\94 ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c **ë¡\9cë\93\9c ë°¸ë\9f°ì\84\9c**ë\9d¼ê³ ë¶\88립니다.
+ì\9d´ ì»´í\8f¬ë\84\8cí\8a¸ê°\80 ì\9a\94ì²ì\9d\98 **ë¶\80í\95\98(load)**를 ë°\9bì\95\84 ì\9b\8c커ë\93¤ì\97\90 (ê°\80ë\8a¥í\95\98ë©´) **ê· í\98\95 ì\9e\88ê²\8c** ë¶\84ì\82°í\95\9cë\8b¤ë©´, ë³´í\86µ **ë¡\9cë\93\9c ë°¸ë\9f°ì\84\9c**ë\9d¼ê³ ë¶\80ë¦\85니다.
/// tip | 팁
-HTTPS를 위해 사용된 **TLS 종료 프록시** 요소 또한 **로드 밸런서**가 될 수 있습니다.
+HTTPS에 사용되는 동일한 **TLS 종료 프록시** 컴포넌트가 **로드 밸런서**이기도 한 경우가 많습니다.
///
-ë\98\90í\95\9c 컨í\85\8cì\9d´ë\84\88ë¡\9c ì\9e\91ì\97\85í\95 ë\95\8c, 컨í\85\8cì\9d´ë\84\88를 ì\8b\9cì\9e\91í\95\98ê³ ê´\80리í\95\98기 ì\9c\84í\95´ ì\82¬ì\9a©í\95\9c ê²\83ê³¼ ë\8f\99ì\9d¼í\95\9c ì\8b\9cì\8a¤í\85\9cì\9d\80 ì\9d´ë¯¸ í\95´ë\8b¹ **ë¡\9cë\93\9c ë°¸ë\9f°ì\84\9c**ë¡\9c ë¶\80í\84° ì\97¬ë\9f¬ë¶\84ì\9d\98 ì\95±ì\97\90 í\95´ë\8b¹í\95\98ë\8a\94 컨í\85\8cì\9d´ë\84\88ë¡\9c **ë\84¤í\8a¸ì\9b\8cí\81¬ í\86µì\8b **(ì\98\88를 ë\93¤ì\96´, HTTP ì\9a\94ì²)ì\9d\84 ì \84ì\86¡í\95\98ë\8a\94 ë\82´ë¶\80ì \81ì\9d¸ ë\8f\84구를 ê°\80ì§\80ê³ ì\9e\88ì\9d\84 ê²\83ì\9e\85ë\8b\88ë\8b¤ (ì\97¬ê¸°ì\84\9cë\8f\84 ë¡\9cë\93\9c ë°¸ë\9f°ì\84\9cë\8a\94 **TLS ì¢\85ë£\8c í\94\84ë¡\9dì\8b\9c**ì\9d¼ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤).
+ë\98\90í\95\9c 컨í\85\8cì\9d´ë\84\88ë¡\9c ì\9e\91ì\97\85í\95 ë\95\8c, ì\9d´ë¥¼ ì\8b\9cì\9e\91í\95\98ê³ ê´\80리í\95\98ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\9d\80 ì\9d´ë¯¸ í\95´ë\8b¹ **ë¡\9cë\93\9c ë°¸ë\9f°ì\84\9c**(ë\98\90ë\8a\94 **TLS ì¢\85ë£\8c í\94\84ë¡\9dì\8b\9c**)ì\97\90ì\84\9c ì\97¬ë\9f¬ë¶\84ì\9d\98 ì\95±ì\9d´ ì\9e\88ë\8a\94 컨í\85\8cì\9d´ë\84\88ë¡\9c **ë\84¤í\8a¸ì\9b\8cí\81¬ í\86µì\8b **(ì\98\88: HTTP ì\9a\94ì²)ì\9d\84 ì \84ë\8b¬í\95\98ë\8a\94 ë\82´ë¶\80 ë\8f\84구를 ê°\80ì§\80ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤.
-### 하나의 로드 밸런서 - 다중 워커 컨테이너
+### 하나의 로드 밸런서 - 여러 워커 컨테이너 { #one-load-balancer-multiple-worker-containers }
-**쿠버네티스**나 또는 다른 분산 컨테이너 관리 시스템으로 작업할 때, 시스템 내부의 네트워킹 메커니즘을 이용함으로써 메인 **포트**를 감지하고 있는 단일 **로드 밸런서**는 여러분의 앱에서 실행되고 있는 **여러개의 컨테이너**에 통신(요청들)을 전송할 수 있게 됩니다.
+**Kubernetes** 같은 분산 컨테이너 관리 시스템에서는 내부 네트워킹 메커니즘을 통해, 메인 **포트**에서 대기하는 단일 **로드 밸런서**가 여러분의 앱을 실행하는 **여러 컨테이너**로 통신(요청)을 전달할 수 있습니다.
-ì\97¬ë\9f¬ë¶\84ì\9d\98 ì\95±ì\97\90ì\84\9c ì\8b¤í\96\89ë\90\98ê³ ì\9e\88ë\8a\94 ê°\81ê°\81ì\9d\98 컨í\85\8cì\9d´ë\84\88ë\8a\94 ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c **í\95\98ë\82\98ì\9d\98 í\94\84ë¡\9cì\84¸ì\8a¤**ë§\8c ê°\80ì§\88 ê²\83ì\9e\85ë\8b\88ë\8b¤ (ì\98\88를 ë\93¤ì\96´, FastAPI ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90ì\84\9c ì\8b¤í\96\89ë\90\98ë\8a\94 í\95\98ë\82\98ì\9d\98 Uvicorn í\94\84ë¡\9cì\84¸ì\8a¤ì²\98ë\9f¼). ì\9d´ 컨í\85\8cì\9d´ë\84\88ë\93¤ì\9d\80 모ë\91\90 ê°\99ì\9d\80 ê²\83ì\9d\84 ì\8b¤í\96\89í\95\98ë\8a\94 ì \90ì\97\90ì\84\9c **ë\8f\99ì\9d¼í\95\9c 컨í\85\8cì\9d´ë\84\88**ì\9d´ì§\80ë§\8c, í\94\84ë¡\9cì\84¸ì\8a¤, ë©\94모리 ë\93±ì\9d\80 ê³µì\9c í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤. ì\9d´ ë°©ì\8b\9dì\9c¼ë¡\9c ì\97¬ë\9f¬ë¶\84ì\9d\80 CPUì\9d\98 **ì\84\9cë¡\9c ë\8b¤ë¥¸ ì½\94ì\96´ë\93¤** ë\98\90ë\8a\94 **ì\84\9cë¡\9c ë\8b¤ë¥¸ 머ì\8b ë\93¤**ì\9d\84 **ë³\91ë ¬í\99\94**í\95\98ë\8a\94 이점을 얻을 수 있습니다.
+ì\95±ì\9d\84 ì\8b¤í\96\89í\95\98ë\8a\94 ê°\81 컨í\85\8cì\9d´ë\84\88ë\8a\94 ë³´í\86µ **í\94\84ë¡\9cì\84¸ì\8a¤ í\95\98ë\82\98ë§\8c** ê°\80ì§\91ë\8b\88ë\8b¤(ì\98\88: FastAPI ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\8b¤í\96\89í\95\98ë\8a\94 Uvicorn í\94\84ë¡\9cì\84¸ì\8a¤). 모ë\91\90 ê°\99ì\9d\80 ê²\83ì\9d\84 ì\8b¤í\96\89í\95\98ë\8a\94 **ë\8f\99ì\9d¼í\95\9c 컨í\85\8cì\9d´ë\84\88**ì\9d´ì§\80ë§\8c, ê°\81ì\9e\90 ê³ ì\9c í\95\9c í\94\84ë¡\9cì\84¸ì\8a¤, ë©\94모리 ë\93±ì\9d\84 ê°\80ì§\91ë\8b\88ë\8b¤. ì\9d´ë \87ê²\8c í\95\98ë©´ CPUì\9d\98 **ì\84\9cë¡\9c ë\8b¤ë¥¸ ì½\94ì\96´** ë\98\90ë\8a\94 **ì\84\9cë¡\9c ë\8b¤ë¥¸ 머ì\8b **ì\97\90ì\84\9c **ë³\91ë ¬í\99\94**ì\9d\98 이점을 얻을 수 있습니다.
-또한 **로드 밸런서**가 있는 분산 컨테이너 시스템은 여러분의 앱에 있는 컨테이너 각각에 **차례대로 요청을 분산**시킬 것 입니다. 따라서 각 요청은 여러분의 앱에서 실행되는 여러개의 **복제된 컨테이너들** 중 하나에 의해 다루어질 것 입니다.
+그리고 **로드 밸런서**가 있는 분산 컨테이너 시스템은 여러분의 앱을 실행하는 각 컨테이너에 **번갈아가며** 요청을 **분산**합니다. 따라서 각 요청은 여러분의 앱을 실행하는 여러 **복제된 컨테이너** 중 하나에서 처리될 수 있습니다.
-그리고 일반적으로 **로드 밸런서**는 여러분의 클러스터에 있는 *다른* 앱으로 가는 요청들도 다룰 수 있으며 (예를 들어, 다른 도메인으로 가거나 다른 URL 경로 접두사를 가지는 경우), 이 통신들을 클러스터에 있는 *바로 그 다른* 어플리케이션으로 제대로 전송할 수 있습니다.
+또한 보통 이 **로드 밸런서**는 클러스터 내 *다른* 앱으로 가는 요청(예: 다른 도메인, 또는 다른 URL 경로 접두사 아래로 가는 요청)도 처리할 수 있으며, 그 통신을 클러스터에서 실행 중인 *그 다른* 애플리케이션의 올바른 컨테이너로 전달할 수 있습니다.
-### 단일 프로세스를 가지는 컨테이너
+### 컨테이너당 하나의 프로세스 { #one-process-per-container }
-ì\9d´ ì\8b\9cë\82\98리ì\98¤ì\9d\98 ê²½ì\9a°, ì\97¬ë\9f¬ë¶\84ì\9d\80 ì\9d´ë¯¸ í\81´ë\9f¬ì\8a¤í\84° ë \88벨ì\97\90ì\84\9c ë³µì \9c를 ë\8b¤ë£¨ê³ ì\9e\88ì\9d\84 ê²\83ì\9d´ë¯\80ë¡\9c **컨í\85\8cì\9d´ë\84\88 ë\8b¹ ë\8b¨ì\9d¼ (Uvicorn) í\94\84ë¡\9cì\84¸ì\8a¤**를 ê°\80ì§\80ê³ ì\9e\90 í\95 ê²\83ì\9e\85니다.
+ì\9d´ ì\8b\9cë\82\98리ì\98¤ì\97\90ì\84\9cë\8a\94 ì\9d´ë¯¸ í\81´ë\9f¬ì\8a¤í\84° ë \88벨ì\97\90ì\84\9c ë³µì \9c를 ì²\98리í\95\98ê³ ì\9e\88ì\9c¼ë¯\80ë¡\9c, **컨í\85\8cì\9d´ë\84\88ë\8b¹ ë\8b¨ì\9d¼ (Uvicorn) í\94\84ë¡\9cì\84¸ì\8a¤**를 ë\91\90ë\8a\94 ê²\83ì\9d´ ì¢\8bì\9d\84 ê°\80ë\8a¥ì\84±ì\9d´ í\81½니다.
-따라서, 여러분은 Gunicorn 이나 Uvicorn 워커, 또는 Uvicorn 워커를 사용하는 Uvicorn 매니저와 같은 프로세스 매니저를 가지고 싶어하지 **않을** 것입니다. 여러분은 컨테이너 당 **단일 Uvicorn 프로세스**를 가지고 싶어할 것입니다 (그러나 아마도 다중 컨테이너를 가질 것입니다).
+따라서 이 경우 컨테이너에서 `--workers` 커맨드 라인 옵션 같은 방식으로 여러 워커를 두고 싶지는 **않을** 것입니다. 컨테이너당 **단일 Uvicorn 프로세스**만 두고(하지만 컨테이너는 여러 개일 수 있습니다) 싶을 것입니다.
-ì\9d´ë¯¸ ì\97¬ë\9f¬ë¶\84ì\9d´ í\81´ë\9f¬ì\8a¤í\84° ì\8b\9cì\8a¤í\85\9cì\9d\84 ê´\80리í\95\98ê³ ì\9e\88ì\9c¼ë¯\80ë¡\9c, (Uvicorn ì\9b\8c커를 ê´\80리í\95\98ë\8a\94 Gunicorn ì\9d´ë\82\98 Uvicorn ì²\98ë\9f¼) 컨í\85\8cì\9d´ë\84\88 ë\82´ì\97\90 ë\8b¤ë¥¸ í\94\84ë¡\9cì\84¸ì\8a¤ 매ë\8b\88ì \80를 ê°\80ì§\80ë\8a\94 ê²\83ì\9d\80 **ë¶\88í\95\84ì\9a\94í\95\9c ë³µì\9e¡ì\84±**ë§\8c ë\8d\94í\95\98ê²\8c ë\90 ê²\83ì\9e\85니다.
+컨í\85\8cì\9d´ë\84\88 ë\82´ë¶\80ì\97\90 (ì\97¬ë\9f¬ ì\9b\8c커를 ì\9c\84í\95\9c) ë\98\90 ë\8b¤ë¥¸ í\94\84ë¡\9cì\84¸ì\8a¤ 매ë\8b\88ì \80를 ë\91\90ë\8a\94 ê²\83ì\9d\80, ì\9d´ë¯¸ í\81´ë\9f¬ì\8a¤í\84° ì\8b\9cì\8a¤í\85\9cì\97\90ì\84\9c ì²\98리í\95\98ê³ ì\9e\88ë\8a\94 **ë¶\88í\95\84ì\9a\94í\95\9c ë³µì\9e¡ì\84±**ë§\8c ì¶\94ê°\80í\95 ê°\80ë\8a¥ì\84±ì\9d´ í\81½니다.
-### 다중 프로세스를 가지는 컨테이너와 특수한 경우들
+### 여러 프로세스를 가진 컨테이너와 특수한 경우 { #containers-with-multiple-processes-and-special-cases }
-ë\8b¹ì\97°í\95\9c ë§\90ì\9d´ì§\80ë§\8c, ì\97¬ë\9f¬ë¶\84ì\9d´ ë\82´ë¶\80ì \81ì\9c¼ë¡\9c **Uvicorn ì\9b\8c커 í\94\84ë¡\9cì\84¸ì\8a¤ë\93¤**를 ì\8b\9cì\9e\91í\95\98ë\8a\94 **Gunicorn í\94\84ë¡\9cì\84¸ì\8a¤ 매ë\8b\88ì \80**를 ê°\80ì§\80ë\8a\94 ë\8b¨ì\9d¼ 컨í\85\8cì\9d´ë\84\88를 ì\9b\90í\95\98ë\8a\94 **í\8a¹ì\88\98í\95\9c ê²½ì\9a°**ë\8f\84 ì\9e\88ì\9d\84 ê²\83ì\9e\85니다.
+ë¬¼ë¡ ì»¨í\85\8cì\9d´ë\84\88 í\95\98ë\82\98ì\97\90 ì\97¬ë\9f¬ **Uvicorn ì\9b\8c커 í\94\84ë¡\9cì\84¸ì\8a¤**를 ë\91\90ê³ ì\8b¶ì\9d\84 ì\88\98 ì\9e\88ë\8a\94 **í\8a¹ì\88\98í\95\9c ê²½ì\9a°**ë\8f\84 ì\9e\88ì\8aµ니다.
-그런 경우에, 여러분들은 **Gunicorn**을 프로세스 매니저로 포함하는 **공식 도커 이미지**를 사용할 수 있습니다. 이 프로세스 매니저는 다중 **Uvicorn 워커 프로세스들**을 실행하며, 디폴트 세팅으로 현재 CPU 코어에 기반하여 자동으로 워커 개수를 조정합니다. 이 사항에 대해서는 아래의 [Gunicorn과 함께하는 공식 도커 이미지 - Uvicorn](#official-docker-image-with-gunicorn-uvicorn)에서 더 다루겠습니다.
+그런 경우에는 `--workers` 커맨드 라인 옵션을 사용해 실행할 워커 수를 설정할 수 있습니다:
-이런 경우에 해당하는 몇가지 예시가 있습니다:
+```{ .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"]
+```
-#### Prometheus와 다른 이유들
+1. 여기서는 `--workers` 커맨드 라인 옵션으로 워커 수를 4로 설정합니다.
-ì\97¬ë\9f¬ë¶\84ì\9d\80 **ë\8b¨ì\9d¼ í\94\84ë¡\9cì\84¸ì\8a¤**를 ê°\80ì§\80ë\8a\94 **ë\8b¤ì¤\91 컨í\85\8cì\9d´ë\84\88** ë\8c\80ì\8b **ë\8b¤ì¤\91 í\94\84ë¡\9cì\84¸ì\8a¤**를 ê°\80ì§\80ë\8a\94 **ë\8b¨ì\9d¼ 컨í\85\8cì\9d´ë\84\88**를 ì±\84í\83\9dí\95\98ë\8a\94 **ë\8b¤ë¥¸ ì\9d´ì\9c **ê°\80 ì\9e\88ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\9d´ë\9f° ë°©ì\8b\9dì\9d´ ì\9d\98미ê°\80 ì\9e\88ì\9d\84 ì\88\98 ì\9e\88ë\8a\94 ì\98\88ì\8b\9cë\8a\94 ë\8b¤ì\9d\8cê³¼ ê°\99ì\8aµë\8b\88ë\8b¤:
-예를 들어 (여러분의 장치 설정에 따라) Prometheus 익스포터와 같이 같은 컨테이너에 들어오는 **각 요청에 대해** 접근권한을 가지는 도구를 사용할 수 있습니다.
+#### 단순한 앱 { #a-simple-app }
-ì\9d´ ê²½ì\9a°ì\97\90 ì\97¬ë\9f¬ë¶\84ì\9d´ **ì\97¬ë\9f¬ê°\9cì\9d\98 컨í\85\8cì\9d´ë\84\88ë\93¤**ì\9d\84 ê°\80ì§\80ê³ ì\9e\88ë\8b¤ë©´, Prometheusê°\80 **ë©\94í\8a¸ë¦ì\9d\84 ì\9d½ì\96´ ë\93¤ì\9d¼ ë\95\8c**, ë\94\94í\8f´í\8a¸ë¡\9c **매ë²\88 í\95\98ë\82\98ì\9d\98 컨í\85\8cì\9d´ë\84\88**(í\8a¹ì \95 리í\80\98ì\8a¤í\8a¸ë¥¼ ê´\80리í\95\98ë\8a\94 ë°\94ë¡\9c ê·¸ 컨í\85\8cì\9d´ë\84\88)ë¡\9c ë¶\80í\84° ì\9d½ì\96´ë\93¤ì\9d¼ ê²\83ì\9e\85ë\8b\88ë\8b¤. ì\9d´ë\8a\94 모ë\93 ë³µì \9cë\90\9c 컨í\85\8cì\9d´ë\84\88ì\97\90 ë\8c\80í\95´ **ì¶\95ì \81ë\90\9c ë©\94í\8a¸ë¦ë\93¤**ì\9d\84 ì\9d½ì\96´ë\93¤ì\9d´ë\8a\94 ê²\83ê³¼ ë\8c\80ë¹\84ë\90©니다.
+ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ **ì¶©ë¶\84í\9e\88 ë\8b¨ì\88\9c**í\95´ì\84\9c í\81´ë\9f¬ì\8a¤í\84°ê°\80 ì\95\84ë\8b\8c **ë\8b¨ì\9d¼ ì\84\9cë²\84**ì\97\90ì\84\9c ì\8b¤í\96\89í\95 ì\88\98 ì\9e\88ë\8b¤ë©´, 컨í\85\8cì\9d´ë\84\88ì\97\90 í\94\84ë¡\9cì\84¸ì\8a¤ 매ë\8b\88ì \80를 ë\91\90ê³ ì\8b¶ì\9d\84 ì\88\98 ì\9e\88ì\8aµ니다.
-그렇다면 이 경우에는 **다중 프로세스**를 가지는 **하나의 컨테이너**를 두어서 같은 컨테이너에서 모든 내부 프로세스에 대한 Prometheus 메트릭을 수집하는 로컬 도구(예를 들어 Prometheus 익스포터 같은)를 두어서 이 메그릭들을 하나의 컨테이너에 내에서 공유하는 방법이 더 단순할 것입니다.
+#### Docker Compose { #docker-compose }
+
+**Docker Compose**로 클러스터가 아닌 **단일 서버**에 배포하는 경우, 공유 네트워크와 **로드 밸런싱**을 유지하면서(Docker Compose로) 컨테이너 복제를 관리하는 쉬운 방법이 없을 수 있습니다.
+
+그렇다면 **프로세스 매니저**가 컨테이너 내부에서 **여러 워커 프로세스**를 시작하는 **단일 컨테이너**를 원할 수 있습니다.
---
-요점은, 이 중의 **어느것도** 여러분들이 반드시 따라야하는 **확정된 사실**이 아니라는 것입니다. 여러분은 이 아이디어들을 **여러분의 고유한 이용 사례를 평가**하는데 사용하고, 여러분의 시스템에 가장 적합한 접근법이 어떤 것인지 결정하며, 다음의 개념들을 관리하는 방법을 확인할 수 있습니다:
+핵심은, 이것들 중 **어느 것도** 무조건 따라야 하는 **절대적인 규칙**은 아니라는 것입니다. 이 아이디어들을 사용해 **여러분의 사용 사례를 평가**하고, 여러분의 시스템에 가장 적합한 접근 방식을 결정하면서 다음 개념을 어떻게 관리할지 확인할 수 있습니다:
* 보안 - HTTPS
-* 구동하기
+* 시작 시 자동 실행
* 재시작
-* 복제 (실행 중인 프로세스 개수)
+* 복제(실행 중인 프로세스 수)
* 메모리
-* 시작하기 전 단계들
+* 시작 전 사전 단계
-## 메모리
+## 메모리 { #memory }
-만약 여러분이 **컨테이너 당 단일 프로세스**를 실행한다면, 여러분은 각 컨테이너(복제된 경우에는 여러개의 컨테이너들)에 대해 잘 정의되고, 안정적이며, 제한된 용량의 메모리 소비량을 가지고 있을 것입니다.
+**컨테이너당 단일 프로세스**를 실행하면, 각 컨테이너(복제된 경우 여러 개)마다 소비하는 메모리 양이 대체로 잘 정의되고 안정적이며 제한된 값이 됩니다.
-ê·¸ë\9f¬ë©´ ì\97¬ë\9f¬ë¶\84ì\9d\98 컨í\85\8cì\9d´ë\84\88 ê´\80리 ì\8b\9cì\8a¤í\85\9c(ì\98\88를 ë\93¤ì\96´ **ì¿ ë²\84ë\84¤í\8b°ì\8a¤**) ì\84¤ì \95ì\97\90ì\84\9c ì\95\9eì\84\9c ì \95ì\9d\98ë\90\9c ê²\83ê³¼ ê°\99ì\9d\80 ë©\94모리 ì \9cí\95\9cê³¼ ì\9a\94구ì\82¬í\95ì\9d\84 ì\84¤ì \95í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ë\9f° ë°©ë²\95ì\9c¼ë¡\9c **ê°\80ì\9a© 머ì\8b **ì\9d´ í\95\84ì\9a\94ë¡\9cí\95\98ë\8a\94 ë©\94모리ì\99\80 í\81´ë\9f¬ì\8a¤í\84°ì\97\90 ì\9e\88ë\8a\94 ê°\80ì\9a© 머ì\8b ë\93¤ì\9d\84 ì\97¼ë\91\90ì\97\90 ë\91\90ê³ **컨테이너를 복제**할 수 있습니다.
+ê·¸ë\9f° ë\8b¤ì\9d\8c 컨í\85\8cì\9d´ë\84\88 ê´\80리 ì\8b\9cì\8a¤í\85\9c(ì\98\88: **Kubernetes**) ì\84¤ì \95ì\97\90ì\84\9c ë\8f\99ì\9d¼í\95\98ê²\8c ë©\94모리 ì \9cí\95\9cê³¼ ì\9a\94구ì\82¬í\95ì\9d\84 ì\84¤ì \95í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë\9f¬ë©´ í\81´ë\9f¬ì\8a¤í\84°ì\97\90ì\84\9c ì\82¬ì\9a© ê°\80ë\8a¥í\95\9c 머ì\8b ì\97\90 ì\9e\88ë\8a\94 ë©\94모리ì\99\80 컨í\85\8cì\9d´ë\84\88ê°\80 í\95\84ì\9a\94ë¡\9c í\95\98ë\8a\94 ë©\94모리 ì\96\91ì\9d\84 ê³ ë ¤í\95´ **컨테이너를 복제**할 수 있습니다.
-만약 여러분의 어플리케이션이 **단순**하다면, 이것은 **문제가 되지 않을** 것이고, 고정된 메모리 제한을 구체화할 필요도 없을 것입니다. 하지만 여러분의 어플리케이션이 (예를 들어 **머신 러닝** 모델같이) **많은 메모리를 소요한다면**, 어플리케이션이 얼마나 많은 양의 메모리를 사용하는지 확인하고 **각 머신에서** 사용하는 **컨테이너의 수**를 조정할 필요가 있습니다 (그리고 필요에 따라 여러분의 클러스터에 머신을 추가할 수 있습니다).
+애플리케이션이 **단순**하다면 이는 아마도 **문제가 되지 않을** 것이고, 엄격한 메모리 제한을 지정할 필요가 없을 수도 있습니다. 하지만 **많은 메모리를 사용한다면**(예: **머신 러닝** 모델), 얼마나 많은 메모리를 소비하는지 확인하고, **각 머신**에서 실행되는 **컨테이너 수**를 조정해야 합니다(필요하다면 클러스터에 머신을 더 추가할 수도 있습니다).
-만약 여러분이 **컨테이너 당 여러개의 프로세스**를 실행한다면 (예를 들어 공식 도커 이미지 처럼), 여러분은 시작된 프로세스 개수가 가용한 것 보다 **더 많은 메모리를 소비**하지 않는지 확인해야 합니다.
+**컨테이너당 여러 프로세스**를 실행한다면, 시작되는 프로세스 수가 사용 가능한 것보다 **더 많은 메모리를 소비하지** 않는지 확인해야 합니다.
-## 시작하기 전 단계들과 컨테이너
+## 시작 전 단계와 컨테이너 { #previous-steps-before-starting-and-containers }
-만약 여러분이 컨테이너(예를 들어 도커, 쿠버네티스)를 사용한다면, 여러분이 접근할 수 있는 주요 방법은 크게 두가지가 있습니다.
+컨테이너(예: Docker, Kubernetes)를 사용한다면, 사용할 수 있는 주요 접근 방식은 두 가지입니다.
-### 다중 컨테이너
+### 여러 컨테이너 { #multiple-containers }
-만약 여러분이 **여러개의 컨테이너**를 가지고 있다면, 아마도 각각의 컨테이너는 **하나의 프로세스**를 가지고 있을 것입니다(예를 들어, **쿠버네티스** 클러스터에서). 그러면 여러분은 복제된 워커 컨테이너를 실행하기 **이전에**, 하나의 컨테이너에 있는 **이전의 단계들을** 수행하는 단일 프로세스를 가지는 **별도의 컨테이너들**을 가지고 싶을 것입니다.
+**여러 컨테이너**가 있고 각 컨테이너가 보통 **단일 프로세스**를 실행한다면(예: **Kubernetes** 클러스터), 복제된 워커 컨테이너를 실행하기 **전에**, 단일 컨테이너에서 단일 프로세스로 **시작 전 사전 단계**를 수행하는 **별도의 컨테이너**를 두고 싶을 가능성이 큽니다.
/// info | 정보
-만약 여러분이 쿠버네티스를 사용하고 있다면, 아마도 이는 <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>일 것입니다.
+Kubernetes를 사용한다면, 이는 아마도 <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>일 것입니다.
///
-만약 여러분의 이용 사례에서 이전 단계들을 **병렬적으로 여러번** 수행하는데에 문제가 없다면 (예를 들어 데이터베이스 이전을 실행하지 않고 데이터베이스가 준비되었는지 확인만 하는 경우), 메인 프로세스를 시작하기 전에 이 단계들을 각 컨테이너에 넣을 수 있습니다.
-
-### 단일 컨테이너
-
-만약 여러분의 셋업이 **다중 프로세스**(또는 하나의 프로세스)를 시작하는 **하나의 컨테이너**를 가지는 단순한 셋업이라면, 사전 단계들을 앱을 포함하는 프로세스를 시작하기 직전에 같은 컨테이너에서 실행할 수 있습니다. 공식 도커 이미지는 이를 내부적으로 지원합니다.
+사용 사례에서 시작 전 사전 단계를 **여러 번 병렬로 실행**해도 문제가 없다면(예: 데이터베이스 마이그레이션을 실행하는 것이 아니라, 데이터베이스가 준비되었는지 확인만 하는 경우), 메인 프로세스를 시작하기 직전에 각 컨테이너에 그 단계를 넣을 수도 있습니다.
-## Gunicorn과 함께하는 공식 도커 이미지 - Uvicorn
+### 단일 컨테이너 { #single-container }
-앞 챕터에서 자세하게 설명된 것 처럼, Uvicorn 워커와 같이 실행되는 Gunicorn을 포함하는 공식 도커 이미지가 있습니다: [서버 워커 - Uvicorn과 함께하는 Gunicorn](server-workers.md){.internal-link target=_blank}.
+**단일 컨테이너**에서 여러 **워커 프로세스**(또는 단일 프로세스)를 시작하는 단순한 셋업이라면, 앱이 있는 프로세스를 시작하기 직전에 같은 컨테이너에서 시작 전 사전 단계를 실행할 수 있습니다.
-이 이미지는 주로 위에서 설명된 상황에서 유용할 것입니다: [다중 프로세스를 가지는 컨테이너와 특수한 경우들](#containers-with-multiple-processes-and-special-cases).
-
-* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
-
-/// warning | 경고
+### 베이스 도커 이미지 { #base-docker-image }
-여러분이 이 베이스 이미지 또는 다른 유사한 이미지를 필요로 하지 **않을** 높은 가능성이 있으며, [위에서 설명된 것처럼: FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi) 처음부터 이미지를 빌드하는 것이 더 나을 수 있습니다.
+과거에는 공식 FastAPI Docker 이미지가 있었습니다: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. 하지만 이제는 deprecated되었습니다. ⛔️
-///
+아마도 이 베이스 도커 이미지(또는 유사한 다른 이미지)는 **사용하지 않는** 것이 좋습니다.
-이 이미지는 가능한 CPU 코어에 기반한 **몇개의 워커 프로세스**를 설정하는 **자동-튜닝** 메커니즘을 포함하고 있습니다.
+**Kubernetes**(또는 다른 도구)를 사용하고, 클러스터 레벨에서 여러 **컨테이너**로 **복제**를 이미 설정해 둔 경우라면, 위에서 설명한 대로 **처음부터 이미지를 빌드하는 것**이 더 낫습니다: [FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi).
-이 이미지는 **민감한 디폴트** 값을 가지고 있지만, 여러분들은 여전히 **환경 변수** 또는 설정 파일을 통해 설정값을 수정하고 업데이트 할 수 있습니다.
+그리고 여러 워커가 필요하다면, `--workers` 커맨드 라인 옵션을 간단히 사용하면 됩니다.
-또한 스크립트를 통해 <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**시작하기 전 사전 단계**</a>를 실행하는 것을 지원합니다.
+/// note Technical Details | 기술 세부사항
-/// tip | 팁
+이 Docker 이미지는 Uvicorn이 죽은 워커를 관리하고 재시작하는 기능을 지원하지 않던 시기에 만들어졌습니다. 그래서 Gunicorn과 Uvicorn을 함께 사용해야 했고, Gunicorn이 Uvicorn 워커 프로세스를 관리하고 재시작하도록 하기 위해 상당한 복잡성이 추가되었습니다.
-모든 설정과 옵션을 보려면, 도커 이미지 페이지로 이동합니다: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
+하지만 이제 Uvicorn(그리고 `fastapi` 명령)은 `--workers`를 지원하므로, 베이스 도커 이미지를 사용하는 대신 직접 이미지를 빌드하지 않을 이유가 없습니다(코드 양도 사실상 거의 같습니다 😅).
///
-### 공식 도커 이미지에 있는 프로세스 개수
-
-이 이미지에 있는 **프로세스 개수**는 가용한 CPU **코어들**로 부터 **자동으로 계산**됩니다.
-
-이것이 의미하는 바는 이미지가 CPU로부터 **최대한의 성능**을 **쥐어짜낸다**는 것입니다.
-
-여러분은 이 설정 값을 **환경 변수**나 기타 방법들로 조정할 수 있습니다.
-
-그러나 프로세스의 개수가 컨테이너가 실행되고 있는 CPU에 의존한다는 것은 또한 **소요되는 메모리의 크기** 또한 이에 의존한다는 것을 의미합니다.
-
-그렇기 때문에, 만약 여러분의 어플리케이션이 많은 메모리를 요구하고 (예를 들어 머신러닝 모델처럼), 여러분의 서버가 CPU 코어 수는 많지만 **적은 메모리**를 가지고 있다면, 여러분의 컨테이너는 가용한 메모리보다 많은 메모리를 사용하려고 시도할 수 있으며, 결국 퍼포먼스를 크게 떨어뜨릴 수 있습니다(심지어 고장이 날 수도 있습니다). 🚨
+## 컨테이너 이미지 배포하기 { #deploy-the-container-image }
-### `Dockerfile` 생성하기
-
-이 이미지에 기반해 `Dockerfile`을 생성하는 방법은 다음과 같습니다:
-
-```Dockerfile
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
-
-COPY ./requirements.txt /app/requirements.txt
-
-RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
-
-COPY ./app /app
-```
-
-### 더 큰 어플리케이션
-
-만약 여러분이 [다중 파일을 가지는 더 큰 어플리케이션](../tutorial/bigger-applications.md){.internal-link target=_blank}을 생성하는 섹션을 따랐다면, 여러분의 `Dockerfile`은 대신 이렇게 생겼을 것입니다:
-
-```Dockerfile hl_lines="7"
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
-
-COPY ./requirements.txt /app/requirements.txt
-
-RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
-
-COPY ./app /app/app
-```
-
-### 언제 사용할까
-
-여러분들이 **쿠버네티스**(또는 유사한 다른 도구) 사용하거나 클러스터 레벨에서 다중 컨테이너를 이용해 이미 **사본**을 설정하고 있다면, 공식 베이스 이미지(또는 유사한 다른 이미지)를 사용하지 **않는** 것 좋습니다. 그런 경우에 여러분은 다음에 설명된 것 처럼 **처음부터 이미지를 빌드하는 것**이 더 낫습니다: [FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi).
-
-이 이미지는 위의 [다중 프로세스를 가지는 컨테이너와 특수한 경우들](#containers-with-multiple-processes-and-special-cases)에서 설명된 특수한 경우에 대해서만 주로 유용할 것입니다. 예를 들어, 만약 여러분의 어플리케이션이 **충분히 단순**해서 CPU에 기반한 디폴트 프로세스 개수를 설정하는 것이 잘 작동한다면, 클러스터 레벨에서 수동으로 사본을 설정할 필요가 없을 것이고, 여러분의 앱에서 하나 이상의 컨테이너를 실행하지도 않을 것입니다. 또는 만약에 여러분이 **도커 컴포즈**로 배포하거나, 단일 서버에서 실행하거나 하는 경우에도 마찬가지입니다.
-
-## 컨테이너 이미지 배포하기
-
-컨테이너 (도커) 이미지를 완성한 뒤에 이를 배포하는 방법에는 여러가지 방법이 있습니다.
+컨테이너(Docker) 이미지를 만든 후에는 이를 배포하는 여러 방법이 있습니다.
예를 들어:
-* 단일 서버에서 **도커 컴포즈**로 배포하기
-* **쿠버네티스** 클러스터로 배포하기
-* 도커 스왐 모드 클러스터로 배포하기
-* 노마드 같은 다른 도구로 배포하기
-* 여러분의 컨테이너 이미지를 배포해주는 클라우드 서비스로 배포하기
-
-## Poetry의 도커 이미지
-
-만약 여러분들이 프로젝트 의존성을 관리하기 위해 <a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a>를 사용한다면, 도커의 멀티-스테이지 빌딩을 사용할 수 있습니다:
-
-```{ .dockerfile .annotate }
-# (1)
-FROM python:3.9 as requirements-stage
-
-# (2)
-WORKDIR /tmp
-
-# (3)
-RUN pip install poetry
-
-# (4)
-COPY ./pyproject.toml ./poetry.lock* /tmp/
-
-# (5)
-RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
-
-# (6)
-FROM python:3.9
-
-# (7)
-WORKDIR /code
-
-# (8)
-COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
-
-# (9)
-RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-
-# (10)
-COPY ./app /code/app
-
-# (11)
-CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
-```
-
-1. 첫 스테이지로, `requirements-stage`라고 이름 붙였습니다.
-
-2. `/tmp`를 현재의 워킹 디렉터리로 설정합니다.
+* 단일 서버에서 **Docker Compose**로
+* **Kubernetes** 클러스터로
+* Docker Swarm Mode 클러스터로
+* Nomad 같은 다른 도구로
+* 컨테이너 이미지를 받아 배포해주는 클라우드 서비스로
- 이 위치에 우리는 `requirements.txt` 파일을 생성할 것입니다.
+## `uv`를 사용하는 도커 이미지 { #docker-image-with-uv }
-3. 이 도커 스테이지에서 Poetry를 설치합니다.
+프로젝트를 설치하고 관리하기 위해 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>를 사용한다면, <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">uv Docker guide</a>를 따를 수 있습니다.
-4. 파일 `pyproject.toml`와 `poetry.lock`를 `/tmp` 디렉터리로 복사합니다.
+## 요약 { #recap }
- `./poetry.lock*` (`*`로 끝나는) 파일을 사용하기 때문에, 파일이 아직 사용가능하지 않더라도 고장나지 않을 것입니다.
-
-5. `requirements.txt` 파일을 생성합니다.
-
-6. 이것이 마지막 스테이지로, 여기에 위치한 모든 것이 마지막 컨테이너 이미지에 포함될 것입니다.
-
-7. 현재의 워킹 디렉터리를 `/code`로 설정합니다.
-
-8. 파일 `requirements.txt`를 `/code` 디렉터리로 복사합니다.
-
- 이 파일은 오직 이전의 도커 스테이지에만 존재하며, 때문에 복사하기 위해서 `--from-requirements-stage` 옵션이 필요합니다.
-
-9. 생성된 `requirements.txt` 파일에 패키지 의존성을 설치합니다.
-
-10. `app` 디렉터리를 `/code` 디렉터리로 복사합니다.
-
-11. `uvicorn` 커맨드를 실행하여, `app.main`에서 불러온 `app` 객체를 사용하도록 합니다.
-
-/// tip | 팁
-
-버블 숫자를 클릭해 각 줄이 하는 일을 알아볼 수 있습니다.
-
-///
-
-**도커 스테이지**란 `Dockefile`의 일부로서 나중에 사용하기 위한 파일들을 생성하기 위한 **일시적인 컨테이너 이미지**로 작동합니다.
-
-첫 스테이지는 오직 **Poetry를 설치**하고 Poetry의 `pyproject.toml` 파일로부터 프로젝트 의존성을 위한 **`requirements.txt`를 생성**하기 위해 사용됩니다.
-
-이 `requirements.txt` 파일은 **다음 스테이지**에서 `pip`로 사용될 것입니다.
-
-마지막 컨테이너 이미지에는 **오직 마지막 스테이지만** 보존됩니다. 이전 스테이지(들)은 버려집니다.
-
-Poetry를 사용할 때 **도커 멀티-스테이지 빌드**를 사용하는 것이 좋은데, 여러분들의 프로젝트 의존성을 설치하기 위해 마지막 컨테이너 이미지에 **오직** `requirements.txt` 파일만 필요하지, Poetry와 그 의존성은 있을 필요가 없기 때문입니다.
-
-이 다음 (또한 마지막) 스테이지에서 여러분들은 이전에 설명된 것과 비슷한 방식으로 방식으로 이미지를 빌드할 수 있습니다.
-
-### TLS 종료 프록시의 배후 - Poetry
-
-이전에 언급한 것과 같이, 만약 여러분이 컨테이너를 Nginx 또는 Traefik과 같은 TLS 종료 프록시 (로드 밸런서) 뒤에서 실행하고 있다면, 커맨드에 `--proxy-headers` 옵션을 추가합니다:
-
-```Dockerfile
-CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
-```
-
-## 요약
-
-컨테이너 시스템(예를 들어 **도커**나 **쿠버네티스**)을 사용하여 모든 **배포 개념**을 다루는 것은 꽤 간단합니다:
+컨테이너 시스템(예: **Docker**, **Kubernetes**)을 사용하면 모든 **배포 개념**을 다루는 것이 상당히 단순해집니다:
* HTTPS
-* 구동하기
+* 시작 시 자동 실행
* 재시작
-* 복제 (실행 중인 프로세스 개수)
+* 복제(실행 중인 프로세스 수)
* 메모리
-* 시작하기 전 단계들
-
-대부분의 경우에서 여러분은 어떤 베이스 이미지도 사용하지 않고 공식 파이썬 도커 이미지에 기반해 **처음부터 컨테이너 이미지를 빌드**할 것입니다.
+* 시작 전 사전 단계
-`Dockerfile`에 있는 지시 사항을 **순서대로** 다루고 **도커 캐시**를 사용하는 것으로 여러분은 **빌드 시간을 최소화**할 수 있으며, 이로써 생산성을 최대화할 수 있습니다 (그리고 지루함을 피할 수 있죠) 😎
+대부분의 경우 베이스 이미지는 사용하지 않고, 공식 Python Docker 이미지에 기반해 **처음부터 컨테이너 이미지를 빌드**하는 것이 좋습니다.
-특별한 경우에는, FastAPI를 위한 공식 도커 이미지를 사용할 수도 있습니다. 🤓
+`Dockerfile`에서 지시어의 **순서**와 **Docker 캐시**를 신경 쓰면 **빌드 시간을 최소화**해 생산성을 최대화할 수 있습니다(그리고 지루함도 피할 수 있습니다). 😎
-# 배포하기 - 들어가면서
+# 배포 { #deployment }
-**FastAPI**을 배포하는 것은 비교적 쉽습니다.
+**FastAPI** 애플리케이션을 배포하는 것은 비교적 쉽습니다.
-## 배포의 의미
+## 배포의 의미 { #what-does-deployment-mean }
-**배포**란 애플리케이션을 **사용자가 사용**할 수 있도록 하는 데 필요한 단계를 수행하는 것을 의미합니다.
+애플리케이션을 **배포**한다는 것은 **사용자가 사용**할 수 있도록 하는 데 필요한 단계를 수행하는 것을 의미합니다.
-**ì\9b¹ API**ì\9d\98 ê²½ì\9a°, ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c **ì\82¬ì\9a©ì\9e\90**ê°\80 ì¤\91ë\8b¨ì\9d´ë\82\98 ì\98¤ë¥\98 ì\97\86ì\9d´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90 í\9a¨ì\9c¨ì \81ì\9c¼ë¡\9c **ì \91ê·¼**í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d ì¢\8bì\9d\80 ì\84±ë\8a¥, ì\95\88ì \95ì\84± ë\93±ì\9d\84 ì \9cê³µí\95\98ë\8a\94 **ì\84\9cë²\84 í\94\84ë¡\9cê·¸ë\9e¨ê³¼** í\95¨ê»\98 **ì\9b\90격 ì\8b\9cì\8a¤í\85\9c**ì\97\90 ì\9d´ë¥¼ ì\84¤ì¹\98í\95\98ë\8a\94 ì\9e\91ì\97\85ì\9d\84 ì\9d\98미합니다.
+**ì\9b¹ API**ì\9d\98 ê²½ì\9a°, ì\9d¼ë°\98ì \81ì\9c¼ë¡\9c **ì\9b\90격 머ì\8b **ì\97\90 ì\9d´ë¥¼ ì\84¤ì¹\98í\95\98ê³ , ì¢\8bì\9d\80 ì\84±ë\8a¥, ì\95\88ì \95ì\84± ë\93±ì\9d\84 ì \9cê³µí\95\98ë\8a\94 **ì\84\9cë²\84 í\94\84ë¡\9cê·¸ë\9e¨**ê³¼ í\95¨ê»\98 구ì\84±í\95\98ì\97¬ **ì\82¬ì\9a©ì\9e\90**ê°\80 ì¤\91ë\8b¨ì\9d´ë\82\98 문ì \9c ì\97\86ì\9d´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90 í\9a¨ì\9c¨ì \81ì\9c¼ë¡\9c **ì \91ê·¼**í\95 ì\88\98 ì\9e\88ê²\8c í\95\98ë\8a\94 ê²\83ì\9d\84 í\8f¬í\95¨합니다.
-이는 지속적으로 코드를 변경하고, ì§\80ì\9a°ê³ , ì\88\98ì \95í\95\98ê³ , ê°\9cë°\9c ì\84\9cë²\84를 ì¤\91ì§\80í\96\88ë\8b¤ê°\80 ë\8b¤ì\8b\9c ì\8b\9cì\9e\91í\95\98ë\8a\94 ë\93±ì\9d\98 **ê°\9cë°\9c** ë\8b¨ê³\84ì\99\80 ë\8c\80ì¡°ë\90©ë\8b\88ë\8b¤.
+이는 지속적으로 코드를 변경하고, ë§\9dê°\80ë\9c¨ë¦¬ê³ ê³ ì¹\98ê³ , ê°\9cë°\9c ì\84\9cë²\84를 ì¤\91ì§\80í\96\88ë\8b¤ê°\80 ë\8b¤ì\8b\9c ì\8b\9cì\9e\91í\95\98ë\8a\94 ë\93±ì\9d\98 **ê°\9cë°\9c** ë\8b¨ê³\84ì\99\80 ë\8c\80ì¡°ë\90©ë\8b\88ë\8b¤.
-## 배포 전략
+## 배포 전략 { #deployment-strategies }
-사용하는 도구나 특정 사례에 따라 여러 가지 방법이 있습니다.
+구체적인 사용 사례와 사용하는 도구에 따라 여러 가지 방법이 있습니다.
-배포도구들을 사용하여 직접 **서버에 배포**하거나, 배포작업의 일부를 수행하는 **클라우드 서비스** 또는 다른 방법을 사용할 수도 있습니다.
+여러 도구를 조합해 직접 **서버를 배포**할 수도 있고, 작업의 일부를 대신해 주는 **클라우드 서비스**를 사용할 수도 있으며, 다른 가능한 선택지도 있습니다.
-**FastAPI** 애플리케이션을 배포할 때 선택할 수 있는 몇 가지 주요 방법을 보여 드리겠습니다 (대부분 다른 유형의 웹 애플리케이션에도 적용됩니다).
+예를 들어, FastAPI 뒤에 있는 저희 팀은 FastAPI로 작업하는 것과 같은 개발자 경험을 유지하면서, FastAPI 앱을 클라우드에 가능한 한 간소화된 방식으로 배포할 수 있도록 <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>를 만들었습니다.
-다음 차례에 자세한 내용과 이를 위한 몇 가지 기술을 볼 수 있습니다. ✨
+**FastAPI** 애플리케이션을 배포할 때 아마 염두에 두어야 할 몇 가지 주요 개념을 보여드리겠습니다(대부분은 다른 유형의 웹 애플리케이션에도 적용됩니다).
+
+다음 섹션에서 염두에 둘 더 많은 세부사항과 이를 위한 몇 가지 기술을 볼 수 있습니다. ✨
-# 서버 워커 - 구니콘과 유비콘
+# 서버 워커 - 워커와 함께 사용하는 Uvicorn { #server-workers-uvicorn-with-workers }
-ì \84ë\8b¨ê³\84ì\97\90ì\84\9c의 배포 개념들을 다시 확인해보겠습니다:
+ì\9d´ì \84의 배포 개념들을 다시 확인해보겠습니다:
* 보안 - HTTPS
-* 서버 시작과 동시에 실행하기
+* 서버 시작 시 실행
* 재시작
-* **복제본 (실행 중인 프로세스의 숫자)**
+* **복제(실행 중인 프로세스 수)**
* 메모리
-* ì\8b\9cì\9e\91í\95\98기 ì \84ì\9d\98 ì\97¬ë\9f¬ ë\8b¨ê³\84ë\93¤
+* ì\8b\9cì\9e\91í\95\98기 ì \84ì\9d\98 ì\9d´ì \84 ë\8b¨ê³\84
-지금까지 문서의 모든 튜토리얼을 참고하여 **단일 프로세스**로 Uvicorn과 같은 **서버 프로그램**을 실행했을 것입니다.
+지금까지 문서의 모든 튜토리얼을 참고하면서, `fastapi` 명령처럼 Uvicorn을 실행하는 **서버 프로그램**을 사용해 **단일 프로세스**로 실행해 왔을 가능성이 큽니다.
-애플리케이션을 배포할 때 **다중 코어**를 활용하고 더 많은 요청을 처리할 수 있도록 **프로세스 복제본**이 필요합니다.
+애플리케이션을 배포할 때는 **다중 코어**를 활용하고 더 많은 요청을 처리할 수 있도록 **프로세스 복제**를 하고 싶을 가능성이 큽니다.
-ì \84 ê³¼ì \95ì\9d´ì\97\88ë\8d\98 [ë°°í\8f¬ ê°\9cë\85\90ë\93¤](concepts.md){.internal-link target=_blank}ì\97\90ì\84\9c 본 ê²\83ì²\98ë\9f¼ ì\97¬ë\9f¬ê°\80ì§\80 ë°©ë²\95ì\9d´ ì¡´ì\9e¬í\95©니다.
+ì\9d´ì \84 ì\9e¥ì\9d\98 [ë°°í\8f¬ ê°\9cë\85\90ë\93¤](concepts.md){.internal-link target=_blank}ì\97\90ì\84\9c 본 ê²\83ì²\98ë\9f¼, ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8a\94 ì \84ë\9eµì\9d´ ì\97¬ë\9f¬ ê°\80ì§\80 ì\9e\88ì\8aµ니다.
-ì§\80ê¸\88ë¶\80í\84° <a href="https://gunicorn.org/" class="external-link" target="_blank">**구ë\8b\88ì½\98**</a>ì\9d\84 **ì\9c ë¹\84ì½\98 ì\9b\8c커 í\94\84ë¡\9cì\84¸ì\8a¤**ì\99\80 í\95¨ê»\98 ì\82¬ì\9a©í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ì\95\8cë ¤드리겠습니다.
+ì\97¬ê¸°ì\84\9cë\8a\94 `fastapi` ëª\85ë ¹ì\9d\84 ì\82¬ì\9a©í\95\98ê±°ë\82\98 `uvicorn` ëª\85ë ¹ì\9d\84 ì§\81ì \91 ì\82¬ì\9a©í\95´ì\84\9c, **ì\9b\8c커 í\94\84ë¡\9cì\84¸ì\8a¤**ì\99\80 í\95¨ê»\98 **Uvicorn**ì\9d\84 ì\82¬ì\9a©í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ë³´ì\97¬드리겠습니다.
/// info | 정보
-만약 도커와 쿠버네티스 같은 컨테이너를 사용하고 있다면 다음 챕터 [FastAPI와 컨테이너 - 도커](docker.md){.internal-link target=_blank}에서 더 많은 정보를 얻을 수 있습니다.
+Docker나 Kubernetes 같은 컨테이너를 사용하고 있다면, 다음 장인 [컨테이너에서의 FastAPI - 도커](docker.md){.internal-link target=_blank}에서 더 자세히 설명하겠습니다.
-특히, 쿠버네티스에서 실행할 때는 구니콘을 사용하지 않고 대신 컨테이너당 하나의 유비콘 프로세스를 실행하는 것이 좋습니다. 이 장의 뒷부분에서 설명하겠습니다.
+특히 **Kubernetes**에서 실행할 때는 워커를 사용하기보다는, 대신 **컨테이너당 단일 Uvicorn 프로세스 하나**를 실행하고 싶을 가능성이 크지만, 해당 내용은 그 장의 뒤에서 설명하겠습니다.
///
-## 구니콘과 유비콘 워커
+## 여러 워커 { #multiple-workers }
-**Gunicorn**은 **WSGI 표준**을 주로 사용하는 애플리케이션 서버입니다. 이것은 구니콘이 플라스크와 쟝고와 같은 애플리케이션을 제공할 수 있다는 것을 의미합니다. 구니콘 자체는 최신 **<a href="https://asgi.readthedocs.io/en/latest/" class="external-link" target="_blank">ASGI 표준</a>**을 사용하기 때문에 FastAPI와 호환되지 않습니다.
+`--workers` 커맨드라인 옵션으로 여러 워커를 시작할 수 있습니다:
-하지만 구니콘은 **프로세스 관리자**역할을 하고 사용자에게 특정 **워커 프로세스 클래스**를 알려줍니다. 그런 다음 구니콘은 해당 클래스를 사용하여 하나 이상의 **워커 프로세스**를 시작합니다.
+//// tab | `fastapi`
-그리고 **유비콘**은 **구니콘과 호환되는 워커 클래스**가 있습니다.
-
-이 조합을 사용하여 구니콘은 **프로세스 관리자** 역할을 하며 **포트**와 **IP**를 관찰하고, **유비콘 클래스**를 실행하는 워커 프로세스로 통신 정보를 **전송**합니다.
-
-그리고 나서 구니콘과 호환되는 **유비콘 워커** 클래스는 구니콘이 보낸 데이터를 FastAPI에서 사용하기 위한 ASGI 표준으로 변환하는 일을 담당합니다.
-
-## 구니콘과 유비콘 설치하기
+`fastapi` 명령을 사용한다면:
<div class="termy">
```console
-$ pip install "uvicorn[standard]" gunicorn
-
----> 100%
-```
-
-</div>
+$ <font color="#4E9A06">fastapi</font> run --workers 4 <u style="text-decoration-style:solid">main.py</u>
-이 명령어는 유비콘 `standard` 추가 패키지(좋은 성능을 위한)와 구니콘을 설치할 것입니다.
+ <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
-<div class="termy">
-
-```console
-$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80
-
-[19499] [INFO] Starting gunicorn 20.1.0
-[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
-[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
-[19511] [INFO] Booting worker with pid: 19511
-[19513] [INFO] Booting worker with pid: 19513
-[19514] [INFO] Booting worker with pid: 19514
-[19515] [INFO] Booting worker with pid: 19515
-[19511] [INFO] Started server process [19511]
-[19511] [INFO] Waiting for application startup.
-[19511] [INFO] Application startup complete.
-[19513] [INFO] Started server process [19513]
-[19513] [INFO] Waiting for application startup.
-[19513] [INFO] Application startup complete.
-[19514] [INFO] Started server process [19514]
-[19514] [INFO] Waiting for application startup.
-[19514] [INFO] Application startup complete.
-[19515] [INFO] Started server process [19515]
-[19515] [INFO] Waiting for application startup.
-[19515] [INFO] Application startup complete.
-```
-
-</div>
+ <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>
-* 이것은 유비콘과 똑같은 문법입니다. `main`은 파이썬 모듈 네임 "`main`"을 의미하므로 `main.py`파일을 뜻합니다. 그리고 `app`은 **FastAPI** 어플리케이션이 들어 있는 변수의 이름입니다.
- * `main:app`이 파이썬의 `import` 문법과 흡사한 면이 있다는 걸 알 수 있습니다:
+ <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
- ```Python
- from main import app
- ```
+ <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>
- * 곧, `main:app`안에 있는 콜론의 의미는 파이썬에서 `from main import app`에서의 `import`와 같습니다.
-* `--workers`: 사용할 워커 프로세스의 개수이며 숫자만큼의 유비콘 워커를 실행합니다. 이 예제에서는 4개의 워커를 실행합니다.
-* `--worker-class`: 워커 프로세스에서 사용하기 위한 구니콘과 호환되는 워커클래스.
- * 이런식으로 구니콘이 import하여 사용할 수 있는 클래스를 전달해줍니다:
+ Logs:
- ```Python
- import uvicorn.workers.UvicornWorker
- ```
-
-* `--bind`: 구니콘이 관찰할 IP와 포트를 의미합니다. 콜론 (`:`)을 사용하여 IP와 포트를 구분합니다.
- * 만약에 `--bind 0.0.0.0:80` (구니콘 옵션) 대신 유비콘을 직접 실행하고 싶다면 `--host 0.0.0.0`과 `--port 80`을 사용해야 합니다.
-
-출력에서 각 프로세스에 대한 **PID** (process ID)를 확인할 수 있습니다. (단순한 숫자입니다)
-
-출력 내용:
-
-* 구니콘 **프로세스 매니저**는 PID `19499`로 실행됩니다. (직접 실행할 경우 숫자가 다를 수 있습니다)
-* 다음으로 `Listening at: http://0.0.0.0:80`을 시작합니다.
-* 그런 다음 사용해야할 `uvicorn.workers.UvicornWorker`의 워커클래스를 탐지합니다.
-* 그리고 PID `19511`, `19513`, `19514`, 그리고 `19515`를 가진 **4개의 워커**를 실행합니다.
-
-
-또한 구니콘은 워커의 수를 유지하기 위해 **죽은 프로세스**를 관리하고 **재시작**하는 작업을 책임집니다. 이것은 이번 장 상단 목록의 **재시작** 개념을 부분적으로 도와주는 것입니다.
-
-그럼에도 불구하고 필요할 경우 외부에서 **구니콘을 재시작**하고, 혹은 **서버를 시작할 때 실행**할 수 있도록 하고 싶어할 것입니다.
+ <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` 명령을 직접 사용하는 편이 좋다면:
<div class="termy">
</div>
-새로운 옵션인 `--workers`은 유비콘에게 4개의 워커 프로세스를 사용한다고 알려줍니다.
+////
-각 프로세스의 **PID**를 확인할 수 있습니다. `27365`는 상위 프로세스(**프로세스 매니저**), 그리고 각각의 워커프로세스는 `27368`, `27369`, `27370`, 그리고 `27367`입니다.
+여기서 새로운 옵션은 `--workers`뿐이며, Uvicorn에게 워커 프로세스 4개를 시작하라고 알려줍니다.
-## 배포 개념들
+또한 각 프로세스의 **PID**도 확인할 수 있는데, 상위 프로세스(이것이 **프로세스 관리자**)의 PID는 `27365`이고, 각 워커 프로세스의 PID는 `27368`, `27369`, `27370`, `27367`입니다.
-여기에서는 **유비콘 워커 프로세스**를 관리하는 **구니콘**(또는 유비콘)을 사용하여 애플리케이션을 **병렬화**하고, CPU **멀티 코어**의 장점을 활용하고, **더 많은 요청**을 처리할 수 있는 방법을 살펴보았습니다.
+## 배포 개념들 { #deployment-concepts }
-워커를 사용하는 것은 배포 개념 목록에서 주로 **복제본** 부분과 **재시작**에 약간 도움이 되지만 다른 배포 개념들도 다루어야 합니다:
+여기서는 여러 **워커**를 사용해 애플리케이션 실행을 **병렬화**하고, CPU의 **다중 코어**를 활용하며, **더 많은 요청**을 제공할 수 있는 방법을 살펴봤습니다.
+
+위의 배포 개념 목록에서 워커를 사용하는 것은 주로 **복제** 부분에 도움이 되고, **재시작**에도 약간 도움이 되지만, 나머지 항목들도 여전히 신경 써야 합니다:
* **보안 - HTTPS**
-* **서버 시작과 동시에 실행하기**
+* **서버 시작 시 실행**
* ***재시작***
-* 복제본 (실행 중인 프로세스의 숫자)
+* 복제(실행 중인 프로세스 수)
* **메모리**
-* **시작하기 전의 여러 단계들**
-
-
-## 컨테이너와 도커
+* **시작하기 전의 이전 단계**
-다음 장인 [FastAPI와 컨테이너 - 도커](docker.md){.internal-link target=_blank}에서 다른 **배포 개념들**을 다루는 전략들을 알려드리겠습니다.
+## 컨테이너와 도커 { #containers-and-docker }
-ë\98\90í\95\9c ê°\84ë\8b¨í\95\9c ì¼\80ì\9d´ì\8a¤ì\97\90ì\84\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8a\94, **구ë\8b\88ì½\98ê³¼ ì\9c ë¹\84ì½\98 ì\9b\8c커**ê°\80 í\8f¬í\95¨ë\8f¼ ì\9e\88ë\8a\94 **ê³µì\8b\9d ë\8f\84커 ì\9d´ë¯¸ì§\80**ì\99\80 í\95¨ê»\98 ëª\87 ê°\80ì§\80 기본 구ì\84±ì\9d\84 ë³´ì\97¬ë\93\9c리겠습니다.
+ë\8b¤ì\9d\8c ì\9e¥ì\9d¸ [컨í\85\8cì\9d´ë\84\88ì\97\90ì\84\9cì\9d\98 FastAPI - ë\8f\84커](docker.md){.internal-link target=_blank}ì\97\90ì\84\9cë\8a\94 ë\8b¤ë¥¸ **ë°°í\8f¬ ê°\9cë\85\90ë\93¤**ì\9d\84 ì²\98리í\95\98기 ì\9c\84í\95´ ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8a\94 ëª\87 ê°\80ì§\80 ì \84ë\9eµì\9d\84 ì\84¤ëª\85í\95\98겠습니다.
-그리고 단일 유비콘 프로세스(구니콘 없이)를 실행할 수 있도록 **사용자 자신의 이미지를 처음부터 구축**하는 방법도 보여드리겠습니다. 이는 간단한 과정이며, **쿠버네티스**와 같은 분산 컨테이너 관리 시스템을 사용할 때 수행할 작업입니다.
+단일 Uvicorn 프로세스를 실행하기 위해, **처음부터 여러분만의 이미지를 직접 빌드**하는 방법을 보여드리겠습니다. 이는 간단한 과정이며, **Kubernetes** 같은 분산 컨테이너 관리 시스템을 사용할 때 아마도 이렇게 하고 싶을 것입니다.
-## 요약
+## 요약 { #recap }
-당신은 **구니콘**(또는 유비콘)을 유비콘 워커와 함께 프로세스 관리자로 사용하여 **멀티-코어 CPU**를 활용하는 **멀티 프로세스를 병렬로 실행**할 수 있습니다.
+`fastapi` 또는 `uvicorn` 명령에서 `--workers` CLI 옵션을 사용해 여러 워커 프로세스를 실행하면, **멀티 코어 CPU**를 활용해 **여러 프로세스를 병렬로 실행**할 수 있습니다.
-다른 배포 개념을 직접 다루면서 **자신만의 배포 시스템**을 구성하는 경우 이러한 도구와 개념들을 활용할 수 있습니다.
+다른 배포 개념들을 직접 처리하면서 **자체 배포 시스템**을 구축하는 경우, 이러한 도구와 아이디어를 활용할 수 있습니다.
-다음 장에서 컨테이너(예: 도커 및 쿠버네티스)와 함께하는 **FastAPI**에 대해 배워보세요. 이러한 툴에는 다른 **배포 개념**들을 간단히 해결할 수 있는 방법이 있습니다. ✨
+다음 장에서 컨테이너(예: Docker 및 Kubernetes)와 함께 사용하는 **FastAPI**에 대해 알아보세요. 해당 도구들이 다른 **배포 개념들**도 간단히 해결하는 방법이 있다는 것을 확인할 수 있습니다. ✨
-# FastAPI 버전들에 대하여
+# FastAPI 버전들에 대하여 { #about-fastapi-versions }
-**FastAPI** ë\8a\94 ì\9d´ë¯¸ ë§\8eì\9d\80 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ê³¼ ì\8b\9cì\8a¤í\85\9cë\93¤ì\9d\84 ë§\8cë\93\9cë\8a\94ë\8d° ì\82¬ì\9a©ë\90\98ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë¦¬ê³ 100%ì\9d\98 í\85\8cì\8a¤í\8a¸ ì \95í\99\95ì\84±ì\9d\84 ê°\80ì§\80ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤. í\95\98ì§\80ë§\8c ì\9d´ê²\83ì\9d\80 ì\95\84ì§\81ê¹\8cì§\80ë\8f\84 ë¹ ë¥´ê²\8c ë°\9cì \84í\95\98ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤.
+**FastAPI**ë\8a\94 ì\9d´ë¯¸ ë§\8eì\9d\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ê³¼ ì\8b\9cì\8a¤í\85\9cì\97\90ì\84\9c í\94\84ë¡\9cë\8d\95ì\85\98ì\9c¼ë¡\9c ì\82¬ì\9a©ë\90\98ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë¦¬ê³ í\85\8cì\8a¤í\8a¸ 커ë²\84리ì§\80ë\8a\94 100%ë¡\9c ì\9c ì§\80ë\90©ë\8b\88ë\8b¤. í\95\98ì§\80ë§\8c ê°\9cë°\9cì\9d\80 ì\97¬ì \84í\9e\88 ë¹ ë¥´ê²\8c ì§\84í\96\89ë\90\98ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤.
-새로운 특징들이 빈번하게 추가되고, 오류들이 지속적으로 수정되고 있습니다. 그리고 코드가 계속적으로 향상되고 있습니다.
+새로운 기능이 자주 추가되고, 버그가 규칙적으로 수정되며, 코드는 계속해서 지속적으로 개선되고 있습니다.
-이것이 아직도 최신 버전이 `0.x.x`인 이유입니다. 이것은 각각의 버전들이 잠재적으로 변할 수 있다는 것을 보여줍니다. 이는 <a href="https://semver.org/" class="external-link" target="_blank">유의적 버전</a> 관습을 따릅니다.
+그래서 현재 버전이 아직 `0.x.x`인 것입니다. 이는 각 버전이 잠재적으로 하위 호환성이 깨지는 변경을 포함할 수 있음을 반영합니다. 이는 <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> 관례를 따릅니다.
-지금 바로 **FastAPI**로 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ë§\8cë\93¤ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ë\95\8c (ì\95\84ë§\88 ì§\80ê¸\88ê¹\8cì§\80 ê·¸ë\9e\98 ì\99\94ë\8d\98 ê²\83ì²\98ë\9f¼), ì\82¬ì\9a©í\95\98ë\8a\94 ë²\84ì \84ì\9d´ ì½\94ë\93\9cì\99\80 ì\9e\98 ë§\9eë\8a\94ì§\80 í\99\95ì\9d¸í\95´ì\95¼í\95©ë\8b\88ë\8b¤.
+지금 바로 **FastAPI**로 í\94\84ë¡\9cë\8d\95ì\85\98 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ë§\8cë\93¤ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤(ê·¸ë¦¬ê³ ì\95\84ë§\88ë\8f\84 í\95\9cë\8f\99ì\95\88 ê·¸ë \87ê²\8c í\95´ì\98¤ì\85¨ì\9d\84 ê²\83ì\9e\85ë\8b\88ë\8b¤). ë\8b¤ë§\8c ë\82\98머ì§\80 ì½\94ë\93\9cì\99\80 í\95¨ê»\98 ì\98¬ë°\94르ê²\8c ë\8f\99ì\9e\91í\95\98ë\8a\94 ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ê³ ì\9e\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95\98기ë§\8c í\95\98ë©´ ë\90©ë\8b\88ë\8b¤.
-## `fastapi` 버전을 표시
+## `fastapi` 버전을 고정하기 { #pin-your-fastapi-version }
-가장 먼저 해야할 것은 응용 프로그램이 잘 작동하는 가장 최신의 구체적인 **FastAPI** 버전을 표시하는 것입니다.
+가장 먼저 해야 할 일은 여러분의 애플리케이션에서 올바르게 동작하는 것으로 알고 있는 **FastAPI**의 최신 구체 버전에 맞춰 사용 중인 버전을 "고정(pin)"하는 것입니다.
-ì\98\88를 ë\93¤ì\96´, ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\97\90 `0.45.0` ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\96\88ë\8b¤ê³ ê°\80ì \95í\95©니다.
+ì\98\88를 ë\93¤ì\96´, ì\95±ì\97\90ì\84\9c `0.112.0` ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ê³ ì\9e\88ë\8b¤ê³ ê°\80ì \95í\95´ ë³´ê² ì\8aµ니다.
-만약에 `requirements.txt` 파일을 사용했다면, 다음과 같이 버전을 명세할 수 있습니다:
+`requirements.txt` 파일을 사용한다면 다음과 같이 버전을 지정할 수 있습니다:
```txt
-fastapi==0.45.0
+fastapi[standard]==0.112.0
```
-이것은 `0.45.0` 버전을 사용했다는 것을 의미합니다.
+이는 정확히 `0.112.0` 버전을 사용한다는 의미입니다.
-또는 다음과 같이 표시할 수 있습니다:
+또는 다음과 같이 고정할 수도 있습니다:
```txt
-fastapi>=0.45.0,<0.46.0
+fastapi[standard]>=0.112.0,<0.113.0
```
-이것은 `0.45.0` 버전과 같거나 높으면서 `0.46.0` 버전 보다는 낮은 버전을 사용했다는 것을 의미합니다. 예를 들어, `0.45.2` 버전과 같은 경우는 해당 조건을 만족합니다.
-
-만약에 Poetry, Pipenv, 또는 그밖의 다양한 설치 도구를 사용한다면, 패키지에 구체적인 버전을 정의할 수 있는 방법을 가지고 있을 것입니다.
+이는 `0.112.0` 이상이면서 `0.113.0` 미만의 버전을 사용한다는 의미입니다. 예를 들어 `0.112.2` 버전도 허용됩니다.
-## 이용가능한 버전들
+`uv`, Poetry, Pipenv 등 다른 도구로 설치를 관리한다면, 모두 패키지의 특정 버전을 정의할 수 있는 방법을 제공합니다.
-[Release Notes](../release-notes.md){.internal-link target=_blank}를 통해 사용할 수 있는 버전들을 확인할 수 있습니다.(예를 들어, 가장 최신의 버전을 확인할 수 있습니다.)
+## 이용 가능한 버전들 { #available-versions }
+사용 가능한 버전(예: 현재 최신 버전이 무엇인지 확인하기 위해)은 [Release Notes](../release-notes.md){.internal-link target=_blank}에서 확인할 수 있습니다.
-## 버전들에 대해
+## 버전들에 대해 { #about-versions }
-ì\9c ì\9d\98ì \81 ë²\84ì \84 ê´\80ì\8aµì\9d\84 ë\94°ë\9d¼ì\84\9c, `1.0.0` ì\9d´í\95\98ì\9d\98 모ë\93 ë²\84ì \84ë\93¤ì\9d\80 ì\9e ì\9e¬ì \81ì\9c¼ë¡\9c ê¸\89ë³\80í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+Semantic Versioning ê´\80ë¡\80ì\97\90 ë\94°ë¥´ë©´, `1.0.0` 미ë§\8cì\9d\98 ì\96´ë\96¤ ë²\84ì \84ì\9d´ë\93 ì\9e ì\9e¬ì \81ì\9c¼ë¡\9c í\95\98ì\9c\84 í\98¸í\99\98ì\84±ì\9d´ 깨ì§\80ë\8a\94 ë³\80ê²½ì\9d\84 ì¶\94ê°\80í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-FastAPI는 오류를 수정하고, 일반적인 변경사항을 위해 "패치"버전의 관습을 따릅니다.
+FastAPI는 또한 "PATCH" 버전 변경은 버그 수정과 하위 호환성이 깨지지 않는 변경을 위한 것이라는 관례를 따릅니다.
/// tip | 팁
-여기서 말하는 "패치"란 버전의 마지막 숫자로, 예를 들어 `0.2.3` 버전에서 "패치"는 `3`을 의미합니다.
+"PATCH"는 마지막 숫자입니다. 예를 들어 `0.2.3`에서 PATCH 버전은 `3`입니다.
///
-따라서 다음과 같이 버전을 표시할 수 있습니다:
+따라서 다음과 같이 버전을 고정할 수 있어야 합니다:
```txt
fastapi>=0.45.0,<0.46.0
```
-수정된 사항과 새로운 요소들이 "마이너" 버전에 추가되었습니다.
+하위 호환성이 깨지는 변경과 새로운 기능은 "MINOR" 버전에 추가됩니다.
/// tip | 팁
-"마이너"란 버전 넘버의 가운데 숫자로, 예를 들어서 `0.2.3`의 "마이너" 버전은 `2`입니다.
+"MINOR"는 가운데 숫자입니다. 예를 들어 `0.2.3`에서 MINOR 버전은 `2`입니다.
///
-## FastAPI 버전의 업그레이드
+## FastAPI 버전 업그레이드하기 { #upgrading-the-fastapi-versions }
-ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ê²\80ì\82¬í\95´ì\95¼합니다.
+ì\95±ì\97\90 í\85\8cì\8a¤í\8a¸ë¥¼ ì¶\94ê°\80í\95´ì\95¼ 합니다.
-(Starlette 덕분에), **FastAPI** 를 이용하여 굉장히 쉽게 할 수 있습니다. [Testing](../tutorial/testing.md){.internal-link target=_blank}문서를 확인해 보십시오:
+**FastAPI**에서는 매우 쉽습니다(Starlette 덕분에). 문서를 확인해 보세요: [Testing](../tutorial/testing.md){.internal-link target=_blank}
-검사를 해보고 난 후에, **FastAPI** 버전을 더 최신으로 업그레이드 할 수 있습니다. 그리고 코드들이 테스트에 정상적으로 작동하는지 확인을 해야합니다.
+테스트를 갖춘 뒤에는 **FastAPI** 버전을 더 최신 버전으로 업그레이드하고, 테스트를 실행하여 모든 코드가 올바르게 동작하는지 확인하세요.
-ë§\8cì\95½ì\97\90 모ë\93 ê²\83ì\9d´ ì \95ì\83\81 ì\9e\91ë\8f\99í\95\98ê±°ë\82\98 í\95\84ì\9a\94í\95\9c ë¶\80ë¶\84ì\9d\84 ë³\80ê²½í\95\98ê³ , 모ë\93 ê²\80ì\82¬ë¥¼ í\86µê³¼í\95\9cë\8b¤ë©´, ì\83\88ë¡\9cì\9a´ ë²\84ì \84ì\9d\98 `fastapi`를 í\91\9cì\8b\9c할 수 있습니다.
+모ë\93 ê²\83ì\9d´ ë\8f\99ì\9e\91í\95\98ê±°ë\82\98 í\95\84ì\9a\94í\95\9c ë³\80ê²½ì\9d\84 í\95\9c ë\92¤ 모ë\93 í\85\8cì\8a¤í\8a¸ê°\80 í\86µê³¼í\95\9cë\8b¤ë©´, `fastapi`를 ê·¸ ì\83\88ë¡\9cì\9a´ ìµ\9cì\8b ë²\84ì \84ì\9c¼ë¡\9c ê³ ì \95할 수 있습니다.
-## Starlette에 대해
+## Starlette에 대해 { #about-starlette }
-`starlette`의 버전은 표시할 수 없습니다.
+`starlette`의 버전은 고정하지 않는 것이 좋습니다.
-서로다른 버전의 **FastAPI**가 구체적이고 새로운 버전의 Starlette을 사용할 것입니다.
+서로 다른 **FastAPI** 버전은 Starlette의 특정한 더 새로운 버전을 사용하게 됩니다.
-ê·¸ë\9f¬ë¯\80ë¡\9c **FastAPI**ê°\80 ì\95\8cë§\9eì\9d\80 Starlette ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ë\8f\84ë¡\9d í\95\98ì\8bì\8b\9cì\98¤.
+ë\94°ë\9d¼ì\84\9c **FastAPI**ê°\80 ì\98¬ë°\94른 Starlette ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ë\8f\84ë¡\9d ê·¸ë\83¥ ë\91\90ë©´ ë\90©ë\8b\88ë\8b¤.
-## Pydantic에 대해
+## Pydantic에 대해 { #about-pydantic }
-Pydantic은 **FastAPI** 를 위한 검사를 포함하고 있습니다. 따라서, 새로운 버전의 Pydantic(`1.0.0`이상)은 항상 FastAPI와 호환됩니다.
+Pydantic은 자체 테스트에 **FastAPI**에 대한 테스트도 포함하고 있으므로, Pydantic의 새 버전(`1.0.0` 초과)은 항상 FastAPI와 호환됩니다.
-ì\9e\91ì\97\85ì\9d\84 í\95\98ê³ ì\9e\88ë\8a\94 `1.0.0` ì\9d´ì\83\81ì\9d\98 모ë\93 ë²\84ì \84ê³¼ `2.0.0` ì\9d´í\95\98ì\9d\98 Pydantic ë²\84ì \84ì\9d\84 í\91\9cì\8b\9c할 수 있습니다.
+ì\97¬ë\9f¬ë¶\84ì\97\90ê²\8c ë§\9eë\8a\94 `1.0.0` ì´\88ê³¼ì\9d\98 ì\96´ë\96¤ Pydantic ë²\84ì \84ì\9c¼ë¡\9cë\93 ê³ ì \95할 수 있습니다.
-예를 들어 다음과 같습니다:
+예를 들어:
```txt
-pydantic>=1.2.0,<2.0.0
+pydantic>=2.7.0,<3.0.0
```
-# 환경 변수
+# 환경 변수 { #environment-variables }
/// tip | 팁
///
-환경 변수는 파이썬 코드의 **바깥**인, **운영 체제**에 존재하는 변수입니다. 파이썬 코드나 다른 프로그램에서 읽을 수 있습니다.
+환경 변수(또는 "**env var**"라고도 합니다)는 파이썬 코드의 **바깥**인, **운영 체제**에 존재하는 변수이며, 파이썬 코드(또는 다른 프로그램에서도)에서 읽을 수 있습니다.
-í\99\98ê²½ ë³\80ì\88\98ë\8a\94 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98 **ì\84¤ì \95**ì\9d\84 ì²\98리í\95\98ê±°ë\82\98, í\8c\8cì\9d´ì\8d¬ì\9d\98 **ì\84¤ì¹\98** ê³¼ì \95ì\9d\98 ì\9d¼ë¶\80ë¡\9c ì\9c ì\9a©í\95©니다.
+í\99\98ê²½ ë³\80ì\88\98ë\8a\94 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98 **ì\84¤ì \95**ì\9d\84 ì²\98리í\95\98ê±°ë\82\98, í\8c\8cì\9d´ì\8d¬ì\9d\98 **ì\84¤ì¹\98** ê³¼ì \95ì\9d\98 ì\9d¼ë¶\80ë¡\9c ì\9c ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµ니다.
-## 환경 변수를 만들고 사용하기
+## 환경 변수를 만들고 사용하기 { #create-and-use-env-vars }
파이썬 없이도, **셸 (터미널)** 에서 환경 변수를 **생성** 하고 사용할 수 있습니다.
////
-## 파이썬에서 환경 변수 읽기
+## 파이썬에서 env var 읽기 { #read-env-vars-in-python }
-í\8c\8cì\9d´ì\8d¬ **ë°\94ê¹¥**ì\9d¸ í\84°ë¯¸ë\84\90ì\97\90ì\84\9c(ë\8b¤ë¥¸ ë\8f\84구ë¡\9cë\8f\84 ê°\80ë\8a¥) í\99\98ê²½ ë³\80ì\88\98를 ì\83\9dì\84±ë\8f\84 í\95 ì\88\98ë\8f\84 ì\9e\88ê³ , ì\9d´ë¥¼ **í\8c\8cì\9d´ì\8d¬ì\97\90ì\84\9c ì\9d½ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.**
+í\8c\8cì\9d´ì\8d¬ **ë°\94ê¹¥**ì\9d¸ í\84°ë¯¸ë\84\90ì\97\90ì\84\9c(ë\98\90ë\8a\94 ë\8b¤ë¥¸ ì\96´ë\96¤ ë°©ë²\95ì\9c¼ë¡\9cë\93 ) í\99\98ê²½ ë³\80ì\88\98를 ë§\8cë\93¤ê³ , ê·¸ë\9f° ë\8b¤ì\9d\8c **í\8c\8cì\9d´ì\8d¬ì\97\90ì\84\9c ì\9d½ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤**.
예를 들어 다음과 같은 `main.py` 파일이 있다고 합시다:
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> 의 두 번째 인자는 반환할 기본값입니다.
-ì\97¬ê¸°ì\84\9cë\8a\94 `"World"`를 ë\84£ì\97\88기ì\97\90 기본ê°\92ì\9c¼ë¡\9cì\8d¨ ì\82¬ì\9a©ë\90©ë\8b\88ë\8b¤. ë\84£ì§\80 ì\95\8aì\9c¼ë©´ `None` ì\9d´ 기본ê°\92ì\9c¼ë¡\9c ì\82¬ì\9a©ë\90©ë\8b\88ë\8b¤.
+ì \9cê³µí\95\98ì§\80 ì\95\8aì\9c¼ë©´ 기본ê°\92ì\9d\80 `None`ì\9d´ë©°, ì\97¬ê¸°ì\84\9cë\8a\94 ì\82¬ì\9a©í\95 기본ê°\92ì\9c¼ë¡\9c `"World"`를 ì \9cê³µí\95©ë\8b\88ë\8b¤.
///
환경변수는 코드 바깥에서 설정될 수 있지만, 코드에서 읽을 수 있고, 나머지 파일과 함께 저장(`git`에 커밋)할 필요가 없으므로, 구성이나 **설정** 에 사용하는 것이 일반적입니다.
-**특정 프로그램 호출**에 대해서만 사용할 수 있는 환경 변수를 만들 수도 있습니다. 해당 프로그램에서만 사용할 수 있고, 해당 프로그램이 실행되는 동안만 사용할 수 있습니다.
+또한 **특정 프로그램 호출**에 대해서만 사용할 수 있는 환경 변수를 만들 수도 있는데, 해당 프로그램에서만 사용할 수 있고, 해당 프로그램이 실행되는 동안만 사용할 수 있습니다.
그렇게 하려면 프로그램 바로 앞, 같은 줄에 환경 변수를 만들어야 합니다:
///
-## 타입과 검증
+## 타입과 검증 { #types-and-validation }
-이 환경변수들은 오직 **텍스트 문자열**로만 처리할 수 있습니다. 텍스트 문자열은 파이썬 외부에 있으며 다른 프로그램 및 나머지 시스템(Linux, Windows, macOS 등 다른 운영 체제)과 호환되어야 합니다.
+이 환경변수들은 오직 **텍스트 문자열**로만 처리할 수 있습니다. 텍스트 문자열은 파이썬 외부에 있으며 다른 프로그램 및 나머지 시스템(그리고 Linux, Windows, macOS 같은 서로 다른 운영 체제에서도)과 호환되어야 합니다.
즉, 파이썬에서 환경 변수로부터 읽은 **모든 값**은 **`str`**이 되고, 다른 타입으로의 변환이나 검증은 코드에서 수행해야 합니다.
-**애플리케이션 설정**을 처리하기 위한 환경 변수 사용에 대한 자세한 내용은 [고급 사용자 가이드 - 설정 및 환경 변수](./advanced/settings.md){.internal-link target=\_blank} 에서 확인할 수 있습니다.
+**애플리케이션 설정**을 처리하기 위한 환경 변수 사용에 대한 자세한 내용은 [고급 사용자 가이드 - 설정 및 환경 변수](./advanced/settings.md){.internal-link target=_blank} 에서 확인할 수 있습니다.
-## `PATH` 환경 변수
+## `PATH` 환경 변수 { #path-environment-variable }
-**`PATH`**라고 불리는, **특별한** 환경변수가 있습니다. 운영체제(Linux, Windows, macOS 등)에서 실행할 프로그램을 찾기위해 사용됩니다.
+**`PATH`**라고 불리는, **특별한** 환경변수가 있습니다. 운영체제(Linux, macOS, Windows)에서 실행할 프로그램을 찾기위해 사용됩니다.
변수 `PATH`의 값은 Linux와 macOS에서는 콜론 `:`, Windows에서는 세미콜론 `;`으로 구분된 디렉토리로 구성된 긴 문자열입니다.
이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다:
-- `/usr/local/bin`
-- `/usr/bin`
-- `/bin`
-- `/usr/sbin`
-- `/sbin`
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
////
이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다:
-- `C:\Program Files\Python312\Scripts`
-- `C:\Program Files\Python312`
-- `C:\Windows\System32`
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
////
찾으면 **사용합니다**. 그렇지 않으면 **다른 디렉토리**에서 계속 찾습니다.
-### 파이썬 설치와 `PATH` 업데이트
+### 파이썬 설치와 `PATH` 업데이트 { #installing-python-and-updating-the-path }
파이썬을 설치할 때, 아마 `PATH` 환경 변수를 업데이트 할 것이냐고 물어봤을 겁니다.
////
-이 정보는 [가상 환경](virtual-environments.md){.internal-link target=\_blank} 에 대해 알아볼 때 유용할 것입니다.
+이 정보는 [가상 환경](virtual-environments.md){.internal-link target=_blank} 에 대해 알아볼 때 유용할 것입니다.
-## 결론
+## 결론 { #conclusion }
-이 문서를 읽고 **환경 변수**가 무엇이고 파이썬에서 어떻게 사용하는지 기본적으로 이해하셨을 겁니다.
+이 문서를 통해 **환경 변수**가 무엇이고 파이썬에서 어떻게 사용하는지 기본적으로 이해하셨을 겁니다.
-또한 <a href="https://ko.wikipedia.org/wiki/환경_변수" class="external-link" target="_blank">환경 변수에 대한 위키피디아(한국어)</a>에서 이에 대해 자세히 알아볼 수 있습니다.
+또한 <a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">환경 변수에 대한 위키피디아</a>에서 이에 대해 자세히 알아볼 수 있습니다.
많은 경우에서, 환경 변수가 어떻게 유용하고 적용 가능한지 바로 명확하게 알 수는 없습니다. 하지만 개발할 때 다양한 시나리오에서 계속 나타나므로 이에 대해 아는 것이 좋습니다.
-# 조건부적인 OpenAPI
+# 조건부 OpenAPI { #conditional-openapi }
-필요한 경우, 설정 및 환경 변수를 사용하여 환경에 따라 조건부로 OpenAPI를 구성하고 완전히 비활성화할 수도 있습니다.
+필요한 경우, 설정 및 환경 변수를 사용하여 환경에 따라 OpenAPI를 조건부로 구성하고 완전히 비활성화할 수도 있습니다.
-## 보안, API 및 docs에 대해서
+## 보안, API 및 docs에 대해서 { #about-security-apis-and-docs }
프로덕션에서, 문서화된 사용자 인터페이스(UI)를 숨기는 것이 API를 보호하는 방법이 *되어서는 안 됩니다*.
-ì\9d´ë\8a\94 APIì\97\90 ì¶\94ê°\80ì \81ì\9d¸ ë³´ì\95\88ì\9d\84 ì \9cê³µí\95\98ì§\80 ì\95\8aì\9c¼ë©°, *ê²½ë¡\9c ì\9e\91ì\97\85*ì\9d\80 여전히 동일한 위치에서 사용 할 수 있습니다.
+ì\9d´ë\8a\94 APIì\97\90 ì¶\94ê°\80ì \81ì\9d¸ ë³´ì\95\88ì\9d\84 ì \9cê³µí\95\98ì§\80 ì\95\8aì\9c¼ë©°, *ê²½ë¡\9c ì²\98리*ë\8a\94 여전히 동일한 위치에서 사용 할 수 있습니다.
코드에 보안 결함이 있다면, 그 결함은 여전히 존재할 것입니다.
-문서를 숨기는 것은 API와 상호작용하는 방법을 이해하기 어렵게 만들며, 프로덕션에서 디버깅을 더 어렵게 만들 수 있습니다. 이는 단순히 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">'모호성에 의한 보안'</a>의 한 형태로 간주될 수 있습니다.
+문서를 숨기는 것은 API와 상호작용하는 방법을 이해하기 어렵게 만들며, 프로덕션에서 디버깅을 더 어렵게 만들 수 있습니다. 이는 단순히 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">Security through obscurity</a>의 한 형태로 간주될 수 있습니다.
API를 보호하고 싶다면, 예를 들어 다음과 같은 더 나은 방법들이 있습니다:
-* 요청 본문과 응답에 대해 잘 정의된 Pydantic 모델을 사용하도록 하세요.
-
+* 요청 본문과 응답에 대해 잘 정의된 Pydantic 모델이 있는지 확인하세요.
* 종속성을 사용하여 필요한 권한과 역할을 구성하세요.
-
-* 평문 비밀번호를 절대 저장하지 말고, 오직 암호화된 비밀번호만 저장하세요.
-
-* Passlib과 JWT 토큰과 같은 잘 알려진 암호화 도구들을 구현하고 사용하세요.
-
+* 평문 비밀번호를 절대 저장하지 말고, 비밀번호 해시만 저장하세요.
+* pwdlib와 JWT 토큰 등과 같은 잘 알려진 암호화 도구들을 구현하고 사용하세요.
* 필요한 곳에 OAuth2 범위를 사용하여 더 세분화된 권한 제어를 추가하세요.
+* ...등등.
-* 등등....
-
-그럼에도 불구하고, 특정 환경(예: 프로덕션)에서 또는 환경 변수의 설정에 따라 API 문서를 비활성화해야 하는 매우 특정한 사용 사례가 있을 수 있습니다.
+그럼에도 불구하고, 특정 환경(예: 프로덕션)에서 또는 환경 변수의 설정에 따라 API docs를 비활성화해야 하는 매우 특정한 사용 사례가 있을 수 있습니다.
-## 설정 및 환경변수의 조건부 OpenAPI
+## 설정 및 환경변수의 조건부 OpenAPI { #conditional-openapi-from-settings-and-env-vars }
-동일한 Pydantic 설정을 사용하여 생성된 OpenAPI 및 문서 UI를 쉽게 구성할 수 있습니다.
+동일한 Pydantic 설정을 사용하여 생성된 OpenAPI 및 docs UI를 쉽게 구성할 수 있습니다.
예를 들어:
-{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
+{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
여기서 `openapi_url` 설정을 기본값인 `"/openapi.json"`으로 선언합니다.
그런 뒤, 우리는 `FastAPI` 앱을 만들 때 그것을 사용합니다.
-환경 변수 `OPENAPI_URL`을 빈 문자열로 설정하여 OpenAPI(문서 UI 포함)를 비활성화할 수도 있습니다. 예를 들어:
+그런 다음 환경 변수 `OPENAPI_URL`을 빈 문자열로 설정하여 OpenAPI(UI docs 포함)를 비활성화할 수도 있습니다. 예를 들어:
<div class="termy">
-# Swagger UI 구성
+# Swagger UI 구성 { #configure-swagger-ui }
추가적인 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI 매개변수</a>를 구성할 수 있습니다.
FastAPI는 이 구성을 **JSON** 형식으로 변환하여 JavaScript와 호환되도록 합니다. 이는 Swagger UI에서 필요로 하는 형식입니다.
-## 구문 강조 비활성화
+## 구문 강조 비활성화 { #disable-syntax-highlighting }
예를 들어, Swagger UI에서 구문 강조 기능을 비활성화할 수 있습니다.
그러나 `syntaxHighlight`를 `False`로 설정하여 구문 강조 기능을 비활성화할 수 있습니다:
-{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
...그럼 Swagger UI에서 더 이상 구문 강조 기능이 표시되지 않습니다:
<img src="/img/tutorial/extending-openapi/image03.png">
-## 테마 변경
+## 테마 변경 { #change-the-theme }
동일한 방식으로 `"syntaxHighlight.theme"` 키를 사용하여 구문 강조 테마를 설정할 수 있습니다 (중간에 점이 포함된 것을 참고하십시오).
-{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
이 설정은 구문 강조 색상 테마를 변경합니다:
<img src="/img/tutorial/extending-openapi/image04.png">
-## 기본 Swagger UI 매개변수 변경
+## 기본 Swagger UI 매개변수 변경 { #change-default-swagger-ui-parameters }
FastAPI는 대부분의 사용 사례에 적합한 몇 가지 기본 구성 매개변수를 포함하고 있습니다.
기본 구성에는 다음이 포함됩니다:
-{* ../../fastapi/openapi/docs.py ln[8:23] hl[17:23] *}
+{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
`swagger_ui_parameters` 인수에 다른 값을 설정하여 이러한 기본값 중 일부를 재정의할 수 있습니다.
예를 들어, `deepLinking`을 비활성화하려면 `swagger_ui_parameters`에 다음 설정을 전달할 수 있습니다:
-{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
-## 기타 Swagger UI 매개변수
+## 기타 Swagger UI 매개변수 { #other-swagger-ui-parameters }
-사용할 수 있는 다른 모든 구성 옵션을 확인하려면, Swagger UI 매개변수에 대한 공식 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">문서</a>를 참조하십시오.
+사용할 수 있는 다른 모든 구성 옵션을 확인하려면, Swagger UI 매개변수에 대한 공식 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI 매개변수 문서</a>를 참조하십시오.
-## JavaScript 전용 설정
+## JavaScript 전용 설정 { #javascript-only-settings }
Swagger UI는 **JavaScript 전용** 객체(예: JavaScript 함수)로 다른 구성을 허용하기도 합니다.
이들은 문자열이 아닌 **JavaScript** 객체이므로 Python 코드에서 직접 전달할 수 없습니다.
-ì\9d´ì\99\80 ê°\99ì\9d\80 JavaScript ì \84ì\9a© 구ì\84±ì\9d\84 ì\82¬ì\9a©í\95´ì\95¼ í\95\98ë\8a\94 ê²½ì\9a°, ì\9c\84ì\9d\98 ë°©ë²\95 ì¤\91 í\95\98ë\82\98를 ì\82¬ì\9a©í\95\98ì\97¬ 모ë\93 Swagger UI ê²½ë¡\9c ì\9e\91ì\97\85ì\9d\84 ì\9e¬ì \95ì\9d\98í\95\98ê³ í\95\84ì\9a\94í\95\9c JavaScript를 ì\88\98ë\8f\99ì\9c¼ë¡\9c ì\9e\91ì\84±í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\9d´ì\99\80 ê°\99ì\9d\80 JavaScript ì \84ì\9a© 구ì\84±ì\9d\84 ì\82¬ì\9a©í\95´ì\95¼ í\95\98ë\8a\94 ê²½ì\9a°, ì\9c\84ì\9d\98 ë°©ë²\95 ì¤\91 í\95\98ë\82\98를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. Swagger UI *ê²½ë¡\9c ì²\98리*를 모ë\91\90 ì\9e¬ì \95ì\9d\98í\95\98ê³ í\95\84ì\9a\94í\95\9c JavaScript를 ì\88\98ë\8f\99ì\9c¼ë¡\9c ì\9e\91ì\84±í\95\98ì\84¸ì\9a\94.
-# FastAPI
+# FastAPI { #fastapi }
<style>
.md-content .md-typeset h1 { display: none; }
</style>
<p align="center">
- <a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
+ <a href="https://fastapi.tiangolo.com/ko"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>FastAPI 프레임워크, 고성능, 간편한 학습, 빠른 코드 작성, 준비된 프로덕션</em>
---
-**문서**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
+**문서**: <a href="https://fastapi.tiangolo.com/ko" target="_blank">https://fastapi.tiangolo.com</a>
**소스 코드**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
주요 특징으로:
-* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#_11).
-
+* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#performance).
* **빠른 코드 작성**: 약 200%에서 300%까지 기능 개발 속도 증가. *
* **적은 버그**: 사람(개발자)에 의한 에러 약 40% 감소. *
* **직관적**: 훌륭한 편집기 지원. 모든 곳에서 <abbr title="also known as auto-complete, autocompletion, IntelliSense">자동완성</abbr>. 적은 디버깅 시간.
* **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.
* **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.
* **견고함**: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께.
-* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (이전에 Swagger로 알려졌던) 및 <a href="http://json-schema.org/" class="external-link" target="_blank">JSON 스키마</a>.
+* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (이전에 Swagger로 알려졌던) 및 <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* 내부 개발팀의 프로덕션 애플리케이션을 빌드한 테스트에 근거한 측정</small>
-## 골드 스폰서
+## 스폰서 { #sponsors }
<!-- sponsors -->
-{% if sponsors %}
+### 키스톤 스폰서 { #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 }
+
{% 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/fastapi-people/#sponsors" class="external-link" target="_blank">다른 스폰서</a>
+<a href="https://fastapi.tiangolo.com/ko/fastapi-people/#sponsors" class="external-link" target="_blank">다른 스폰서</a>
-## 의견들
+## 의견들 { #opinions }
"_[...] 저는 요즘 **FastAPI**를 많이 사용하고 있습니다. [...] 사실 우리 팀의 **마이크로소프트 ML 서비스** 전부를 바꿀 계획입니다. 그중 일부는 핵심 **Windows**와 몇몇의 **Office** 제품들이 통합되고 있습니다._"
"_솔직히, 당신이 만든 것은 매우 견고하고 세련되어 보입니다. 여러 면에서 **Hug**가 이렇게 되었으면 합니다 - 그걸 만든 누군가를 보는 것은 많은 영감을 줍니다._"
-<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> 제작자</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
+<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> 제작자</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
---
-## **Typer**, FastAPI의 CLI
+"_프로덕션 Python API를 만들고자 한다면, 저는 **FastAPI**를 강력히 추천합니다. **아름답게 설계**되었고, **사용이 간단**하며, **확장성이 매우 뛰어나**고, 우리의 API 우선 개발 전략에서 **핵심 구성 요소**가 되었으며 Virtual TAC Engineer 같은 많은 자동화와 서비스를 이끌고 있습니다._"
+
+<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 미니 다큐멘터리 { #fastapi-mini-documentary }
+
+2025년 말에 공개된 <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI 미니 다큐멘터리</a>가 있습니다. 온라인에서 시청할 수 있습니다:
+
+<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>
+
+## **Typer**, CLI를 위한 FastAPI { #typer-the-fastapi-of-clis }
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
웹 API 대신 터미널에서 사용할 <abbr title="Command Line Interface">CLI</abbr> 앱을 만들고 있다면, <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>를 확인해 보십시오.
-**Typer**는 FastAPI의 동생입니다. 그리고 **FastAPI의 CLI**가 되기 위해 생겼습니다. ⌨️ 🚀
+**Typer**는 FastAPI의 동생입니다. 그리고 **CLI를 위한 FastAPI**가 되기 위해 생겼습니다. ⌨️ 🚀
-## 요구사항
+## 요구사항 { #requirements }
FastAPI는 거인들의 어깨 위에 서 있습니다:
* 웹 부분을 위한 <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>.
* 데이터 부분을 위한 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>.
-## 설치
-
-<div class="termy">
-
-```console
-$ pip install fastapi
-
----> 100%
-```
+## 설치 { #installation }
-</div>
-
-프로덕션을 위해 <a href="http://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> 또는 <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>과 같은 ASGI 서버도 필요할 겁니다.
+<a href="https://fastapi.tiangolo.com/ko/virtual-environments/" class="external-link" target="_blank">가상 환경</a>을 생성하고 활성화한 다음 FastAPI를 설치하세요:
<div class="termy">
```console
-$ pip install "uvicorn[standard]"
+$ pip install "fastapi[standard]"
---> 100%
```
</div>
-## 예제
+**Note**: 모든 터미널에서 동작하도록 `"fastapi[standard]"`를 따옴표로 감싸 넣었는지 확인하세요.
+
+## 예제 { #example }
-### 만들기
+### 만들기 { #create-it }
-* `main.py` 파일을 만드십시오:
+다음 내용으로 `main.py` 파일을 만드십시오:
```Python
from typing import Union
<details markdown="1">
<summary>또는 <code>async def</code> 사용하기...</summary>
-여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오.
+여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오:
-```Python hl_lines="9 14"
+```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI
**Note**:
-잘 모르겠다면, <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">문서에서 `async`와 `await`</a>에 관한 _"급하세요?"_ 섹션을 확인해 보십시오.
+잘 모르겠다면, <a href="https://fastapi.tiangolo.com/ko/async/#in-a-hurry" target="_blank">문서에서 `async`와 `await`</a>에 관한 _"급하세요?"_ 섹션을 확인해 보십시오.
</details>
-### 실행하기
+### 실행하기 { #run-it }
-서버를 실행하십시오:
+다음 명령으로 서버를 실행하십시오:
<div class="termy">
```console
-$ uvicorn main:app --reload
-
+$ fastapi dev main.py
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [28720]
-INFO: Started server process [28722]
+INFO: Started reloader process [2248755] using WatchFiles
+INFO: Started server process [2248757]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>
<details markdown="1">
-<summary><code>uvicorn main:app --reload</code> 명령에 관하여...</summary>
+<summary><code>fastapi dev main.py</code> 명령에 관하여...</summary>
+
+`fastapi dev` 명령은 `main.py` 파일을 읽고, 그 안의 **FastAPI** 앱을 감지한 다음, <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>을 사용해 서버를 시작합니다.
-명령 `uvicorn main:app`은 다음을 나타냅니다:
+기본적으로 `fastapi dev`는 로컬 개발을 위해 auto-reload가 활성화된 상태로 시작됩니다.
-* `main`: `main.py` 파일 (파이썬 "모듈").
-* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
-* `--reload`: 코드가 변경된 후 서버 재시작하기. 개발환경에서만 사용하십시오.
+자세한 내용은 <a href="https://fastapi.tiangolo.com/ko/fastapi-cli/" target="_blank">FastAPI CLI 문서</a>에서 확인할 수 있습니다.
</details>
-### 확인하기
+### 확인하기 { #check-it }
브라우저로 <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>를 열어보십시오.
* _경로_ `/` 및 `/items/{item_id}`에서 HTTP 요청 받기.
* 두 _경로_ 모두 `GET` <em>연산</em>(HTTP _메소드_ 로 알려진)을 받습니다.
-* _경로_ `/items/{item_id}`는 _경로 매개변수_ `int`형 이어야 하는 `item_id`를 가지고 있습니다.
-* _경로_ `/items/{item_id}`는 선택적인 `str`형 이어야 하는 _경로 매개변수_ `q`를 가지고 있습니다.
+* _경로_ `/items/{item_id}`는 `int`형 이어야 하는 _경로 매개변수_ `item_id`를 가지고 있습니다.
+* _경로_ `/items/{item_id}`는 선택적인 `str`형 _쿼리 매개변수_ `q`를 가지고 있습니다.
-### 대화형 API 문서
+### 대화형 API 문서 { #interactive-api-docs }
이제 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 가보십시오.

-### 대안 API 문서
+### 대안 API 문서 { #alternative-api-docs }
그리고 이제 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 가봅시다.

-## ì\98\88ì \9c ì\8b¬í\99\94
+## ì\98\88ì \9c ì\97\85ê·¸ë \88ì\9d´ë\93\9c { #example-upgrade }
-이제 `PUT` 요청에 있는 본문(Body)을 받기 위해 `main.py`를 수정해봅시다.
+이제 `PUT` 요청에서 본문을 받기 위해 `main.py` 파일을 수정해봅시다.
-Pydantic을 이용해 파이썬 표준 타입으로 본문을 선언합니다.
+Pydantic 덕분에 표준 Python 타입을 사용해 본문을 선언합니다.
-```Python hl_lines="4 9 10 11 12 25 26 27"
+```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI
return {"item_name": item.name, "item_id": item_id}
```
-서버가 자동으로 리로딩 할 수 있어야 합니다 (위에서 `uvicorn` 명령에 `--reload`을 추가 했기 때문입니다).
+`fastapi dev` 서버는 자동으로 리로딩되어야 합니다.
-### 대화형 API 문서 업그레이드
+### 대화형 API 문서 업그레이드 { #interactive-api-docs-upgrade }
이제 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 이동합니다.
-* 대화형 API 문서ê°\80 ì\83\88 본문과 í\95¨ê»\98 ì\9e\90ë\8f\99ì\9c¼ë¡\9c ì\97\85ë\8d°ì\9d´í\8a¸ í\95©ë\8b\88ë\8b¤:
+* 대화형 API 문서ë\8a\94 ì\83\88 본문ì\9d\84 í\8f¬í\95¨í\95´ ì\9e\90ë\8f\99ì\9c¼ë¡\9c ì\97\85ë\8d°ì\9d´í\8a¸ë\90©ë\8b\88ë\8b¤:

-* "Try it out" ë²\84í\8a¼ì\9d\84 í\81´ë¦í\95\98ë©´, 매ê°\9cë³\80ì\88\98를 ì±\84ì\9a¸ ì\88\98 ì\9e\88ê²\8c í\95´ì£¼ê³ ì§\81ì \91 APIì\99\80 ì\83\81í\98¸ì\9e\91ì\9a© 할 수 있습니다:
+* "Try it out" ë²\84í\8a¼ì\9d\84 í\81´ë¦í\95\98ë©´, 매ê°\9cë³\80ì\88\98를 ì±\84ì\9a°ê³ APIì\99\80 ì§\81ì \91 ì\83\81í\98¸ì\9e\91ì\9a©할 수 있습니다:

-* ê·¸ë\9f¬ê³ ë\82\98ì\84\9c "Execute" ë²\84í\8a¼ì\9d\84 ë\88\84르면, ì\82¬ì\9a©ì\9e\90 ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤ë\8a\94 APIì\99\80 í\86µì\8b í\95\98ê³ ë§¤ê°\9cë³\80ì\88\98를 ì \84ì\86¡í\95\98ë©° ê·¸ 결과를 ê°\80ì ¸ì\99\80ì\84\9c 화면에 표시합니다:
+* ê·¸ë\9f° ë\8b¤ì\9d\8c "Execute" ë²\84í\8a¼ì\9d\84 í\81´ë¦í\95\98ë©´, ì\82¬ì\9a©ì\9e\90 ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤ê°\80 APIì\99\80 í\86µì\8b í\95\98ê³ ë§¤ê°\9cë³\80ì\88\98를 ì \84ì\86¡í\95\9c ë\92¤ 결과를 ë°\9bì\95\84 화면에 표시합니다:

-### 대안 API 문서 업그레이드
+### 대안 API 문서 업그레이드 { #alternative-api-docs-upgrade }
그리고 이제, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 이동합니다.

-### 요약
+### 요약 { #recap }
요약하면, 여러분은 매개변수의 타입, 본문 등을 함수 매개변수로서 **한번에** 선언했습니다.
* 타입 검사.
* 데이터 검증:
* 데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러.
- * 중첩된 JSON 객체에 대한 유효성 검사.
-* 입력 데이터 <abbr title="다음으로 알려진: 직렬화, 파싱, 마샬링">변환</abbr>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:
+ * 깊이 중첩된 JSON 객체에 대한 유효성 검사.
+* 입력 데이터 <abbr title="also known as: serialization, parsing, marshalling">변환</abbr>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:
* JSON.
* 경로 매개변수.
* 쿼리 매개변수.
* 헤더.
* 폼(Forms).
* 파일.
-* 출력 데이터 <abbr title="다음으로 알려진: 직렬화, 파싱, 마샬링">변환</abbr>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):
+* 출력 데이터 <abbr title="also known as: serialization, parsing, marshalling">변환</abbr>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):
* 파이썬 타입 변환 (`str`, `int`, `float`, `bool`, `list`, 등).
* `datetime` 객체.
* `UUID` 객체.
* `GET` 및 `PUT` 요청에 `item_id`가 경로에 있는지 검증.
* `GET` 및 `PUT` 요청에 `item_id`가 `int` 타입인지 검증.
* 그렇지 않다면 클라이언트는 유용하고 명확한 에러를 볼 수 있습니다.
-* `GET` 요청에 `q`라는 선택적인 쿼리 매개변수가 검사(`http://127.0.0.1:8000/items/foo?q=somequery`처럼).
+* `GET` 요청에 `q`라는 선택적인 쿼리 매개변수가 있는지 검사(`http://127.0.0.1:8000/items/foo?q=somequery`처럼).
* `q` 매개변수는 `= None`으로 선언되었기 때문에 선택사항입니다.
* `None`이 없다면 필수사항입니다(`PUT`의 경우와 마찬가지로).
* `/items/{item_id}`으로의 `PUT` 요청은 본문을 JSON으로 읽음:
* `name`을 필수 속성으로 갖고 `str` 형인지 검사.
- * `price`을 필수 속성으로 갖고 `float` 형인지 검사.
- * ë§\8cì\95½ 주ì\96´ì§\84ë\8b¤ë©´, `is_offer`를 ì\84 í\83\9d ì\86\8dì\84±ì\9c¼ë¡\9c ê°\96ê³ `bool` í\98\95ì\9d¸지 검사.
+ * `price`를 필수 속성으로 갖고 `float` 형이어야 하는지 검사.
+ * ë§\8cì\95½ 주ì\96´ì§\84ë\8b¤ë©´, `is_offer`를 ì\84 í\83\9d ì\86\8dì\84±ì\9c¼ë¡\9c ê°\96ê³ `bool` í\98\95ì\9d´ì\96´ì\95¼ í\95\98ë\8a\94지 검사.
* 이 모든 것은 깊이 중첩된 JSON 객체에도 적용됩니다.
* JSON을 변환하거나 JSON으로 변환하는 것을 자동화.
* 다음에서 사용할 수 있는 모든 것을 OpenAPI로 문서화:

-더 많은 기능을 포함한 보다 완전한 예제의 경우, <a href="https://fastapi.tiangolo.com/tutorial/">튜토리얼 - 사용자 가이드</a>를 보십시오.
+더 많은 기능을 포함한 보다 완전한 예제의 경우, <a href="https://fastapi.tiangolo.com/ko/tutorial/">튜토리얼 - 사용자 가이드</a>를 보십시오.
**스포일러 주의**: 튜토리얼 - 사용자 가이드는:
* 서로 다른 장소에서 **매개변수** 선언: **헤더**, **쿠키**, **폼 필드** 그리고 **파일**.
* `maximum_length` 또는 `regex`처럼 **유효성 제약**하는 방법.
-* 강력하고 사용하기 쉬운 **<abbr title="컴포넌트, 리소스, 제공자, 서비스, injectables라 알려진">의존성 주입</abbr>** 시스템.
+* 강력하고 사용하기 쉬운 **<abbr title="also known as components, resources, providers, services, injectables">의존성 주입</abbr>** 시스템.
* **OAuth2** 지원을 포함한 **JWT tokens** 및 **HTTP Basic**을 갖는 보안과 인증.
* (Pydantic 덕분에) **깊은 중첩 JSON 모델**을 선언하는데 더 진보한 (하지만 마찬가지로 쉬운) 기술.
+* <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> 및 기타 라이브러리와의 **GraphQL** 통합.
* (Starlette 덕분에) 많은 추가 기능:
* **웹 소켓**
- * **GraphQL**
* HTTPX 및 `pytest`에 기반한 극히 쉬운 테스트
* **CORS**
* **쿠키 세션**
* ...기타 등등.
-## 성능
+### 앱 배포하기(선택 사항) { #deploy-your-app-optional }
+
+선택적으로 FastAPI 앱을 <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>에 배포할 수 있습니다. 아직이라면 대기자 명단에 등록해 보세요. 🚀
+
+이미 **FastAPI Cloud** 계정이 있다면(대기자 명단에서 초대해 드렸습니다 😉), 한 번의 명령으로 애플리케이션을 배포할 수 있습니다.
-ë\8f\85립ë\90\9c TechEmpower 벤ì¹\98ë§\88í\81¬ì\97\90ì\84\9c Uvicornì\97\90ì\84\9c ì\9e\91ë\8f\99í\95\98ë\8a\94 FastAPI ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ <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">ì\82¬ì\9a© ê°\80ë\8a¥í\95\9c ê°\80ì\9e¥ ë¹ ë¥¸ í\94\84ë \88ì\9e\84ì\9b\8cí\81¬ ì¤\91 í\95\98ë\82\98</a>ë¡\9c Starletteì\99\80 Uvicorn(FastAPIì\97\90ì\84\9c ë\82´ë¶\80ì \81ì\9c¼ë¡\9c ì\82¬ì\9a©)ì\97\90ë§\8c ë°\91ë\8f\8cê³ ì\9e\88ì\8aµë\8b\88ë\8b¤. (*)
+ë°°í\8f¬í\95\98기 ì \84ì\97\90, ë¡\9cê·¸ì\9d¸ë\90\98ì\96´ ì\9e\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95\98ì\84¸ì\9a\94:
-자세한 내용은 <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">벤치마크</a> 섹션을 보십시오.
+<div class="termy">
+
+```console
+$ fastapi login
+
+You are logged in to FastAPI Cloud 🚀
+```
-## 선택가능한 의존성
+</div>
+
+그런 다음 앱을 배포하세요:
+
+<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>
+
+이게 전부입니다! 이제 해당 URL에서 앱에 접근할 수 있습니다. ✨
+
+#### FastAPI Cloud 소개 { #about-fastapi-cloud }
+
+**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**는 **FastAPI** 뒤에 있는 동일한 작성자와 팀이 만들었습니다.
+
+최소한의 노력으로 API를 **빌드**, **배포**, **접근**하는 과정을 간소화합니다.
+
+FastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데까지 확장해 줍니다. 🎉
+
+FastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 스폰서이자 자금 제공자입니다. ✨
+
+#### 다른 클라우드 제공자에 배포하기 { #deploy-to-other-cloud-providers }
+
+FastAPI는 오픈 소스이며 표준을 기반으로 합니다. 선택한 어떤 클라우드 제공자에도 FastAPI 앱을 배포할 수 있습니다.
+
+클라우드 제공자의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓
+
+## 성능 { #performance }
+
+독립된 TechEmpower 벤치마크에서 Uvicorn에서 작동하는 FastAPI 애플리케이션이 <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">사용 가능한 가장 빠른 Python 프레임워크 중 하나</a>로 Starlette와 Uvicorn(FastAPI에서 내부적으로 사용)에만 밑돌고 있습니다. (*)
+
+자세한 내용은 <a href="https://fastapi.tiangolo.com/ko/benchmarks/" class="internal-link" target="_blank">벤치마크</a> 섹션을 보십시오.
+
+## 의존성 { #dependencies }
+
+FastAPI는 Pydantic과 Starlette에 의존합니다.
+
+### `standard` 의존성 { #standard-dependencies }
+
+FastAPI를 `pip install "fastapi[standard]"`로 설치하면 `standard` 그룹의 선택적 의존성이 함께 설치됩니다.
Pydantic이 사용하는:
Starlette이 사용하는:
-* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - `TestClient`를 사용하려면 필요.
-* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
-* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr>의 지원을 원하면 필요.
-* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` 지원을 위해 필요.
-* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Starlette의 `SchemaGenerator` 지원을 위해 필요 (FastAPI와 쓸때는 필요 없을 것입니다).
-* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - `GraphQLApp` 지원을 위해 필요.
+* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient`를 사용하려면 필요.
+* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
+* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 form <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr> 지원을 원하면 필요.
-FastAPI / Starlette이 사용하는:
+FastAPI가 사용하는:
-* <a href="http://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - 애플리케이션을 로드하고 제공하는 서버.
-* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse`을 사용하려면 필요.
-* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse`를 사용하려면 필요.
+* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - 애플리케이션을 로드하고 제공하는 서버를 위한 것입니다. 여기에는 고성능 서빙에 필요한 일부 의존성(예: `uvloop`)이 포함된 `uvicorn[standard]`가 포함됩니다.
+* `fastapi-cli[standard]` - `fastapi` 명령을 제공하기 위한 것입니다.
+ * 여기에는 FastAPI 애플리케이션을 <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>에 배포할 수 있게 해주는 `fastapi-cloud-cli`가 포함됩니다.
+
+### `standard` 의존성 없이 { #without-standard-dependencies }
+
+`standard` 선택적 의존성을 포함하고 싶지 않다면, `pip install "fastapi[standard]"` 대신 `pip install fastapi`로 설치할 수 있습니다.
-`pip install fastapi[all]`를 통해 이 모두를 설치 할 수 있습니다.
+### `fastapi-cloud-cli` 없이 { #without-fastapi-cloud-cli }
+
+표준 의존성과 함께 FastAPI를 설치하되 `fastapi-cloud-cli` 없이 설치하고 싶다면, `pip install "fastapi[standard-no-fastapi-cloud-cli]"`로 설치할 수 있습니다.
+
+### 추가 선택적 의존성 { #additional-optional-dependencies }
+
+추가로 설치하고 싶을 수 있는 의존성도 있습니다.
+
+추가 선택적 Pydantic 의존성:
+
+* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - 설정 관리를 위한 것입니다.
+* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - Pydantic에서 사용할 추가 타입을 위한 것입니다.
+
+추가 선택적 FastAPI 의존성:
+
+* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse`를 사용하려면 필요.
+* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse`를 사용하려면 필요.
-## 라이센스
+## 라이센스 { #license }
이 프로젝트는 MIT 라이센스 조약에 따라 라이센스가 부여됩니다.
-# 배우기
+# 배우기 { #learn }
-ì\97¬ê¸° **FastAPI**를 ë°°ì\9a°ê¸° ì\9c\84í\95\9c ì\9e\85문 ì\9e\90ë£\8cì\99\80 자습서가 있습니다.
+ì\97¬ê¸° **FastAPI**를 ë°°ì\9a°ê¸° ì\9c\84í\95\9c ì\9e\85문 ì\84¹ì\85\98ê³¼ 자습서가 있습니다.
-여러분은 FastAPI를 배우기 위해 **책**, **강의**, **공식 자료** 그리고 추천받은 방법을 고려할 수 있습니다. 😎
+여러분은 이것을 FastAPI를 배우기 위한 **책**, **강의**, **공식**이자 권장되는 방법으로 생각할 수 있습니다. 😎
-# Full Stack FastAPI 템플릿
+# Full Stack FastAPI 템플릿 { #full-stack-fastapi-template }
템플릿은 일반적으로 특정 설정과 함께 제공되지만, 유연하고 커스터마이징이 가능하게 디자인 되었습니다. 이 특성들은 여러분이 프로젝트의 요구사항에 맞춰 수정, 적용을 할 수 있게 해주고, 템플릿이 완벽한 시작점이 되게 해줍니다. 🏁
GitHub 저장소: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI 템플릿</a>
-## Full Stack FastAPI 템플릿 - 기술 스택과 기능들
+## Full Stack FastAPI 템플릿 - 기술 스택과 기능들 { #full-stack-fastapi-template-technology-stack-and-features }
-- ⚡ [**FastAPI**](https://fastapi.tiangolo.com): Python 백엔드 API.
- - 🧰 [SQLModel](https://sqlmodel.tiangolo.com): Python SQL 데이터 상호작용을 위한 (ORM).
- - 🔍 [Pydantic](https://docs.pydantic.dev): FastAPI에 의해 사용되는, 데이터 검증과 설정관리.
- - 💾 [PostgreSQL](https://www.postgresql.org): SQL 데이터베이스.
-- 🚀 [React](https://react.dev): 프론트엔드.
- - 💃 TypeScript, hooks, [Vite](https://vitejs.dev) 및 기타 현대적인 프론트엔드 스택을 사용.
- - 🎨 [Chakra UI](https://chakra-ui.com): 프론트엔드 컴포넌트.
+- ⚡ Python 백엔드 API를 위한 [**FastAPI**](https://fastapi.tiangolo.com/ko).
+ - 🧰 Python SQL 데이터베이스 상호작용을 위한 [SQLModel](https://sqlmodel.tiangolo.com) (ORM).
+ - 🔍 FastAPI에 의해 사용되는, 데이터 검증과 설정 관리를 위한 [Pydantic](https://docs.pydantic.dev).
+ - 💾 SQL 데이터베이스로서의 [PostgreSQL](https://www.postgresql.org).
+- 🚀 프론트엔드를 위한 [React](https://react.dev).
+ - 💃 TypeScript, hooks, Vite 및 기타 현대적인 프론트엔드 스택을 사용.
+ - 🎨 프론트엔드 컴포넌트를 위한 [Tailwind CSS](https://tailwindcss.com) 및 [shadcn/ui](https://ui.shadcn.com).
- 🤖 자동으로 생성된 프론트엔드 클라이언트.
- - 🧪 E2E 테스트를 위한 [Playwright](https://playwright.dev).
+ - 🧪 End-to-End 테스트를 위한 [Playwright](https://playwright.dev).
- 🦇 다크 모드 지원.
-- 🐋 [Docker Compose](https://www.docker.com): 개발 환경과 프로덕션(운영).
+- 🐋 개발 환경과 프로덕션(운영)을 위한 [Docker Compose](https://www.docker.com).
- 🔒 기본으로 지원되는 안전한 비밀번호 해싱.
-- 🔑 JWT 토큰 인증.
+- 🔑 JWT (JSON Web Token) 인증.
- 📫 이메일 기반 비밀번호 복구.
-- ✅ [Pytest]를 이용한 테스트(https://pytest.org).
-- 📞 [Traefik](https://traefik.io): 리버스 프록시 / 로드 밸런서.
+- ✅ [Pytest](https://pytest.org)를 이용한 테스트.
+- 📞 리버스 프록시 / 로드 밸런서로서의 [Traefik](https://traefik.io).
- 🚢 Docker Compose를 이용한 배포 지침: 자동 HTTPS 인증서를 처리하기 위한 프론트엔드 Traefik 프록시 설정 방법을 포함.
- 🏭 GitHub Actions를 기반으로 CI (지속적인 통합) 및 CD (지속적인 배포).
-# 파이썬 타입 소개
+# 파이썬 타입 소개 { #python-types-intro }
-파이썬은 선택적으로 "타입 힌트(type hints)"를 지원합니다.
+파이썬은 선택적으로 "타입 힌트(type hints)"(“type annotations”라고도 함)를 지원합니다.
-이러한 **타입 힌트**들은 변수의 <abbr title="예를 들면: str, int, float, bool">타입</abbr>을 선언할 수 있게 해주는 특수한 구문입니다.
+이러한 **"타입 힌트"** 또는 애너테이션은 변수의 <abbr title="for example: str, int, float, bool">타입</abbr>을 선언할 수 있게 해주는 특수한 구문입니다.
-ë³\80ì\88\98ì\9d\98 í\83\80ì\9e\85ì\9d\84 ì§\80ì \95í\95\98ë©´ ì\97\90ë\94\94í\84°ì\99\80 í\88´ì\9d´ ë\8d\94 ë§\8eì\9d\80 ë\8f\84ì\9b\80ì\9d\84 ì¤\84 ì\88\98 ì\9e\88ê²\8c ë\90©니다.
+ë³\80ì\88\98ì\9d\98 í\83\80ì\9e\85ì\9d\84 ì\84 ì\96¸í\95\98ë©´ ì\97\90ë\94\94í\84°ì\99\80 ë\8f\84구ê°\80 ë\8d\94 ë\82\98ì\9d\80 ì§\80ì\9b\90ì\9d\84 ì \9cê³µí\95 ì\88\98 ì\9e\88ì\8aµ니다.
-이 문서는 파이썬 타입 힌트에 대한 **빠른 자습서 / 내용환기** 수준의 문서입니다. 여기서는 **FastAPI**를 쓰기 위한 최소한의 내용만을 다룹니다.
+이 문서는 파이썬 타입 힌트에 대한 **빠른 자습서 / 내용 환기**입니다. **FastAPI**와 함께 사용하기 위해 필요한 최소한만 다룹니다... 실제로는 아주 조금만 있으면 됩니다.
-**FastAPI**는 타입 힌트에 기반을 두고 있으며, 이는 많은 장점과 이익이 있습니다.
+**FastAPI**는 모두 이러한 타입 힌트에 기반을 두고 있으며, 이는 많은 장점과 이점을 제공합니다.
-비록 **FastAPI**를 쓰지 않는다고 하더라도, 조금이라도 알아두면 도움이 될 것입니다.
+하지만 **FastAPI**를 전혀 사용하지 않더라도, 타입 힌트를 조금만 배워도 도움이 됩니다.
/// note | 참고
-파이썬에 능숙하셔서 타입 힌트에 대해 모두 아신다면, 다음 챕터로 건너뛰세요.
+파이썬에 능숙하고 타입 힌트에 대해 이미 모두 알고 있다면, 다음 장으로 건너뛰세요.
///
-## 동기 부여
+## 동기 부여 { #motivation }
-ê°\84ë\8b¨í\95\9c ì\98\88ì \9cë¶\80í\84° 시작해봅시다:
+ê°\84ë\8b¨í\95\9c ì\98\88ì \9cë¡\9c 시작해봅시다:
-{* ../../docs_src/python_types/tutorial001.py *}
+{* ../../docs_src/python_types/tutorial001_py39.py *}
-
-이 프로그램을 실행한 결과값:
+이 프로그램을 호출하면 다음이 출력됩니다:
```
John Doe
```
-í\95¨ì\88\98ë\8a\94 ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d´ ì\8b¤í\96\89ë\90©ë\8b\88ë\8b¤:
+ì\9d´ í\95¨ì\88\98ë\8a\94 ë\8b¤ì\9d\8cì\9d\84 ì\88\98í\96\89í\95©ë\8b\88ë\8b¤:
* `first_name`과 `last_name`를 받습니다.
-* `title()`로 각 첫 문자를 대문자로 변환시킵니다.
-* 두 단어를 중간에 공백을 두고 <abbr title="두 개를 하나로 차례차례 이어지게 하다">연결</abbr>합니다.
-
-{* ../../docs_src/python_types/tutorial001.py hl[2] *}
+* `title()`로 각각의 첫 글자를 대문자로 변환합니다.
+* 가운데에 공백을 두고 <abbr title="Puts them together, as one. With the contents of one after the other.">연결</abbr>합니다.
+{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
-### ì½\94ë\93\9c ì\88\98ì \95
+### ì\88\98ì \95í\95\98기 { #edit-it }
-이건 매우 간단한 프로그램입니다.
+매우 간단한 프로그램입니다.
-그런데 처음부터 작성한다고 생각을 해봅시다.
+하지만 이제, 이것을 처음부터 작성한다고 상상해봅시다.
-ì\97¬ë\9f¬ë¶\84ì\9d\80 매ê°\9cë³\80ì\88\98를 ì¤\80ë¹\84í\96\88ê³ , í\95¨ì\88\98를 ì \95ì\9d\98í\95\98기 ì\8b\9cì\9e\91í\96\88ì\9d\84 ê²\81ë\8b\88ë\8b¤.
+ì\96´ë\8a\90 ì\8b\9cì \90ì\97\94 í\95¨ì\88\98를 ì \95ì\9d\98í\95\98기 ì\8b\9cì\9e\91í\96\88ê³ , 매ê°\9cë³\80ì\88\98ë\8f\84 ì¤\80ë¹\84í\95´ë\91\90ì\97\88ì\9d\84 ê²\81ë\8b\88ë\8b¤...
-이때 "첫 글자를 대문자로 바꾸는 함수"를 호출해야 합니다.
+그런데 "첫 글자를 대문자로 변환하는 그 메서드"를 호출해야 합니다.
-`upper`였나? 아니면 `uppercase`? `first_uppercase`? `capitalize`?
+`upper`였나요? `uppercase`였나요? `first_uppercase`? `capitalize`?
-그때 개발자들의 오랜 친구, 에디터 자동완성을 시도해봅니다.
+그 다음, 개발자들의 오랜 친구인 에디터 자동완성을 시도합니다.
-당신은 `first_name`를 입력한 뒤 점(`.`)을 입력하고 자동완성을 켜기 위해서 `Ctrl+Space`를 눌렀습니다.
+함수의 첫 번째 매개변수인 `first_name`을 입력하고, 점(`.`)을 찍은 다음, 완성을 트리거하기 위해 `Ctrl+Space`를 누릅니다.
-하지만 슬프게도 아무런 도움이 되지 않습니다:
+하지만, 슬프게도 쓸만한 게 아무것도 없습니다:
<img src="/img/python-types/image01.png">
-### 타입 추가하기
+### 타입 추가하기 { #add-types }
이전 버전에서 한 줄만 수정해봅시다.
-ì \80í\9d¬ë\8a\94 ì\9d´ í\95¨ì\88\98ì\9d\98 매ê°\9cë³\80ì\88\98 ë¶\80ë¶\84:
+í\95¨ì\88\98ì\9d\98 매ê°\9cë³\80ì\88\98ì\9d¸ ì \95í\99\95í\9e\88 ì\9d´ ë¶\80ë¶\84ì\9d\84:
```Python
first_name, last_name
```
-ì\9d\84 ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d´ ë°\94ê¿\80 ê²\81ë\8b\88ë\8b¤:
+ì\97\90ì\84\9c:
```Python
first_name: str, last_name: str
```
-이게 다입니다.
+로 바꾸겠습니다.
-이게 "타입 힌트"입니다:
+이게 다입니다.
-{* ../../docs_src/python_types/tutorial002.py hl[1] *}
+이것들이 "타입 힌트"입니다:
+{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
-타입힌트는 다음과 같이 기본 값을 선언하는 것과는 다릅니다:
+이것은 다음처럼 기본값을 선언하는 것과는 다릅니다:
```Python
first_name="john", last_name="doe"
```
-이는 다른 것입니다.
+다른 것입니다.
-등호(`=`) 대신 콜론(`:`)을 쓰고 있습니다.
+등호(`=`)가 아니라 콜론(`:`)을 사용합니다.
-일반적으로 타입힌트를 추가한다고 해서 특별하게 어떤 일이 일어나지도 않습니다.
+그리고 보통 타입 힌트를 추가해도, 타입 힌트 없이 일어나는 일과 비교해 특별히 달라지는 것은 없습니다.
-그렇지만 이제, 다시 함수를 만드는 도중이라고 생각해봅시다. 다만 이번엔 타입 힌트가 있습니다.
+하지만 이제, 타입 힌트를 포함해 그 함수를 다시 만드는 중이라고 상상해봅시다.
-ê°\99ì\9d\80 ì\83\81í\99©ì\97\90ì\84\9c `Ctrl+Space`ë¡\9c ì\9e\90ë\8f\99ì\99\84ì\84±ì\9d\84 ì\9e\91ë\8f\99ì\8b\9cí\82¤ë©´,
+ê°\99ì\9d\80 ì§\80ì \90ì\97\90ì\84\9c `Ctrl+Space`ë¡\9c ì\9e\90ë\8f\99ì\99\84ì\84±ì\9d\84 í\8a¸ë¦¬ê±°í\95\98ë©´ ë\8b¤ì\9d\8cì\9d´ ë³´ì\9e\85ë\8b\88ë\8b¤:
<img src="/img/python-types/image02.png">
-아래와 같이 "그렇지!"하는 옵션이 나올때까지 스크롤을 내려서 볼 수 있습니다:
+그러면 스크롤하며 옵션을 보다가, "기억나는" 것을 찾을 수 있습니다:
<img src="/img/python-types/image03.png">
-## 더 큰 동기부여
-
-아래 함수를 보면, 이미 타입 힌트가 적용되어 있는 걸 볼 수 있습니다:
+## 더 큰 동기부여 { #more-motivation }
-{* ../../docs_src/python_types/tutorial003.py hl[1] *}
+이 함수를 확인해보세요. 이미 타입 힌트가 있습니다:
+{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
-편집기가 변수의 타입을 알고 있기 때문에, 자동완성 뿐 아니라 에러도 확인할 수 있습니다:
+에디터가 변수의 타입을 알고 있기 때문에, 자동완성만 되는 게 아니라 오류 검사도 할 수 있습니다:
<img src="/img/python-types/image04.png">
-이제 고쳐야하는 걸 알기 때문에, `age`를 `str(age)`과 같이 문자열로 바꾸게 됩니다:
-
-{* ../../docs_src/python_types/tutorial004.py hl[2] *}
+이제 고쳐야 한다는 것을 알고, `age`를 `str(age)`로 문자열로 바꿉니다:
+{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
-## 타입 선언
+## 타입 선언 { #declaring-types }
-ë°©ê¸\88 í\95¨ì\88\98ì\9d\98 매ê°\9cë³\80ì\88\98ë¡\9cì\8d¨ í\83\80ì\9e\85 í\9e\8cí\8a¸ë¥¼ ì\84 ì\96¸í\95\98ë\8a\94 주ì\9a\94 ì\9e¥ì\86\8c를 ë³´ì\95\98ì\8aµ니다.
+ë°©ê¸\88 í\83\80ì\9e\85 í\9e\8cí\8a¸ë¥¼ ì\84 ì\96¸í\95\98ë\8a\94 주ì\9a\94 ì\9c\84ì¹\98를 ë³´ì\95\98ì\8aµë\8b\88ë\8b¤. í\95¨ì\88\98 매ê°\9cë³\80ì\88\98ì\9e\85니다.
-이 위치는 여러분이 **FastAPI**와 함께 이를 사용하는 주요 장소입니다.
+이것은 **FastAPI**와 함께 사용할 때도 주요 위치입니다.
-### Simple 타입
+### Simple 타입 { #simple-types }
`str`뿐 아니라 모든 파이썬 표준 타입을 선언할 수 있습니다.
-예를 들면:
+예를 들어 다음을 사용할 수 있습니다:
* `int`
* `float`
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+### 타입 매개변수가 있는 Generic(제네릭) 타입 { #generic-types-with-type-parameters }
-### 타입 매개변수를 활용한 Generic(제네릭) 타입
+`dict`, `list`, `set`, `tuple`처럼 다른 값을 담을 수 있는 데이터 구조가 있습니다. 그리고 내부 값에도 각자의 타입이 있을 수 있습니다.
-`dict`, `list`, `set`, `tuple`과 같은 값을 저장할 수 있는 데이터 구조가 있고, 내부의 값은 각자의 타입을 가질 수도 있습니다.
+이렇게 내부 타입을 가지는 타입을 "**generic**" 타입이라고 부릅니다. 그리고 내부 타입까지 포함해 선언할 수도 있습니다.
-타입과 내부 타입을 선언하기 위해서는 파이썬 표준 모듈인 `typing`을 이용해야 합니다.
+이런 타입과 내부 타입을 선언하려면 표준 파이썬 모듈 `typing`을 사용할 수 있습니다. 이 모듈은 이러한 타입 힌트를 지원하기 위해 존재합니다.
-구체적으로는 아래 타입 힌트를 지원합니다.
+#### 더 최신 버전의 Python { #newer-versions-of-python }
-#### `List`
+`typing`을 사용하는 문법은 Python 3.6부터 최신 버전까지, Python 3.9, Python 3.10 등을 포함한 모든 버전과 **호환**됩니다.
-예를 들면, `str`의 `list`인 변수를 정의해봅시다.
+파이썬이 발전함에 따라 **더 최신 버전**에서는 이러한 타입 애너테이션 지원이 개선되며, 많은 경우 타입 애너테이션을 선언하기 위해 `typing` 모듈을 import해서 사용할 필요조차 없게 됩니다.
-`typing`에서 `List`(대문자 `L`)를 import 합니다.
+프로젝트에서 더 최신 버전의 파이썬을 선택할 수 있다면, 그 추가적인 단순함을 활용할 수 있습니다.
-{* ../../docs_src/python_types/tutorial006.py hl[1] *}
+이 문서 전체에는 각 파이썬 버전과 호환되는 예제가 있습니다(차이가 있을 때).
+예를 들어 "**Python 3.6+**"는 Python 3.6 이상(3.7, 3.8, 3.9, 3.10 등 포함)과 호환된다는 뜻입니다. 그리고 "**Python 3.9+**"는 Python 3.9 이상(3.10 등 포함)과 호환된다는 뜻입니다.
-ì½\9cë¡ (`:`) 문ë²\95ì\9d\84 ì\9d´ì\9a©í\95\98ì\97¬ ë³\80ì\88\98를 ì\84 ì\96¸í\95©ë\8b\88ë\8b¤.
+**ìµ\9cì\8b ë²\84ì \84ì\9d\98 Python**ì\9d\84 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8b¤ë©´, ìµ\9cì\8b ë²\84ì \84ì\9a© ì\98\88ì \9c를 ì\82¬ì\9a©í\95\98ì\84¸ì\9a\94. ì\98\88를 ë\93¤ì\96´ "**Python 3.10+**"ì²\98ë\9f¼, ê°\80ì\9e¥ **ì¢\8bê³ ê°\80ì\9e¥ ë\8b¨ì\88\9cí\95\9c 문ë²\95**ì\9d\84 ê°\96ê²\8c ë\90©ë\8b\88ë\8b¤.
-타입으로는 `List`를 넣어줍니다.
+#### List { #list }
-ì\9d´ë\95\8c ë°°ì\97´ì\9d\80 ë\82´ë¶\80 í\83\80ì\9e\85ì\9d\84 í\8f¬í\95¨í\95\98ë\8a\94 í\83\80ì\9e\85ì\9d´ê¸° ë\95\8c문ì\97\90 ë\8c\80ê´\84í\98¸ ì\95\88ì\97\90 ë\84£ì\96´ì¤\8dë\8b\88다.
+ì\98\88를 ë\93¤ì\96´, `str`ì\9d\98 `list`ì\9d¸ ë³\80ì\88\98를 ì \95ì\9d\98í\95´ë´\85ì\8b\9c다.
-{* ../../docs_src/python_types/tutorial006.py hl[4] *}
+같은 콜론(`:`) 문법으로 변수를 선언합니다.
+타입으로 `list`를 넣습니다.
-/// tip | 팁
+`list`는 내부 타입을 포함하는 타입이므로, 그 타입들을 대괄호 안에 넣습니다:
+
+{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+
+/// info | 정보
-대괄호 안의 내부 타입은 "타입 매개변수(type paramters)"라고 합니다.
+대괄호 안의 내부 타입은 "type parameters"라고 부릅니다.
-이번 예제에서는 `str`이 `List`에 들어간 타입 매개변수 입니다.
+이 경우 `str`이 `list`에 전달된 타입 매개변수입니다.
///
-이는 "`items`은 `list`인데, 배열에 들어있는 아이템 각각은 `str`이다"라는 뜻입니다.
+이는 "변수 `items`는 `list`이고, 이 `list`의 각 아이템은 `str`이다"라는 뜻입니다.
-ì\9d´ë \87ê²\8c í\95¨ì\9c¼ë¡\9cì\8d¨, ì\97\90ë\94\94í\84°ë\8a\94 ë°°ì\97´ì\97\90 ë\93¤ì\96´ì\9e\88ë\8a\94 ì\95\84ì\9d´í\85\9cì\9d\84 ì²\98리í\95 ë\95\8cë\8f\84 ë\8f\84ì\9b\80ì\9d\84 ì¤\84 ì\88\98 ì\9e\88ê²\8c ë\90©니다:
+ì\9d´ë \87ê²\8c í\95\98ë©´, ì\97\90ë\94\94í\84°ë\8a\94 리ì\8a¤í\8a¸ì\9d\98 ì\95\84ì\9d´í\85\9cì\9d\84 ì²\98리í\95\98ë\8a\94 ë\8f\99ì\95\88ì\97\90ë\8f\84 ì§\80ì\9b\90ì\9d\84 ì \9cê³µí\95 ì\88\98 ì\9e\88ì\8aµ니다:
<img src="/img/python-types/image05.png">
-타입이 없으면 이건 거의 불가능이나 다름 없습니다.
+타입이 없으면, 이는 거의 불가능합니다.
+
+변수 `item`이 리스트 `items`의 요소 중 하나라는 점에 주목하세요.
+
+그리고 에디터는 여전히 이것이 `str`임을 알고, 그에 대한 지원을 제공합니다.
+
+#### Tuple과 Set { #tuple-and-set }
+
+`tuple`과 `set`도 동일하게 선언할 수 있습니다:
+
+{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+
+이는 다음을 의미합니다:
+
+* 변수 `items_t`는 3개의 아이템을 가진 `tuple`이며, `int`, 또 다른 `int`, 그리고 `str`입니다.
+* 변수 `items_s`는 `set`이며, 각 아이템의 타입은 `bytes`입니다.
+
+#### Dict { #dict }
+
+`dict`를 정의하려면, 쉼표로 구분된 2개의 타입 매개변수를 전달합니다.
+
+첫 번째 타입 매개변수는 `dict`의 키를 위한 것입니다.
+
+두 번째 타입 매개변수는 `dict`의 값을 위한 것입니다:
+
+{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+
+이는 다음을 의미합니다:
-변수 `item`은 `items`의 개별 요소라는 사실을 알아두세요.
+* 변수 `prices`는 `dict`입니다:
+ * 이 `dict`의 키는 `str` 타입입니다(예: 각 아이템의 이름).
+ * 이 `dict`의 값은 `float` 타입입니다(예: 각 아이템의 가격).
-그리고 에디터는 계속 `str`라는 사실을 알고 도와줍니다.
+#### Union { #union }
-#### `Tuple`과 `Set`
+변수가 **여러 타입 중 어떤 것이든** 될 수 있다고 선언할 수 있습니다. 예를 들어 `int` 또는 `str`입니다.
-`tuple`과 `set`도 동일하게 선언할 수 있습니다.
+Python 3.6 이상(3.10 포함)에서는 `typing`의 `Union` 타입을 사용하고, 대괄호 안에 허용할 수 있는 타입들을 넣을 수 있습니다.
-{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
+Python 3.10에는 가능한 타입들을 <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>세로 막대(`|`)</abbr>로 구분해 넣을 수 있는 **새 문법**도 있습니다.
+//// tab | Python 3.10+
-이 뜻은 아래와 같습니다:
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008b_py310.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial008b_py39.py!}
+```
-* 변수 `items_t`는, 차례대로 `int`, `int`, `str`인 `tuple`이다.
-* 변수 `items_s`는, 각 아이템이 `bytes`인 `set`이다.
+////
-#### `Dict`
+두 경우 모두 이는 `item`이 `int` 또는 `str`일 수 있다는 뜻입니다.
-`dict`를 선언하려면 컴마로 구분된 2개의 파라미터가 필요합니다.
+#### `None`일 수도 있음 { #possibly-none }
-첫 번째 매개변수는 `dict`의 키(key)이고,
+값이 `str` 같은 타입일 수도 있지만, `None`일 수도 있다고 선언할 수 있습니다.
-두 번째 매개변수는 `dict`의 값(value)입니다.
+Python 3.6 이상(3.10 포함)에서는 `typing` 모듈에서 `Optional`을 import해서 사용하여 선언할 수 있습니다.
-{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
+```Python hl_lines="1 4"
+{!../../docs_src/python_types/tutorial009_py39.py!}
+```
+
+그냥 `str` 대신 `Optional[str]`을 사용하면, 값이 항상 `str`이라고 가정하고 있지만 실제로는 `None`일 수도 있는 상황에서 에디터가 오류를 감지하도록 도와줍니다.
+`Optional[Something]`은 사실 `Union[Something, None]`의 축약이며, 서로 동등합니다.
-이 뜻은 아래와 같습니다:
+또한 이는 Python 3.10에서 `Something | None`을 사용할 수 있다는 의미이기도 합니다:
-* 변수 `prices`는 `dict`이다:
- * `dict`의 키(key)는 `str`타입이다. (각 아이템의 이름(name))
- * `dict`의 값(value)는 `float`타입이다. (각 아이템의 가격(price))
+//// tab | Python 3.10+
-#### `Optional`
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial009_py310.py!}
+```
+
+////
-`str`과 같이 타입을 선언할 때 `Optional`을 쓸 수도 있는데, "선택적(Optional)"이기때문에 `None`도 될 수 있습니다:
+//// tab | Python 3.9+
```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009.py!}
+{!> ../../docs_src/python_types/tutorial009_py39.py!}
```
-`Optional[str]`을 `str` 대신 쓰게 되면, 특정 값이 실제로는 `None`이 될 수도 있는데 항상 `str`이라고 가정하는 상황에서 에디터가 에러를 찾게 도와줄 수 있습니다.
+////
+
+//// tab | Python 3.9+ alternative
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial009b_py39.py!}
+```
+
+////
+
+#### `Union` 또는 `Optional` 사용하기 { #using-union-or-optional }
+
+Python 3.10 미만 버전을 사용한다면, 아주 **주관적인** 관점에서의 팁입니다:
+
+* 🚨 `Optional[SomeType]` 사용을 피하세요
+* 대신 ✨ **`Union[SomeType, None]`을 사용하세요** ✨.
+
+둘은 동등하고 내부적으로는 같은 것이지만, `Optional`이라는 단어가 값이 선택 사항인 것처럼 보일 수 있기 때문에 `Optional` 대신 `Union`을 권장합니다. 실제 의미는 값이 선택 사항이라는 뜻이 아니라, "값이 `None`일 수 있다"는 뜻이기 때문입니다. 선택 사항이 아니고 여전히 필수인 경우에도요.
+
+`Union[SomeType, None]`이 의미를 더 명확하게 드러낸다고 생각합니다.
+
+이건 단지 단어와 이름의 문제입니다. 하지만 그런 단어들이 여러분과 팀원이 코드에 대해 생각하는 방식에 영향을 줄 수 있습니다.
+
+예로, 이 함수를 봅시다:
-#### Generic(제네릭) 타입
+{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-이 타입은 대괄호 안에 매개변수를 가지며, 종류는:
+매개변수 `name`은 `Optional[str]`로 정의되어 있지만, **선택 사항이 아닙니다**. 매개변수 없이 함수를 호출할 수 없습니다:
-* `List`
-* `Tuple`
-* `Set`
-* `Dict`
+```Python
+say_hi() # Oh, no, this throws an error! 😱
+```
+
+기본값이 없기 때문에 `name` 매개변수는 **여전히 필수입니다**(*optional*이 아님). 그럼에도 `name`은 값으로 `None`을 허용합니다:
+
+```Python
+say_hi(name=None) # This works, None is valid 🎉
+```
+
+좋은 소식은 Python 3.10을 사용하면, 타입의 유니온을 정의하기 위해 간단히 `|`를 사용할 수 있어서 이런 걱정을 할 필요가 없다는 점입니다:
+
+{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
+
+그러면 `Optional`이나 `Union` 같은 이름에 대해 걱정할 필요도 없습니다. 😎
+
+#### Generic(제네릭) 타입 { #generic-types }
+
+대괄호 안에 타입 매개변수를 받는 이러한 타입들은 **Generic types** 또는 **Generics**라고 부릅니다. 예를 들면:
+
+//// tab | Python 3.10+
+
+대괄호와 내부 타입을 사용해, 동일한 내장 타입들을 제네릭으로 사용할 수 있습니다:
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
+
+그리고 이전 파이썬 버전과 마찬가지로 `typing` 모듈의 다음도 사용할 수 있습니다:
+
+* `Union`
* `Optional`
-* ...등등
+* ...그 밖의 것들.
-위와 같은 타입은 **Generic(제네릭) 타입** 혹은 **Generics(제네릭스)**라고 불립니다.
+Python 3.10에서는 제네릭 `Union`과 `Optional`을 사용하는 대안으로, 타입 유니온을 선언하기 위해 <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>세로 막대(`|`)</abbr>를 사용할 수 있는데, 훨씬 더 좋고 단순합니다.
-### 타입으로서의 클래스
+////
-변수의 타입으로 클래스를 선언할 수도 있습니다.
+//// tab | Python 3.9+
+
+대괄호와 내부 타입을 사용해, 동일한 내장 타입들을 제네릭으로 사용할 수 있습니다:
-이름(name)을 가진 `Person` 클래스가 있다고 해봅시다.
+* `list`
+* `tuple`
+* `set`
+* `dict`
-{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
+그리고 `typing` 모듈의 제네릭들:
+* `Union`
+* `Optional`
+* ...그 밖의 것들.
+
+////
+
+### 타입으로서의 클래스 { #classes-as-types }
+
+변수의 타입으로 클래스를 선언할 수도 있습니다.
-그렇게 하면 변수를 `Person`이라고 선언할 수 있게 됩니다.
+이름을 가진 `Person` 클래스가 있다고 해봅시다:
-{* ../../docs_src/python_types/tutorial010.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+그러면 `Person` 타입의 변수를 선언할 수 있습니다:
-그리고 역시나 모든 에디터 도움을 받게 되겠죠.
+{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+
+그리고 다시, 에디터의 모든 지원을 받을 수 있습니다:
<img src="/img/python-types/image06.png">
-## Pydantic 모델
+이는 "`one_person`은 `Person` 클래스의 **인스턴스**"라는 뜻입니다.
+
+"`one_person`은 `Person`이라는 **클래스**다"라는 뜻이 아닙니다.
-<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>은 데이터 검증(Validation)을 위한 파이썬 라이브러리입니다.
+## Pydantic 모델 { #pydantic-models }
-당신은 속성들을 포함한 클래스 형태로 "모양(shape)"을 선언할 수 있습니다.
+<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>은 데이터 검증을 수행하는 파이썬 라이브러리입니다.
-그리고 각 속성은 타입을 가지고 있습니다.
+속성을 가진 클래스 형태로 데이터의 "모양(shape)"을 선언합니다.
-이 클래스를 활용하여서 값을 가지고 있는 인스턴스를 만들게 되면, 필요한 경우에는 적당한 타입으로 변환까지 시키기도 하여 데이터가 포함된 객체를 반환합니다.
+그리고 각 속성은 타입을 가집니다.
-그ë¦¬ê³ ê²°ê³¼ ê°\9dì²´ì\97\90 ë\8c\80í\95´ì\84\9cë\8a\94 ì\97\90ë\94\94í\84°ì\9d\98 ë\8f\84ì\9b\80ì\9d\84 ë°\9bì\9d\84 ì\88\98 ì\9e\88ê²\8c ë\90©ë\8b\88ë\8b¤.
+그 ë\8b¤ì\9d\8c ê·¸ í\81´ë\9e\98ì\8a¤ì\9d\98 ì\9d¸ì\8a¤í\84´ì\8a¤ë¥¼ ëª\87 ê°\80ì§\80 ê°\92ì\9c¼ë¡\9c ì\83\9dì\84±í\95\98ë©´, ê°\92ë\93¤ì\9d\84 ê²\80ì¦\9dí\95\98ê³ , (ê·¸ë\9f° ê²½ì\9a°ë\9d¼ë©´) ì \81ì \88í\95\9c í\83\80ì\9e\85ì\9c¼ë¡\9c ë³\80í\99\98í\95\9c ë\92¤, 모ë\93 ë\8d°ì\9d´í\84°ë¥¼ ê°\80ì§\84 ê°\9d체를 ì \9cê³µí\95©ë\8b\88ë\8b¤.
-Pydantic 공식 문서 예시:
+그리고 그 결과 객체에 대해 에디터의 모든 지원을 받을 수 있습니다.
-{* ../../docs_src/python_types/tutorial011.py *}
+Pydantic 공식 문서의 예시:
+{* ../../docs_src/python_types/tutorial011_py310.py *}
/// info | 정보
-Pydantic<에 대해 더 배우고 싶다면 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">공식 문서</a>를 참고하세요.</a>
+<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic에 대해 더 알아보려면 문서를 확인하세요</a>.
///
-**FastAPI**는 모두 Pydantic을 기반으로 되어 있습니다.
+**FastAPI**는 모두 Pydantic에 기반을 두고 있습니다.
+
+이 모든 것은 [자습서 - 사용자 안내서](tutorial/index.md){.internal-link target=_blank}에서 실제로 많이 보게 될 것입니다.
+
+/// tip | 팁
+
+Pydantic은 기본값 없이 `Optional` 또는 `Union[Something, None]`을 사용할 때 특별한 동작이 있습니다. 이에 대해서는 Pydantic 문서의 <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>에서 더 읽을 수 있습니다.
+
+///
+
+## 메타데이터 애너테이션이 있는 타입 힌트 { #type-hints-with-metadata-annotations }
+
+파이썬에는 `Annotated`를 사용해 이러한 타입 힌트에 **추가 <abbr title="Data about the data, in this case, information about the type, e.g. a description.">메타데이터</abbr>**를 넣을 수 있는 기능도 있습니다.
+
+Python 3.9부터 `Annotated`는 표준 라이브러리의 일부이므로, `typing`에서 import할 수 있습니다.
-이 모든 것이 실제로 어떻게 사용되는지에 대해서는 [자습서 - 사용자 안내서](tutorial/index.md){.internal-link target=_blank} 에서 더 많이 확인하실 수 있습니다.
+{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+
+파이썬 자체는 이 `Annotated`로 아무것도 하지 않습니다. 그리고 에디터와 다른 도구들에게는 타입이 여전히 `str`입니다.
+
+하지만 `Annotated`의 이 공간을 사용해, 애플리케이션이 어떻게 동작하길 원하는지에 대한 추가 메타데이터를 **FastAPI**에 제공할 수 있습니다.
+
+기억해야 할 중요한 점은 `Annotated`에 전달하는 **첫 번째 *타입 매개변수***가 **실제 타입**이라는 것입니다. 나머지는 다른 도구를 위한 메타데이터일 뿐입니다.
+
+지금은 `Annotated`가 존재하며, 표준 파이썬이라는 것만 알면 됩니다. 😎
+
+나중에 이것이 얼마나 **강력**할 수 있는지 보게 될 것입니다.
+
+/// tip | 팁
+
+이것이 **표준 파이썬**이라는 사실은, 에디터에서 가능한 **최고의 개발자 경험**을 계속 얻을 수 있다는 뜻이기도 합니다. 사용하는 도구로 코드를 분석하고 리팩터링하는 등에서도요. ✨
+
+또한 코드가 많은 다른 파이썬 도구 및 라이브러리와 매우 호환된다는 뜻이기도 합니다. 🚀
+
+///
-## **FastAPI**에서의 타입 힌트
+## **FastAPI**에서의 타입 힌트 { #type-hints-in-fastapi }
-**FastAPI**ë\8a\94 ì\97¬ë\9f¬ ë¶\80ë¶\84ì\97\90ì\84\9c í\83\80ì\9e\85 í\9e\8cí\8a¸ì\9d\98 ì\9e¥ì \90ì\9d\84 ì·¨í\95\98ê³ ì\9e\88ì\8aµ니다.
+**FastAPI**ë\8a\94 ì\9d´ë\9f¬í\95\9c í\83\80ì\9e\85 í\9e\8cí\8a¸ë¥¼ í\99\9cì\9a©í\95´ ì\97¬ë\9f¬ ê°\80ì§\80를 í\95©니다.
-**FastAPI**에서 타입 힌트와 함께 매개변수를 선언하면 장점은:
+**FastAPI**에서는 타입 힌트로 매개변수를 선언하면 다음을 얻습니다:
* **에디터 도움**.
* **타입 확인**.
-...ê·¸ë¦¬ê³ **FastAPI**ë\8a\94 ê°\99ì\9d\80 ì \95ì\9d\98를 ì\95\84ë\9e\98ì\97\90ë\8f\84 ì \81용합니다:
+...ê·¸ë¦¬ê³ **FastAPI**ë\8a\94 ê°\99ì\9d\80 ì\84 ì\96¸ì\9d\84 ë\8b¤ì\9d\8cì\97\90ë\8f\84 ì\82¬용합니다:
-* **요구사항 정의**: 요청 경로 매개변수, 쿼리 매개변수, 헤더, 바디, 의존성 등.
-* **데이터 변환**: 요청에서 요구한 타입으로.
-* **데이터 검증**: 각 요청마다:
- * ë\8d°ì\9d´í\84°ê°\80 ì\9c í\9a¨í\95\98ì§\80 ì\95\8aì\9d\80 ê²½ì\9a°ì\97\90ë\8a\94 **ì\9e\90ë\8f\99ì\9c¼ë¡\9c ì\97\90ë\9f¬**를 ë°\9cì\83\9d합니다.
-* OpenAPI를 활용한 **API 문서화**:
- * 자동으로 상호작용하는 유저 인터페이스에 쓰이게 됩니다.
+* **요구사항 정의**: 요청 경로 매개변수, 쿼리 매개변수, 헤더, 바디, 의존성 등에서.
+* **데이터 변환**: 요청에서 필요한 타입으로.
+* **데이터 검증**: 각 요청에서:
+ * ë\8d°ì\9d´í\84°ê°\80 ì\9c í\9a¨í\95\98ì§\80 ì\95\8aì\9d\84 ë\95\8c í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ì\97\90 ë°\98í\99\98ë\90\98ë\8a\94 **ì\9e\90ë\8f\99 ì\98¤ë¥\98**를 ì\83\9dì\84±합니다.
+* OpenAPI를 사용해 API를 **문서화**:
+ * 자동 상호작용 문서 UI에서 사용됩니다.
-ì\9c\84 ë\82´ì\9a©ì\9d´ ë\8b¤ì\86\8c ì¶\94ì\83\81ì \81ì\9d¼ ì\88\98ë\8f\84 ì\9e\88ì§\80ë§\8c, ê±±ì \95ë§\88ì\84¸ì\9a\94. [ì\9e\90ì\8aµì\84\9c - ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c](tutorial/index.md){.internal-link target=_blank}ì\97\90ì\84\9c ì \84ë¶\80 í\99\95ì\9d¸ ê°\80ë\8a¥í\95©니다.
+ì\9d´ 모ë\93 ê²\83ì\9d´ ë\8b¤ì\86\8c ì¶\94ì\83\81ì \81ì\9c¼ë¡\9c ë\93¤ë¦´ ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤. ê±±ì \95í\95\98ì§\80 ë§\88ì\84¸ì\9a\94. [ì\9e\90ì\8aµì\84\9c - ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c](tutorial/index.md){.internal-link target=_blank}ì\97\90ì\84\9c ì\8b¤ì \9cë¡\9c í\99\95ì\9d¸í\95\98ê²\8c ë\90 ê²\83ì\9e\85니다.
-가장 중요한 건, 표준 파이썬 타입을 한 곳에서(클래스를 더하거나, 데코레이터 사용하는 대신) 사용함으로써 **FastAPI**가 당신을 위해 많은 일을 해준다는 사실이죠.
+가장 중요한 점은 표준 파이썬 타입을 한 곳에서 사용함으로써(더 많은 클래스, 데코레이터 등을 추가하는 대신) **FastAPI**가 여러분을 위해 많은 일을 해준다는 사실입니다.
/// info | 정보
-만약 모든 자습서를 다 보았음에도 타입에 대해서 더 보고자 방문한 경우에는 <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`에서 제공하는 "cheat sheet"</a>이 좋은 자료가 될 겁니다.
+자습서를 모두 끝내고 타입에 대해 더 알아보기 위해 다시 돌아왔다면, 좋은 자료로 <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`의 "cheat sheet"</a>가 있습니다.
///
-# 리소스
+# 리소스 { #resources }
-추가 리소스, 외부 링크, 기사 등. ✈️
+추가 리소스, 외부 링크 등. ✈️
-# 백그라운드 작업
+# 백그라운드 작업 { #background-tasks }
-FastAPI에서는 응답을 반환한 후에 실행할 백그라운드 작업을 정의할 수 있습니다.
+FastAPI에서는 응답을 반환한 *후에* 실행할 백그라운드 작업을 정의할 수 있습니다.
-백그라운드 작업은 클라이언트가 응답을 받기 위해 작업이 완료될 때까지 기다릴 필요가 없기 때문에 요청 후에 발생해야하는 작업에 매우 유용합니다.
+백그라운드 작업은 요청 후에 발생해야 하지만, 클라이언트가 응답을 받기 전에 작업이 완료될 때까지 기다릴 필요가 없는 작업에 유용합니다.
-ì\9d´ë\9f¬í\95\9c ì\9e\91ì\97\85ì\97\90ë\8a\94 ë\8b¤ì\9d\8cì\9d´ í\8f¬í\95¨ë\90©니다.
+ì\98\88를 ë\93¤ë©´ ë\8b¤ì\9d\8cê³¼ ê°\99ì\8aµ니다.
-* 작업을 수행한 후 전송되는 이메일 알림
- * ì\9d´ë©\94ì\9d¼ ì\84\9cë²\84ì\97\90 ì\97°ê²°í\95\98ê³ ì\9d´ë©\94ì\9d¼ì\9d\84 ì \84ì\86¡í\95\98ë\8a\94 ê²\83ì\9d\80 (ëª\87 ì´\88 ì \95ë\8f\84) "ë\8a\90린" ê²½í\96¥ì\9d´ ì\9e\88ì\9c¼ë¯\80ë¡\9c, ì\9d\91ë\8bµì\9d\80 ì¦\89ì\8b\9c ë°\98í\99\98í\95\98ê³ ì\9d´ë©\94ì\9d¼ ì\95\8c림ì\9d\80 백그ë\9d¼ì\9a´ë\93\9cì\97\90ì\84\9c ì \84ì\86¡í\95\98ë\8a\94 ê²\8c ê°\80ë\8a¥í\95©니다.
+* 작업을 수행한 후 전송되는 이메일 알림:
+ * ì\9d´ë©\94ì\9d¼ ì\84\9cë²\84ì\97\90 ì\97°ê²°í\95\98ê³ ì\9d´ë©\94ì\9d¼ì\9d\84 ì \84ì\86¡í\95\98ë\8a\94 ê²\83ì\9d\80 (ëª\87 ì´\88 ì \95ë\8f\84) "ë\8a\90린" ê²½í\96¥ì\9d´ ì\9e\88ì\9c¼ë¯\80ë¡\9c, ì\9d\91ë\8bµì\9d\80 ì¦\89ì\8b\9c ë°\98í\99\98í\95\98ê³ ì\9d´ë©\94ì\9d¼ ì\95\8c림ì\9d\80 백그ë\9d¼ì\9a´ë\93\9cì\97\90ì\84\9c ì \84ì\86¡í\95 ì\88\98 ì\9e\88ì\8aµ니다.
* 데이터 처리:
- * 예를 들어 처리에 오랜 시간이 걸리는 데이터를 받았을 때 "Accepted" (HTTP 202)을 반환하고, 백그라운드에서 데이터를 처리할 수 있습니다.
+ * 예를 들어 처리에 오랜 시간이 걸리는 프로세스를 거쳐야 하는 파일을 받았다면, "Accepted"(HTTP 202) 응답을 반환하고 백그라운드에서 파일을 처리할 수 있습니다.
-## `백그라운드 작업` 사용
+## `BackgroundTasks` 사용 { #using-backgroundtasks }
-먼저 아래와 같이 `BackgroundTasks`를 임포트하고, `BackgroundTasks`를 _경로 작동 함수_ 에서 매개변수로 가져오고 정의합니다.
+먼저 `BackgroundTasks`를 임포트하고, `BackgroundTasks` 타입 선언으로 *경로 처리 함수*에 매개변수를 정의합니다:
-{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
-**FastAPI** 는 `BackgroundTasks` 개체를 생성하고, 매개 변수로 전달합니다.
+**FastAPI**가 `BackgroundTasks` 타입의 객체를 생성하고 해당 매개변수로 전달합니다.
-## 작업 함수 생성
+## 작업 함수 생성 { #create-a-task-function }
-백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85ì\9c¼ë¡\9c ì\8b¤í\96\89í\95 í\95¨ì\88\98를 ì \95ì\9d\98합니다.
+백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85ì\9c¼ë¡\9c ì\8b¤í\96\89í\95 í\95¨ì\88\98를 ì\83\9dì\84±합니다.
-이것은 단순히 매개변수를 받을 수 있는 표준 함수일 뿐입니다.
+이는 매개변수를 받을 수 있는 표준 함수일 뿐입니다.
-**FastAPI**는 이것이 `async def` 함수이든, 일반 `def` 함수이든 내부적으로 이를 올바르게 처리합니다.
+`async def` 함수일 수도, 일반 `def` 함수일 수도 있으며, **FastAPI**가 이를 올바르게 처리하는 방법을 알고 있습니다.
-이 경우, 아래 작업은 파일에 쓰는 함수입니다. (이메일 보내기 시물레이션)
+이 경우 작업 함수는 파일에 쓰기를 수행합니다(이메일 전송을 시뮬레이션).
-ê·¸ë¦¬ê³ ì\9d´ ì\9e\91ì\97\85ì\9d\80 `async`ì\99\80 `await`를 ì\82¬ì\9a©í\95\98ì§\80 ì\95\8aì\9c¼ë¯\80ë¡\9c ì\9d¼ë°\98 `def` í\95¨ì\88\98ë¡\9c ì\84 ì\96¸í\95©ë\8b\88ë\8b¤.
+ê·¸ë¦¬ê³ ì\93°ê¸° ì\9e\91ì\97\85ì\9d\80 `async`ì\99\80 `await`를 ì\82¬ì\9a©í\95\98ì§\80 ì\95\8aì\9c¼ë¯\80ë¡\9c, ì\9d¼ë°\98 `def`ë¡\9c í\95¨ì\88\98를 ì \95ì\9d\98í\95©ë\8b\88ë\8b¤:
-{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
-## 백그라운드 작업 추가
+## 백그라운드 작업 추가 { #add-the-background-task }
-_경로 작동 함수_ 내에서 작업 함수를 `.add_task()` 함수 통해 _백그라운드 작업_ 개체에 전달합니다.
+*경로 처리 함수* 내부에서 `.add_task()` 메서드로 작업 함수를 *백그라운드 작업* 객체에 전달합니다:
-{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
-`.add_task()` 함수는 다음과 같은 인자를 받습니다 :
+`.add_task()`는 다음 인자를 받습니다:
-- 백그라운드에서 실행되는 작업 함수 (`write_notification`).
-- 작업 함수에 순서대로 전달되어야 하는 일련의 인자 (`email`).
-- 작업 함수에 전달되어야하는 모든 키워드 인자 (`message="some notification"`).
+* 백그라운드에서 실행될 작업 함수(`write_notification`).
+* 작업 함수에 순서대로 전달되어야 하는 인자 시퀀스(`email`).
+* 작업 함수에 전달되어야 하는 키워드 인자(`message="some notification"`).
-## 의존성 주입
+## 의존성 주입 { #dependency-injection }
-`BackgroundTasks`를 ì\9d\98ì¡´ì\84± 주ì\9e\85 ì\8b\9cì\8a¤í\85\9cê³¼ í\95¨ê»\98 ì\82¬ì\9a©í\95\98ë©´ _ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98_, ì¢\85ì\86\8dì\84±, í\95\98ì\9c\84 ì¢\85ì\86\8dì\84± ë\93± ì\97¬ë\9f¬ ì\88\98ì¤\80ì\97\90ì\84\9c BackgroundTasks ì\9c í\98\95의 매개변수를 선언할 수 있습니다.
+`BackgroundTasks`ë\8a\94 ì\9d\98ì¡´ì\84± 주ì\9e\85 ì\8b\9cì\8a¤í\85\9cì\97\90ì\84\9cë\8f\84 ë\8f\99ì\9e\91í\95\98ë©°, *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*, ì\9d\98ì¡´ì\84±(dependable), í\95\98ì\9c\84 ì\9d\98ì¡´ì\84± ë\93± ì\97¬ë\9f¬ ì\88\98ì¤\80ì\97\90ì\84\9c `BackgroundTasks` í\83\80ì\9e\85의 매개변수를 선언할 수 있습니다.
-**FastAPI**는 각 경우에 수행할 작업과 동일한 개체를 내부적으로 재사용하기에, 모든 백그라운드 작업이 함께 병합되고 나중에 백그라운드에서 실행됩니다.
+**FastAPI**는 각 경우에 무엇을 해야 하는지와 동일한 객체를 어떻게 재사용해야 하는지를 알고 있으므로, 모든 백그라운드 작업이 함께 병합되어 이후 백그라운드에서 실행됩니다:
-{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
-이 예제에서는 응답이 반환된 후에 `log.txt` 파일에 메시지가 기록됩니다.
+{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
-요청에 쿼리가 있는 경우 백그라운드 작업의 로그에 기록됩니다.
-ê·¸ë¦¬ê³ _ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98_ ì\97\90ì\84\9c ì\83\9dì\84±ë\90\9c ë\98\90 ë\8b¤ë¥¸ 백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85ì\9d\80 ê²½ë¡\9c 매ê°\9c ë³\80ì\88\98를 í\99\9cì\9a©í\95\98ì\97¬ ì\82¬ì\9a©í\95\98ì\97¬ ë©\94ì\8b\9cì§\80를 ì\9e\91ì\84±í\95©ë\8b\88ë\8b¤.
+ì\9d´ ì\98\88ì \9cì\97\90ì\84\9cë\8a\94 ì\9d\91ë\8bµì\9d´ ì \84ì\86¡ë\90\9c *í\9b\84ì\97\90* ë©\94ì\8b\9cì§\80ê°\80 `log.txt` í\8c\8cì\9d¼ì\97\90 ì\9e\91ì\84±ë\90©ë\8b\88ë\8b¤.
-## 기술적 세부사항
+요청에 쿼리가 있었다면, 백그라운드 작업으로 로그에 작성됩니다.
+
+그 다음 *경로 처리 함수*에서 생성된 또 다른 백그라운드 작업이 `email` 경로 매개변수를 사용해 메시지를 작성합니다.
+
+## 기술적 세부사항 { #technical-details }
`BackgroundTasks` 클래스는 <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>에서 직접 가져옵니다.
-`BackgroundTasks` 클래스는 FastAPI에서 직접 임포트하거나 포함하기 때문에 실수로 `BackgroundTask` (끝에 `s`가 없음)을 임포트하더라도 starlette.background에서 `BackgroundTask`를 가져오는 것을 방지할 수 있습니다.
+FastAPI에 직접 임포트/포함되어 있으므로 `fastapi`에서 임포트할 수 있고, 실수로 `starlette.background`에서 대안인 `BackgroundTask`(끝에 `s`가 없음)를 임포트하는 것을 피할 수 있습니다.
-(`BackgroundTask`가 아닌) `BackgroundTasks`를 사용하면, _경로 작동 함수_ 매개변수로 사용할 수 있게 되고 나머지는 **FastAPI**가 대신 처리하도록 할 수 있습니다. 이것은 `Request` 객체를 직접 사용하는 것과 같은 방식입니다.
+`BackgroundTask`가 아닌 `BackgroundTasks`만 사용하면, 이를 *경로 처리 함수*의 매개변수로 사용할 수 있고 나머지는 **FastAPI**가 `Request` 객체를 직접 사용할 때처럼 대신 처리해 줍니다.
-FastAPIì\97\90ì\84\9c `BackgroundTask`를 ë\8b¨ë\8f\85ì\9c¼ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ì\9d\80 ì\97¬ì \84í\9e\88 ê°\80ë\8a¥í\95©ë\8b\88ë\8b¤. í\95\98ì§\80ë§\8c ê°\9d체를 ì½\94ë\93\9cì\97\90ì\84\9c ì\83\9dì\84±í\95\98ê³ , ì\9d´ ê°\9d체를 í\8f¬í\95¨í\95\98ë\8a\94 Starlette `Response`를 ë°\98í\99\98í\95´ì\95¼ í\95©ë\8b\88ë\8b¤.
+FastAPIì\97\90ì\84\9c `BackgroundTask`ë§\8c ë\8b¨ë\8f\85ì\9c¼ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ë\8f\84 ê°\80ë\8a¥í\95\98ì§\80ë§\8c, ì½\94ë\93\9cì\97\90ì\84\9c ê°\9d체를 ì\83\9dì\84±í\95\98ê³ ì\9d´ë¥¼ í\8f¬í\95¨í\95\98ë\8a\94 Starlette `Response`를 ë°\98í\99\98í\95´ì\95¼ í\95©ë\8b\88ë\8b¤.
-<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`Starlette의 공식 문서`</a>에서 백그라운드 작업에 대한 자세한 내용을 확인할 수 있습니다.
+더 자세한 내용은 <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">Starlette의 Background Tasks 공식 문서</a>에서 확인할 수 있습니다.
-## 경고
+## 주의사항 { #caveat }
-ë§\8cì\95½ 무거ì\9a´ 백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85ì\9d\84 ì\88\98í\96\89í\95´ì\95¼í\95\98ê³ ë\8f\99ì\9d¼í\95\9c í\94\84ë¡\9cì\84¸ì\8a¤ì\97\90ì\84\9c ì\8b¤í\96\89í\95 í\95\84ì\9a\94ê°\80 ì\97\86ë\8a\94 ê²½ì\9a° (ì\98\88: ë©\94모리, ë³\80ì\88\98 ë\93±ì\9d\84 ê³µì\9c í\95 í\95\84ì\9a\94ê°\80 ì\97\86ì\9d\8c) <a href="https://docs.celeryq.dev" class="external-link" target="_blank">`Celery`</a>ì\99\80 ê°\99ì\9d\80 í\81° ë\8f\84구를 ì\82¬ì\9a©í\95\98ë©´ ë\8f\84ì\9b\80ì\9d´ ë\90 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+무거ì\9a´ 백그ë\9d¼ì\9a´ë\93\9c ê³\84ì\82°ì\9d\84 ì\88\98í\96\89í\95´ì\95¼ í\95\98ê³ , ë°\98ë\93\9cì\8b\9c ë\8f\99ì\9d¼í\95\9c í\94\84ë¡\9cì\84¸ì\8a¤ì\97\90ì\84\9c ì\8b¤í\96\89í\95 í\95\84ì\9a\94ê°\80 ì\97\86ë\8b¤ë©´(ì\98\88: ë©\94모리, ë³\80ì\88\98 ë\93±ì\9d\84 ê³µì\9c í\95 í\95\84ì\9a\94ê°\80 ì\97\86ì\9d\8c) <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a> ê°\99ì\9d\80 ë\8d\94 í\81° ë\8f\84구를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ì\9d´ ë\8f\84ì\9b\80ì\9d´ ë\90 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-RabbitMQ 또는 Redis와 같은 메시지/작업 큐 시스템 보다 복잡한 구성이 필요한 경향이 있지만, 여러 작업 프로세스를 특히 여러 서버의 백그라운드에서 실행할 수 있습니다.
+이들은 RabbitMQ나 Redis 같은 메시지/작업 큐 관리자 등 더 복잡한 설정을 필요로 하는 경향이 있지만, 여러 프로세스에서, 특히 여러 서버에서 백그라운드 작업을 실행할 수 있습니다.
-그러나 동일한 FastAPI 앱에서 변수 및 개체에 접근해야햐는 작은 백그라운드 수행이 필요한 경우 (예 : 알림 이메일 보내기) 간단하게 `BackgroundTasks`를 사용해보세요.
+하지만 동일한 **FastAPI** 앱의 변수와 객체에 접근해야 하거나(또는 이메일 알림 전송처럼) 작은 백그라운드 작업을 수행해야 한다면, `BackgroundTasks`를 간단히 사용하면 됩니다.
-## 요약
+## 요약 { #recap }
-백그라운드 작업을 추가하기 위해 _경로 작동 함수_ 에 매개변수로 `BackgroundTasks`를 가져오고 사용합니다.
+*경로 처리 함수*와 의존성에서 매개변수로 `BackgroundTasks`를 임포트해 사용하여 백그라운드 작업을 추가합니다.
-# 본문 - 필드
+# 본문 - 필드 { #body-fields }
-`Query`, `Path`ì\99\80 `Body`를 ì\82¬ì\9a©í\95´ *ê²½ë¡\9c ì\9e\91ë\8f\99 함수* 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 `Field`를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다.
+`Query`, `Path`ì\99\80 `Body`를 ì\82¬ì\9a©í\95´ *ê²½ë¡\9c ì²\98리 함수* 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 `Field`를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다.
-## `Field` 임포트
+## `Field` 임포트 { #import-field }
먼저 이를 임포트해야 합니다:
///
-## 모델 어트리뷰트 선언
+## 모델 어트리뷰트 선언 { #declare-model-attributes }
그 다음 모델 어트리뷰트와 함께 `Field`를 사용할 수 있습니다:
`Field`는 `Query`, `Path`와 `Body`와 같은 방식으로 동작하며, 모두 같은 매개변수들 등을 가집니다.
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
실제로 `Query`, `Path`등, 여러분이 앞으로 볼 다른 것들은 공통 클래스인 `Param` 클래스의 서브클래스 객체를 만드는데, 그 자체로 Pydantic의 `FieldInfo` 클래스의 서브클래스입니다.
/// tip | 팁
-주목í\95 ì \90ì\9d\80 í\83\80ì\9e\85, 기본 ê°\92 ë°\8f `Field`ë¡\9c ì\9d´ë£¨ì\96´ì§\84 ê°\81 모ë\8d¸ ì\96´í\8a¸ë¦¬ë·°í\8a¸ê°\80 `Path`, `Query`ì\99\80 `Body`ë\8c\80ì\8b `Field`를 ì\82¬ì\9a©í\95\98ë\8a\94 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*의 매개변수와 같은 구조를 가진다는 점 입니다.
+주목í\95 ì \90ì\9d\80 í\83\80ì\9e\85, 기본 ê°\92 ë°\8f `Field`ë¡\9c ì\9d´ë£¨ì\96´ì§\84 ê°\81 모ë\8d¸ ì\96´í\8a¸ë¦¬ë·°í\8a¸ê°\80 `Path`, `Query`ì\99\80 `Body`ë\8c\80ì\8b `Field`를 ì\82¬ì\9a©í\95\98ë\8a\94 *ê²½ë¡\9c ì²\98리 함수*의 매개변수와 같은 구조를 가진다는 점 입니다.
///
-## 별도 정보 추가
+## 별도 정보 추가 { #add-extra-information }
`Field`, `Query`, `Body`, 그 외 안에 별도 정보를 선언할 수 있습니다. 이는 생성된 JSON 스키마에 포함됩니다.
///
-## 요약
+## 요약 { #recap }
모델 어트리뷰트를 위한 추가 검증과 메타데이터 선언하기 위해 Pydantic의 `Field` 를 사용할 수 있습니다.
-# 본문 - 다중 매개변수
+# 본문 - 다중 매개변수 { #body-multiple-parameters }
-ì§\80ê¸\88ë¶\80í\84° `Path`ì\99\80 `Query`를 ì\96´ë\96»ê²\8c ì\82¬ì\9a©í\95\98ë\8a\94ì§\80 í\99\95ì\9d¸í\95\98겠습니다.
+ì\9d´ì \9c `Path`ì\99\80 `Query`를 ì\96´ë\96»ê²\8c ì\82¬ì\9a©í\95\98ë\8a\94ì§\80 í\99\95ì\9d¸í\96\88ì\9c¼ë\8b\88, ì\9a\94ì² ë³¸ë¬¸ ì\84 ì\96¸ì\97\90 ë\8c\80í\95\9c ë\8d\94 ê³ ê¸\89 ì\82¬ì\9a©ë²\95ì\9d\84 ì\82´í\8e´ë³´겠습니다.
-요청 본문 선언에 대한 심화 사용법을 알아보겠습니다.
+## `Path`, `Query` 및 본문 매개변수 혼합 { #mix-path-query-and-body-parameters }
-## `Path`, `Query` 및 본문 매개변수 혼합
+먼저, 물론 `Path`, `Query` 및 요청 본문 매개변수 선언을 자유롭게 혼합해서 사용할 수 있고, **FastAPI**는 어떤 동작을 할지 압니다.
-ë\8b¹ì\97°í\95\98ê²\8c `Path`, `Query` ë°\8f ì\9a\94ì² ë³¸ë¬¸ 매ê°\9cë³\80ì\88\98 ì\84 ì\96¸ì\9d\84 ì\9e\90ì\9c ë¡ê²\8c í\98¼í\95©í\95´ì\84\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ê³ , **FastAPI**ë\8a\94 ì\96´ë\96¤ ë\8f\99ì\9e\91ì\9d\84 í\95 ì§\80 ì\95\95ë\8b\88ë\8b¤.
+ë\98\90í\95\9c 기본 ê°\92ì\9d\84 `None`ì\9c¼ë¡\9c ì\84¤ì \95í\95´ 본문 매ê°\9cë³\80ì\88\98를 ì\84 í\83\9dì\82¬í\95ì\9c¼ë¡\9c ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
-또한, 기본 값을 `None`으로 설정해 본문 매개변수를 선택사항으로 선언할 수 있습니다.
-
-{* ../../docs_src/body_multiple_params/tutorial001.py hl[19:21] *}
+{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
/// note | 참고
-ì\9d´ ê²½ì\9a°ì\97\90ë\8a\94 본문ì\9c¼ë¡\9c ë¶\80í\84° ê°\80ì ¸ì\98¨ ` item`ì\9d\80 기본ê°\92ì\9d´ `None`ì\9d´ê¸° ë\95\8c문ì\97\90, ì\84 í\83\9dì\82¬í\95ì\9d´ë\9d¼ë\8a\94 ì \90ì\9d\84 ì\9c ì\9d\98í\95´ì\95¼ í\95©니다.
+ì\9d´ ê²½ì\9a°ì\97\90ë\8a\94 본문ì\97\90ì\84\9c ê°\80ì ¸ì\98¬ `item`ì\9d´ ì\84 í\83\9dì\82¬í\95ì\9d´ë\9d¼ë\8a\94 ì \90ì\9d\84 ì\9c ì\9d\98í\95\98ì\84¸ì\9a\94. 기본ê°\92ì\9d´ `None`ì\9d´ê¸° ë\95\8c문ì\9e\85니다.
///
-## 다중 본문 매개변수
+## 다중 본문 매개변수 { #multiple-body-parameters }
-이전 예제에서 보듯이, *경로 작동*은 아래와 같이 `Item` 속성을 가진 JSON 본문을 예상합니다:
+이전 예제에서, *경로 처리*는 아래처럼 `Item`의 속성을 가진 JSON 본문을 예상합니다:
```JSON
{
하지만, 다중 본문 매개변수 역시 선언할 수 있습니다. 예. `item`과 `user`:
-{* ../../docs_src/body_multiple_params/tutorial002.py hl[22] *}
+{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
+
-이 경우에, **FastAPI**는 이 함수 안에 한 개 이상의 본문 매개변수(Pydantic 모델인 두 매개변수)가 있다고 알 것입니다.
+이 경우에, **FastAPI**는 이 함수에 본문 매개변수가 1개보다 많다는 것을 알아챌 것입니다(두 매개변수가 Pydantic 모델입니다).
-ê·¸ë\9e\98ì\84\9c, 본문ì\9d\98 매ê°\9cë³\80ì\88\98 ì\9d´ë¦\84ì\9d\84 í\82¤(í\95\84ë\93\9c ëª\85)ë¡\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ê³ , ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\80 본문ì\9d\84 ì\98\88측합니다:
+ê·¸ë\9e\98ì\84\9c, 본문ì\97\90ì\84\9c 매ê°\9cë³\80ì\88\98 ì\9d´ë¦\84ì\9d\84 í\82¤(í\95\84ë\93\9c ì\9d´ë¦\84)ë¡\9c ì\82¬ì\9a©í\95\98ê³ , ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\80 본문ì\9d\84 ì\98\88ì\83\81합니다:
```JSON
{
/// note | 참고
-이전과 같이 `item`이 선언 되었더라도, 본문 내의 `item` 키가 있을 것이라고 예측합니다.
+`item`이 이전과 같은 방식으로 선언되었더라도, 이제는 본문에서 `item` 키 안에 있을 것으로 예상된다는 점을 유의하세요.
///
-FastAPI는 요청을 자동으로 변환해, 매개변수의 `item`과 `user`를 특별한 내용으로 받도록 할 것입니다.
+**FastAPI**는 요청에서 자동으로 변환을 수행하여, 매개변수 `item`이 해당하는 내용을 받고 `user`도 마찬가지로 받도록 합니다.
-복합 데이터의 검증을 수행하고 OpenAPI 스키마 및 자동 문서를 문서화합니다.
+복합 데이터의 검증을 수행하고, OpenAPI 스키마 및 자동 문서에도 그에 맞게 문서화합니다.
-## 본문 내의 단일 값
+## 본문 내의 단일 값 { #singular-values-in-body }
-쿼리 및 경로 매개변수에 대한 추가 데이터를 정의하는 `Query`와 `Path`와 같이, **FastAPI**는 동등한 `Body`를 제공합니다.
+쿼리 및 경로 매개변수에 대한 추가 데이터를 정의하는 `Query`와 `Path`가 있는 것과 같은 방식으로, **FastAPI**는 동등한 `Body`를 제공합니다.
-예를 들어 이전의 모델을 확장하면, `item`과 `user`와 동일한 본문에 또 다른 `importance`라는 키를 갖도록 할 수있습니다.
+예를 들어 이전 모델을 확장해서, `item`과 `user` 외에도 같은 본문에 `importance`라는 다른 키를 두고 싶을 수 있습니다.
-ë\8b¨ì\9d¼ ê°\92ì\9d\84 ê·¸ë\8c\80ë¡\9c ì\84 ì\96¸í\95\9cë\8b¤ë©´, **FastAPI**ë\8a\94 쿼리 매ê°\9cë³\80ì\88\98ë¡\9c 가정할 것입니다.
+ë\8b¨ì\9d¼ ê°\92ì\9d´ë¯\80ë¡\9c ê·¸ë\8c\80ë¡\9c ì\84 ì\96¸í\95\98ë©´, **FastAPI**ë\8a\94 ì\9d´ë¥¼ 쿼리 매ê°\9cë³\80ì\88\98ë\9d¼ê³ 가정할 것입니다.
-하지만, **FastAPI**의 `Body`를 사용해 다른 본문 키로 처리하도록 제어할 수 있습니다:
+하지만 `Body`를 사용하여 다른 본문 키로 처리하도록 **FastAPI**에 지시할 수 있습니다:
+{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
-{* ../../docs_src/body_multiple_params/tutorial003.py hl[23] *}
-
-이 경우에는 **FastAPI**는 본문을 이와 같이 예측할 것입니다:
+이 경우에는 **FastAPI**가 다음과 같은 본문을 예상할 것입니다:
```JSON
{
}
```
-다시 말해, 데이터 타입, 검증, 문서 등을 변환합니다.
+다시 말해, 데이터 타입을 변환하고, 검증하고, 문서화하는 등의 작업을 수행합니다.
-## 다중 본문 매개변수와 쿼리
+## 다중 본문 매개변수와 쿼리 { #multiple-body-params-and-query }
-ë\8b¹ì\97°í\9e\88, í\95\84ì\9a\94í\95 ë\95\8cë§\88ë\8b¤ ì¶\94ê°\80ì \81ì\9d¸ 쿼리 매ê°\9cë³\80ì\88\98를 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ê³ , ì\9d´ë\8a\94 본문 매ê°\9cë³\80ì\88\98ì\97\90 ì¶\94ê°\80ë\90©니다.
+ë¬¼ë¡ , í\95\84ì\9a\94í\95 ë\95\8cë§\88ë\8b¤ ì\96´ë\96¤ 본문 매ê°\9cë³\80ì\88\98ì\97\90 ì¶\94ê°\80ë¡\9c 쿼리 매ê°\9cë³\80ì\88\98ë\8f\84 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\8aµ니다.
-기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `Query`를 추가할 필요가 없고, 아래처럼 할 수 있습니다:
+기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `Query`를 추가할 필요 없이 이렇게 하면 됩니다:
-{* ../../docs_src/body_multiple_params/tutorial004.py hl[27] *}
+```Python
+q: Union[str, None] = None
+```
-이렇게:
+또는 Python 3.10 이상에서는:
```Python
-q: Optional[str] = None
+q: str | None = None
```
-/// info | 정보
+예를 들어:
-`Body` 또한 `Query`, `Path` 그리고 이후에 볼 다른 것들처럼 동일한 추가 검증과 메타데이터 매개변수를 갖고 있습니다.
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
-///
-## 단일 본문 매개변수 삽입하기
+/// info | 정보
+
+`Body` 또한 `Query`, `Path` 그리고 이후에 볼 다른 것들과 마찬가지로 동일한 추가 검증과 메타데이터 매개변수를 모두 갖고 있습니다.
-Pydantic 모델 `Item`의 `item`을 본문 매개변수로 오직 한개만 갖고있다고 하겠습니다.
+///
-기본적으로 **FastAPI**는 직접 본문으로 예측할 것입니다.
+## 단일 본문 매개변수 삽입하기 { #embed-a-single-body-parameter }
-하지만, 만약 모델 내용에 `item `키를 가진 JSON으로 예측하길 원한다면, 추가적인 본문 매개변수를 선언한 것처럼 `Body`의 특별한 매개변수인 `embed`를 사용할 수 있습니다:
+Pydantic 모델 `Item`에서 가져온 단일 `item` 본문 매개변수만 있다고 하겠습니다.
-{* ../../docs_src/body_multiple_params/tutorial005.py hl[17] *}
+기본적으로 **FastAPI**는 그 본문을 직접 예상합니다.
-아래 처럼:
+하지만 추가 본문 매개변수를 선언할 때처럼, `item` 키를 가지고 그 안에 모델 내용이 들어 있는 JSON을 예상하게 하려면, `Body`의 특별한 매개변수 `embed`를 사용할 수 있습니다:
```Python
-item: Item = Body(..., embed=True)
+item: Item = Body(embed=True)
```
-이 경우에 **FastAPI**는 본문을 아래 대신에:
+다음과 같이요:
-```JSON hl_lines="2"
-{
- "name": "Foo",
- "description": "The pretender",
- "price": 42.0,
- "tax": 3.2
-}
-```
+{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
-아래 처럼 예측할 것 입니다:
-```JSON
+이 경우 **FastAPI**는 다음과 같은 본문을 예상합니다:
+
+```JSON hl_lines="2"
{
"item": {
"name": "Foo",
}
```
-## 정리
+다음 대신에:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+## 정리 { #recap }
-ì\9a\94ì²ì\9d´ ë\8b¨ í\95\9cê°\9cì\9d\98 본문ì\9d\84 ê°\80ì§\80ê³ ì\9e\88ë\8d\94ë\9d¼ë\8f\84, *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*ë¡\9c 다중 본문 매개변수를 추가할 수 있습니다.
+ì\9a\94ì²ì\9d\80 본문ì\9d\84 í\95\98ë\82\98ë§\8c ê°\80ì§\88 ì\88\98 ì\9e\88ì§\80ë§\8c, *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ì\97\90 다중 본문 매개변수를 추가할 수 있습니다.
-하지만, **FastAPI**는 이를 처리하고, 함수에 올바른 데이터를 제공하며, *경로 작동*으로 올바른 스키마를 검증하고 문서화 합니다.
+하지만 **FastAPI**는 이를 처리하고, 함수에 올바른 데이터를 제공하며, *경로 처리*에서 올바른 스키마를 검증하고 문서화합니다.
-또한, 단일 값을 본문의 일부로 받도록 선언할 수 있습니다.
+또한 단일 값을 본문의 일부로 받도록 선언할 수 있습니다.
-그리고 **FastAPI**는 단 한개의 매개변수가 선언 되더라도, 본문 내의 키로 삽입 시킬 수 있습니다.
+그리고 단 하나의 매개변수만 선언되어 있더라도, **FastAPI**에 본문을 키 안에 삽입하도록 지시할 수 있습니다.
-# 본문 - 중첩 모델
+# 본문 - 중첩 모델 { #body-nested-models }
-**FastAPI**를 이용하면 (Pydantic 덕분에) 단독으로 깊이 중첩된 모델을 정의, 검증, 문서화하며 사용할 수 있습니다.
-## 리스트 필드
+**FastAPI**를 사용하면 (Pydantic 덕분에) 임의로 깊게 중첩된 모델을 정의, 검증, 문서화하고 사용할 수 있습니다.
-어트리뷰트를 서브타입으로 정의할 수 있습니다. 예를 들어 파이썬 `list`는:
-
-{* ../../docs_src/body_nested_models/tutorial001.py hl[14] *}
-
-이는 `tags`를 항목 리스트로 만듭니다. 각 항목의 타입을 선언하지 않더라도요.
+## 리스트 필드 { #list-fields }
-## 타입 매개변수가 있는 리스트 필드
-
-하지만 파이썬은 내부의 타입이나 "타입 매개변수"를 선언할 수 있는 특정 방법이 있습니다:
+어트리뷰트를 서브타입으로 정의할 수 있습니다. 예를 들어 파이썬 `list`는:
-### typing의 `List` 임포트
+{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
-먼저, 파이썬 표준 `typing` 모듈에서 `List`를 임포트합니다:
+이는 `tags`를 리스트로 만들지만, 리스트 요소의 타입을 선언하지는 않습니다.
-{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
+## 타입 매개변수가 있는 리스트 필드 { #list-fields-with-type-parameter }
-### 타입 매개변수로 `List` 선언
+하지만 파이썬에는 내부 타입, 즉 "타입 매개변수"를 사용해 리스트를 선언하는 특정한 방법이 있습니다:
-`list`, `dict`, `tuple`과 같은 타입 매개변수(내부 타입)를 갖는 타입을 선언하려면:
+### 타입 매개변수로 `list` 선언 { #declare-a-list-with-a-type-parameter }
-* `typing` 모듈에서 임포트
-* 대괄호를 사용하여 "타입 매개변수"로 내부 타입 전달: `[` 및 `]`
+`list`, `dict`, `tuple`처럼 타입 매개변수(내부 타입)를 갖는 타입을 선언하려면,
+대괄호 `[` 및 `]`를 사용해 내부 타입(들)을 "타입 매개변수"로 전달하세요.
```Python
-from typing import List
-
-my_list: List[str]
+my_list: list[str]
```
이 모든 것은 타입 선언을 위한 표준 파이썬 문법입니다.
마찬가지로 예제에서 `tags`를 구체적으로 "문자열의 리스트"로 만들 수 있습니다:
-{* ../../docs_src/body_nested_models/tutorial002.py hl[14] *}
+{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
-## 집합 타입
+## 집합 타입 { #set-types }
-그런데 생각해보니 태그는 반복되면 안 되고, 고유한(Unique) 문자열이어야 할 것 같습니다.
+그런데 생각해보니 태그는 반복되면 안 되고, 아마 고유한 문자열이어야 할 것입니다.
-ê·¸ë¦¬ê³ í\8c\8cì\9d´ì\8d¬ì\9d\80 집합을 위한 특별한 데이터 타입 `set`이 있습니다.
+ê·¸ë¦¬ê³ í\8c\8cì\9d´ì\8d¬ì\97\90ë\8a\94 ê³ ì\9c í\95\9c í\95목ë\93¤ì\9d\98 집합을 위한 특별한 데이터 타입 `set`이 있습니다.
-그렇다면 `Set`을 임포트 하고 `tags`를 `str`의 `set`으로 선언할 수 있습니다:
+그렇다면 `tags`를 문자열의 집합으로 선언할 수 있습니다:
-{* ../../docs_src/body_nested_models/tutorial003.py hl[1,14] *}
+{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
-덕분에 중복 데이터가 있는 요청을 수신하더라도 고유한 항목들의 집합으로 변환됩니다.
+이렇게 하면 중복 데이터가 있는 요청을 받더라도 고유한 항목들의 집합으로 변환됩니다.
-그리고 해당 데이터를 출력 할 때마다 소스에 중복이 있더라도 고유한 항목들의 집합으로 출력됩니다.
+그리고 해당 데이터를 출력할 때마다, 소스에 중복이 있더라도 고유한 항목들의 집합으로 출력됩니다.
또한 그에 따라 주석이 생기고 문서화됩니다.
-## 중첩 모델
+## 중첩 모델 { #nested-models }
Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다.
-그런데 해당 타입 자체로 또다른 Pydantic 모델의 타입이 될 수 있습니다.
+그런데 그 타입 자체가 또 다른 Pydantic 모델일 수 있습니다.
-그러므로 특정한 어트리뷰트의 이름, 타입, 검증을 사용하여 깊게 중첩된 JSON "객체"를 선언할 수 있습니다.
+따라서 특정한 어트리뷰트 이름, 타입, 검증을 사용하여 깊게 중첩된 JSON "객체"를 선언할 수 있습니다.
-모든 것이 단독으로 중첩됩니다.
+모든 것이 임의의 깊이로 중첩됩니다.
-### 서브모델 정의
+### 서브모델 정의 { #define-a-submodel }
-ì\98\88를 ë\93¤ì\96´, `Image` 모ë\8d¸ì\9d\84 ì\84 ì\96¸할 수 있습니다:
+ì\98\88를 ë\93¤ì\96´, `Image` 모ë\8d¸ì\9d\84 ì \95ì\9d\98할 수 있습니다:
-{* ../../docs_src/body_nested_models/tutorial004.py hl[9:11] *}
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
-### ì\84\9cë¸\8c모ë\93\88ì\9d\84 í\83\80ì\9e\85ì\9c¼ë¡\9c ì\82¬ì\9a©
+### ì\84\9cë¸\8c모ë\8d¸ì\9d\84 í\83\80ì\9e\85ì\9c¼ë¡\9c ì\82¬ì\9a© { #use-the-submodel-as-a-type }
-그리고 어트리뷰트의 타입으로 사용할 수 있습니다:
+ê·¸ë¦¬ê³ ì\9d´ë¥¼ ì\96´í\8a¸ë¦¬ë·°í\8a¸ì\9d\98 í\83\80ì\9e\85ì\9c¼ë¡\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
-{* ../../docs_src/body_nested_models/tutorial004.py hl[20] *}
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
이는 **FastAPI**가 다음과 유사한 본문을 기대한다는 것을 의미합니다:
}
```
-ë\8b¤ì\8b\9c í\95\9cë²\88, **FastAPI**를 ì\82¬ì\9a©í\95\98ì\97¬ í\95´ë\8b¹ ì\84 ì\96¸ì\9d\84 í\95¨ì\9c¼ë¡\9cì\8d¨ 얻는 것은:
+ë\8b¤ì\8b\9c í\95\9cë²\88, **FastAPI**ë¡\9c ê·¸ ì\84 ì\96¸ë§\8c í\95´ë\8f\84 얻는 것은:
* 중첩 모델도 편집기 지원(자동완성 등)
* 데이터 변환
* 데이터 검증
* 자동 문서화
-## 특별한 타입과 검증
+## 특별한 타입과 검증 { #special-types-and-validation }
-`str`, `int`, `float` 등과 같은 단일 타입과는 별개로, `str`을 상속하는 더 복잡한 단일 타입을 사용할 수 있습니다.
+`str`, `int`, `float` 등과 같은 일반적인 단일 타입과는 별개로, `str`을 상속하는 더 복잡한 단일 타입을 사용할 수 있습니다.
-모든 옵션을 보려면, <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydantic's exotic types</a> 문서를 확인하세요. 다음 장에서 몇가지 예제를 볼 수 있습니다.
+사용할 수 있는 모든 옵션을 보려면 <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydantic의 Type Overview</a>를 확인하세요. 다음 장에서 몇 가지 예제를 볼 수 있습니다.
-예를 들어 `Image` 모델 안에 `url` 필드를 `str` 대신 Pydantic의 `HttpUrl`로 선언할 수 있습니다:
+예를 들어 `Image` 모델에는 `url` 필드가 있으므로, 이를 `str` 대신 Pydantic의 `HttpUrl` 인스턴스로 선언할 수 있습니다:
-{* ../../docs_src/body_nested_models/tutorial005.py hl[4,10] *}
+{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
-ì\9d´ 문ì\9e\90ì\97´ì\9d´ ì\9c í\9a¨í\95\9c URLì\9d¸ì§\80 ê²\80ì\82¬í\95\98ê³ JSON ì\8a¤í\82¤ë§\88/OpenAPIë¡\9c 문ì\84\9cí\99\94 됩니다.
+ì\9d´ 문ì\9e\90ì\97´ì\9d\80 ì\9c í\9a¨í\95\9c URLì\9d¸ì§\80 ê²\80ì\82¬ë\90\98ë©°, JSON Schema / OpenAPIì\97\90ë\8f\84 ê·¸ì\97\90 ë§\9eê²\8c 문ì\84\9cí\99\94됩니다.
-## 서브모델 리스트를 갖는 어트리뷰트
+## 서브모델 리스트를 갖는 어트리뷰트 { #attributes-with-lists-of-submodels }
`list`, `set` 등의 서브타입으로 Pydantic 모델을 사용할 수도 있습니다:
-{* ../../docs_src/body_nested_models/tutorial006.py hl[20] *}
+{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
-ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d\80 JSON 본문ì\9c¼ë¡\9c ì\98\88ì\83\81(ë³\80í\99\98, ê²\80ì¦\9d, 문ì\84\9cí\99\94 ë\93±ì\9d\84)합니다:
+ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d\80 JSON 본문ì\9d\84 ì\98\88ì\83\81(ë³\80í\99\98, ê²\80ì¦\9d, 문ì\84\9cí\99\94 ë\93±)합니다:
```JSON hl_lines="11"
{
/// info | 정보
-`images` í\82¤ê°\80 ì\96´ë\96»ê²\8c 이미지 객체 리스트를 갖는지 주목하세요.
+`images` í\82¤ê°\80 ì\9d´ì \9c 이미지 객체 리스트를 갖는지 주목하세요.
///
-## 깊게 중첩된 모델
+## 깊게 중첩된 모델 { #deeply-nested-models }
-단독으로 깊게 중첩된 모델을 정의할 수 있습니다:
+임의로 깊게 중첩된 모델을 정의할 수 있습니다:
-{* ../../docs_src/body_nested_models/tutorial007.py hl[9,14,20,23,27] *}
+{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
/// info | 정보
-`Offer`가 선택사항 `Image` 리스트를 차례로 갖는 `Item` 리스트를 어떻게 가지고 있는지 주목하세요
+`Offer`가 `Item`의 리스트를 가지고, 그 `Item`이 다시 선택 사항인 `Image` 리스트를 갖는지 주목하세요
///
-## 순수 리스트의 본문
+## 순수 리스트의 본문 { #bodies-of-pure-lists }
-예상되는 JSON 본문의 최상위 값이 JSON `array`(파이썬 `list`)면, Pydantic 모델에서와 마찬가지로 함수의 매개변수에서 타입을 선언할 수 있습니다:
+ì\98\88ì\83\81ë\90\98ë\8a\94 JSON 본문ì\9d\98 ìµ\9cì\83\81ì\9c\84 ê°\92ì\9d´ JSON `array`(í\8c\8cì\9d´ì\8d¬ `list`)ë\9d¼ë©´, Pydantic 모ë\8d¸ì\97\90ì\84\9cì\99\80 ë§\88ì°¬ê°\80ì§\80ë¡\9c í\95¨ì\88\98ì\9d\98 매ê°\9cë³\80ì\88\98ì\97\90ì\84\9c í\83\80ì\9e\85ì\9d\84 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
```Python
-images: List[Image]
+images: list[Image]
```
이를 아래처럼:
-{* ../../docs_src/body_nested_models/tutorial008.py hl[15] *}
+{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
-## 어디서나 편집기 지원
+## 어디서나 편집기 지원 { #editor-support-everywhere }
-그리고 어디서나 편집기 지원을 받을수 있습니다.
+그리고 어디서나 편집기 지원을 받을 수 있습니다.
리스트 내부 항목의 경우에도:
<img src="/img/tutorial/body-nested-models/image01.png">
-Pydantic 모델 대신에 `dict`를 직접 사용하여 작업할 경우, 이러한 편집기 지원을 받을수 없습니다.
+Pydantic 모델 대신 `dict`로 직접 작업한다면 이런 종류의 편집기 지원을 받을 수 없습니다.
-하지만 수신한 딕셔너리가 자동으로 변환되고 출력도 자동으로 JSON으로 변환되므로 걱정할 필요는 없습니다.
+하지만 그 부분에 대해서도 걱정할 필요는 없습니다. 들어오는 dict는 자동으로 변환되고, 출력도 자동으로 JSON으로 변환됩니다.
-## 단독 `dict`의 본문
+## 임의의 `dict` 본문 { #bodies-of-arbitrary-dicts }
-일부 타입의 키와 다른 타입의 값을 사용하여 `dict`로 본문을 선언할 수 있습니다.
+또한 키는 어떤 타입이고 값은 다른 타입인 `dict`로 본문을 선언할 수 있습니다.
-(Pydantic을 사용한 경우처럼) 유효한 필드/어트리뷰트 이름이 무엇인지 알 필요가 없습니다.
+이렇게 하면 (Pydantic 모델을 사용하는 경우처럼) 유효한 필드/어트리뷰트 이름이 무엇인지 미리 알 필요가 없습니다.
-아직 모르는 키를 받으려는 경우 유용합니다.
+아직 모르는 키를 받으려는 경우에 유용합니다.
---
-ë\8b¤ë¥¸ ì\9c ì\9a©í\95\9c ê²½ì\9a°ë\8a\94 ë\8b¤ë¥¸ í\83\80ì\9e\85ì\9d\98 í\82¤ë¥¼ ê°\80ì§\88 ë\95\8cì\9e\85ë\8b\88ë\8b¤. ì\98\88. `int`.
+ë\98\90 ë\8b¤ë¥¸ ì\9c ì\9a©í\95\9c ê²½ì\9a°ë\8a\94 ë\8b¤ë¥¸ í\83\80ì\9e\85(ì\98\88: `int`)ì\9d\98 í\82¤ë¥¼ ê°\96ê³ ì\8b¶ì\9d\84 ë\95\8cì\9e\85ë\8b\88ë\8b¤.
여기서 그 경우를 볼 것입니다.
-이 경우, `float` 값을 가진 `int` 키가 있는 모든 `dict`를 받아들입니다:
+이 경우, `int` 키와 `float` 값을 가진 한 어떤 `dict`든 받아들입니다:
-{* ../../docs_src/body_nested_models/tutorial009.py hl[15] *}
+{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
/// tip | 팁
-JSON은 오직 `str`형 키만 지원한다는 것을 염두에 두세요.
+JSON은 키로 `str`만 지원한다는 것을 염두에 두세요.
-하지만 Pydantic은 자동 데이터 변환이 있습니다.
+하지만 Pydantic은 자동 데이터 변환 기능이 있습니다.
-즉, API 클라이언트가 문자열을 키로 보내더라도 해당 문자열이 순수한 정수를 포함하는한 Pydantic은 이를 변환하고 검증합니다.
+즉, API 클라이언트는 키로 문자열만 보낼 수 있더라도, 해당 문자열이 순수한 정수를 포함하기만 하면 Pydantic이 이를 변환하고 검증합니다.
-ê·¸ë\9f¬ë¯\80ë¡\9c `weights`ë¡\9c ë°\9bì\9d\80 `dict`ë\8a\94 ì\8b¤ì \9cë¡\9c `int` í\82¤ì\99\80 `float` ê°\92ì\9d\84 ê°\80ì§\91니다.
+ê·¸ë¦¬ê³ `weights`ë¡\9c ë°\9bë\8a\94 `dict`ë\8a\94 ì\8b¤ì \9cë¡\9c `int` í\82¤ì\99\80 `float` ê°\92ì\9d\84 ê°\96ê²\8c ë\90©니다.
///
-## 요약
+## 요약 { #recap }
-**FastAPI**를 ì\82¬ì\9a©í\95\98ë©´ Pydantic 모ë\8d¸ì\9d´ ì \9cê³µí\95\98ë\8a\94 ìµ\9cë\8c\80 ì\9c ì\97°ì\84±ì\9d\84 í\99\95ë³´í\95\98ë©´ì\84\9c ì½\94ë\93\9c를 ê°\84ë\8b¨í\95\98ê³ ì§§ê²\8c, ê·¸ë¦¬ê³ ì\9a°ì\95\84í\95\98ê²\8c ì\9c ì§\80í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+**FastAPI**를 사용하면 Pydantic 모델이 제공하는 최대 유연성을 확보하면서 코드를 간단하고 짧고 우아하게 유지할 수 있습니다.
-물론 아래의 이점도 있습니다:
+하지만 아래의 모든 이점도 있습니다:
-* 편집기 지원 (자동완성이 어디서나!)
-* 데이터 변환 (일명 파싱/직렬화)
+* 편집기 지원(어디서나 자동완성!)
+* 데이터 변환(일명 파싱/직렬화)
* 데이터 검증
* 스키마 문서화
* 자동 문서
-# 요청 본문
+# 요청 본문 { #request-body }
클라이언트(브라우저라고 해봅시다)로부터 여러분의 API로 데이터를 보내야 할 때, **요청 본문**으로 보냅니다.
**요청** 본문은 클라이언트에서 API로 보내지는 데이터입니다. **응답** 본문은 API가 클라이언트로 보내는 데이터입니다.
-여러분의 API는 대부분의 경우 **응답** 본문을 보내야 합니다. 하지만 클라이언트는 **요청** 본문을 매 번 보낼 필요가 없습니다.
+여러분의 API는 대부분의 경우 **응답** 본문을 보내야 합니다. 하지만 클라이언트는 항상 **요청 본문**을 보낼 필요는 없고, 때로는 (쿼리 매개변수와 함께) 어떤 경로만 요청하고 본문은 보내지 않을 수도 있습니다.
**요청** 본문을 선언하기 위해서 모든 강력함과 이점을 갖춘 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> 모델을 사용합니다.
///
-## Pydantic의 `BaseModel` 임포트
+## Pydantic의 `BaseModel` 임포트 { #import-pydantics-basemodel }
먼저 `pydantic`에서 `BaseModel`를 임포트해야 합니다:
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
-## 여러분의 데이터 모델 만들기
+## 여러분의 데이터 모델 만들기 { #create-your-data-model }
`BaseModel`를 상속받은 클래스로 여러분의 데이터 모델을 선언합니다.
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
+
쿼리 매개변수를 선언할 때와 같이, 모델 어트리뷰트가 기본 값을 가지고 있어도 이는 필수가 아닙니다. 그외에는 필수입니다. 그저 `None`을 사용하여 선택적으로 만들 수 있습니다.
예를 들면, 위의 이 모델은 JSON "`object`" (혹은 파이썬 `dict`)을 다음과 같이 선언합니다:
```JSON
{
"name": "Foo",
- "description": "선택적인 설명란",
+ "description": "An optional description",
"price": 45.2,
"tax": 3.5
}
}
```
-## 매개변수로서 선언하기
+## 매개변수로서 선언하기 { #declare-it-as-a-parameter }
-ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다.
+ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì²\98리*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다.
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
...그리고 만들어낸 모델인 `Item`으로 타입을 선언합니다.
-## 결과
+## 결과 { #results }
위에서의 단순한 파이썬 타입 선언으로, **FastAPI**는 다음과 같이 동작합니다:
* 만약 데이터가 유효하지 않다면, 정확히 어떤 것이 그리고 어디에서 데이터가 잘 못 되었는지 지시하는 친절하고 명료한 에러를 반환할 것입니다.
* 매개변수 `item`에 포함된 수신 데이터를 제공합니다.
* 함수 내에서 매개변수를 `Item` 타입으로 선언했기 때문에, 모든 어트리뷰트와 그에 대한 타입에 대한 편집기 지원(완성 등)을 또한 받을 수 있습니다.
-* 여러분의 모델을 위한 <a href="https://json-schema.org" class="external-link" target="_blank">JSON 스키마</a> 정의를 생성합니다. 여러분의 프로젝트에 적합하다면 여러분이 사용하고 싶은 곳 어디에서나 사용할 수 있습니다.
-* 이러한 스키마는, 생성된 OpenAPI 스키마 일부가 될 것이며, 자동 문서화 <abbr title="사용자 인터페이스">UI</abbr>에 사용됩니다.
+* 여러분의 모델을 위한 <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> 정의를 생성합니다. 여러분의 프로젝트에 적합하다면 여러분이 사용하고 싶은 곳 어디에서나 사용할 수 있습니다.
+* 이러한 스키마는, 생성된 OpenAPI 스키마 일부가 될 것이며, 자동 문서화 <abbr title="User Interfaces – 사용자 인터페이스">UIs</abbr>에 사용됩니다.
-## 자동 문서화
+## 자동 문서화 { #automatic-docs }
모델의 JSON 스키마는 생성된 OpenAPI 스키마에 포함되며 대화형 API 문서에 표시됩니다:
<img src="/img/tutorial/body/image01.png">
-ì\9d´ë¥¼ í\95\84ì\9a\94ë¡\9c í\95\98ë\8a\94 ê°\81ê°\81ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99*내부의 API 문서에도 사용됩니다:
+ì\9d´ë¥¼ í\95\84ì\9a\94ë¡\9c í\95\98ë\8a\94 ê°\81ê°\81ì\9d\98 *ê²½ë¡\9c ì²\98리* 내부의 API 문서에도 사용됩니다:
<img src="/img/tutorial/body/image02.png">
-## 편집기 지원
+## 편집기 지원 { #editor-support }
편집기에서, 함수 내에서 타입 힌트와 완성을 어디서나 (만약 Pydantic model 대신에 `dict`을 받을 경우 나타나지 않을 수 있습니다) 받을 수 있습니다:
단순한 우연이 아닙니다. 프레임워크 전체가 이러한 디자인을 중심으로 설계되었습니다.
-그 어떤 실행 전에, 모든 편집기에서 작동할 수 있도록 보장하기 위해 설계 단계에서 혹독하게 테스트되었습니다.
+그 어떤 구현 전에, 모든 편집기에서 작동할 수 있도록 보장하기 위해 설계 단계에서 혹독하게 테스트되었습니다.
이를 지원하기 위해 Pydantic 자체에서 몇몇 변경점이 있었습니다.
이전 스크린샷은 <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>를 찍은 것입니다.
-í\95\98ì§\80ë§\8c ë\98\91ê°\99ì\9d\80 í\8e¸ì§\91기 ì§\80ì\9b\90ì\9d\84 <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>ì\97\90ì\84\9c ë°\9bì\9d\84 ì\88\98 ì\9e\88ê±°ë\82\98, ë\8c\80ë¶\80ë¶\84ì\9d\98 ë\8b¤ë¥¸ 편집기에서도 받을 수 있습니다:
+í\95\98ì§\80ë§\8c ë\98\91ê°\99ì\9d\80 í\8e¸ì§\91기 ì§\80ì\9b\90ì\9d\84 <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>ì\99\80 ë\8c\80ë¶\80ë¶\84ì\9d\98 ë\8b¤ë¥¸ í\8c\8cì\9d´ì\8d¬ 편집기에서도 받을 수 있습니다:
<img src="/img/tutorial/body/image05.png">
다음 사항을 포함해 Pydantic 모델에 대한 편집기 지원을 향상시킵니다:
-* 자동 완성
-* 타입 확인
-* 리팩토링
-* 검색
-* 점검
+* auto-completion
+* type checks
+* refactoring
+* searching
+* inspections
///
-## 모델 사용하기
+## 모델 사용하기 { #use-the-model }
함수 안에서 모델 객체의 모든 어트리뷰트에 직접 접근 가능합니다:
-{* ../../docs_src/body/tutorial002_py310.py hl[19] *}
+{* ../../docs_src/body/tutorial002_py310.py *}
-## 요청 본문 + 경로 매개변수
+## 요청 본문 + 경로 매개변수 { #request-body-path-parameters }
경로 매개변수와 요청 본문을 동시에 선언할 수 있습니다.
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
-## 요청 본문 + 경로 + 쿼리 매개변수
+
+## 요청 본문 + 경로 + 쿼리 매개변수 { #request-body-path-query-parameters }
**본문**, **경로** 그리고 **쿼리** 매개변수 모두 동시에 선언할 수도 있습니다.
FastAPI는 `q`의 값이 필요없음을 알게 될 것입니다. 기본 값이 `= None`이기 때문입니다.
-`Union[str, None]`에 있는 `Union`은 FastAPI에 의해 사용된 것이 아니지만, 편집기로 하여금 더 나은 지원과 에러 탐지를 지원할 것입니다.
+Python 3.10+의 `str | None` 또는 Python 3.9+의 `Union[str, None]`에 있는 `Union`은 FastAPI가 `q` 값이 필수가 아님을 판단하기 위해 사용하지 않습니다. 기본 값이 `= None`이기 때문에 필수가 아님을 알게 됩니다.
+
+하지만 타입 어노테이션을 추가하면 편집기가 더 나은 지원을 제공하고 오류를 감지할 수 있습니다.
///
-## Pydantic없이
+## Pydantic없이 { #without-pydantic }
-만약 Pydantic 모델을 사용하고 싶지 않다면, **Body** 매개변수를 사용할 수도 있습니다. [Body - 다중 매개변수: 본문에 있는 유일한 값](body-multiple-params.md#_2){.internal-link target=_blank} 문서를 확인하세요.
+만약 Pydantic 모델을 사용하고 싶지 않다면, **Body** 매개변수를 사용할 수도 있습니다. [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank} 문서를 확인하세요.
-# 쿠키 매개변수 모델
+# 쿠키 매개변수 모델 { #cookie-parameter-models }
관련있는 **쿠키**들의 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다. 🍪
-ì\9d´ë¥¼ í\86µí\95´ **ì\97¬ë\9f¬ ì\9c\84ì¹\98**ì\97\90ì\84\9c **모ë\8d¸ì\9d\84 ì\9e¬ì\82¬ì\9a©** í\95 ì\88\98 ì\9e\88ê³ ëª¨ë\93 매ê°\9cë³\80ì\88\98ì\97\90 ë\8c\80í\95\9c ì\9c í\9a¨ì\84± ê²\80ì\82¬ ë°\8f ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ í\95\9c ë²\88ì\97\90 ì\84 ì\96¸í\95 ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤. ð\9f\98\8d
+ì\9d´ë¥¼ í\86µí\95´ **ì\97¬ë\9f¬ ì\9c\84ì¹\98**ì\97\90ì\84\9c **모ë\8d¸ì\9d\84 ì\9e¬ì\82¬ì\9a©** í\95 ì\88\98 ì\9e\88ê³ ëª¨ë\93 매ê°\9cë³\80ì\88\98ì\97\90 ë\8c\80í\95\9c ì\9c í\9a¨ì\84± ê²\80ì\82¬ ë°\8f ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ í\95\9c ë²\88ì\97\90 ì\84 ì\96¸í\95 ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤. ð\9f\98\8e
/// note | 참고
///
-## Pydantic 모델을 사용한 쿠키
+## Pydantic 모델을 사용한 쿠키 { #cookies-with-a-pydantic-model }
**Pydantic 모델**에 필요한 **쿠키** 매개변수를 선언한 다음, 해당 매개변수를 `Cookie`로 선언합니다:
**FastAPI**는 요청에서 받은 **쿠키**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
-## 문서 확인하기
+## 문서 확인하기 { #check-the-docs }
문서 UI `/docs`에서 정의한 쿠키를 볼 수 있습니다:
명심하세요, 내부적으로 **브라우저는 쿠키를 특별한 방식으로 처리**하기 때문에 **자바스크립트**가 쉽게 쿠키를 건드릴 수 **없습니다**.
-`/docs`ì\97\90ì\84\9c **API 문ì\84\9c UI**ë¡\9c ì\9d´ë\8f\99í\95\98ë©´ *ê²½ë¡\9c ì\9e\91ì\97\85*에 대한 쿠키의 **문서**를 볼 수 있습니다.
+`/docs`ì\97\90ì\84\9c **API 문ì\84\9c UI**ë¡\9c ì\9d´ë\8f\99í\95\98ë©´ *ê²½ë¡\9c ì²\98리*에 대한 쿠키의 **문서**를 볼 수 있습니다.
하지만 아무리 **데이터를 입력**하고 "실행(Execute)"을 클릭해도, 문서 UI는 **자바스크립트**로 작동하기 때문에 쿠키는 전송되지 않고, 아무 값도 쓰지 않은 것처럼 **오류** 메시지를 보게 됩니다.
///
-## 추가 쿠키 금지하기
+## 추가 쿠키 금지하기 { #forbid-extra-cookies }
일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 쿠키를 **제한**할 수 있습니다.
-이제 API는 자신의 <abbr title="농담입니다, 혹시나 해서요. 쿠키 동의와 관련해서 할 수 있는 것은 없지만, 이제 API조차도 잘못된 쿠키를 거부할 수 있다는 점이 재밌습니다. 쿠키 드세요. 🍪">쿠키 동의</abbr>를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪
+이제 API는 자신의 <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>를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪
Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:
-{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
+{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
클라이언트가 **추가 쿠키**를 보내려고 시도하면, **오류** 응답을 받게 됩니다.
-<abbr title="이건 또 다른 농담입니다. 제 말에 귀 기울이지 마세요. 커피랑 쿠키 좀 드세요. ☕">API가 거부</abbr>하는데도 동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들. 🍪
+동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들, <abbr title="This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕">API가 거부</abbr>하는데도. 🍪
-예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` <abbr title="산타는 쿠키가 부족한 것을 못마땅해합니다. 🎅 알겠습니다, 쿠키 농담은 이제 없습니다.">쿠키가 허용되지 않는다</abbr>는 **오류** 응답을 받게 됩니다:
+예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` <abbr title="Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.">쿠키가 허용되지 않는다</abbr>는 **오류** 응답을 받게 됩니다:
```json
{
}
```
-## 요약
+## 요약 { #summary }
-**Pydantic 모델**을 사용하여 **FastAPI**에서 <abbr title="가기 전에 마지막 쿠키를 드세요. 🍪">**쿠키**</abbr>를 선언할 수 있습니다. 😍
+**Pydantic 모델**을 사용하여 **FastAPI**에서 <abbr title="Have a last cookie before you go. 🍪">**쿠키**</abbr>를 선언할 수 있습니다. 😎
-# 쿠키 매개변수
+# 쿠키 매개변수 { #cookie-parameters }
쿠키 매개변수를 `Query`와 `Path` 매개변수들과 같은 방식으로 정의할 수 있습니다.
-## `Cookie` 임포트
+## `Cookie` 임포트 { #import-cookie }
먼저 `Cookie`를 임포트합니다:
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
-## `Cookie` 매개변수 선언
+## `Cookie` 매개변수 선언 { #declare-cookie-parameters }
그런 다음, `Path`와 `Query`처럼 동일한 구조를 사용하는 쿠키 매개변수를 선언합니다.
`Cookie`는 `Path` 및 `Query`의 "자매"클래스입니다. 이 역시 동일한 공통 `Param` 클래스를 상속합니다.
-`Query`, `Path`, `Cookie` 그리고 다른 것들은 `fastapi`에서 임포트 할 때, 실제로는 특별한 클래스를 반환하는 함수임을 기억하세요.
+하지만 `fastapi`에서 `Query`, `Path`, `Cookie` 그리고 다른 것들을 임포트할 때, 실제로는 특별한 클래스를 반환하는 함수임을 기억하세요.
///
///
-## 요약
+/// info | 정보
+
+**브라우저는 쿠키를** 내부적으로 특별한 방식으로 처리하기 때문에, **JavaScript**가 쉽게 쿠키를 다루도록 허용하지 않는다는 점을 염두에 두세요.
+
+`/docs`의 **API docs UI**로 이동하면 *경로 처리*에 대한 쿠키 **문서**를 확인할 수 있습니다.
+
+하지만 **데이터를 채우고** "Execute"를 클릭하더라도, docs UI는 **JavaScript**로 동작하기 때문에 쿠키가 전송되지 않고, 아무 값도 입력하지 않은 것처럼 **오류** 메시지를 보게 될 것입니다.
+
+///
+
+## 요약 { #recap }
-`Cookie`는 `Query`, `Path`와 동일한 패턴을 사용하여 선언합니다.
+`Query`와 `Path`에서 사용하는 것과 동일한 공통 패턴으로, `Cookie`를 사용해 쿠키를 선언합니다.
-# 교차 출처 리소스 공유
+# CORS (교차-출처 리소스 공유) { #cors-cross-origin-resource-sharing }
-<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS 또는 "교차-출처 리소스 공유"</a>란, 브라우저에서 동작하는 프론트엔드가 자바스크립트로 코드로 백엔드와 통신하고, 백엔드는 해당 프론트엔드와 다른 "출처"에 존재하는 상황을 의미합니다.
+<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS 또는 "Cross-Origin Resource Sharing"</a>란, 브라우저에서 실행되는 프론트엔드에 백엔드와 통신하는 JavaScript 코드가 있고, 백엔드가 프론트엔드와 다른 "출처(origin)"에 있는 상황을 의미합니다.
-## 출처
+## 출처 { #origin }
-출처란 프로토콜(`http` , `https`), 도메인(`myapp.com`, `localhost`, `localhost.tiangolo.com` ), 그리고 포트(`80`, `443`, `8080` )의 조합을 의미합니다.
+출처란 프로토콜(`http`, `https`), 도메인(`myapp.com`, `localhost`, `localhost.tiangolo.com`), 그리고 포트(`80`, `443`, `8080`)의 조합을 의미합니다.
따라서, 아래는 모두 상이한 출처입니다:
* `https://localhost`
* `http://localhost:8080`
-모두 `localhost` 에 있지만, 서로 다른 프로토콜과 포트를 사용하고 있으므로 다른 "출처"입니다.
+모두 `localhost`에 있더라도, 서로 다른 프로토콜이나 포트를 사용하므로 서로 다른 "출처"입니다.
-## 단계
+## 단계 { #steps }
-브라우저 내 `http://localhost:8080`에서 동작하는 프론트엔드가 있고, 자바스크립트는 `http://localhost`를 통해 백엔드와 통신한다고 가정해봅시다(포트를 명시하지 않는 경우, 브라우저는 `80` 을 기본 포트로 간주합니다).
+그러면 브라우저에서 `http://localhost:8080`으로 실행되는 프론트엔드가 있고, 그 JavaScript가 `http://localhost`에서 실행되는 백엔드와 통신하려고 한다고 해봅시다(포트를 명시하지 않았기 때문에, 브라우저는 기본 포트 `80`을 가정합니다).
-그러면 브라우저는 백엔드에 HTTP `OPTIONS` 요청을 보내고, 백엔드에서 이 다른 출처(`http://localhost:8080`)와의 통신을 허가하는 적절한 헤더를 보내면, 브라우저는 프론트엔드의 자바스크립트가 백엔드에 요청을 보낼 수 있도록 합니다.
+그러면 브라우저는 `:80`-백엔드에 HTTP `OPTIONS` 요청을 보내고, 백엔드가 이 다른 출처(`http://localhost:8080`)로부터의 통신을 허가하는 적절한 헤더를 보내면, `:8080`-브라우저는 프론트엔드의 JavaScript가 `:80`-백엔드에 요청을 보낼 수 있도록 합니다.
-이를 위해, 백엔드는 "허용된 출처(allowed origins)" 목록을 가지고 있어야만 합니다.
+이를 위해, `:80`-백엔드는 "허용된 출처(allowed origins)" 목록을 가지고 있어야 합니다.
-이 경우, í\94\84ë¡ í\8a¸ì\97\94ë\93\9cê°\80 ì \9cë\8c\80ë¡\9c ë\8f\99ì\9e\91í\95\98기 ì\9c\84í\95´ `http://localhost:8080`ì\9d\84 목ë¡\9dì\97\90 í\8f¬í\95¨í\95´ì\95¼ í\95©ë\8b\88ë\8b¤.
+이 경우, `:8080`-í\94\84ë¡ í\8a¸ì\97\94ë\93\9cê°\80 ì\98¬ë°\94르ê²\8c ë\8f\99ì\9e\91í\95\98ë ¤ë©´ 목ë¡\9dì\97\90 `http://localhost:8080`ì\9d´ í\8f¬í\95¨ë\90\98ì\96´ì\95¼ í\95©ë\8b\88ë\8b¤.
-## 와일드카드
+## 와일드카드 { #wildcards }
-모ë\93 ì¶\9cì²\98를 í\97\88ì\9a©í\95\98기 ì\9c\84í\95´ 목ë¡\9dì\9d\84 `"*"` ("ì\99\80ì\9d¼ë\93\9cì¹´ë\93\9c")ë¡\9c ì\84 ì\96¸í\95\98ë\8a\94 ê²\83ë\8f\84 ê°\80ë\8a¥í\95©니다.
+ë\98\90í\95\9c 목ë¡\9dì\9d\84 `"*"`("ì\99\80ì\9d¼ë\93\9cì¹´ë\93\9c")ë¡\9c ì\84 ì\96¸í\95´ 모ë\91\90 í\97\88ì\9a©ë\90\9cë\8b¤ê³ ë§\90í\95 ì\88\98ë\8f\84 ì\9e\88ì\8aµ니다.
-하지만 이것은 특정한 유형의 통신만을 허용하며, 쿠키 및 액세스 토큰과 사용되는 인증 헤더(Authoriztion header) 등이 포함된 경우와 같이 자격 증명(credentials)이 포함된 통신은 허용되지 않습니다.
+하지만 그러면 자격 증명(credentials)이 포함된 모든 것을 제외하고 특정 유형의 통신만 허용하게 됩니다. 예: 쿠키, Bearer Token에 사용되는 것과 같은 Authorization 헤더 등.
-따라서 모든 작업을 의도한대로 실행하기 위해, 허용되는 출처를 명시적으로 지정하는 것이 좋습니다.
+따라서 모든 것이 올바르게 동작하게 하려면, 허용된 출처를 명시적으로 지정하는 것이 더 좋습니다.
-## `CORSMiddleware` 사용
+## `CORSMiddleware` 사용 { #use-corsmiddleware }
-`CORSMiddleware` 을 사용하여 **FastAPI** 응용 프로그램의 교차 출처 리소스 공유 환경을 설정할 수 있습니다.
+`CORSMiddleware`를 사용하여 **FastAPI** 애플리케이션에서 이를 설정할 수 있습니다.
-* `CORSMiddleware` 임포트.
-* í\97\88ì\9a©ë\90\98ë\8a\94 ì¶\9cì²\98(문ì\9e\90ì\97´ í\98\95ì\8b\9d)ì\9d\98 리ì\8a¤í\8a¸ ì\83\9dì\84±.
-* FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가.
+* `CORSMiddleware`를 임포트합니다.
+* í\97\88ì\9a©ë\90\9c ì¶\9cì²\98(문ì\9e\90ì\97´)ì\9d\98 리ì\8a¤í\8a¸ë¥¼ ì\83\9dì\84±í\95©ë\8b\88ë\8b¤.
+* **FastAPI** 애플리케이션에 "미들웨어(middleware)"로 추가합니다.
-ë°±ì\97\94ë\93\9cì\97\90ì\84\9c ë\8b¤ì\9d\8cì\9d\98 ì\82¬í\95ì\9d\84 í\97\88ì\9a©í\95 ì§\80ì\97\90 ë\8c\80í\95´ ì\84¤ì \95í\95 ì\88\98ë\8f\84 있습니다:
+ë\98\90í\95\9c ë°±ì\97\94ë\93\9cê°\80 ë\8b¤ì\9d\8cì\9d\84 í\97\88ì\9a©í\95 ì§\80 ì\97¬ë¶\80ë\8f\84 ì§\80ì \95í\95 ì\88\98 있습니다:
-* 자격증명 (인증 헤더, 쿠키 등).
-* 특정한 HTTP 메소드(`POST`, `PUT`) 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 메소드.
-* 특정한 HTTP 헤더 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 헤더.
+* 자격 증명(Authorization 헤더, 쿠키 등).
+* 특정 HTTP 메서드(`POST`, `PUT`) 또는 와일드카드 `"*"`를 사용한 모든 메서드.
+* 특정 HTTP 헤더 또는 와일드카드 `"*"`를 사용한 모든 헤더.
-{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
-`CORSMiddleware` 에서 사용하는 기본 매개변수는 제한적이므로, 브라우저가 교차-도메인 상황에서 특정한 출처, 메소드, 헤더 등을 사용할 수 있도록 하려면 이들을 명시적으로 허용해야 합니다.
-다음의 인자들이 지원됩니다:
+`CORSMiddleware` 구현에서 사용하는 기본 매개변수는 기본적으로 제한적이므로, 브라우저가 Cross-Domain 컨텍스트에서 특정 출처, 메서드 또는 헤더를 사용할 수 있도록 하려면 이를 명시적으로 활성화해야 합니다.
-* `allow_origins` - 교차-출처 요청을 보낼 수 있는 출처의 리스트입니다. 예) `['https://example.org', 'https://www.example.org']`. 모든 출처를 허용하기 위해 `['*']` 를 사용할 수 있습니다.
-* `allow_origin_regex` - 교차-출처 요청을 보낼 수 있는 출처를 정규표현식 문자열로 나타냅니다. `'https://.*\.example\.org'`.
-* `allow_methods` - 교차-출처 요청을 허용하는 HTTP 메소드의 리스트입니다. 기본값은 `['GET']` 입니다. `['*']` 을 사용하여 모든 표준 메소드들을 허용할 수 있습니다.
-* `allow_headers` - 교차-출처를 지원하는 HTTP 요청 헤더의 리스트입니다. 기본값은 `[]` 입니다. 모든 헤더들을 허용하기 위해 `['*']` 를 사용할 수 있습니다. `Accept`, `Accept-Language`, `Content-Language` 그리고 `Content-Type` 헤더는 CORS 요청시 언제나 허용됩니다.
-* `allow_credentials` - 교차-출처 요청시 쿠키 지원 여부를 설정합니다. 기본값은 `False` 입니다. 또한 해당 항목을 허용할 경우 `allow_origins` 는 `['*']` 로 설정할 수 없으며, 출처를 반드시 특정해야 합니다.
-* `expose_headers` - 브라우저에 접근할 수 있어야 하는 모든 응답 헤더를 가리킵니다. 기본값은 `[]` 입니다.
-* `max_age` - 브라우저가 CORS 응답을 캐시에 저장하는 최대 시간을 초 단위로 설정합니다. 기본값은 `600` 입니다.
+다음 인자들이 지원됩니다:
-미들웨어는 두가지 특정한 종류의 HTTP 요청에 응답합니다...
+* `allow_origins` - 교차-출처 요청을 보낼 수 있도록 허용해야 하는 출처의 리스트입니다. 예: `['https://example.org', 'https://www.example.org']`. 모든 출처를 허용하려면 `['*']`를 사용할 수 있습니다.
+* `allow_origin_regex` - 교차-출처 요청을 보낼 수 있도록 허용해야 하는 출처와 매칭할 정규표현식 문자열입니다. 예: `'https://.*\.example\.org'`.
+* `allow_methods` - 교차-출처 요청에 허용되어야 하는 HTTP 메서드의 리스트입니다. 기본값은 `['GET']`입니다. 모든 표준 메서드를 허용하려면 `['*']`를 사용할 수 있습니다.
+* `allow_headers` - 교차-출처 요청에 대해 지원되어야 하는 HTTP 요청 헤더의 리스트입니다. 기본값은 `[]`입니다. 모든 헤더를 허용하려면 `['*']`를 사용할 수 있습니다. `Accept`, `Accept-Language`, `Content-Language`, `Content-Type` 헤더는 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">단순 CORS 요청</a>에 대해 항상 허용됩니다.
+* `allow_credentials` - 교차-출처 요청에 대해 쿠키를 지원해야 함을 나타냅니다. 기본값은 `False`입니다.
-### CORS 사전 요청
+ `allow_credentials`가 `True`로 설정된 경우 `allow_origins`, `allow_methods`, `allow_headers` 중 어느 것도 `['*']`로 설정할 수 없습니다. 모두 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">명시적으로 지정</a>되어야 합니다.
-`Origin` 및 `Access-Control-Request-Method` 헤더와 함께 전송하는 모든 `OPTIONS` 요청입니다.
+* `expose_headers` - 브라우저에서 접근 가능해야 하는 모든 응답 헤더를 나타냅니다. 기본값은 `[]`입니다.
+* `max_age` - 브라우저가 CORS 응답을 캐시하는 최대 시간을 초 단위로 설정합니다. 기본값은 `600`입니다.
-이 경우 미들웨어는 들어오는 요청을 가로채 적절한 CORS 헤더와, 정보 제공을 위한 `200` 또는 `400` 응답으로 응답합니다.
+미들웨어는 두 가지 특정한 종류의 HTTP 요청에 응답합니다...
-### 단순한 요청
+### CORS 사전 요청 { #cors-preflight-requests }
-`Origin` 헤더를 가진 모든 요청. 이 경우 미들웨어는 요청을 정상적으로 전달하지만, 적절한 CORS 헤더를 응답에 포함시킵니다.
+`Origin` 및 `Access-Control-Request-Method` 헤더가 있는 모든 `OPTIONS` 요청입니다.
-## 더 많은 정보
+이 경우 미들웨어는 들어오는 요청을 가로채 적절한 CORS 헤더와 함께, 정보 제공 목적으로 `200` 또는 `400` 응답을 반환합니다.
-<abbr title="교차-출처 리소스 공유">CORS</abbr>에 대한 더 많은 정보를 알고싶다면, <a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS 문서</a>를 참고하기 바랍니다.
+### 단순한 요청 { #simple-requests }
-/// note | 기술적 세부 사항
+`Origin` 헤더가 있는 모든 요청입니다. 이 경우 미들웨어는 요청을 정상적으로 통과시키지만, 응답에 적절한 CORS 헤더를 포함합니다.
-`from starlette.middleware.cors import CORSMiddleware` 역시 사용할 수 있습니다.
+## 더 많은 정보 { #more-info }
-**FastAPI**는 개발자인 당신의 편의를 위해 `fastapi.middleware` 에서 몇가지의 미들웨어를 제공합니다. 하지만 대부분의 미들웨어가 Stralette으로부터 직접 제공됩니다.
+<abbr title="Cross-Origin Resource Sharing – 교차-출처 리소스 공유">CORS</abbr>에 대한 더 많은 정보는 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS 문서</a>를 참고하세요.
+
+/// note | 기술 세부사항
+
+`from starlette.middleware.cors import CORSMiddleware`도 사용할 수 있습니다.
+
+**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.middleware`에 여러 미들웨어를 제공합니다. 하지만 사용 가능한 미들웨어 대부분은 Starlette에서 직접 제공됩니다.
///
-# 디버깅
+# 디버깅 { #debugging }
예를 들면 Visual Studio Code 또는 PyCharm을 사용하여 편집기에서 디버거를 연결할 수 있습니다.
-## `uvicorn` 호출
+## `uvicorn` 호출 { #call-uvicorn }
-FastAPI 애플리케이션에서 `uvicorn`을 직접 임포트하여 실행합니다
+FastAPI 애플리케이션에서 `uvicorn`을 직접 임포트하여 실행합니다:
-{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
-### `__name__ == "__main__"` 에 대하여
+### `__name__ == "__main__"` 에 대하여 { #about-name-main }
`__name__ == "__main__"`의 주요 목적은 다음과 같이 파일이 호출될 때 실행되는 일부 코드를 갖는 것입니다.
from myapp import app
```
-#### 추가 세부사항
+#### 추가 세부사항 { #more-details }
파일 이름이 `myapp.py`라고 가정해 보겠습니다.
# Some more code
```
-이 경우 `myapp.py` 내부의 자동 변수에는 값이 `"__main__"`인 변수 `__name__`이 없습니다.
+이 경우 `myapp.py` 내부의 자동 변수 `__name__`에는 값이 `"__main__"`이 들어가지 않습니다.
따라서 다음 행
/// info | 정보
-자세한 내용은 <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">공식 Python 문서</a>를 확인하세요
+자세한 내용은 <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">공식 Python 문서</a>를 확인하세요.
///
-## 디버거로 코드 실행
+## 디버거로 코드 실행 { #run-your-code-with-your-debugger }
코드에서 직접 Uvicorn 서버를 실행하고 있기 때문에 디버거에서 직접 Python 프로그램(FastAPI 애플리케이션)을 호출할 수 있습니다.
Pycharm을 사용하는 경우 다음을 수행할 수 있습니다
-* "Run" 메뉴를 엽니다
+* "Run" 메뉴를 엽니다.
* "Debug..." 옵션을 선택합니다.
* 그러면 상황에 맞는 메뉴가 나타납니다.
* 디버그할 파일을 선택합니다(이 경우 `main.py`).
-# 의존성으로서의 클래스
+# 의존성으로서의 클래스 { #classes-as-dependencies }
-**의존성 주입** 시스템에 대해 자세히 살펴보기 전에 이전 예제를 업그레이드 해보겠습니다.
+**의존성 주입** 시스템에 대해 더 깊이 살펴보기 전에, 이전 예제를 업그레이드해 보겠습니다.
-## 이전 예제의 `딕셔너리`
+## 이전 예제의 `dict` { #a-dict-from-the-previous-example }
-이전 예제에서, 우리는 의존성(의존 가능한) 함수에서 `딕셔너리`객체를 반환하고 있었습니다:
+이전 예제에서는 의존성("dependable")에서 `dict`를 반환하고 있었습니다:
-{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
-우리는 *경로 작동 함수*의 매개변수 `commons`에서 `딕셔너리` 객체를 얻습니다.
+하지만 그러면 *경로 처리 함수*의 매개변수 `commons`에서 `dict`를 받게 됩니다.
-ê·¸ë¦¬ê³ ì\9a°ë¦¬ë\8a\94 ì\97\90ë\94\94í\84°ë\93¤ì\9d´ `ë\94\95ì\85\94ë\84\88리` ê°\9dì²´ì\9d\98 í\82¤ë\82\98 ë°¸ë¥\98ì\9d\98 ì\9e\90ë£\8cí\98\95ì\9d\84 ì\95\8c ì\88\98 ì\97\86기 ë\95\8c문ì\97\90 ì\9e\90ë\8f\99 ì\99\84ì\84±ê³¼ ê°\99ì\9d\80 기ë\8a¥ì\9d\84 ì \9cê³µí\95´ ì¤\84 수 없다는 것을 알고 있습니다.
+ê·¸ë¦¬ê³ ì\97\90ë\94\94í\84°ë\8a\94 `dict`ì\9d\98 í\82¤ì\99\80 ê°\92 í\83\80ì\9e\85ì\9d\84 ì\95\8c ì\88\98 ì\97\86기 ë\95\8c문ì\97\90 `dict`ì\97\90 ë\8c\80í\95´ì\84\9cë\8a\94 (ì\99\84ì\84± 기ë\8a¥ ê°\99ì\9d\80) ë§\8eì\9d\80 ì§\80ì\9b\90ì\9d\84 ì \9cê³µí\95 수 없다는 것을 알고 있습니다.
-ë\8d\94 ë\82\98ì\9d\80 ë°©ë²\95ì\9d´ ì\9e\88ì\9d\84 ê²\83 ê°\99ì\8aµë\8b\88ë\8b¤...
+더 나은 방법이 있습니다...
-## ì\9d\98ì¡´ì\84±ì\9c¼ë¡\9c ì\82¬ì\9a© ê°\80ë\8a¥í\95\9c ê²\83
+## ì\9d\98ì¡´ì\84±ì\9d´ ë\90\98기 ì\9c\84í\95\9c ì¡°ê±´ { #what-makes-a-dependency }
-지금까지 함수로 선언된 의존성을 봐왔습니다.
+지금까지는 함수로 선언된 의존성을 봤습니다.
-아마도 더 일반적이기는 하겠지만 의존성을 선언하는 유일한 방법은 아닙니다.
+하지만 그것만이 의존성을 선언하는 유일한 방법은 아닙니다(아마도 더 일반적이긴 하겠지만요).
-핵심 요소는 의존성이 "호출 가능"해야 한다는 것입니다
+핵심 요소는 의존성이 "호출 가능(callable)"해야 한다는 것입니다.
-파이썬에서ì\9d\98 "**í\98¸ì¶\9c ê°\80ë\8a¥**"ì\9d\80 í\8c\8cì\9d´ì\8d¬ì\9d´ í\95¨ì\88\98ì²\98ë\9f¼ "í\98¸ì¶\9c"í\95 ì\88\98 ì\9e\88ë\8a\94 모ë\93 ê²\83ì\9e\85ë\8b\88ë\8b¤.
+파이썬에서 "**í\98¸ì¶\9c ê°\80ë\8a¥(callable)**"ì\9d´ë\9e\80 í\8c\8cì\9d´ì\8d¬ì\9d´ í\95¨ì\88\98ì²\98ë\9f¼ "í\98¸ì¶\9c"í\95 ì\88\98 ì\9e\88ë\8a\94 모ë\93 ê²\83ì\9e\85ë\8b\88ë\8b¤.
-따라서, 만약 당신이 `something`(함수가 아닐 수도 있음) 객체를 가지고 있고,
+따라서 `something`(함수가 _아닐_ 수도 있습니다)이라는 객체가 있고, 다음처럼 "호출"(실행)할 수 있다면:
```Python
something()
something(some_argument, some_keyword_argument="foo")
```
-상기와 같은 방식으로 "호출(실행)" 할 수 있다면 "호출 가능"이 됩니다.
+그것은 "호출 가능(callable)"입니다.
-## 의존성으로서의 클래스
+## 의존성으로서의 클래스 { #classes-as-dependencies_1 }
-파이썬 클래스의 인스턴스를 생성하기 위해 사용하는 것과 동일한 문법을 사용한다는 걸 알 수 있습니다.
+파이썬 클래스의 인스턴스를 만들 때도 같은 문법을 사용한다는 것을 알 수 있을 겁니다.
예를 들어:
fluffy = Cat(name="Mr Fluffy")
```
-이 경우에 `fluffy`는 클래스 `Cat`의 인스턴스입니다. 그리고 우리는 `fluffy`를 만들기 위해서 `Cat`을 "호출"했습니다.
+이 경우 `fluffy`는 클래스 `Cat`의 인스턴스입니다.
-따라서, 파이썬 클래스는 **호출 가능**합니다.
+그리고 `fluffy`를 만들기 위해 `Cat`을 "호출"하고 있습니다.
-그래서 **FastAPI**에서는 파이썬 클래스를 의존성으로 사용할 수 있습니다.
+따라서 파이썬 클래스도 **호출 가능(callable)**합니다.
-FastAPI가 실질적으로 확인하는 것은 "호출 가능성"(함수, 클래스 또는 다른 모든 것)과 정의된 매개변수들입니다.
+그러면 **FastAPI**에서는 파이썬 클래스를 의존성으로 사용할 수 있습니다.
-"호출 가능"한 것을 의존성으로서 **FastAPI**에 전달하면, 그 "호출 가능"한 것의 매개변수들을 분석한 후 이를 *경로 작동 함수*를 위한 매개변수와 동일한 방식으로 처리합니다. 하위-의존성 또한 같은 방식으로 처리합니다.
+FastAPI가 실제로 확인하는 것은 그것이 "호출 가능(callable)"(함수, 클래스, 또는 다른 무엇이든)한지와 정의된 매개변수들입니다.
-매개변수가 없는 "호출 가능"한 것 역시 매개변수가 없는 *경로 작동 함수*와 동일한 방식으로 적용됩니다.
+**FastAPI**에서 "호출 가능(callable)"한 것을 의존성으로 넘기면, 그 "호출 가능(callable)"한 것의 매개변수들을 분석하고 *경로 처리 함수*의 매개변수와 동일한 방식으로 처리합니다. 하위 의존성도 포함해서요.
-그래서, 우리는 위 예제에서의 `common_paramenters` 의존성을 클래스 `CommonQueryParams`로 바꿀 수 있습니다.
+이것은 매개변수가 전혀 없는 callable에도 적용됩니다. 매개변수가 없는 *경로 처리 함수*에 적용되는 것과 동일합니다.
-{* ../../docs_src/dependencies/tutorial002.py hl[11:15] *}
+그러면 위의 의존성("dependable") `common_parameters`를 클래스 `CommonQueryParams`로 바꿀 수 있습니다:
-클래스의 인스턴스를 생성하는 데 사용되는 `__init__` 메서드에 주목하기 바랍니다:
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
-{* ../../docs_src/dependencies/tutorial002.py hl[12] *}
+클래스의 인스턴스를 만들 때 사용하는 `__init__` 메서드에 주목하세요:
-...이전 `common_parameters`와 동일한 매개변수를 가집니다:
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
-{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
+...이전의 `common_parameters`와 동일한 매개변수를 가지고 있습니다:
-이 매개변수들은 **FastAPI**가 의존성을 "해결"하기 위해 사용할 것입니다
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
-함수와 클래스 두 가지 방식 모두, 아래 요소를 갖습니다:
+이 매개변수들이 **FastAPI**가 의존성을 "해결"하는 데 사용할 것들입니다.
-* `문자열`이면서 선택사항인 쿼리 매개변수 `q`.
-* 기본값이 `0`이면서 `정수형`인 쿼리 매개변수 `skip`
-* 기본값이 `100`이면서 `정수형`인 쿼리 매개변수 `limit`
+두 경우 모두 다음을 갖게 됩니다:
-두 가지 방식 모두, 데이터는 변환, 검증되고 OpenAPI 스키마에 문서화됩니다.
+* `str`인 선택적 쿼리 매개변수 `q`.
+* 기본값이 `0`인 `int` 쿼리 매개변수 `skip`.
+* 기본값이 `100`인 `int` 쿼리 매개변수 `limit`.
-## 사용해봅시다!
+두 경우 모두 데이터는 변환되고, 검증되며, OpenAPI 스키마에 문서화되는 등 여러 처리가 적용됩니다.
-이제 아래의 클래스를 이용해서 의존성을 정의할 수 있습니다.
+## 사용하기 { #use-it }
-{* ../../docs_src/dependencies/tutorial002.py hl[19] *}
+이제 이 클래스를 사용해 의존성을 선언할 수 있습니다.
-**FastAPI**는 `CommonQueryParams` 클래스를 호출합니다. 이것은 해당 클래스의 "인스턴스"를 생성하고 그 인스턴스는 함수의 매개변수 `commons`로 전달됩니다.
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
-## 타입 힌팅 vs `Depends`
+**FastAPI**는 `CommonQueryParams` 클래스를 호출합니다. 그러면 해당 클래스의 "인스턴스"가 생성되고, 그 인스턴스가 함수의 매개변수 `commons`로 전달됩니다.
-위 코드에서 `CommonQueryParams`를 두 번 작성한 방식에 주목하십시오:
+## 타입 어노테이션 vs `Depends` { #type-annotation-vs-depends }
+
+위 코드에서 `CommonQueryParams`를 두 번 작성하는 방식에 주목하세요:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
+
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
-마지막 `CommonQueryParams` 변수를 보면:
+////
+
+마지막 `CommonQueryParams`는, 다음에서:
```Python
-... = Depends(CommonQueryParams)
+... Depends(CommonQueryParams)
```
-... **FastAPI**가 실제로 어떤 것이 의존성인지 알기 위해서 사용하는 방법입니다.
-FastAPI는 선언된 매개변수들을 추출할 것이고 실제로 이 변수들을 호출할 것입니다.
+...**FastAPI**가 실제로 무엇이 의존성인지 알기 위해 사용하는 것입니다.
+
+FastAPI는 여기에서 선언된 매개변수들을 추출하고, 실제로 이것을 호출합니다.
---
-이 경우에, 첫번째 `CommonQueryParams` 변수를 보면:
+이 경우 첫 번째 `CommonQueryParams`는 다음에서:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[CommonQueryParams, ...
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
+
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons: CommonQueryParams ...
```
-... **FastAPI**는 `CommonQueryParams` 변수에 어떠한 특별한 의미도 부여하지 않습니다. FastAPI는 이 변수를 데이터 변환, 검증 등에 활용하지 않습니다. (활용하려면 `= Depends(CommonQueryParams)`를 사용해야 합니다.)
+////
+
+...**FastAPI**에 특별한 의미가 없습니다. FastAPI는 이를 데이터 변환, 검증 등에 사용하지 않습니다(그런 용도로는 `Depends(CommonQueryParams)`를 사용하고 있기 때문입니다).
+
+실제로는 이렇게만 작성해도 됩니다:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[Any, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
-사실 아래와 같이 작성해도 무관합니다:
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons = Depends(CommonQueryParams)
```
-..전체적인 코드는 아래와 같습니다:
+////
-{* ../../docs_src/dependencies/tutorial003.py hl[19] *}
+...다음과 같이요:
-그러나 자료형을 선언하면 에디터가 매개변수 `commons`로 전달될 것이 무엇인지 알게 되고, 이를 통해 코드 완성, 자료형 확인 등에 도움이 될 수 있으므로 권장됩니다.
+{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
-<!-- <img src="/img/tutorial/dependencies/image02.png"> -->
+하지만 타입을 선언하는 것을 권장합니다. 그러면 에디터가 매개변수 `commons`에 무엇이 전달되는지 알 수 있고, 코드 완성, 타입 체크 등에서 도움을 받을 수 있습니다:
-## 코드 단축
+<img src="/img/tutorial/dependencies/image02.png">
-그러나 여기 `CommonQueryParams`를 두 번이나 작성하는, 코드 반복이 있다는 것을 알 수 있습니다:
+## 단축 { #shortcut }
+
+하지만 `CommonQueryParams`를 두 번 작성하는 코드 반복이 있다는 것을 볼 수 있습니다:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
+
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
-**FastAPI**는 *특히* 의존성이 **FastAPI**가 클래스 자체의 인스턴스를 생성하기 위해 "호출"하는 클래스인 경우, 조금 더 쉬운 방법을 제공합니다.
+////
+
+**FastAPI**는 이런 경우를 위한 단축 방법을 제공합니다. 이때 의존성은 *특히* **FastAPI**가 "호출"해서 클래스 자체의 인스턴스를 만들도록 하는 클래스입니다.
-이러한 특정한 경우에는 아래처럼 사용할 수 있습니다:
+이 특정한 경우에는 다음과 같이 할 수 있습니다:
-이렇게 쓰는 것 대신:
+다음처럼 작성하는 대신:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
+
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
-...이렇게 쓸 수 있습니다.:
+////
+
+...이렇게 작성합니다:
+
+//// tab | Python 3.9+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends()]
+```
+
+////
+
+//// tab | Python 3.9+ non-Annotated
+
+/// tip | 팁
+
+가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.
+
+///
```Python
commons: CommonQueryParams = Depends()
```
-의존성을 매개변수의 타입으로 선언하는 경우 `Depends(CommonQueryParams)`처럼 클래스 이름 전체를 *다시* 작성하는 대신, 매개변수를 넣지 않은 `Depends()`의 형태로 사용할 수 있습니다.
+////
+
+의존성을 매개변수의 타입으로 선언하고, `Depends(CommonQueryParams)` 안에 클래스 전체를 *다시* 작성하는 대신 매개변수 없이 `Depends()`를 사용합니다.
-아래에 같은 예제가 있습니다:
+그러면 같은 예제는 다음처럼 보일 겁니다:
-{* ../../docs_src/dependencies/tutorial004.py hl[19] *}
+{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
-...이렇게 코드를 단축하여도 **FastAPI**는 무엇을 해야하는지 알고 있습니다.
+...그리고 **FastAPI**는 무엇을 해야 하는지 알게 됩니다.
/// tip | 팁
-ë§\8cì\95½ ì\9d´ê²\83ì\9d´ ë\8f\84ì\9b\80ì\9d´ ë\90\98기보ë\8b¤ ë\8d\94 í\97·ê°\88리ê²\8c ë§\8cë\93 ë\8b¤ë©´, ì\9e\8aì\96´ë²\84리ì\8bì\8b\9cì\98¤. ì\9d´ê²\83ì\9d´ ë°\98ë\93\9cì\8b\9c í\95\84ì\9a\94í\95\9c ê²\83ì\9d\80 ì\95\84ë\8b\99ë\8b\88ë\8b¤.
+ë\8f\84ì\9b\80ì\9d´ ë\90\98기보ë\8b¤ ë\8d\94 í\97·ê°\88린ë\8b¤ë©´, 무ì\8b\9cí\95\98ì\84¸ì\9a\94. ì\9d´ê±´ *í\95\84ì\88\98*ê°\80 ì\95\84ë\8b\99ë\8b\88ë\8b¤.
-이것은 단지 손쉬운 방법일 뿐입니다. 왜냐하면 **FastAPI**는 코드 반복을 최소화할 수 있는 방법을 고민하기 때문입니다.
+그저 단축 방법일 뿐입니다. **FastAPI**는 코드 반복을 최소화하도록 도와주는 것을 중요하게 생각하기 때문입니다.
///
-# 경로 작동 데코레이터에서의 의존성
+# 경로 작동 데코레이터에서의 의존성 { #dependencies-in-path-operation-decorators }
몇몇 경우에는, *경로 작동 함수* 안에서 의존성의 반환 값이 필요하지 않습니다.
그런 경우에, `Depends`를 사용하여 *경로 작동 함수*의 매개변수로 선언하는 것보다 *경로 작동 데코레이터*에 `dependencies`의 `list`를 추가할 수 있습니다.
-## *경로 작동 데코레이터*에 `dependencies` 추가하기
+## *경로 작동 데코레이터*에 `dependencies` 추가하기 { #add-dependencies-to-the-path-operation-decorator }
*경로 작동 데코레이터*는 `dependencies`라는 선택적인 인자를 받습니다.
일부 편집기에서는 사용되지 않는 함수 매개변수를 검사하고 오류로 표시합니다.
-*경로 작동 데코레이터*에서 `dependencies`를 사용하면 편집기/도구 오류를 피하며 실행되도록 할 수 있습니다.
+*경로 작동 데코레이터*에서 이러한 `dependencies`를 사용하면 편집기/도구 오류를 피하면서도 실행되도록 할 수 있습니다.
또한 코드에서 사용되지 않는 매개변수를 보고 불필요하다고 생각할 수 있는 새로운 개발자의 혼란을 방지하는데 도움이 될 수 있습니다.
///
-## 의존성 오류와 값 반환하기
+## 의존성 오류와 값 반환하기 { #dependencies-errors-and-return-values }
평소에 사용하던대로 같은 의존성 *함수*를 사용할 수 있습니다.
-### 의존성 요구사항
+### 의존성 요구사항 { #dependency-requirements }
(헤더같은) 요청 요구사항이나 하위-의존성을 선언할 수 있습니다:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
-### 오류 발생시키기
+### 오류 발생시키기 { #raise-exceptions }
-다음 의존성은 기존 의존성과 동일하게 예외를 `raise`를 일으킬 수 있습니다:
+다음 의존성은 기존 의존성과 동일하게 예외를 `raise`할 수 있습니다:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
-### 값 반환하기
+### 값 반환하기 { #return-values }
값을 반환하거나, 그러지 않을 수 있으며 값은 사용되지 않습니다.
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
-## *경로 작동* 모음에 대한 의존성
+## *경로 작동* 모음에 대한 의존성 { #dependencies-for-a-group-of-path-operations }
나중에 여러 파일을 가지고 있을 수 있는 더 큰 애플리케이션을 구조화하는 법([더 큰 애플리케이션 - 여러 파일들](../../tutorial/bigger-applications.md){.internal-link target=_blank})을 읽을 때, *경로 작동* 모음에 대한 단일 `dependencies` 매개변수를 선언하는 법에 대해서 배우게 될 것입니다.
-## 전역 의존성
+## 전역 의존성 { #global-dependencies }
다음으로 각 *경로 작동*에 적용되도록 `FastAPI` 애플리케이션 전체에 의존성을 추가하는 법을 볼 것입니다.
-# yield를 사용하는 의존성
+# `yield`를 사용하는 의존성 { #dependencies-with-yield }
-FastAPI는 <abbr title='때로는 "종료 코드", "정리 코드", "종료 처리 코드", "닫기 코드", "컨텍스트 관리자 종료 코드" 등으로도 불립니다'>작업 완료 후 추가 단계를 수행하는</abbr> 의존성을 지원합니다.
+FastAPI는 <abbr title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc. – 때로는 "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code" 등으로도 불립니다'>작업 완료 후 추가 단계를 수행하는</abbr> 의존성을 지원합니다.
이를 구현하려면 `return` 대신 `yield`를 사용하고, 추가로 실행할 단계 (코드)를 그 뒤에 작성하세요.
///
-## `yield`를 사용하는 데이터베이스 의존성
+## `yield`를 사용하는 데이터베이스 의존성 { #a-database-dependency-with-yield }
예를 들어, 이 기능을 사용하면 데이터베이스 세션을 생성하고 작업이 끝난 후에 세션을 종료할 수 있습니다.
응답을 생성하기 전에는 `yield`문을 포함하여 그 이전의 코드만이 실행됩니다:
-{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *}
+{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
-yieldë\90\9c ê°\92ì\9d\80 *ê²½ë¡\9c ì\9e\91ì\97\85* 및 다른 의존성들에 주입되는 값 입니다:
+yieldë\90\9c ê°\92ì\9d\80 *ê²½ë¡\9c ì²\98리* 및 다른 의존성들에 주입되는 값 입니다:
-{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
+{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
-`yield`문 다음의 코드는 응답을 생성한 후 보내기 전에 실행됩니다:
+`yield`문 다음의 코드는 응답을 생성한 후 실행됩니다:
-{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *}
+{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
/// tip | 팁
///
-## `yield`와 `try`를 사용하는 의존성
+## `yield`와 `try`를 사용하는 의존성 { #a-dependency-with-yield-and-try }
`yield`를 사용하는 의존성에서 `try` 블록을 사용한다면, 의존성을 사용하는 도중 발생한 모든 예외를 받을 수 있습니다.
-ì\98\88를 ë\93¤ì\96´, ë\8b¤ë¥¸ ì\9d\98ì¡´ì\84±ì\9d´ë\82\98 *ê²½ë¡\9c ì\9e\91ì\97\85*의 중간에 데이터베이스 트랜잭션 "롤백"이 발생하거나 다른 오류가 발생한다면, 해당 예외를 의존성에서 받을 수 있습니다.
+ì\98\88를 ë\93¤ì\96´, ë\8b¤ë¥¸ ì\9d\98ì¡´ì\84±ì\9d´ë\82\98 *ê²½ë¡\9c ì²\98리*의 중간에 데이터베이스 트랜잭션 "롤백"이 발생하거나 다른 오류가 발생한다면, 해당 예외를 의존성에서 받을 수 있습니다.
따라서, 의존성 내에서 `except SomeException`을 사용하여 특정 예외를 처리할 수 있습니다.
마찬가지로, `finally`를 사용하여 예외 발생 여부와 관계 없이 종료 단계까 실행되도록 할 수 있습니다.
-{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
+{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
-## `yield`를 사용하는 하위 의존성
+## `yield`를 사용하는 하위 의존성 { #sub-dependencies-with-yield }
모든 크기와 형태의 하위 의존성과 하위 의존성의 "트리"도 가질 수 있으며, 이들 모두가 `yield`를 사용할 수 있습니다.
/// note | 기술 세부사항
-파이썬의 <a href=“https://docs.python.org/3/library/contextlib.html” class=“external-link” target=“_blank”>Context Managers</a> 덕분에 이 기능이 작동합니다.
+파이썬의 <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">Context Managers</a> 덕분에 이 기능이 작동합니다.
-**FastAPI**ë\8a\94 ì\9d´ë¥¼ ë\82´ë¶\80ì \81ì\9c¼ë¡\9c 컨í\85\8dì\8a¤í\8a¸ ê´\80리ì\9e\90를 ì\82¬ì\9a©í\95\98ì\97¬ 구í\98\84합니다.
+**FastAPI**ë\8a\94 ì\9d´ë¥¼ ë\82´ë¶\80ì \81ì\9c¼ë¡\9c ì\82¬ì\9a©í\95\98ì\97¬ ì\9d´ë¥¼ ë\8b¬ì\84±합니다.
///
-## `yield`와 `HTTPException`를 사용하는 의존성
+## `yield`와 `HTTPException`를 사용하는 의존성 { #dependencies-with-yield-and-httpexception }
-`yield`와 `try` 블록이 있는 의존성을 사용하여 예외를 처리할 수 있다는 것을 알게 되었습니다.
+`yield`를 사용하는 의존성에서 `try` 블록을 사용해 코드를 실행하고, 그 다음 `finally` 뒤에 종료 코드를 실행할 수 있다는 것을 보았습니다.
-같은 방식으로, `yield` 이후의 종료 코드에서 `HTTPException`이나 유사한 예외를 발생시킬 수 있습니다.
+또한 `except`를 사용해 발생한 예외를 잡고 그에 대해 무언가를 할 수도 있습니다.
+
+예를 들어, `HTTPException` 같은 다른 예외를 발생시킬 수 있습니다.
/// tip | 팁
-이는 다소 고급 기술이며, 대부분의 경우 경로 연산 함수 등 나머지 애플리케이션 코드 내부에서 예외 (`HTTPException` 포함)를 발생시킬 수 있으므로 실제로는 필요하지 않을 것입니다.
+이는 다소 고급 기술이며, 대부분의 경우 실제로는 필요하지 않을 것입니다. 예를 들어, *경로 처리 함수* 등 나머지 애플리케이션 코드 내부에서 예외 (`HTTPException` 포함)를 발생시킬 수 있기 때문입니다.
하지만 필요한 경우 사용할 수 있습니다. 🤓
{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
-ì\98\88ì\99¸ë¥¼ ì²\98리í\95\98ê³ (ë\98\90ë\8a\94 ì¶\94ê°\80ë¡\9c ë\8b¤ë¥¸ `HTTPException`ì\9d\84 ë°\9cì\83\9dì\8b\9cí\82¤ê¸° ì\9c\84í\95´) ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8a\94 ë\98\90 ë\8b¤ë¥¸ ë°©ë²\95ì\9d\80 [ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 ì\98\88ì\99¸ ì²\98리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}를 ì\83\9dì\84±í\95\98ë\8a\94 ê²\83 ì\9e\85ë\8b\88ë\8b¤.
+ì\98\88ì\99¸ë¥¼ ì\9e¡ê³ ê·¸ì\97\90 기ë°\98í\95´ ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 ì\9d\91ë\8bµì\9d\84 ì\83\9dì\84±í\95\98ë ¤ë©´, [ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 ì\98\88ì\99¸ ì²\98리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}를 ì\83\9dì\84±í\95\98ì\84¸ì\9a\94.
-## `yield`와 `except`를 사용하는 의존성
+## `yield`와 `except`를 사용하는 의존성 { #dependencies-with-yield-and-except }
-`yield`를 사용하는 의존성에서 `except`를 사용하여 예외를 포착하고 예외를 다시 발생시키지 않거나 (또는 새 예외를 발생시키지 않으면), FastAPI는 해당 예외가 발생했는지 알 수 없습니다. 이는 일반적인 Python 방식과 동일합니다:
+`yield`를 사용하는 의존성에서 `except`를 사용하여 예외를 포착하고 예외를 다시 발생시키지 않거나 (또는 새 예외를 발생시키지 않으면), FastAPI는 일반적인 Python에서와 마찬가지로 예외가 있었다는 것을 알아차릴 수 없습니다:
{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
-이 경우, `HTTPException`이나 유사한 예외를 발생시키지 않기 때문에 클라이언트는 HTTP 500 Internal Server Error 응답을 보게 되지만, 서버는 어떤 오류가 발생했는지에 대한 **로그**나 다른 표시를 전혀 가지지 않게 됩니다. 😱
+이 경우, `HTTPException`이나 유사한 예외를 발생시키지 않기 때문에 클라이언트는 마땅히 *HTTP 500 Internal Server Error* 응답을 보게 되지만, 서버에는 어떤 오류였는지에 대한 **로그**나 다른 표시가 **전혀 남지 않게 됩니다**. 😱
-### `yield`와 `except`를 사용하는 의존성에서 항상 `raise` 하기
+### `yield`와 `except`를 사용하는 의존성에서 항상 `raise` 하기 { #always-raise-in-dependencies-with-yield-and-except }
-`yield`가 있는 의존성에서 예외를 잡았을 때는 `HTTPException`이나 유사한 예외를 새로 발생시키지 않는 한, 반드시 원래의 예외를 다시 발생시켜야 합니다.
+`yield`가 있는 의존성에서 예외를 잡았을 때, 다른 `HTTPException`이나 유사한 예외를 발생시키는 것이 아니라면, **원래 예외를 다시 발생시켜야 합니다**.
`raise`를 사용하여 동일한 예외를 다시 발생시킬 수 있습니다:
{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
-ì\9d´ì \9c í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ë\8a\94 ë\8f\99ì\9d¼í\95\9c *HTTP 500 Internal Server Error* ì\98¤ë¥\98 ì\9d\91ë\8bµì\9d\84 ë°\9bê²\8c ë\90\98ì§\80ë§\8c, ì\84\9cë²\84 ë¡\9cê·¸ì\97\90ë\8a\94 ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 ì\98\88ì\99¸ì\9d¸ `InternalError"가 기록됩니다. 😎
+ì\9d´ì \9c í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ë\8a\94 ë\8f\99ì\9d¼í\95\9c *HTTP 500 Internal Server Error* ì\9d\91ë\8bµì\9d\84 ë°\9bê²\8c ë\90\98ì§\80ë§\8c, ì\84\9cë²\84 ë¡\9cê·¸ì\97\90ë\8a\94 ì\82¬ì\9a©ì\9e\90 ì \95ì\9d\98 `InternalError`가 기록됩니다. 😎
-## `yield`를 사용하는 의존성의 실행 순서
+## `yield`를 사용하는 의존성의 실행 순서 { #execution-of-dependencies-with-yield }
실행 순서는 아래 다이어그램과 거의 비슷합니다. 시간은 위에서 아래로 흐릅니다. 그리고 각 열은 상호 작용하거나 코드를 실행하는 부분 중 하나입니다.
/// info | 정보
-클라이언트에 **하나의 응답** 만 전송됩니다. 이는 오류 응답 중 하나일 수도 있고,*경로 작업*에서 생성된 응답일 수도 있습니다.
+클라이언트에는 **하나의 응답**만 전송됩니다. 이는 오류 응답 중 하나일 수도 있고, *경로 처리*에서 생성된 응답일 수도 있습니다.
이러한 응답 중 하나가 전송된 후에는 다른 응답을 보낼 수 없습니다.
/// tip | 팁
-이 다이어그램은 `HTTPException`을 보여주지만, `yield`를 사용하는 의존성에서 처리한 예외나 [사용자 정의 예외처리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.를 사용하여 처리한 다른 예외도 발생시킬 수 있습니다.
-
-어떤 예외가 발생하든, `HTTPException`을 포함하여 yield를 사용하는 의존성으로 전달됩니다. 대부분의 경우 예외를 다시 발생시키거나 새로운 예외를 발생시켜야 합니다.
+*경로 처리 함수*의 코드에서 어떤 예외를 발생시키면 `HTTPException`을 포함해 `yield`를 사용하는 의존성으로 전달됩니다. 대부분의 경우 해당 예외(또는 새 예외)를 `yield`를 사용하는 의존성에서 다시 발생시켜, 제대로 처리되도록 해야 합니다.
///
-## `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성
+## 조기 종료와 `scope` { #early-exit-and-scope }
-/// warning | 경고
+일반적으로 `yield`를 사용하는 의존성의 종료 코드는 클라이언트로 **응답이 전송된 후에** 실행됩니다.
-이러한 기술적 세부 사항은 대부분 필요하지 않으므로 이 섹션을 건너뛰고 아래에서 계속 진행해도 됩니다.
+하지만 *경로 처리 함수*에서 반환한 뒤에는 더 이상 해당 의존성이 필요 없다는 것을 알고 있다면, `Depends(scope="function")`을 사용하여 FastAPI에 *경로 처리 함수*가 반환된 후, 하지만 **응답이 전송되기 전에** 의존성을 종료(닫기)해야 한다고 알려줄 수 있습니다.
-이러한 세부 정보는 주로 FastAPI 0.106.0 이전 버전에서 `yield`가 있는 의존성의 리소스를 백그라운드 작업에서 사용했던 경우메 유용합니다.
+{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
-///
+`Depends()`는 다음이 될 수 있는 `scope` 매개변수를 받습니다:
-### `yield`와 `except`를 사용하는 의존성, 기술 세부사항
+* `"function"`: 요청을 처리하는 *경로 처리 함수* 전에 의존성을 시작하고, *경로 처리 함수*가 끝난 후, 하지만 응답이 클라이언트로 전송되기 **전에** 의존성을 종료합니다. 즉, 의존성 함수는 *경로 처리 **함수***를 **둘러싸며** 실행됩니다.
+* `"request"`: 요청을 처리하는 *경로 처리 함수* 전에 의존성을 시작하고(`"function"`을 사용할 때와 유사), 응답이 클라이언트로 전송된 **후에** 종료합니다. 즉, 의존성 함수는 **요청**과 응답 사이클을 **둘러싸며** 실행됩니다.
-FastAPI 0.110.0 이전에는 `yield`가 포함된 의존성을 사용한 후 해당 의존성에서 `except`가 포함된 예외를 캡처하고 다시 예외를 발생시키지 않으면 예외가 자동으로 예외 핸들러 또는 내부 서버 오류 핸들러로 발생/전달되었습니다.
+지정하지 않고 의존성이 `yield`를 사용한다면, 기본 `scope`는 `"request"`입니다.
-이는 처리기 없이 전달된 예외(내부 서버 오류)에서 처리되지 않은 메모리 소비를 수정하고 일반 파이썬 코드의 동작과 일치하도록 하기 위해 0.110.0 버전에서 변경되었습니다.
+### 하위 의존성을 위한 `scope` { #scope-for-sub-dependencies }
-### 백그라운드 작업과 `yield`를 사용하는 의존성, 기술 세부사항
+`scope="request"`(기본값)로 의존성을 선언하면, 모든 하위 의존성도 `scope`가 `"request"`여야 합니다.
-FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성 종료 코드는 응답이 전송된 이후에 실행되었기 때문에, [예외 처리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 상태였습니다.
+하지만 `scope`가 `"function"`인 의존성은 `scope`가 `"function"`인 의존성과 `"request"`인 의존성을 모두 의존성으로 가질 수 있습니다.
-이는 주로 백그라운드 작업 내에서 의존성에서 "yield된" 동일한 객체를 사용할 수 있도록 하기 위해 이런 방식으로 설계되었습니다. 종료 코드는 백그라운드 작업이 완료된 후에 실행되었기 때문입니다
-
-하지만 이렇게 하면 리소스를 불필요하게 양보한 의존성(예: 데이터베이스 연결)에서 보유하면서 응답이 네트워크를 통해 이동할 때까지 기다리는 것을 의미하기 때문에 FastAPI 0.106.0에서 변경되었습니다.
-
-/// tip | 팁
+이는 어떤 의존성이든, 종료 코드에서 하위 의존성을 계속 사용해야 할 수도 있으므로, 하위 의존성보다 먼저 종료 코드를 실행할 수 있어야 하기 때문입니다.
-또한 백그라운드 작업은 일반적으로 자체 리소스(예: 자체 데이터베이스 연결)를 사용하여 별도로 처리해야 하는 독립적인 로직 집합입니다.
+```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`가 있는 의존성의 리소스에 의존하지 않는 데이터만 내부적으로 사용해야합니다.
+## `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성 { #dependencies-with-yield-httpexception-except-and-background-tasks }
-예를 들어, 동일한 데이터베이스 세션을 사용하는 대신, 백그라운드 작업 내부에서 새로운 데이터베이스 세션을 생성하고 이 새로운 세션을 사용하여 데이터베이스에서 객체를 가져와야 합니다. 그리고 데이터베이스 객체를 백그라운드 작업 함수의 매개변수로 직접 전달하는 대신, 해당 객체의 ID를 전달한 다음 백그라운드 작업 함수 내부에서 객체를 다시 가져와야 합니다
+`yield`를 사용하는 의존성은 시간이 지나면서 서로 다른 사용 사례를 다루고 일부 문제를 수정하기 위해 발전해 왔습니다.
-## 컨텍스트 관리자
+FastAPI의 여러 버전에서 무엇이 바뀌었는지 보고 싶다면, 고급 가이드의 [고급 의존성 - `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}에서 더 자세히 읽을 수 있습니다.
+## 컨텍스트 관리자 { #context-managers }
-### "컨텍스트 관리자"란?
+### "컨텍스트 관리자"란 { #what-are-context-managers }
"컨텍스트 관리자"는 Python에서 `with` 문에서 사용할 수 있는 모든 객체를 의미합니다.
-예를 들어, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank"> `with`를 사용하여 파일을 읽을 수 있습니다</a>:
+예를 들어, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">`with`를 사용하여 파일을 읽을 수 있습니다</a>:
```Python
with open("./somefile.txt") as f:
`yield`가 있는 의존성을 생성하면 **FastAPI**는 내부적으로 이를 위한 컨텍스트 매니저를 생성하고 다른 관련 도구들과 결합합니다.
-### `yield`를 사용하는 의존성에서 컨텍스트 관리자 사용하기
+### `yield`를 사용하는 의존성에서 컨텍스트 관리자 사용하기 { #using-context-managers-in-dependencies-with-yield }
/// warning | 경고
**FastAPI**의 `yield`가 있는 의존성 내에서
`with` 또는 `async with`문을 사용하여 이들을 활용할 수 있습니다:
-{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *}
+{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
/// tip | 팁
-# 전역 의존성
+# 전역 의존성 { #global-dependencies }
-몇몇 애플리케이션에서는 애플리케이션 전체에 의존성을 추가하고 싶을 수 있습니다.
+ëª\87ëª\87 ì\9c í\98\95ì\9d\98 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90ì\84\9cë\8a\94 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98 ì \84ì²´ì\97\90 ì\9d\98ì¡´ì\84±ì\9d\84 ì¶\94ê°\80í\95\98ê³ ì\8b¶ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-[*ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 `dependencies` ì¶\94ê°\80í\95\98기](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}ì\99\80 ì\9c ì\82¬í\95\9c ë°©ë²\95ì\9c¼ë¡\9c `FastAPI` ì\95 í\94\8c리케이션에 그것들을 추가할 수 있습니다.
+[*ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 `dependencies` ì¶\94ê°\80í\95\98기](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}ì\99\80 ì\9c ì\82¬í\95\9c ë°©ë²\95ì\9c¼ë¡\9c `FastAPI` ì\95 í\94\8c리ì¼\80케이션에 그것들을 추가할 수 있습니다.
-ê·¸ë\9f° ê²½ì\9a°ì\97\90, ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 모ë\93 *ê²½ë¡\9c ì\9e\91ë\8f\99*에 적용될 것입니다:
+ê·¸ë\9f° ê²½ì\9a°ì\97\90, ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 모ë\93 *ê²½ë¡\9c ì²\98리*에 적용될 것입니다:
-{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *}
+{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *}
-그리고 [*경로 작동 데코레이터*에 `dependencies` 추가하기](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}에 대한 아이디어는 여전히 적용되지만 여기에서는 앱에 있는 모든 *경로 작동*에 적용됩니다.
-## *경로 작동* 모음에 대한 의존성
+그리고 [*경로 처리 데코레이터*에 `dependencies` 추가하기](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 섹션의 모든 아이디어는 여전히 적용되지만, 이 경우에는 앱의 모든 *경로 처리*에 적용됩니다.
-이후에 여러 파일들을 가지는 더 큰 애플리케이션을 구조화하는 법([더 큰 애플리케이션 - 여러 파일들](../../tutorial/bigger-applications.md){.internal-link target=_blank})을 읽을 때, *경로 작동* 모음에 대한 단일 `dependencies` 매개변수를 선언하는 법에 대해서 배우게 될 것입니다.
+## *경로 처리* 그룹에 대한 의존성 { #dependencies-for-groups-of-path-operations }
+
+나중에 여러 파일을 포함할 수도 있는 더 큰 애플리케이션을 구조화하는 법([더 큰 애플리케이션 - 여러 파일들](../../tutorial/bigger-applications.md){.internal-link target=_blank})을 읽을 때, *경로 처리* 그룹에 대한 단일 `dependencies` 매개변수를 선언하는 법을 배우게 될 것입니다.
-# 의존성
+# 의존성 { #dependencies }
-**FastAPI**는 아주 강력하지만 직관적인 **<abbr title="컴포넌트, 자원, 제공자, 서비스, 인젝터블로 알려져 있습니다">의존성 주입</abbr>** 시스템을 가지고 있습니다.
+**FastAPI**는 아주 강력하지만 직관적인 **<abbr title="also known as components, resources, providers, services, injectables">의존성 주입</abbr>** 시스템을 가지고 있습니다.
이는 사용하기 아주 쉽게 설계했으며, 어느 개발자나 다른 컴포넌트와 **FastAPI**를 쉽게 통합할 수 있도록 만들었습니다.
-## "의존성 주입"은 무엇입니까?
+## "의존성 주입"은 무엇입니까? { #what-is-dependency-injection }
-**"의존성 주입"**은 프로그래밍에서 여러분의 코드(이 경우, 경로 작동 함수)가 작동하고 사용하는 데 필요로 하는 것, 즉 "의존성"을 선언할 수 있는 방법을 의미합니다.
+**"의존성 주입"**은 프로그래밍에서 여러분의 코드(이 경우, *경로 처리 함수*)가 작동하고 사용하는 데 필요로 하는 것, 즉 "의존성"을 선언할 수 있는 방법을 의미합니다.
-그 후에, 시스템(이 경우 FastAPI)은 여러분의 코드가 요구하는 의존성을 제공하기 위해 필요한 모든 작업을 처리합니다.(의존성을 "주입"합니다)
+그 후에, 시스템(이 경우 **FastAPI**)은 여러분의 코드가 요구하는 의존성을 제공하기 위해 필요한 모든 작업을 처리합니다.(의존성을 "주입"합니다)
이는 여러분이 다음과 같은 사항을 필요로 할 때 매우 유용합니다:
이 모든 사항을 할 때 코드 반복을 최소화합니다.
-## 첫번째 단계
+## 첫번째 단계 { #first-steps }
아주 간단한 예제를 봅시다. 너무 간단할 것이기에 지금 당장은 유용하지 않을 수 있습니다.
하지만 이를 통해 **의존성 주입** 시스템이 어떻게 작동하는지에 중점을 둘 것입니다.
-### 의존성 혹은 "디펜더블" 만들기
+### 의존성 혹은 "디펜더블" 만들기 { #create-a-dependency-or-dependable }
의존성에 집중해 봅시다.
-*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*가 가질 수 있는 모든 매개변수를 갖는 단순한 함수입니다:
+*ê²½ë¡\9c ì²\98리 함수*가 가질 수 있는 모든 매개변수를 갖는 단순한 함수입니다:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
**단 두 줄입니다**.
-ê·¸ë¦¬ê³ , ì\9d´ í\95¨ì\88\98ë\8a\94 ì\97¬ë\9f¬ë¶\84ì\9d\98 모ë\93 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*가 가지고 있는 것과 같은 형태와 구조를 가지고 있습니다.
+ê·¸ë¦¬ê³ , ì\9d´ í\95¨ì\88\98ë\8a\94 ì\97¬ë\9f¬ë¶\84ì\9d\98 모ë\93 *ê²½ë¡\9c ì²\98리 함수*가 가지고 있는 것과 같은 형태와 구조를 가지고 있습니다.
-ì\97¬ë\9f¬ë¶\84ì\9d\80 ì\9d´ë¥¼ "ë\8d°ì½\94ë \88ì\9d´í\84°"ê°\80 ì\97\86ë\8a\94 (`@app.get("/some-path")`ê°\80 ì\97\86ë\8a\94) *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*라고 생각할 수 있습니다.
+ì\97¬ë\9f¬ë¶\84ì\9d\80 ì\9d´ë¥¼ "ë\8d°ì½\94ë \88ì\9d´í\84°"ê°\80 ì\97\86ë\8a\94 (`@app.get("/some-path")`ê°\80 ì\97\86ë\8a\94) *ê²½ë¡\9c ì²\98리 함수*라고 생각할 수 있습니다.
그리고 여러분이 원하는 무엇이든 반환할 수 있습니다.
* 선택적인 쿼리 매개변수 `q`, `str`을 자료형으로 가집니다.
* 선택적인 쿼리 매개변수 `skip`, `int`를 자료형으로 가지며 기본 값은 `0`입니다.
-* 선택적인 쿼리 매개변수 `limit`,`int`를 자료형으로 가지며 기본 값은 `100`입니다.
+* 선택적인 쿼리 매개변수 `limit` that is an `int`, and by default is `100`.
그 후 위의 값을 포함한 `dict` 자료형으로 반환할 뿐입니다.
옛날 버전을 가지고 있는 경우, `Annotated`를 사용하려 하면 에러를 맞이하게 될 것입니다.
-`Annotated`를 사용하기 전에 최소 0.95.1로 [FastAPI 버전 업그레이드](../../deployment/versions.md#fastapi_2){.internal-link target=_blank}를 확실하게 하세요.
+`Annotated`를 사용하기 전에 최소 0.95.1로 [FastAPI 버전 업그레이드](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}를 확실하게 하세요.
///
-### `Depends` 불러오기
+### `Depends` 불러오기 { #import-depends }
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
-### "의존자"에 의존성 명시하기
+### "의존자"에 의존성 명시하기 { #declare-the-dependency-in-the-dependant }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*의 매개변수로 `Body`, `Query` 등을 사용하는 방식과 같이 새로운 매개변수로 `Depends`를 사용합니다:
+*ê²½ë¡\9c ì²\98리 함수*의 매개변수로 `Body`, `Query` 등을 사용하는 방식과 같이 새로운 매개변수로 `Depends`를 사용합니다:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
여러분은 직접 **호출하지 않았습니다** (끝에 괄호를 치지 않았습니다), 단지 `Depends()`에 매개변수로 넘겨 줬을 뿐입니다.
-ê·¸ë¦¬ê³ ê·¸ í\95¨ì\88\98ë\8a\94 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*가 작동하는 것과 같은 방식으로 매개변수를 받습니다.
+ê·¸ë¦¬ê³ ê·¸ í\95¨ì\88\98ë\8a\94 *ê²½ë¡\9c ì²\98리 함수*가 작동하는 것과 같은 방식으로 매개변수를 받습니다.
/// tip | 팁
* 올바른 매개변수를 가진 의존성("디펜더블") 함수를 호출합니다.
* 함수에서 결과를 받아옵니다.
-* *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에 있는 매개변수에 그 결과를 할당합니다
+* *ê²½ë¡\9c ì²\98리 함수*에 있는 매개변수에 그 결과를 할당합니다
```mermaid
graph TB
common_parameters --> read_users
```
-ì\9d´ë \87ê²\8c í\95\98ë©´ ê³µì\9a© ì½\94ë\93\9c를 í\95\9cë²\88ë§\8c ì \81ì\96´ë\8f\84 ë\90\98ë©°, **FastAPI**ë\8a\94 *ê²½ë¡\9c ì\9e\91ë\8f\99*을 위해 이에 대한 호출을 처리합니다.
+ì\9d´ë \87ê²\8c í\95\98ë©´ ê³µì\9a© ì½\94ë\93\9c를 í\95\9cë²\88ë§\8c ì \81ì\96´ë\8f\84 ë\90\98ë©°, **FastAPI**ë\8a\94 *ê²½ë¡\9c ì²\98리*을 위해 이에 대한 호출을 처리합니다.
/// check | 확인
///
-## `Annotated`인 의존성 공유하기
+## `Annotated`인 의존성 공유하기 { #share-annotated-dependencies }
위의 예제에서 몇몇 작은 **코드 중복**이 있다는 것을 보았을 겁니다.
이 의존성은 계속해서 예상한대로 작동할 것이며, **제일 좋은 부분**은 **타입 정보가 보존된다는 것입니다**. 즉 여러분의 편집기가 **자동 완성**, **인라인 에러** 등을 계속해서 제공할 수 있다는 것입니다. `mypy`같은 다른 도구도 마찬가지입니다.
-ì\9d´ë\8a\94 í\8a¹í\9e\88 **ë§\8eì\9d\80 *ê²½ë¡\9c ì\9e\91ë\8f\99***에서 **같은 의존성**을 계속해서 사용하는 **거대 코드 기반**안에서 사용하면 유용할 것입니다.
+ì\9d´ë\8a\94 í\8a¹í\9e\88 **ë§\8eì\9d\80 *ê²½ë¡\9c ì²\98리***에서 **같은 의존성**을 계속해서 사용하는 **거대 코드 기반**안에서 사용하면 유용할 것입니다.
-## `async`하게, 혹은 `async`하지 않게
+## `async`하게, 혹은 `async`하지 않게 { #to-async-or-not-to-async }
-ì\9d\98ì¡´ì\84±ì\9d´ (*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에서 처럼 똑같이) **FastAPI**에 의해 호출될 수 있으며, 함수를 정의할 때 동일한 규칙이 적용됩니다.
+ì\9d\98ì¡´ì\84±ì\9d´ (*ê²½ë¡\9c ì²\98리 함수*에서 처럼 똑같이) **FastAPI**에 의해 호출될 수 있으며, 함수를 정의할 때 동일한 규칙이 적용됩니다.
`async def`을 사용하거나 혹은 일반적인 `def`를 사용할 수 있습니다.
-ê·¸ë¦¬ê³ ì\9d¼ë°\98ì \81ì\9d¸ `def` *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98* ì\95\88ì\97\90 `async def`ë¡\9c ì\9d\98ì¡´ì\84±ì\9d\84 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\9c¼ë©°, `async def` *ê²½ë¡\9c ì\9e\91ë\8f\99 함수* 안에 `def`로 의존성을 선언하는 등의 방법이 있습니다.
+ê·¸ë¦¬ê³ ì\9d¼ë°\98ì \81ì\9d¸ `def` *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98* ì\95\88ì\97\90 `async def`ë¡\9c ì\9d\98ì¡´ì\84±ì\9d\84 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\9c¼ë©°, `async def` *ê²½ë¡\9c ì²\98리 함수* 안에 `def`로 의존성을 선언하는 등의 방법이 있습니다.
아무 문제 없습니다. **FastAPI**는 무엇을 할지 알고 있습니다.
/// note | 참고
-잘 모르시겠다면, [Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank} 문서에서 `async`와 `await`에 대해 확인할 수 있습니다.
+잘 모르시겠다면, [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} 문서에서 `async`와 `await`에 대해 확인할 수 있습니다.
///
-## OpenAPI와 통합
+## OpenAPI와 통합 { #integrated-with-openapi }
모든 요청 선언, 검증과 의존성(및 하위 의존성)에 대한 요구 사항은 동일한 OpenAPI 스키마에 통합됩니다.
<img src="/img/tutorial/dependencies/image01.png">
-## 간단한 사용법
+## 간단한 사용법 { #simple-usage }
-ì\9d´ë¥¼ ë³´ë©´, *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*는 *경로*와 *작동*이 매칭되면 언제든지 사용되도록 정의되었으며, **FastAPI**는 올바른 매개변수를 가진 함수를 호출하고 해당 요청에서 데이터를 추출합니다.
+ì\9d´ë¥¼ ë³´ë©´, *ê²½ë¡\9c ì²\98리 함수*는 *경로*와 *작동*이 매칭되면 언제든지 사용되도록 정의되었으며, **FastAPI**는 올바른 매개변수를 가진 함수를 호출하고 해당 요청에서 데이터를 추출합니다.
사실, 모든 (혹은 대부분의) 웹 프레임워크는 이와 같은 방식으로 작동합니다.
여러분은 이러한 함수들을 절대 직접 호출하지 않습니다. 프레임워크(이 경우 **FastAPI**)에 의해 호출됩니다.
-ì\9d\98ì¡´ì\84± 주ì\9e\85 ì\8b\9cì\8a¤í\85\9cê³¼ í\95¨ê»\98ë\9d¼ë©´ **FastAPI**ì\97\90ê²\8c ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*ê°\80 ì\8b¤í\96\89ë\90\98기 ì \84ì\97\90 ì\8b¤í\96\89ë\90\98ì\96´ì\95¼ í\95\98ë\8a\94 무ì\96¸ê°\80ì\97\90 ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수* 또한 "의존"하고 있음을 알릴 수 있으며, **FastAPI**는 이를 실행하고 결과를 "주입"할 것입니다.
+ì\9d\98ì¡´ì\84± 주ì\9e\85 ì\8b\9cì\8a¤í\85\9cê³¼ í\95¨ê»\98ë\9d¼ë©´ **FastAPI**ì\97\90ê²\8c ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ê°\80 ì\8b¤í\96\89ë\90\98기 ì \84ì\97\90 ì\8b¤í\96\89ë\90\98ì\96´ì\95¼ í\95\98ë\8a\94 무ì\96¸ê°\80ì\97\90 ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì²\98리 함수* 또한 "의존"하고 있음을 알릴 수 있으며, **FastAPI**는 이를 실행하고 결과를 "주입"할 것입니다.
"의존성 주입"이라는 동일한 아이디어에 대한 다른 일반적인 용어는 다음과 같습니다:
* 인젝터블
* 컴포넌트
-## **FastAPI** 플러그인
+## **FastAPI** 플러그인 { #fastapi-plug-ins }
-í\86µí\95©ê³¼ "í\94\8cë\9f¬ê·¸ì\9d¸"ì\9d\80 **ì\9d\98ì¡´ì\84± 주ì\9e\85** ì\8b\9cì\8a¤í\85\9cì\9d\84 ì\82¬ì\9a©í\95\98ì\97¬ 구ì¶\95í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. í\95\98ì§\80ë§\8c ì\8b¤ì \9cë¡\9c **"í\94\8cë\9f¬ê·¸ì\9d¸"ì\9d\84 ë§\8cë\93¤ í\95\84ì\9a\94ë\8a\94 ì\97\86ì\8aµë\8b\88ë\8b¤**, ì\99\9cë\83\90í\95\98ë©´ ì\9d\98ì¡´ì\84±ì\9d\84 ì\82¬ì\9a©í\95¨ì\9c¼ë¡\9cì\8d¨ ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에 통합과 상호 작용을 무한대로 선언할 수 있기 때문입니다.
+í\86µí\95©ê³¼ "í\94\8cë\9f¬ê·¸ì\9d¸"ì\9d\80 **ì\9d\98ì¡´ì\84± 주ì\9e\85** ì\8b\9cì\8a¤í\85\9cì\9d\84 ì\82¬ì\9a©í\95\98ì\97¬ 구ì¶\95í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. í\95\98ì§\80ë§\8c ì\8b¤ì \9cë¡\9c **"í\94\8cë\9f¬ê·¸ì\9d¸"ì\9d\84 ë§\8cë\93¤ í\95\84ì\9a\94ë\8a\94 ì\97\86ì\8aµë\8b\88ë\8b¤**, ì\99\9cë\83\90í\95\98ë©´ ì\9d\98ì¡´ì\84±ì\9d\84 ì\82¬ì\9a©í\95¨ì\9c¼ë¡\9cì\8d¨ ì\97¬ë\9f¬ë¶\84ì\9d\98 *ê²½ë¡\9c ì²\98리 함수*에 통합과 상호 작용을 무한대로 선언할 수 있기 때문입니다.
그리고 "말 그대로", 그저 필요로 하는 파이썬 패키지를 임포트하고 단 몇 줄의 코드로 여러분의 API 함수와 통합함으로써, 의존성을 아주 간단하고 직관적인 방법으로 만들 수 있습니다.
관계형 및 NoSQL 데이터베이스, 보안 등, 이에 대한 예시를 다음 장에서 볼 수 있습니다.
-## **FastAPI** 호환성
+## **FastAPI** 호환성 { #fastapi-compatibility }
의존성 주입 시스템의 단순함은 **FastAPI**를 다음과 같은 요소들과 호환할 수 있게 합니다:
* 응답 데이터 주입 시스템
* 기타 등등.
-## 간편하고 강력하다
+## 간편하고 강력하다 { #simple-and-powerful }
계층적인 의존성 주입 시스템은 정의하고 사용하기 쉽지만, 여전히 매우 강력합니다.
끝에는, 계층적인 나무로 된 의존성이 만들어지며, 그리고 **의존성 주입** 시스템은 (하위 의존성도 마찬가지로) 이러한 의존성들을 처리하고 각 단계마다 결과를 제공합니다(주입합니다).
-ì\98\88를 ë\93¤ë©´, ì\97¬ë\9f¬ë¶\84ì\9d´ 4ê°\9cì\9d\98 API ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸(*ê²½ë¡\9c ì\9e\91ë\8f\99*)를 가지고 있다고 해봅시다:
+ì\98\88를 ë\93¤ë©´, ì\97¬ë\9f¬ë¶\84ì\9d´ 4ê°\9cì\9d\98 API ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸(*ê²½ë¡\9c ì²\98리*)를 가지고 있다고 해봅시다:
* `/items/public/`
* `/items/private/`
paying_user --> pro_items
```
-## **OpenAPI**와의 통합
+## **OpenAPI**와의 통합 { #integrated-with-openapi_1 }
-ì\9d´ 모ë\93 ì\9d\98ì¡´ì\84±ì\9d\80 ê°\81ê°\81ì\9d\98 ì\9a\94구ì\82¬í\95ì\9d\84 ì\84 ì\96¸í\95\98ë\8a\94 ë\8f\99ì\8b\9cì\97\90, *ê²½ë¡\9c ì\9e\91ë\8f\99*에 매개변수, 검증 등을 추가합니다.
+ì\9d´ 모ë\93 ì\9d\98ì¡´ì\84±ì\9d\80 ê°\81ê°\81ì\9d\98 ì\9a\94구ì\82¬í\95ì\9d\84 ì\84 ì\96¸í\95\98ë\8a\94 ë\8f\99ì\8b\9cì\97\90, *ê²½ë¡\9c ì²\98리*에 매개변수, 검증 등을 추가합니다.
**FastAPI**는 이 모든 것을 OpenAPI 스키마에 추가할 것이며, 이를 통해 대화형 문서 시스템에 나타날 것입니다.
-# JSON 호환 가능 인코더
+# JSON 호환 가능 인코더 { #json-compatible-encoder }
-ë\8d°ì\9d´í\84° ì\9c í\98\95(ì\98\88: Pydantic 모ë\8d¸)ì\9d\84 JSONê³¼ í\98¸í\99\98ë\90\9c í\98\95í\83\9cë¡\9c ë°\98í\99\98í\95´ì\95¼ í\95\98ë\8a\94 ê²½ì\9a°ê°\80 ì\9e\88ì\8aµë\8b\88ë\8b¤. (ì\98\88: `dict`, `list` ë\93±)
+ë\8d°ì\9d´í\84° ì\9c í\98\95(ì\98\88: Pydantic 모ë\8d¸)ì\9d\84 JSONê³¼ í\98¸í\99\98ë\90\98ë\8a\94 í\98\95í\83\9c(ì\98\88: `dict`, `list` ë\93±)ë¡\9c ë³\80í\99\98í\95´ì\95¼ í\95\98ë\8a\94 ê²½ì\9a°ê°\80 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-예를 들면, 데이터베이스에 저장해야하는 경우입니다.
+예를 들면, 데이터베이스에 저장해야 하는 경우입니다.
-이를 위해, **FastAPI** 에서는 `jsonable_encoder()` 함수를 제공합니다.
+이를 위해, **FastAPI**에서는 `jsonable_encoder()` 함수를 제공합니다.
-## `jsonable_encoder` 사용
+## `jsonable_encoder` 사용 { #using-the-jsonable-encoder }
JSON 호환 가능 데이터만 수신하는 `fake_db` 데이터베이스가 존재한다고 가정하겠습니다.
-예를 들면, `datetime` 객체는 JSON과 호환되는 데이터가 아니므로 이 데이터는 받아들여지지 않습니다.
+예를 들면, `datetime` 객체는 JSON과 호환되지 않으므로 이 데이터베이스는 이를 받지 않습니다.
-따라서 `datetime` 객체는 <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO format</a> 데이터를 포함하는 `str`로 변환되어야 합니다.
+따라서 `datetime` 객체는 <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO format</a>의 데이터를 포함하는 `str`로 변환되어야 합니다.
-같은 방식으로 이 데이터베이스는 Pydantic 모델(속성이 있는 객체)을 받지 않고, `dict` 만을 받습니다.
+같은 방식으로 이 데이터베이스는 Pydantic 모델(속성이 있는 객체)을 받지 않고, `dict`만을 받습니다.
-이를 위해 `jsonable_encoder` 를 사용할 수 있습니다.
+이를 위해 `jsonable_encoder`를 사용할 수 있습니다.
-Pydantic 모델과 같은 객체를 받고 JSON 호환 가능한 버전으로 반환합니다:
+Pydantic 모델 같은 객체를 받고 JSON 호환 가능한 버전을 반환합니다:
-{* ../../docs_src/encoder/tutorial001.py hl[5,22] *}
+{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
-이 예시는 Pydantic 모델을 `dict`로, `datetime` 형식을 `str`로 변환합니다.
+이 예시에서는 Pydantic 모델을 `dict`로, `datetime`을 `str`로 변환합니다.
-이렇게 호출한 결과는 파이썬 표준인 <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>로 인코딩 할 수 있습니다.
+이렇게 호출한 결과는 파이썬 표준인 <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>로 인코딩할 수 있습니다.
-길이가 긴 문자열 형태의 JSON 형식(문자열)의 데이터가 들어있는 상황에서는 `str`로 반환하지 않습니다. JSON과 모두 호환되는 값과 하위 값이 있는 Python 표준 데이터 구조 (예: `dict`)를 반환합니다.
+JSON 형식(문자열)의 데이터가 들어있는 큰 `str`을 반환하지 않습니다. JSON과 모두 호환되는 값과 하위 값이 있는 파이썬 표준 데이터 구조(예: `dict`)를 반환합니다.
/// note | 참고
-실제로 `jsonable_encoder`는 **FastAPI** 에서 내부적으로 데이터를 변환하는 데 사용하지만, 다른 많은 곳에서도 이는 유용합니다.
+`jsonable_encoder`는 실제로 **FastAPI**에서 내부적으로 데이터를 변환하는 데 사용하지만, 다른 많은 시나리오에서도 유용합니다.
///
-# 추가 데이터 자료형
+# 추가 데이터 자료형 { #extra-data-types }
지금까지 일반적인 데이터 자료형을 사용했습니다. 예를 들면 다음과 같습니다:
* 데이터 검증.
* 자동 어노테이션과 문서화.
-## 다른 데이터 자료형
+## 다른 데이터 자료형 { #other-data-types }
아래의 추가적인 데이터 자료형을 사용할 수 있습니다:
* `datetime.timedelta`:
* 파이썬의 `datetime.timedelta`.
* 요청과 응답에서 전체 초(seconds)의 `float`로 표현됩니다.
- * Pydantic은 "ISO 8601 시차 인코딩"으로 표현하는 것 또한 허용합니다. <a href="https://docs.pydantic.dev/latest/concepts/serialization/#json_encoders" class="external-link" target="_blank">더 많은 정보는 이 문서에서 확인하십시오.</a>.
+ * Pydantic은 "ISO 8601 time diff encoding"으로 표현하는 것 또한 허용합니다. <a href="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers" class="external-link" target="_blank">더 많은 정보는 문서를 확인하세요</a>.
* `frozenset`:
* 요청과 응답에서 `set`와 동일하게 취급됩니다:
* 요청 시, 리스트를 읽어 중복을 제거하고 `set`로 변환합니다.
* `Decimal`:
* 표준 파이썬의 `Decimal`.
* 요청과 응답에서 `float`와 동일하게 다뤄집니다.
-* 여기에서 모든 유효한 pydantic 데이터 자료형을 확인할 수 있습니다: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Pydantic 데이터 자료형</a>.
+* 여기에서 모든 유효한 Pydantic 데이터 자료형을 확인할 수 있습니다: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Pydantic 데이터 자료형</a>.
-## 예시
+## 예시 { #example }
-ì\9c\84ì\9d\98 ëª\87ëª\87 ì\9e\90ë£\8cí\98\95ì\9d\84 매ê°\9cë³\80ì\88\98ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 *ê²½ë¡\9c ì\9e\91ë\8f\99* 예시입니다.
+ì\9c\84ì\9d\98 ëª\87ëª\87 ì\9e\90ë£\8cí\98\95ì\9d\84 매ê°\9cë³\80ì\88\98ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 *ê²½ë¡\9c ì²\98리* 예시입니다.
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
-# 추가 모델
+# 추가 모델 { #extra-models }
-지난 예제에 이어서, 연관된 모델을 여러개 갖는 것은 흔한 일입니다.
+지난 예제에 이어서, 연관된 모델을 여러 개 갖는 것은 흔한 일입니다.
특히 사용자 모델의 경우에 그러한데, 왜냐하면:
-* **입력 모델** 은 비밀번호를 가져야 합니다.
-* **출력 모델** 은 비밀번호를 가지면 안됩니다.
-* **데이터베이스 모델** 은 해시처리된 비밀번호를 가질 것입니다.
+* **입력 모델**은 비밀번호를 가질 수 있어야 합니다.
+* **출력 모델**은 비밀번호를 가지면 안 됩니다.
+* **데이터베이스 모델**은 아마도 해시 처리된 비밀번호를 가질 필요가 있을 것입니다.
/// danger | 위험
절대 사용자의 비밀번호를 평문으로 저장하지 마세요. 항상 이후에 검증 가능한 "안전한 해시(secure hash)"로 저장하세요.
-만약 이게 무엇인지 모르겠다면, [security chapters](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.에서 비밀번호 해시에 대해 배울 수 있습니다.
+만약 이게 무엇인지 모르겠다면, [security chapters](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}에서 "password hash"가 무엇인지 배울 수 있습니다.
///
-## 다중 모델
+## 다중 모델 { #multiple-models }
아래는 비밀번호 필드와 해당 필드가 사용되는 위치를 포함하여, 각 모델들이 어떤 형태를 가질 수 있는지 전반적인 예시입니다:
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
+### `**user_in.model_dump()` 에 대하여 { #about-user-in-model-dump }
-/// info | 정보
-
-Pydantic v1에서는 해당 메서드가 `.dict()`로 불렸으며, Pydantic v2에서는 `.model_dump()`로 이름이 변경되었습니다. `.dict()`는 여전히 지원되지만 더 이상 권장되지 않습니다.
-
-여기에서 사용하는 예제는 Pydantic v1과의 호환성을 위해 `.dict()`를 사용하지만, Pydantic v2를 사용할 수 있다면 `.model_dump()`를 사용하는 것이 좋습니다.
-
-///
-
-### `**user_in.dict()` 에 대하여
-
-#### Pydantic의 `.dict()`
+#### Pydantic의 `.model_dump()` { #pydantics-model-dump }
`user_in`은 Pydantic 모델 클래스인 `UserIn`입니다.
-Pydantic 모델은 모델 데이터를 포함한 `dict`를 반환하는 `.dict()` 메서드를 제공합니다.
+Pydantic 모델은 모델 데이터를 포함한 `dict`를 반환하는 `.model_dump()` 메서드를 제공합니다.
따라서, 다음과 같이 Pydantic 객체 `user_in`을 생성할 수 있습니다:
그 다음, 다음과 같이 호출합니다:
```Python
-user_dict = user_in.dict()
+user_dict = user_in.model_dump()
```
이제 변수 `user_dict`에 데이터가 포함된 `dict`를 가지게 됩니다(이는 Pydantic 모델 객체가 아닌 `dict`입니다).
}
```
-#### `dict` 언패킹(Unpacking)
+#### `dict` 언패킹 { #unpacking-a-dict }
`user_dict`와 같은 `dict`를 함수(또는 클래스)에 `**user_dict`로 전달하면, Python은 이를 "언팩(unpack)"합니다. 이 과정에서 `user_dict`의 키와 값을 각각 키-값 인자로 직접 전달합니다.
)
```
-#### 다른 모델 데이터로 새 Pydantic 모델 생성
+#### 다른 모델 데이터로 새 Pydantic 모델 생성 { #a-pydantic-model-from-the-contents-of-another }
-위의 예제에서 `user_in.dict()`로부터 `user_dict`를 생성한 것처럼, 아래 코드는:
+위의 예제에서 `user_in.model_dump()`로부터 `user_dict`를 생성한 것처럼, 아래 코드는:
```Python
-user_dict = user_in.dict()
+user_dict = user_in.model_dump()
UserInDB(**user_dict)
```
다음과 동일합니다:
```Python
-UserInDB(**user_in.dict())
+UserInDB(**user_in.model_dump())
```
-...왜냐하면 `user_in.dict()`는 `dict`이며, 이를 `**`로 Python이 "언팩(unpack)"하도록 하여 `UserInDB`에 전달하기 때문입니다.
+...왜냐하면 `user_in.model_dump()`는 `dict`이며, 이를 `**`로 Python이 "언팩(unpack)"하도록 하여 `UserInDB`에 전달하기 때문입니다.
따라서, 다른 Pydantic 모델의 데이터를 사용하여 새로운 Pydantic 모델을 생성할 수 있습니다.
-#### `dict` 언패킹(Unpacking)과 추가 키워드
+#### `dict` 언패킹과 추가 키워드 { #unpacking-a-dict-and-extra-keywords }
그리고 다음과 같이 추가 키워드 인자 `hashed_password=hashed_password`를 추가하면:
```Python
-UserInDB(**user_in.dict(), hashed_password=hashed_password)
+UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
```
다음과 같은 결과를 생성합니다:
///
-## 중복 줄이기
+## 중복 줄이기 { #reduce-duplication }
코드 중복을 줄이는 것은 **FastAPI**의 핵심 아이디어 중 하나입니다.
모든 데이터 변환, 검증, 문서화 등은 정상적으로 작동할 것입니다.
-이렇게 하면 각 모델 간의 차이점만 선언할 수 있습니다(평문 `password`가 있는 경우, `hashed_password`만 있는 경우, 혹은 비밀번호가 없는 경우):
+이렇게 하면 각 모델 간의 차이점만 선언할 수 있습니다(평문 `password`, `hashed_password`, 그리고 비밀번호가 없는 경우):
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
-## `Union` 또는 `anyOf`
+## `Union` 또는 `anyOf` { #union-or-anyof }
두 가지 이상의 타입을 포함하는 `Union`으로 응답을 선언할 수 있습니다. 이는 응답이 그 중 하나의 타입일 수 있음을 의미합니다.
/// note | 참고
-<a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>을 정의할때는 더 구체적인 타입을 먼저 포함하고, 덜 구체적인 타입을 그 뒤에 나열해야합니다. 아래 예제에서는 `Union[PlaneItem, CarItem]` 를 보면, 더 구체적인 `PlaneItem`이 `CarItem`보다 앞에 위치합니다.
+<a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>을 정의할 때는 더 구체적인 타입을 먼저 포함하고, 덜 구체적인 타입을 그 뒤에 나열해야 합니다. 아래 예제에서는 `Union[PlaneItem, CarItem]`에서 더 구체적인 `PlaneItem`이 `CarItem`보다 앞에 위치합니다.
///
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
-
-### Python 3.10에서 `Union`
+### Python 3.10에서 `Union` { #union-in-python-3-10 }
위의 예제에서는 `response_model` 인자 값으로 `Union[PlaneItem, CarItem]`을 전달합니다.
-이 경우, 이를 **타입 어노테이션(type annotation)** 이 아닌 **인자 값(argument value)** 으로 전달하고 있기 때문에 Python 3.10에서도 `Union`을 사용해야 합니다.
+이 경우, 이를 **타입 어노테이션(type annotation)**이 아닌 **인자 값(argument value)**으로 전달하고 있기 때문에 Python 3.10에서도 `Union`을 사용해야 합니다.
만약 타입 어노테이션에 사용한다면, 다음과 같이 수직 막대(|)를 사용할 수 있습니다:
some_variable: PlaneItem | CarItem
```
-하지만 이를 `response_model=PlaneItem | CarItem`과 같이 할당하면 에러가 발생합니다. 이는 Python이 이를 타입 어노테이션으로 해석하지 않고, `PlaneItem`과 `CarItem` 사이의 **잘못된 연산(invalid operation)**을 시도하기 때문입니다
+하지만 이를 `response_model=PlaneItem | CarItem`과 같이 할당하면 에러가 발생합니다. 이는 Python이 이를 타입 어노테이션으로 해석하지 않고, `PlaneItem`과 `CarItem` 사이의 **잘못된 연산(invalid operation)**을 시도하기 때문입니다.
-## 모델 리스트
+## 모델 리스트 { #list-of-models }
마찬가지로, 객체 리스트 형태의 응답을 선언할 수도 있습니다.
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
-
-## 임의의 `dict` 응답
+## 임의의 `dict` 응답 { #response-with-arbitrary-dict }
Pydantic 모델을 사용하지 않고, 키와 값의 타입만 선언하여 평범한 임의의 `dict`로 응답을 선언할 수도 있습니다.
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
-
-## 요약
+## 요약 { #recap }
여러 Pydantic 모델을 사용하고, 각 경우에 맞게 자유롭게 상속하세요.
-엔터티가 서로 다른 "상태"를 가져야 하는 경우, 엔터티당 단일 데이터 모델을 사용할 필요는 없습니다. 예를 들어, 사용자 "엔터티"가 `password`, `password_hash`, 또는 비밀번호가 없는 상태를 포함할 수 있는 경우처럼 말입니다.
+엔터티가 서로 다른 "상태"를 가져야 하는 경우, 엔터티당 단일 데이터 모델을 사용할 필요는 없습니다. 예를 들어, 사용자 "엔터티"가 `password`, `password_hash`, 그리고 비밀번호가 없는 상태를 포함할 수 있는 경우처럼 말입니다.
-# 첫걸음
+# 첫걸음 { #first-steps }
가장 단순한 FastAPI 파일은 다음과 같이 보일 것입니다:
-{* ../../docs_src/first_steps/tutorial001.py *}
+{* ../../docs_src/first_steps/tutorial001_py39.py *}
위 코드를 `main.py`에 복사합니다.
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-<span style="color: green;">INFO</span>: Started reloader process [28720]
-<span style="color: green;">INFO</span>: Started server process [28722]
-<span style="color: green;">INFO</span>: Waiting for application startup.
-<span style="color: green;">INFO</span>: Application startup complete.
-```
+ <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
-</div>
+ 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>
-/// note | 참고
+ <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
-`uvicorn main:app` 명령은 다음을 의미합니다:
+ <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
+ the following code:
-* `main`: 파일 `main.py` (파이썬 "모듈").
-* `app`: `main.py` 내부의 `app = FastAPI()` 줄에서 생성한 오브젝트.
-* `--reload`: 코드 변경 시 자동으로 서버 재시작. 개발 시에만 사용.
+ <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
-///
+ <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
+ <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
+ <b>fastapi run</b>
+
+ Logs:
+
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
+ <b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
+ to quit<b>)</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
+```
+
+</div>
출력되는 줄들 중에는 아래와 같은 내용이 있습니다:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
-해당 줄은 로컬에서 앱이 서비스되는 URL을 보여줍니다.
+해당 줄은 로컬 머신에서 앱이 서비스되는 URL을 보여줍니다.
-### 확인하기
+### 확인하기 { #check-it }
브라우저로 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>를 여세요.
{"message": "Hello World"}
```
-### 대화형 API 문서
+### 대화형 API 문서 { #interactive-api-docs }
이제 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 가봅니다.

-### 대안 API 문서
+### 대안 API 문서 { #alternative-api-docs }
그리고 이제, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 가봅니다.

-### OpenAPI
+### OpenAPI { #openapi }
**FastAPI**는 API를 정의하기 위한 **OpenAPI** 표준을 사용하여 여러분의 모든 API를 이용해 "스키마"를 생성합니다.
-#### "스키마"
+#### "스키마" { #schema }
"스키마"는 무언가의 정의 또는 설명입니다. 이를 구현하는 코드가 아니라 추상적인 설명일 뿐입니다.
-#### API "스키마"
+#### API "스키마" { #api-schema }
<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>는 API의 스키마를 어떻게 정의하는지 지시하는 규격입니다.
이 스키마 정의는 API 경로, 가능한 매개변수 등을 포함합니다.
-#### 데이터 "스키마"
+#### 데이터 "스키마" { #data-schema }
"스키마"라는 용어는 JSON처럼 어떤 데이터의 형태를 나타낼 수도 있습니다.
이러한 경우 JSON 속성, 가지고 있는 데이터 타입 등을 뜻합니다.
-#### OpenAPI와 JSON 스키마
+#### OpenAPI와 JSON 스키마 { #openapi-and-json-schema }
OpenAPI는 당신의 API에 대한 API 스키마를 정의합니다. 또한 이 스키마는 JSON 데이터 스키마의 표준인 **JSON 스키마**를 사용하여 당신의 API가 보내고 받는 데이터의 정의(또는 "스키마")를 포함합니다.
-#### `openapi.json` 확인
+#### `openapi.json` 확인 { #check-the-openapi-json }
-FastAPI는 자동으로 API의 설명과 함께 JSON (스키마)를 생성합니다.
+가공되지 않은 OpenAPI 스키마가 어떻게 생겼는지 궁금하다면, FastAPI는 자동으로 여러분의 모든 API에 대한 설명과 함께 JSON (스키마)를 생성합니다.
-가공되지 않은 OpenAPI 스키마가 어떻게 생겼는지 궁금하다면, 여기에서 직접 볼 수 있습니다: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
+여기에서 직접 볼 수 있습니다: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
다음과 같이 시작하는 JSON을 확인할 수 있습니다:
```JSON
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
...
```
-#### OpenAPI의 용도
+#### OpenAPI의 용도 { #what-is-openapi-for }
OpenAPI 스키마는 포함된 두 개의 대화형 문서 시스템을 제공합니다.
API와 통신하는 클라이언트(프론트엔드, 모바일, IoT 애플리케이션 등)를 위해 코드를 자동으로 생성하는 데도 사용할 수 있습니다.
-## 단계별 요약
-
-### 1 단계: `FastAPI` 임포트
-
-{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
-
-`FastAPI`는 당신의 API를 위한 모든 기능을 제공하는 파이썬 클래스입니다.
+### 앱 배포하기(선택 사항) { #deploy-your-app-optional }
-/// note | 기술 세부사항
+선택적으로 FastAPI 앱을 <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>에 배포할 수 있습니다. 아직 대기자 명단에 등록하지 않았다면, 등록하러 가세요. 🚀
-`FastAPI`는 `Starlette`를 직접 상속하는 클래스입니다.
+이미 **FastAPI Cloud** 계정이 있다면(대기자 명단에서 초대해 드렸습니다 😉), 한 번의 명령으로 애플리케이션을 배포할 수 있습니다.
-`FastAPI`로 <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>의 모든 기능을 사용할 수 있습니다.
+배포하기 전에, 로그인되어 있는지 확인하세요:
-///
-
-### 2 단계: `FastAPI` "인스턴스" 생성
+<div class="termy">
-{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
+```console
+$ fastapi login
-여기에서 `app` 변수는 `FastAPI` 클래스의 "인스턴스"가 됩니다.
+You are logged in to FastAPI Cloud 🚀
+```
-이것은 당신의 모든 API를 생성하기 위한 상호작용의 주요 지점이 될 것입니다.
+</div>
-이 `app`은 다음 명령에서 `uvicorn`이 참조하고 있는 것과 동일합니다:
+그 다음 앱을 배포합니다:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ fastapi deploy
+
+Deploying to FastAPI Cloud...
+
+✅ Deployment successful!
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
-ì\95\84ë\9e\98ì²\98ë\9f¼ ì\95±ì\9d\84 ë§\8cë\93 ë\8b¤ë©´:
+ì\9d´ê²\8c ì \84ë¶\80ì\9e\85ë\8b\88ë\8b¤! ì\9d´ì \9c í\95´ë\8b¹ URLì\97\90ì\84\9c ì\95±ì\97\90 ì \91ê·¼í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. â\9c¨
-{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
+## 단계별 요약 { #recap-step-by-step }
-이를 `main.py` 파일에 넣고, `uvicorn`을 아래처럼 호출해야 합니다:
+### 1 단계: `FastAPI` 임포트 { #step-1-import-fastapi }
-<div class="termy">
+{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
-```console
-$ uvicorn main:my_awesome_api --reload
+`FastAPI`는 당신의 API를 위한 모든 기능을 제공하는 파이썬 클래스입니다.
-<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
+/// note | 기술 세부사항
-</div>
+`FastAPI`는 `Starlette`를 직접 상속하는 클래스입니다.
-### 3 단계: *경로 작동* 생성
+`FastAPI`로 <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>의 모든 기능을 사용할 수 있습니다.
+
+///
+
+### 2 단계: `FastAPI` "인스턴스" 생성 { #step-2-create-a-fastapi-instance }
-#### 경로
+{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
+
+여기에서 `app` 변수는 `FastAPI` 클래스의 "인스턴스"가 됩니다.
+
+이것은 당신의 모든 API를 생성하기 위한 상호작용의 주요 지점이 될 것입니다.
+
+### 3 단계: *경로 처리* 생성 { #step-3-create-a-path-operation }
+
+#### 경로 { #path }
여기서 "경로"는 첫 번째 `/`부터 시작하는 URL의 뒷부분을 의미합니다.
API를 설계할 때 "경로"는 "관심사"와 "리소스"를 분리하기 위한 주요한 방법입니다.
-#### 작동
+#### 작동 { #operation }
"작동(Operation)"은 HTTP "메소드" 중 하나를 나타냅니다.
우리 역시 이제부터 메소드를 "**작동**"이라고 부를 것입니다.
-#### *ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°* ì \95ì\9d\98
+#### *ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°* ì \95ì\9d\98 { #define-a-path-operation-decorator }
-{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
+{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
-`@app.get("/")`은 **FastAPI**에게 바로 아래에 있는 함수가 다음으로 이동하는 요청을 처리한다는 것을 알려줍니다.
+`@app.get("/")`은 **FastAPI**에게 바로 아래에 있는 함수가 다음으로 이동하는 요청을 처리한다는 것을 알려줍니다:
* 경로 `/`
-* <abbr title="HTTP GET 메소드"><code>get</code> 작동</abbr> 사용
+* <abbr title="an HTTP GET method"><code>get</code> operation</abbr> 사용
/// info | `@decorator` 정보
우리의 경우, 이 데코레이터는 **FastAPI**에게 아래 함수가 **경로** `/`의 `get` **작동**에 해당한다고 알려줍니다.
-ì\9d´ê²\83ì\9d´ "**ê²½ë¡\9c ì\9e\91ë\8f\99 데코레이터**"입니다.
+ì\9d´ê²\83ì\9d´ "**ê²½ë¡\9c ì²\98리 데코레이터**"입니다.
///
///
-### 4 ë\8b¨ê³\84: **ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98** ì \95ì\9d\98
+### 4 ë\8b¨ê³\84: **ê²½ë¡\9c ì²\98리 í\95¨ì\88\98** ì \95ì\9d\98 { #step-4-define-the-path-operation-function }
-ë\8b¤ì\9d\8cì\9d\80 ì\9a°ë¦¬ì\9d\98 "**ê²½ë¡\9c ì\9e\91ë\8f\99 함수**"입니다:
+ë\8b¤ì\9d\8cì\9d\80 ì\9a°ë¦¬ì\9d\98 "**ê²½ë¡\9c ì²\98리 함수**"입니다:
* **경로**: 는 `/`입니다.
* **작동**: 은 `get`입니다.
* **함수**: 는 "데코레이터" 아래에 있는 함수입니다 (`@app.get("/")` 아래).
-{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
이것은 파이썬 함수입니다.
`async def`을 이용하는 대신 일반 함수로 정의할 수 있습니다:
-{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
/// note | 참고
-차이점을 모르겠다면 [Async: *"바쁘신 경우"*](../async.md#_1){.internal-link target=_blank}을 확인하세요.
+차이점을 모르겠다면 [Async: *"바쁘신 경우"*](../async.md#in-a-hurry){.internal-link target=_blank}를 확인하세요.
///
-### 5 단계: 콘텐츠 반환
+### 5 단계: 콘텐츠 반환 { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
`dict`, `list`, 단일값을 가진 `str`, `int` 등을 반환할 수 있습니다.
JSON으로 자동 변환되는 객체들과 모델들(ORM 등을 포함해서)이 많이 있습니다. 가장 마음에 드는 것을 사용하십시오, 이미 지원되고 있을 것입니다.
-## 요약
+### 6 단계: 배포하기 { #step-6-deploy-it }
+
+한 번의 명령으로 **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**에 앱을 배포합니다: `fastapi deploy`. 🎉
+
+#### FastAPI Cloud 소개 { #about-fastapi-cloud }
+
+**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**는 **FastAPI** 뒤에 있는 동일한 작성자와 팀이 만들었습니다.
+
+최소한의 노력으로 API를 **빌드**, **배포**, **접근**하는 과정을 간소화합니다.
+
+FastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**할 때도 제공합니다. 🎉
+
+FastAPI Cloud는 *FastAPI와 친구들* 오픈 소스 프로젝트의 주요 스폰서이자 자금 제공자입니다. ✨
+
+#### 다른 클라우드 제공업체에 배포하기 { #deploy-to-other-cloud-providers }
+
+FastAPI는 오픈 소스이며 표준을 기반으로 합니다. 선택한 어떤 클라우드 제공업체에도 FastAPI 앱을 배포할 수 있습니다.
+
+클라우드 제공업체의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓
+
+## 요약 { #recap }
* `FastAPI` 임포트.
* `app` 인스턴스 생성.
-* (`@app.get("/")`처럼) **경로 작동 데코레이터** 작성.
-* (위에 있는 `def root(): ...`처럼) **경로 작동 함수** 작성.
-* (`uvicorn main:app --reload`처럼) 개발 서버 실행.
+* (`@app.get("/")`처럼) **경로 처리 데코레이터** 작성.
+* (위에 있는 `def root(): ...`처럼) **경로 처리 함수** 작성.
+* `fastapi dev` 명령으로 개발 서버 실행.
+* 선택적으로 `fastapi deploy`로 앱 배포.
-# 헤더 매개변수 모델
+# 헤더 매개변수 모델 { #header-parameter-models }
관련 있는 **헤더 매개변수** 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다.
///
-## Pydantic 모델을 사용한 헤더 매개변수
+## Pydantic 모델을 사용한 헤더 매개변수 { #header-parameters-with-a-pydantic-model }
**Pydantic 모델**에 필요한 **헤더 매개변수**를 선언한 다음, 해당 매개변수를 `Header`로 선언합니다:
**FastAPI**는 요청에서 받은 **헤더**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
-## 문서 확인하기
+## 문서 확인하기 { #check-the-docs }
문서 UI `/docs`에서 필요한 헤더를 볼 수 있습니다:
<img src="/img/tutorial/header-param-models/image01.png">
</div>
-## 추가 헤더 금지하기
+## 추가 헤더 금지하기 { #forbid-extra-headers }
일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 헤더를 **제한**할 수 있습니다.
}
```
-## 요약
+## 밑줄 변환 비활성화하기 { #disable-convert-underscores }
+
+일반적인 헤더 매개변수와 마찬가지로, 매개변수 이름에 밑줄 문자가 있으면 **자동으로 하이픈으로 변환**됩니다.
+
+예를 들어, 코드에 `save_data` 헤더 매개변수가 있으면, 기대되는 HTTP 헤더는 `save-data`이고, 문서에서도 그렇게 표시됩니다.
+
+어떤 이유로든 이 자동 변환을 비활성화해야 한다면, 헤더 매개변수용 Pydantic 모델에서도 비활성화할 수 있습니다.
+
+{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
+
+/// warning | 경고
+
+`convert_underscores`를 `False`로 설정하기 전에, 일부 HTTP 프록시와 서버에서는 밑줄이 포함된 헤더 사용을 허용하지 않는다는 점을 염두에 두세요.
+
+///
+
+## 요약 { #summary }
**Pydantic 모델**을 사용하여 **FastAPI**에서 **헤더**를 선언할 수 있습니다. 😎
-# 헤더 매개변수
+# 헤더 매개변수 { #header-parameters }
헤더 매개변수를 `Query`, `Path` 그리고 `Cookie` 매개변수들과 같은 방식으로 정의할 수 있습니다.
-## `Header` 임포트
+## `Header` 임포트 { #import-header }
먼저 `Header`를 임포트합니다:
-{* ../../docs_src/header_params/tutorial001.py hl[3] *}
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
-## `Header` 매개변수 선언
+## `Header` 매개변수 선언 { #declare-header-parameters }
`Path`, `Query` 그리고 `Cookie`를 사용한 동일한 구조를 이용하여 헤더 매개변수를 선언합니다.
첫 번째 값은 기본값이며, 추가 검증이나 어노테이션 매개변수 모두 전달할 수 있습니다:
-{* ../../docs_src/header_params/tutorial001.py hl[9] *}
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
/// note | 기술 세부사항
///
-## 자동 변환
+## 자동 변환 { #automatic-conversion }
`Header`는 `Path`, `Query` 그리고 `Cookie`가 제공하는 것 외에 기능이 조금 더 있습니다.
만약 언더스코어를 하이픈으로 자동 변환을 비활성화해야 할 어떤 이유가 있다면, `Header`의 `convert_underscores` 매개변수를 `False`로 설정하십시오:
-{* ../../docs_src/header_params/tutorial002.py hl[10] *}
+{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
/// warning | 경고
-`convert_underscore`를 `False`로 설정하기 전에, 어떤 HTTP 프록시들과 서버들은 언더스코어가 포함된 헤더 사용을 허락하지 않는다는 것을 명심하십시오.
+`convert_underscores`를 `False`로 설정하기 전에, 어떤 HTTP 프록시들과 서버들은 언더스코어가 포함된 헤더 사용을 허락하지 않는다는 것을 명심하십시오.
///
-## 중복 헤더
+## 중복 헤더 { #duplicate-headers }
중복 헤더들을 수신할 수 있습니다. 즉, 다중값을 갖는 동일한 헤더를 뜻합니다.
예를 들어, 두 번 이상 나타날 수 있는 `X-Token`헤더를 선언하려면, 다음과 같이 작성합니다:
-{* ../../docs_src/header_params/tutorial003.py hl[9] *}
+{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
-다음과 같은 두 개의 HTTP 헤더를 전송하여 해당 *경로* 와 통신할 경우:
+다음과 같은 두 개의 HTTP 헤더를 전송하여 해당 *경로 처리* 와 통신할 경우:
```
X-Token: foo
}
```
-## 요약
+## 요약 { #recap }
`Header`는 `Query`, `Path`, `Cookie`와 동일한 패턴을 사용하여 선언합니다.
-# 자습서 - 사용자 안내서
+# 자습서 - 사용자 안내서 { #tutorial-user-guide }
-이 자습서는 단계별로 **FastAPI**의 대부분의 기능에 대해 설명합니다.
+이 자습서는 **FastAPI**의 대부분의 기능을 단계별로 사용하는 방법을 보여줍니다.
-ê°\81 ì\84¹ì\85\98ì\9d\80 ì\9d´ì \84 ì\84¹ì\85\98ì\97\90 기ë°\98í\95\98ë\8a\94 ì\88\9cì°¨ì \81ì\9d¸ 구조ë¡\9c ì\9e\91ì\84±ë\90\98ì\97\88ì§\80ë§\8c, ê°\81 주ì \9cë¡\9c 구ë¶\84ë\90\98ì\96´ ì\9e\88기 ë\95\8c문ì\97\90 í\95\84ì\9a\94ì\97\90 ë\94°ë\9d¼ í\8a¹ì \95 ì\84¹ì\85\98ì\9c¼ë¡\9c ë°\94ë¡\9c ì\9d´ë\8f\99í\95\98ì\97¬ í\95\84ì\9a\94í\95\9c ë\82´ì\9a©ì\9d\84 ë°\94ë¡\9c í\99\95ì\9d¸할 수 있습니다.
+ê°\81 ì\84¹ì\85\98ì\9d\80 ì\9d´ì \84 ì\84¹ì\85\98ì\9d\84 ë°\94í\83\95ì\9c¼ë¡\9c ì \90ì§\84ì \81ì\9c¼ë¡\9c 구ì\84±ë\90\98ì§\80ë§\8c, 주ì \9c를 ë¶\84리í\95\9c 구조ë¡\9c ë\90\98ì\96´ ì\9e\88ì\96´ í\8a¹ì \95 API ì\9a\94구ì\82¬í\95ì\9d\84 í\95´ê²°í\95\98기 ì\9c\84í\95´ ì\9b\90í\95\98ë\8a\94 ì\84¹ì\85\98ì\9c¼ë¡\9c ë°\94ë¡\9c ì\9d´ë\8f\99할 수 있습니다.
-또한 í\96¥í\9b\84ì\97\90ë\8f\84 참조 ì\9e\90ë£\8cë¡\9c ì\93°ì\9d¼ ì\88\98 ì\9e\88ë\8f\84ë¡\9d ì\9e\91ì\84±ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤.
+또한 ë\82\98ì¤\91ì\97\90 ì°¸ê³ ì\9e\90ë£\8cë¡\9cë\8f\84 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d ë§\8cë\93¤ì\96´ì¡\8cì\9c¼ë¯\80ë¡\9c, í\95\84ì\9a\94í\95 ë\95\8c ë\8b¤ì\8b\9c ë\8f\8cì\95\84ì\99\80 ì \95í\99\95í\9e\88 í\95\84ì\9a\94í\95\9c ë\82´ì\9a©ì\9d\84 í\99\95ì\9d¸í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-그러므로 필요할 때에 다시 돌아와서 원하는 것을 정확히 찾을 수 있습니다.
+## 코드 실행하기 { #run-the-code }
-## 코드 실행하기
+모든 코드 블록은 복사해서 바로 사용할 수 있습니다(실제로 테스트된 Python 파일입니다).
-모든 코드 블록은 복사하여 바로 사용할 수 있습니다(실제로 테스트된 파이썬 파일입니다).
-
-예제를 실행하려면 코드를 `main.py` 파일에 복사하고 다음을 사용하여 `uvicorn`을 시작합니다:
+예제 중 어떤 것이든 실행하려면, 코드를 `main.py` 파일에 복사하고 다음으로 `fastapi dev`를 시작하세요:
<div class="termy">
```console
-$ uvicorn main:app --reload
+$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
+
+ <span style="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="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-<span style="color: green;">INFO</span>: Started reloader process [28720]
-<span style="color: green;">INFO</span>: Started server process [28722]
-<span style="color: green;">INFO</span>: Waiting for application startup.
-<span style="color: green;">INFO</span>: Application startup complete.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
+ <b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
+ to quit<b>)</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
+ <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
```
</div>
-코드를 작성하거나 복사, 편집할 때, 로컬 환경에서 실행하는 것을 **강력히 권장**합니다.
-
-로컬 편집기에서 사용한다면, 모든 타입 검사와 자동완성 등 작성해야 하는 코드가 얼마나 적은지 보면서 FastAPI의 이점을 비로소 경험할 수 있습니다.
+코드를 작성하거나 복사한 뒤 편집하고, 로컬에서 실행하는 것을 **강력히 권장**합니다.
+에디터에서 사용해 보면, 작성해야 하는 코드가 얼마나 적은지, 모든 타입 검사와 자동완성 등 FastAPI의 이점을 제대로 확인할 수 있습니다.
---
-## FastAPI 설치
+## FastAPI 설치 { #install-fastapi }
-첫 ë²\88째 ë\8b¨ê³\84ë\8a\94 FastAPI를 ì\84¤ì¹\98í\95\98ë\8a\94 ê²\83ì\9e\85ë\8b\88ë\8b¤.
+첫 단계는 FastAPI를 설치하는 것입니다.
-자습시에는 모든 선택적인 의존성 및 기능을 함께 설치하는 것을 추천합니다:
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, **FastAPI를 설치**하세요:
<div class="termy">
```console
-$ pip install "fastapi[all]"
+$ pip install "fastapi[standard]"
---> 100%
```
</div>
-...이는 코드를 실행하는 서버로 사용할 수 있는 `uvicorn` 또한 포함하고 있습니다.
-
/// note | 참고
-부분적으로 설치할 수도 있습니다.
-
-애플리케이션을 운영 환경에 배포하려는 경우 다음과 같이 합니다:
+`pip install "fastapi[standard]"`로 설치하면 `fastapi-cloud-cli`를 포함한 몇 가지 기본 선택적 standard 의존성이 함께 설치되며, 이를 사용해 <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>에 배포할 수 있습니다.
-```
-pip install fastapi
-```
-
-추가로 서버 역할을 하는 `uvicorn`을 설치합니다:
-
-```
-pip install uvicorn
-```
+이러한 선택적 의존성이 필요 없다면 `pip install fastapi`로 대신 설치할 수 있습니다.
-사용하려는 각 선택적인 의존성에 대해서도 동일합니다.
+standard 의존성은 설치하되 `fastapi-cloud-cli` 없이 설치하려면 `pip install "fastapi[standard-no-fastapi-cloud-cli]"`로 설치할 수 있습니다.
///
-## 고급 사용자 안내서
+## 고급 사용자 안내서 { #advanced-user-guide }
-이 **자습서 - 사용자 안내서** 다음에 읽을 수 있는 **고급 사용자 안내서**도 있습니다.
+이 **자습서 - 사용자 안내서**를 읽은 뒤에 나중에 읽을 수 있는 **고급 사용자 안내서**도 있습니다.
-**고급 사용자 안내서**는 현재 문서를 기반으로 하고, 동일한 개념을 사용하며, 추가적인 기능들에 대해 설명합니다.
+**고급 사용자 안내서**는 이 문서를 바탕으로 동일한 개념을 사용하며, 몇 가지 추가 기능을 알려줍니다.
-하지만 (지금 읽고 있는) **자습서 - 사용자 안내서**를 먼저 읽는 것을 권장합니다.
+하지만 먼저 **자습서 - 사용자 안내서**(지금 읽고 있는 내용)를 읽어야 합니다.
-**자습서 - 사용자 안내서**만으로도 완전한 애플리케이션을 구축할 수 있도록 작성되었으며, 필요에 따라 **고급 사용자 안내서**의 추가적인 아이디어를 적용하여 다양한 방식으로 확장할 수 있습니다.
+**자습서 - 사용자 안내서**만으로 완전한 애플리케이션을 만들 수 있도록 설계되었고, 필요에 따라 **고급 사용자 안내서**의 추가 아이디어를 활용해 다양한 방식으로 확장할 수 있습니다.
-# 메타데이터 및 문서화 URL
+# 메타데이터 및 문서화 URL { #metadata-and-docs-urls }
-**FastAPI** ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다.
+**FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다.
-## API에 대한 메타데이터
+## API에 대한 메타데이터 { #metadata-for-api }
OpenAPI 명세 및 자동화된 API 문서 UI에 사용되는 다음 필드를 설정할 수 있습니다:
| 매개변수 | 타입 | 설명 |
|----------|------|-------|
| `title` | `str` | API의 제목입니다. |
-| `summary` | `str` | API에 대한 짧은 요약입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능</small> |
+| `summary` | `str` | API에 대한 짧은 요약입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능.</small> |
| `description` | `str` | API에 대한 짧은 설명입니다. 마크다운을 사용할 수 있습니다. |
-| `version` | `string` | API의 버전입니다. OpenAPI의 버전이 아닌, 여러분의 애플리케이션의 버전을 나타냅니다. 예: `2.5.0` |
+| `version` | `string` | API의 버전입니다. OpenAPI의 버전이 아닌, 여러분의 애플리케이션의 버전을 나타냅니다. 예: `2.5.0`. |
| `terms_of_service` | `str` | API 이용 약관의 URL입니다. 제공하는 경우 URL 형식이어야 합니다. |
| `contact` | `dict` | 노출된 API에 대한 연락처 정보입니다. 여러 필드를 포함할 수 있습니다. <details><summary><code>contact</code> 필드</summary><table><thead><tr><th>매개변수</th><th>타입</th><th>설명</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>연락처 인물/조직의 식별명입니다.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>연락처 정보가 담긴 URL입니다. URL 형식이어야 합니다.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>연락처 인물/조직의 이메일 주소입니다. 이메일 주소 형식이어야 합니다.</td></tr></tbody></table></details> |
-| `license_info` | `dict` | 노출된 API의 라이선스 정보입니다. 여러 필드를 포함할 수 있습니다. <details><summary><code>license_info</code> 필드</summary><table><thead><tr><th>매개변수</th><th>타입</th><th>설명</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>필수</strong> (<code>license_info</code>가 설정된 경우). API에 사용된 라이선스 이름입니다.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API에 대한 <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> 라이선스 표현입니다. <code>identifier</code> 필드는 <code>url</code> 필드와 상호 배타적입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API에 사용된 라이선스의 URL입니다. URL 형식이어야 합니다.</td></tr></tbody></table></details> |
+| `license_info` | `dict` | 노출된 API의 라이선스 정보입니다. 여러 필드를 포함할 수 있습니다. <details><summary><code>license_info</code> 필드</summary><table><thead><tr><th>매개변수</th><th>타입</th><th>설명</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>필수</strong> (<code>license_info</code>가 설정된 경우). API에 사용된 라이선스 이름입니다.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API에 대한 <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> 라이선스 표현입니다. <code>identifier</code> 필드는 <code>url</code> 필드와 상호 배타적입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API에 사용된 라이선스의 URL입니다. URL 형식이어야 합니다.</td></tr></tbody></table></details> |
다음과 같이 설정할 수 있습니다:
-{* ../../docs_src/metadata/tutorial001.py hl[3:16,19:32] *}
+{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
-/// tip
+/// tip | 팁
`description` 필드에 마크다운을 사용할 수 있으며, 출력에서 렌더링됩니다.
<img src="/img/tutorial/metadata/image01.png">
-## 라이선스 식별자
+## 라이선스 식별자 { #license-identifier }
-OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `identifier`를 URL 대신 설정할 수 있습니다.
+OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `url` 대신 `identifier`를 설정할 수도 있습니다.
예:
-{* ../../docs_src/metadata/tutorial001_1.py hl[31] *}
+{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
-## 태그에 대한 메타데이터
+## 태그에 대한 메타데이터 { #metadata-for-tags }
-`openapi_tags` 매ê°\9cë³\80ì\88\98를 ì\82¬ì\9a©í\95\98ì\97¬ ê²½ë¡\9c ì\9e\91ë\8f\99ì\9d\84 그룹í\99\94í\95\98ë\8a\94 ë\8d° ì\82¬ì\9a©ë\90\98ë\8a\94 í\83\9cê·¸ì\97\90 ì¶\94ê°\80 ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ ì¶\94ê°\80í\95 ì\88\98 있습니다.
+`openapi_tags` 매ê°\9cë³\80ì\88\98를 ì\82¬ì\9a©í\95\98ì\97¬ ê²½ë¡\9c ì²\98리ì\9d\84 그룹í\99\94í\95\98ë\8a\94 ë\8d° ì\82¬ì\9a©ë\90\98ë\8a\94 ì\97¬ë\9f¬ í\83\9cê·¸ì\97\90 ì¶\94ê°\80 ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ ì¶\94ê°\80í\95 ì\88\98ë\8f\84 있습니다.
-리ì\8a¤í\8a¸ë\8a\94 ê°\81 í\83\9cê·¸ì\97\90 ë\8c\80í\95´ í\95\98ë\82\98ì\9d\98 ë\94\95ì\85\94ë\84\88리를 í\8f¬í\95¨í\95´ì\95¼ í\95©ë\8b\88ë\8b¤.
+리스트는 각 태그에 대해 하나의 딕셔너리를 포함합니다.
각 딕셔너리에는 다음이 포함될 수 있습니다:
-* `name` (**필수**): `tags` 매개변수에서 *경로 작동*과 `APIRouter`에 사용된 태그 이름과 동일한 `str`입니다.
-* `description`: 태그에 대한 간단한 설명을 담은 `str`입니다. 마크다운을 사용할 수 있으며 문서 UI에 표시됩니다.
+* `name` (**필수**): *경로 처리* 및 `APIRouter`의 `tags` 매개변수에서 사용하는 태그 이름과 동일한 `str`입니다.
+* `description`: 태그에 대한 간단한 설명을 담은 `str`입니다. 마크다운을 포함할 수 있으며 문서 UI에 표시됩니다.
* `externalDocs`: 외부 문서를 설명하는 `dict`이며:
* `description`: 외부 문서에 대한 간단한 설명을 담은 `str`입니다.
* `url` (**필수**): 외부 문서의 URL을 담은 `str`입니다.
-### 태그에 대한 메타데이터 생성
+### 태그에 대한 메타데이터 생성 { #create-metadata-for-tags }
-`users` 및 `items`에 대한 태그 예시와 함께 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달해 보겠습니다:
+`users` 및 `items`에 대한 태그 예시로 시도해 보겠습니다.
-{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
+태그에 대한 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달하세요:
-설명 안에 마크다운을 사용할 수 있습니다. 예를 들어 "login"은 굵게(**login**) 표시되고, "fancy"는 기울임꼴(_fancy_)로 표시됩니다.
+{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
-/// tip
+설명 안에 마크다운을 사용할 수 있다는 점에 유의하세요. 예를 들어 "login"은 굵게(**login**) 표시되고, "fancy"는 기울임꼴(_fancy_)로 표시됩니다.
+
+/// tip | 팁
사용 중인 모든 태그에 메타데이터를 추가할 필요는 없습니다.
///
-### 태그 사용
+### 태그 사용 { #use-your-tags }
-`tags` 매ê°\9cë³\80ì\88\98를 *ê²½ë¡\9c ì\9e\91ë\8f\99* ë°\8f `APIRouter`ì\99\80 í\95¨ê»\98 ì\82¬ì\9a©í\95\98ì\97¬ í\83\9cê·¸ì\97\90 í\95 ë\8b¹í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
+`tags` 매ê°\9cë³\80ì\88\98를 *ê²½ë¡\9c ì²\98리* (ë°\8f `APIRouter`)ì\99\80 í\95¨ê»\98 ì\82¬ì\9a©í\95\98ì\97¬ ì\9d´ë¥¼ ì\84\9cë¡\9c ë\8b¤ë¥¸ í\83\9cê·¸ì\97\90 í\95 ë\8b¹í\95\98ì\84¸ì\9a\94:
-{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
+{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
-/// info
+/// info | 정보
-í\83\9cê·¸ì\97\90 ë\8c\80í\95\9c ì\9e\90ì\84¸í\95\9c ë\82´ì\9a©ì\9d\80 [ê²½ë¡\9c ì\9e\91ë\8f\99 구성](path-operation-configuration.md#tags){.internal-link target=_blank}에서 읽어보세요.
+í\83\9cê·¸ì\97\90 ë\8c\80í\95\9c ì\9e\90ì\84¸í\95\9c ë\82´ì\9a©ì\9d\80 [ê²½ë¡\9c ì²\98리 구성](path-operation-configuration.md#tags){.internal-link target=_blank}에서 읽어보세요.
///
-### 문서 확인
+### 문서 확인 { #check-the-docs }
이제 문서를 확인하면 모든 추가 메타데이터가 표시됩니다:
<img src="/img/tutorial/metadata/image02.png">
-### 태그 순서
+### 태그 순서 { #order-of-tags }
-ê°\81 í\83\9cê·¸ ë©\94í\83\80ë\8d°ì\9d´í\84° ë\94\95ì\85\94ë\84\88리ì\9d\98 ì\88\9cì\84\9cë\8a\94 문ì\84\9c UIì\97\90 í\91\9cì\8b\9cë\90\98ë\8a\94 ì\88\9cì\84\9c를 정의합니다.
+ê°\81 í\83\9cê·¸ ë©\94í\83\80ë\8d°ì\9d´í\84° ë\94\95ì\85\94ë\84\88리ì\9d\98 ì\88\9cì\84\9cë\8a\94 문ì\84\9c UIì\97\90 í\91\9cì\8b\9cë\90\98ë\8a\94 ì\88\9cì\84\9cë\8f\84 정의합니다.
-예를 들어, 알파벳 순서상 `users`는 `items` 뒤에 오지만, 우리는 `users` 메타데이터를 리스트의 첫 번째 딕셔너리로 추가했기 때문에 먼저 표시됩니다.
+예를 들어, 알파벳 순서상 `users`는 `items` 뒤에 오지만, 우리는 해당 메타데이터를 리스트의 첫 번째 딕셔너리로 추가했기 때문에 먼저 표시됩니다.
-## OpenAPI URL
+## OpenAPI URL { #openapi-url }
-OpenAPI 구조는 기본적으로 `/openapi.json`에서 제공됩니다.
+기본적으로 OpenAPI 스키마는 `/openapi.json`에서 제공됩니다.
-`openapi_url` 매개변수를 통해 이를 설정할 수 있습니다.
+하지만 `openapi_url` 매개변수로 이를 설정할 수 있습니다.
-예를 들어, 이를 `/api/v1/openapi.json`에 제공하도록 설정하려면:
+예를 들어, 이를 `/api/v1/openapi.json`에서 제공하도록 설정하려면:
-{* ../../docs_src/metadata/tutorial002.py hl[3] *}
+{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
-OpenAPI 구조를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다.
+OpenAPI 스키마를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다.
-## 문서화 URL
+## 문서화 URL { #docs-urls }
포함된 두 가지 문서화 사용자 인터페이스를 설정할 수 있습니다:
예를 들어, Swagger UI를 `/documentation`에서 제공하고 ReDoc을 비활성화하려면:
-{* ../../docs_src/metadata/tutorial003.py hl[3] *}
+{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
-# 미들웨어
+# 미들웨어 { #middleware }
미들웨어를 **FastAPI** 응용 프로그램에 추가할 수 있습니다.
-"미ë\93¤ì\9b¨ì\96´"ë\8a\94 í\8a¹ì \95 *ê²½ë¡\9c ì\9e\91ë\8f\99*에 의해 처리되기 전, 모든 **요청**에 대해서 동작하는 함수입니다. 또한 모든 **응답**이 반환되기 전에도 동일하게 동작합니다.
+"미ë\93¤ì\9b¨ì\96´"ë\8a\94 í\8a¹ì \95 *ê²½ë¡\9c ì²\98리*에 의해 처리되기 전, 모든 **요청**에 대해서 동작하는 함수입니다. 또한 모든 **응답**이 반환되기 전에도 동일하게 동작합니다.
-* 미들웨어는 응용 프로그램으로 오는 **요청**를 가져옵니다.
-* **요청** 또는 다른 필요한 코드를 실행 시킬 수 있습니다.
-* **ì\9a\94ì²**ì\9d\84 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9c¼ë¡\9c ì \84ë\8b¬í\95\98ì\97¬ ì²\98리í\95©ë\8b\88ë\8b¤.
-* ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 *ê²½ë¡\9c ì\9e\91ì\97\85*ì\97\90ì\84\9c ì\83\9dì\84±í\95\9c **ì\9d\91ë\8bµ**를 ë°\9bì\8aµë\8b\88ë\8b¤.
-* **응답** 또는 다른 필요한 코드를 실행시키는 동작을 할 수 있습니다.
-* **응답**를 반환합니다.
+* 미들웨어는 응용 프로그램으로 오는 각 **요청**을 가져옵니다.
+* 그런 다음 해당 **요청**에 대해 무언가를 하거나 필요한 코드를 실행할 수 있습니다.
+* ê·¸ë\9f° ë\8b¤ì\9d\8c **ì\9a\94ì²**ì\9d\84 ë\82\98머ì§\80 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98(ì\96´ë\96¤ *ê²½ë¡\9c ì²\98리*ê°\80)ì\9d\84 í\86µí\95´ ì²\98리ë\90\98ë\8f\84ë¡\9d ì \84ë\8b¬í\95©ë\8b\88ë\8b¤.
+* ê·¸ë\9f° ë\8b¤ì\9d\8c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98(ì\96´ë\96¤ *ê²½ë¡\9c ì²\98리*ê°\80)ì\9d´ ì\83\9dì\84±í\95\9c **ì\9d\91ë\8bµ**ì\9d\84 ê°\80ì ¸ì\98µë\8b\88ë\8b¤.
+* 그런 다음 해당 **응답**에 대해 무언가를 하거나 필요한 코드를 실행할 수 있습니다.
+* 그런 다음 **응답**을 반환합니다.
/// note | 기술 세부사항
-만약 `yield`를 사용한 의존성을 가지고 있다면, 미들웨어가 실행되고 난 후에 exit이 실행됩니다.
+`yield`를 사용하는 의존성이 있다면, exit 코드는 미들웨어 *후에* 실행됩니다.
-ë§\8cì\95½ (ë\82\98ì¤\91ì\97\90 문ì\84\9cì\97\90ì\84\9c ë\8b¤ë£°) 백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85ì\9d´ ì\9e\88ë\8b¤ë©´, 모ë\93 미ë\93¤ì\9b¨ì\96´ê°\80 ì\8b¤í\96\89ë\90\98ê³ *ë\82\9c 후에* 실행됩니다.
+백그ë\9d¼ì\9a´ë\93\9c ì\9e\91ì\97\85(ë\92¤ì\97\90ì\84\9c ë³´ê²\8c ë\90 [Background Tasks](background-tasks.md){.internal-link target=_blank} ì\84¹ì\85\98ì\97\90ì\84\9c ë\8b¤ë£¹ë\8b\88ë\8b¤)ì\9d´ ì\9e\88ë\8b¤ë©´, 모ë\93 미ë\93¤ì\9b¨ì\96´ *후에* 실행됩니다.
///
-## 미들웨어 만들기
+## 미들웨어 만들기 { #create-a-middleware }
-미들웨어를 작성하기 위해서 함수 상단에 `@app.middleware("http")` 데코레이터를 사용할 수 있습니다.
+미들웨어를 만들기 위해 함수 상단에 데코레이터 `@app.middleware("http")`를 사용합니다.
-미들웨어 함수는 다음 항목들을 받습니다:
+미들웨어 함수는 다음을 받습니다:
* `request`.
* `request`를 매개변수로 받는 `call_next` 함수.
- * ì\9d´ í\95¨ì\88\98ë\8a\94 `request`를 í\95´ë\8b¹í\95\98ë\8a\94 *ê²½ë¡\9c ì\9e\91ì\97\85*ì\9c¼로 전달합니다.
- * 그런 다음, *경로 작업*에 의해 생성된 `response` 를 반환합니다.
-* `response`를 반환하기 전에 추가로 `response`를 수정할 수 있습니다.
+ * ì\9d´ í\95¨ì\88\98ë\8a\94 `request`를 í\95´ë\8b¹í\95\98ë\8a\94 *ê²½ë¡\9c ì²\98리*로 전달합니다.
+ * 그런 다음 해당 *경로 처리*가 생성한 `response`를 반환합니다.
+* 그런 다음 반환하기 전에 `response`를 추가로 수정할 수 있습니다.
-{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
+{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
/// tip | 팁
-사용자 정의 헤더는 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">'X-' 접두사를 사용</a>하여 추가할 수 있습니다.
+사용자 정의 독점 헤더는 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` 접두사를 사용</a>하여 추가할 수 있다는 점을 기억하세요.
-그러나 만약 클라이언트의 브라우저에서 볼 수 있는 사용자 정의 헤더를 가지고 있다면, 그것들을 CORS 설정([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank})에 <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette CORS 문서</a>에 명시된 `expose_headers` 매개변수를 이용하여 헤더들을 추가하여야합니다.
+하지만 브라우저에서 클라이언트가 볼 수 있게 하려는 사용자 정의 헤더가 있다면, <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette의 CORS 문서</a>에 문서화된 `expose_headers` 매개변수를 사용해 CORS 설정([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank})에 추가해야 합니다.
///
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
+
+`from starlette.requests import Request`를 사용할 수도 있습니다.
+
+**FastAPI**는 개발자인 여러분의 편의를 위해 이를 제공합니다. 하지만 이는 Starlette에서 직접 가져온 것입니다.
+
+///
+
+### `response`의 전과 후 { #before-and-after-the-response }
+
+어떤 *경로 처리*가 받기 전에, `request`와 함께 실행될 코드를 추가할 수 있습니다.
+
+또한 `response`가 생성된 후, 반환하기 전에 코드를 추가할 수도 있습니다.
-`from starlette.requests import request`를 사용할 수도 있습니다.
+예를 들어, 요청을 처리하고 응답을 생성하는 데 걸린 시간을 초 단위로 담는 사용자 정의 헤더 `X-Process-Time`을 추가할 수 있습니다:
-**FastAPI**는 개발자에게 편의를 위해 이를 제공합니다. 그러나 Starlette에서 직접 파생되었습니다.
+{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
+
+/// tip | 팁
+
+여기서는 이러한 사용 사례에서 더 정확할 수 있기 때문에 `time.time()` 대신 <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a>를 사용합니다. 🤓
///
-### `response`의 전과 후
+## 여러 미들웨어 실행 순서 { #multiple-middleware-execution-order }
+
+`@app.middleware()` 데코레이터 또는 `app.add_middleware()` 메서드를 사용해 여러 미들웨어를 추가하면, 새로 추가된 각 미들웨어가 애플리케이션을 감싸 스택을 형성합니다. 마지막에 추가된 미들웨어가 *가장 바깥쪽*이고, 처음에 추가된 미들웨어가 *가장 안쪽*입니다.
+
+요청 경로에서는 *가장 바깥쪽* 미들웨어가 먼저 실행됩니다.
+
+응답 경로에서는 마지막에 실행됩니다.
+
+예를 들어:
+
+```Python
+app.add_middleware(MiddlewareA)
+app.add_middleware(MiddlewareB)
+```
-*경로 작동*을 받기 전 `request`와 함께 작동할 수 있는 코드를 추가할 수 있습니다.
+이 경우 실행 순서는 다음과 같습니다:
-그리고 `response` 또한 생성된 후 반환되기 전에 코드를 추가 할 수 있습니다.
+* **요청**: MiddlewareB → MiddlewareA → route
-예를 들어, 요청을 수행하고 응답을 생성하는데 까지 걸린 시간 값을 가지고 있는 `X-Process-Time` 같은 사용자 정의 헤더를 추가할 수 있습니다.
+* **응답**: route → MiddlewareA → MiddlewareB
-{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
+이러한 스태킹 동작은 미들웨어가 예측 가능하고 제어 가능한 순서로 실행되도록 보장합니다.
-## 다른 미들웨어
+## 다른 미들웨어 { #other-middlewares }
-미ë\93¤ì\9b¨ì\96´ì\97\90 ë\8c\80í\95\9c ë\8d\94 ë§\8eì\9d\80 ì \95ë³´ë\8a\94 [ì\88\99ë ¨ë\90\9c ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c: í\96¥ì\83\81ë\90\9c 미ë\93¤ì\9b¨ì\96´](../advanced/middleware.md){.internal-link target=\_blank}에서 확인할 수 있습니다.
+ë\8b¤ë¥¸ 미ë\93¤ì\9b¨ì\96´ì\97\90 ë\8c\80í\95\9c ë\8d\94 ë§\8eì\9d\80 ì \95ë³´ë\8a\94 ë\82\98ì¤\91ì\97\90 [ì\88\99ë ¨ë\90\9c ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c: í\96¥ì\83\81ë\90\9c 미ë\93¤ì\9b¨ì\96´](../advanced/middleware.md){.internal-link target=_blank}에서 확인할 수 있습니다.
-다음 ë¶\80ë¶\84ì\97\90ì\84\9c 미ë\93¤ì\9b¨ì\96´ì\99\80 í\95¨ê»\98 <abbr title="êµ\90ì°¨-ì¶\9cì²\98 리ì\86\8cì\8a¤ ê³µì\9c ">CORS</abbr>를 ì\96´ë\96»ê²\8c ë\8b¤ë£¨ë\8a\94ì§\80ì\97\90 ë\8c\80í\95´ í\99\95ì\9d¸í\95 ê²\83ì\9e\85ë\8b\88ë\8b¤.
+다음 ì\84¹ì\85\98ì\97\90ì\84\9c 미ë\93¤ì\9b¨ì\96´ë¡\9c <abbr title="Cross-Origin Resource Sharing">CORS</abbr>를 ì²\98리í\95\98ë\8a\94 ë°©ë²\95ì\9d\84 ë³´ê²\8c ë\90 ê²\83ì\9e\85ë\8b\88ë\8b¤.
-# ê²½ë¡\9c ì\9e\91ë\8f\99 ì\84¤ì \95
+# ê²½ë¡\9c ì²\98리 ì\84¤ì \95 { #path-operation-configuration }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°*를 ì\84¤ì \95í\95\98기 ì\9c\84í\95´ì\84\9c ì \84ë\8b¬í\95 수 있는 몇 가지 매개변수가 있습니다.
+*ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°*를 ì\84¤ì \95í\95\98기 ì\9c\84í\95´ ì \84ë\8b¬í\95 수 있는 몇 가지 매개변수가 있습니다.
/// warning | 경고
-ì\95\84ë\9e\98 매ê°\9cë³\80ì\88\98ë\93¤ì\9d\80 *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*ê°\80 ì\95\84ë\8b\8c *ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 ì§\81ì \91 ì \84ë\8b¬ë\90\9cë\8b¤ë\8a\94 ì\82¬ì\8b¤ì\9d\84 기ì\96µí\95\98ì\8bì\8b\9cì\98¤.
+ì\95\84ë\9e\98 매ê°\9cë³\80ì\88\98ë\93¤ì\9d\80 *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ê°\80 ì\95\84ë\8b\8c *ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 ì§\81ì \91 ì \84ë\8b¬ë\90\9cë\8b¤ë\8a\94 ì\82¬ì\8b¤ì\9d\84 기ì\96µí\95\98ì\84¸ì\9a\94.
///
-## 응답 상태 코드
+## 응답 상태 코드 { #response-status-code }
-*ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\98 ì\9d\91ë\8bµì\97\90 ì\82¬ì\9a©ë\90 (HTTP) `status_code`를 ì \95ì\9d\98í\95 수 있습니다.
+*ê²½ë¡\9c ì²\98리*ì\9d\98 ì\9d\91ë\8bµì\97\90 ì\82¬ì\9a©ë\90 (HTTP) `status_code`를 ì \95ì\9d\98í\95 수 있습니다.
-`404`와 같은 `int`형 코드를 직접 전달할수 있습니다.
+`404`와 같은 `int`형 코드를 직접 전달할 수 있습니다.
-í\95\98ì§\80ë§\8c ê°\81 ì½\94ë\93\9cì\9d\98 ì\9d\98미를 모른ë\8b¤ë©´, `status`ì\97\90 ì\9e\88ë\8a\94 ë\8b¨ì¶\95 ì\83\81ì\88\98ë\93¤ì\9d\84 ì\82¬ì\9a©í\95 수 있습니다:
+í\95\98ì§\80ë§\8c ê°\81 ì\88«ì\9e\90 ì½\94ë\93\9cê°\80 무ì\97\87ì\9d\84 ì\9d\98미í\95\98ë\8a\94ì§\80 기ì\96µí\95\98ì§\80 못í\95\9cë\8b¤ë©´, `status`ì\97\90 ì\9e\88ë\8a\94 ë\8b¨ì¶\95 ì\83\81ì\88\98ë\93¤ì\9d\84 ì\82¬ì\9a©í\95 수 있습니다:
-{* ../../docs_src/path_operation_configuration/tutorial001.py hl[3,17] *}
+{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
-각 상태 코드들은 응답에 사용되며, OpenAPI 스키마에 추가됩니다.
+해당 상태 코드는 응답에 사용되며, OpenAPI 스키마에 추가됩니다.
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
다음과 같이 임포트하셔도 좋습니다. `from starlette import status`.
-**FastAPI**는 개발자 여러분의 편의를 위해서 `starlette.status`와 동일한 `fastapi.status`를 제공합니다. 하지만 Starlette에서 직접 온 것입니다.
+**FastAPI**는 개발자 여러분의 편의를 위해 `starlette.status`와 동일한 `fastapi.status`를 제공합니다. 하지만 이는 Starlette에서 직접 온 것입니다.
///
-## 태그
+## 태그 { #tags }
-(보통 단일 `str`인) `str`로 구성된 `list`와 함께 매개변수 `tags`를 전달하여, `경로 작동`에 태그를 추가할 수 있습니다:
+(보통 단일 `str`인) `str`로 구성된 `list`와 함께 매개변수 `tags`를 전달하여, *경로 처리*에 태그를 추가할 수 있습니다:
-{* ../../docs_src/path_operation_configuration/tutorial002.py hl[17,22,27] *}
+{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
전달된 태그들은 OpenAPI의 스키마에 추가되며, 자동 문서 인터페이스에서 사용됩니다:
<img src="/img/tutorial/path-operation-configuration/image01.png">
-## 요약과 기술
+### Enum을 사용한 태그 { #tags-with-enums }
+
+큰 애플리케이션이 있다면, **여러 태그**가 쌓이게 될 수 있고, 관련된 *경로 처리*에 항상 **같은 태그**를 사용하는지 확인하고 싶을 것입니다.
+
+이런 경우에는 태그를 `Enum`에 저장하는 것이 합리적일 수 있습니다.
+
+**FastAPI**는 일반 문자열과 동일한 방식으로 이를 지원합니다:
+
+{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
+
+## 요약과 설명 { #summary-and-description }
`summary`와 `description`을 추가할 수 있습니다:
-{* ../../docs_src/path_operation_configuration/tutorial003.py hl[20:21] *}
+{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
-## 독스트링으로 만든 기술
+## 독스트링으로 만든 설명 { #description-from-docstring }
-ì\84¤ëª\85ì\9d\80 ë³´í\86µ 길ì\96´ì§\80ê³ ì\97¬ë\9f¬ ì¤\84ì\97\90 걸ì³\90ì\9e\88기 ë\95\8c문ì\97\90, *ê²½ë¡\9c ì\9e\91ë\8f\99* 기ì\88 ì\9d\84 í\95¨ì\88\98 <abbr title="í\95¨ì\88\98ì\95\88ì\97\90 ì\9e\88ë\8a\94 첫ë²\88째 í\91\9cí\98\84ì\8b\9dì\9c¼ë¡\9c, 문ì\84\9cë¡\9c ì\82¬ì\9a©ë\90 ì\97¬ë\9f¬ ì¤\84ì\97\90 걸ì¹\9c (ë³\80ì\88\98ì\97\90 í\95 ë\8b¹ë\90\98ì§\80 ì\95\8aì\9d\80) 문ì\9e\90ì\97´"> ë\8f\85ì\8a¤í\8a¸ë§\81</abbr> ì\97\90 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤, ì\9d´ë¥¼ **FastAPI**ê°\80 ë\8f\85ì\8a¤í\8a¸ë§\81ì\9c¼ë¡\9cë¶\80í\84° 읽습니다.
+ì\84¤ëª\85ì\9d\80 ë³´í\86µ 길ì\96´ì§\80ê³ ì\97¬ë\9f¬ ì¤\84ì\97\90 걸ì³\90ì\9e\88기 ë\95\8c문ì\97\90, *ê²½ë¡\9c ì²\98리* ì\84¤ëª\85ì\9d\84 í\95¨ì\88\98 <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation â\80\93 문ì\84\9cí\99\94ì\97\90 ì\82¬ì\9a©ë\90\98ë\8a\94 í\95¨ì\88\98 ë\82´ë¶\80 첫 í\91\9cí\98\84ì\8b\9dì\9d\98 ì\97¬ë\9f¬ ì¤\84 문ì\9e\90ì\97´(ì\96´ë\96¤ ë³\80ì\88\98ì\97\90ë\8f\84 í\95 ë\8b¹ë\90\98ì§\80 ì\95\8aì\9d\8c)">docstring</abbr>ì\97\90 ì\84 ì\96¸í\95 ì\88\98 ì\9e\88ì\9c¼ë©°, **FastAPI**ë\8a\94 그곳ì\97\90ì\84\9c ì\9d´ë¥¼ 읽습니다.
-<a href="https://ko.wikipedia.org/wiki/%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4" class="external-link" target="_blank">마크다운</a> 문법으로 독스트링을 작성할 수 있습니다, 작성된 마크다운 형식의 독스트링은 (마크다운의 들여쓰기를 고려하여) 올바르게 화면에 출력됩니다.
+독스트링에는 <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a>을 작성할 수 있으며, (독스트링의 들여쓰기를 고려하여) 올바르게 해석되고 표시됩니다.
-{* ../../docs_src/path_operation_configuration/tutorial004.py hl[19:27] *}
+{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
이는 대화형 문서에서 사용됩니다:
<img src="/img/tutorial/path-operation-configuration/image02.png">
-## 응답 기술
+## 응답 설명 { #response-description }
`response_description` 매개변수로 응답에 관한 설명을 명시할 수 있습니다:
-{* ../../docs_src/path_operation_configuration/tutorial005.py hl[21] *}
+{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
/// info | 정보
-`response_description`ì\9d\80 구체ì \81ì\9c¼ë¡\9c ì\9d\91ë\8bµì\9d\84 ì§\80ì¹í\95\98ë©°, `description`ì\9d\80 ì\9d¼ë°\98ì \81ì\9d¸ *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\84 지칭합니다.
+`response_description`ì\9d\80 구체ì \81ì\9c¼ë¡\9c ì\9d\91ë\8bµì\9d\84 ì§\80ì¹í\95\98ë©°, `description`ì\9d\80 ì\9d¼ë°\98ì \81ì\9d¸ *ê²½ë¡\9c ì²\98리*를 지칭합니다.
///
/// check | 확인
-OpenAPIë\8a\94 ê°\81 *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d´ 응답에 관한 설명을 요구할 것을 명시합니다.
+OpenAPIë\8a\94 ê°\81 *ê²½ë¡\9c ì²\98리*ê°\80 응답에 관한 설명을 요구할 것을 명시합니다.
-ë\94°ë\9d¼ì\84\9c, ì\9d\91ë\8bµì\97\90 ê´\80í\95\9c ì\84¤ëª\85ì\9d´ ì\97\86ì\9d\84ê²½ì\9a°, **FastAPI**ê°\80 ì\9e\90ë\8f\99ì\9c¼ë¡\9c "ì\84±ê³µ ì\9d\91ë\8bµ" ì¤\91 í\95\98ë\82\98를 생성합니다.
+ë\94°ë\9d¼ì\84\9c, ì\9d\91ë\8bµì\97\90 ê´\80í\95\9c ì\84¤ëª\85ì\9d\84 ì \9cê³µí\95\98ì§\80 ì\95\8aì\9c¼ë©´, **FastAPI**ê°\80 "Successful response" ì¤\91 í\95\98ë\82\98를 ì\9e\90ë\8f\99ì\9c¼ë¡\9c 생성합니다.
///
<img src="/img/tutorial/path-operation-configuration/image03.png">
-## 단일 *경로 작동* 지원중단
+## *경로 처리* 지원중단하기 { #deprecate-a-path-operation }
-단일 *경로 작동*을 없애지 않고 <abbr title="구식, 사용하지 않는것이 권장됨">지원중단</abbr>을 해야한다면, `deprecated` 매개변수를 전달하면 됩니다.
+*경로 처리*를 제거하지 않고 <abbr title="obsolete, recommended not to use it – 구식이며 사용하지 않는 것이 권장됨">deprecated</abbr>로 표시해야 한다면, `deprecated` 매개변수를 전달하면 됩니다:
-{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
+{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
-대화형 문서에 지원중단이라고 표시됩니다.
+대화형 문서에서 지원중단으로 명확하게 표시됩니다:
<img src="/img/tutorial/path-operation-configuration/image04.png">
-지원중단된 경우와 지원중단 되지 않은 경우에 대한 *경로 작동*이 어떻게 보이는 지 확인하십시오.
+지원중단된 *경로 처리*와 지원중단되지 않은 *경로 처리*가 어떻게 보이는지 확인해 보세요:
<img src="/img/tutorial/path-operation-configuration/image05.png">
-## 정리
+## 정리 { #recap }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 매ê°\9cë³\80ì\88\98(ë\93¤)를 ì \84ë\8b¬í\95¨ì\9c¼ë¡\9c *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\84 ì\84¤ì \95í\95\98ê³ ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ ì¶\94ê°\80í\95 수 있습니다.
+*ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°*ì\97\90 매ê°\9cë³\80ì\88\98(ë\93¤)를 ì \84ë\8b¬í\95\98ì\97¬ *ê²½ë¡\9c ì²\98리*를 ì\84¤ì \95í\95\98ê³ ë©\94í\83\80ë\8d°ì\9d´í\84°ë¥¼ ì\89½ê²\8c ì¶\94ê°\80í\95 수 있습니다.
-# 경로 매개변수와 숫자 검증
+# 경로 매개변수와 숫자 검증 { #path-parameters-and-numeric-validations }
`Query`를 사용하여 쿼리 매개변수에 더 많은 검증과 메타데이터를 선언하는 방법과 동일하게 `Path`를 사용하여 경로 매개변수에 검증과 메타데이터를 같은 타입으로 선언할 수 있습니다.
-## 경로 임포트
+## `Path` 임포트 { #import-path }
-먼저 `fastapi`에서 `Path`를 임포트합니다:
+먼ì \80 `fastapi`ì\97\90ì\84\9c `Path`를 ì\9e\84í\8f¬í\8a¸í\95\98ê³ , `Annotated`ë\8f\84 ì\9e\84í\8f¬í\8a¸í\95©ë\8b\88ë\8b¤:
-{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[3] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
-## 메타데이터 선언
+/// info | 정보
+
+FastAPI는 0.95.0 버전에서 `Annotated` 지원을 추가했고(그리고 이를 권장하기 시작했습니다).
+
+더 오래된 버전이 있다면 `Annotated`를 사용하려고 할 때 오류가 발생합니다.
+
+`Annotated`를 사용하기 전에 최소 0.95.1까지 [FastAPI 버전 업그레이드](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}를 꼭 하세요.
+
+///
+
+## 메타데이터 선언 { #declare-metadata }
`Query`에 동일한 매개변수를 선언할 수 있습니다.
-예를 들어, `title` 메타데이터 값을 경로 매개변수 `item_id`에 선언하려면 다음과 같이 입력할 수 있습니다:
+예를 들어, 경로 매개변수 `item_id`에 `title` 메타데이터 값을 선언하려면 다음과 같이 입력할 수 있습니다:
-{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
/// note | 참고
-ê²½ë¡\9c 매ê°\9cë³\80ì\88\98ë\8a\94 ê²½ë¡\9cì\9d\98 ì\9d¼ë¶\80ì\97¬ì\95¼ í\95\98ë¯\80ë¡\9c ì\96¸ì \9cë\82\98 í\95\84ì\88\98ì \81입니다.
+ê²½ë¡\9c 매ê°\9cë³\80ì\88\98ë\8a\94 ê²½ë¡\9cì\9d\98 ì\9d¼ë¶\80ì\97¬ì\95¼ í\95\98ë¯\80ë¡\9c ì\96¸ì \9cë\82\98 í\95\84ì\88\98ì\9e\85ë\8b\88ë\8b¤. `None`ì\9c¼ë¡\9c ì\84 ì\96¸í\95\98ê±°ë\82\98 기본ê°\92ì\9d\84 ì§\80ì \95í\95\98ë\8d\94ë\9d¼ë\8f\84 ì\95\84무 ì\98\81í\96¥ì\9d´ ì\97\86ì\9c¼ë©°, í\95ì\83\81 í\95\84ì\88\98입니다.
-즉, `...`로 선언해서 필수임을 나타내는게 좋습니다.
+///
-그럼에도 `None`으로 선언하거나 기본값을 지정할지라도 아무 영향을 끼치지 않으며 언제나 필수입니다.
+## 필요한 대로 매개변수 정렬하기 { #order-the-parameters-as-you-need }
-///
+/// tip | 팁
-## 필요한 경우 매개변수 정렬하기
+`Annotated`를 사용한다면 이것은 아마 그렇게 중요하지 않거나 필요하지 않을 수 있습니다.
+
+///
`str` 형인 쿼리 매개변수 `q`를 필수로 선언하고 싶다고 해봅시다.
-해당 매개변수에 대해 아무런 선언을 할 필요가 없으므로 `Query`를 정말로 써야할 필요는 없습니다.
+해당 매개변수에 대해 아무런 선언을 할 필요가 없으므로 `Query`를 정말로 써야 할 필요는 없습니다.
+
+하지만 `item_id` 경로 매개변수는 여전히 `Path`를 사용해야 합니다. 그리고 어떤 이유로 `Annotated`를 사용하고 싶지 않다고 해봅시다.
-하지만 `item_id` 경로 매개변수는 여전히 `Path`를 사용해야 합니다.
+파이썬은 "기본값"이 있는 값을 "기본값"이 없는 값 앞에 두면 불평합니다.
+
+하지만 순서를 재정렬해서 기본값이 없는 값(쿼리 매개변수 `q`)을 앞에 둘 수 있습니다.
+
+**FastAPI**에서는 중요하지 않습니다. 이름, 타입 그리고 기본값 선언(`Query`, `Path` 등)로 매개변수를 감지하며 순서는 신경 쓰지 않습니다.
+
+따라서 함수를 다음과 같이 선언할 수 있습니다:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+
+하지만 `Annotated`를 사용하면 이 문제가 없다는 점을 기억하세요. `Query()`나 `Path()`에 함수 매개변수 기본값을 사용하지 않기 때문에, 순서는 중요하지 않습니다.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+
+## 필요한 대로 매개변수 정렬하기, 트릭 { #order-the-parameters-as-you-need-tricks }
+
+/// tip | 팁
+
+`Annotated`를 사용한다면 이것은 아마 그렇게 중요하지 않거나 필요하지 않을 수 있습니다.
+
+///
-파이썬은 "기본값"이 없는 값 앞에 "기본값"이 있는 값을 입력하면 불평합니다.
+유용할 수 있는 **작은 트릭**이 하나 있지만, 자주 필요하진 않을 겁니다.
-그러나 매개변수들을 재정렬함으로써 기본값(쿼리 매개변수 `q`)이 없는 값을 처음 부분에 위치 할 수 있습니다.
+만약 다음을 원한다면:
-**FastAPI**에서는 중요하지 않습니다. 이름, 타입 그리고 선언구(`Query`, `Path` 등)로 매개변수를 감지하며 순서는 신경 쓰지 않습니다.
+* `Query`나 어떤 기본값 없이 쿼리 매개변수 `q`를 선언하기
+* `Path`를 사용해서 경로 매개변수 `item_id`를 선언하기
+* 이들을 다른 순서로 두기
+* `Annotated`를 사용하지 않기
-따라서 함수를 다음과 같이 선언 할 수 있습니다:
+...이를 위해 파이썬에는 작은 특별한 문법이 있습니다.
-{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
+함수의 첫 번째 매개변수로 `*`를 전달하세요.
-## 필요한 경우 매개변수 정렬하기, 트릭
+파이썬은 `*`으로 아무것도 하지 않지만, 뒤따르는 모든 매개변수는 키워드 인자(키-값 쌍)로 호출되어야 함을 알게 됩니다. 이는 <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>로도 알려져 있습니다. 기본값이 없더라도 마찬가지입니다.
-`Query`나 아무런 기본값으로도 `q` 경로 매개변수를 선언하고 싶지 않지만 `Path`를 사용하여 경로 매개변수를 `item_id` 다른 순서로 선언하고 싶다면, 파이썬은 이를 위한 작고 특별한 문법이 있습니다.
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
-`*`를 함수의 첫 번째 매개변수로 전달하세요.
+### `Annotated`를 쓰면 더 좋습니다 { #better-with-annotated }
-파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 <abbr title="유래: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다.
+`Annotated`를 사용하면 함수 매개변수 기본값을 사용하지 않기 때문에 이 문제가 발생하지 않으며, 아마 `*`도 사용할 필요가 없다는 점을 기억하세요.
-{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
-## 숫자 검증: 크거나 같음
+## 숫자 검증: 크거나 같음 { #number-validations-greater-than-or-equal }
-`Query`와 `Path`(나중에 볼 다른 것들도)를 사용하여 문자열 뿐만 아니라 숫자의 제약을 선언할 수 있습니다.
+`Query`와 `Path`(그리고 나중에 볼 다른 것들)를 사용하여 숫자 제약을 선언할 수 있습니다.
-여기서 `ge=1`인 경우, `item_id`는 `1`보다 "크거나(`g`reater) 같은(`e`qual)" 정수형 숫자여야 합니다.
+여기서 `ge=1`인 경우, `item_id`는 `1`보다 "`g`reater than or `e`qual"(크거나 같은) 정수형 숫자여야 합니다.
-{* ../../docs_src/path_params_numeric_validations/tutorial004.py hl[8] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
-## 숫자 검증: 크거나 같음 및 작거나 같음
+## 숫자 검증: 크거나 및 작거나 같음 { #number-validations-greater-than-and-less-than-or-equal }
동일하게 적용됩니다:
-* `gt`: 크거나(`g`reater `t`han)
-* `le`: 작거나 같은(`l`ess than or `e`qual)
+* `gt`: `g`reater `t`han
+* `le`: `l`ess than or `e`qual
-{* ../../docs_src/path_params_numeric_validations/tutorial005.py hl[9] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
-## 숫자 검증: 부동소수, 크거나 및 작거나
+## 숫자 검증: 부동소수, 크거나 및 작거나 { #number-validations-floats-greater-than-and-less-than }
숫자 검증은 `float` 값에도 동작합니다.
-여기에서 <abbr title="greater than or equal"><code>ge</code></abbr>뿐만 아니라 <abbr title="greater than"><code>gt</code></abbr>를 선언 할 수있는 것이 중요해집니다. 예를 들어 필요한 경우, 값이 `1`보다 작더라도 반드시 `0`보다 커야합니다.
+여기에서 <abbr title="greater than"><code>gt</code></abbr>를, <abbr title="greater than or equal"><code>ge</code></abbr>뿐만 아니라 선언할 수 있다는 점이 중요해집니다. 예를 들어 값이 `1`보다 작더라도, 반드시 `0`보다 커야 한다고 요구할 수 있습니다.
즉, `0.5`는 유효한 값입니다. 그러나 `0.0` 또는 `0`은 그렇지 않습니다.
<abbr title="less than"><code>lt</code></abbr> 역시 마찬가지입니다.
-{* ../../docs_src/path_params_numeric_validations/tutorial006.py hl[11] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
-## 요약
+## 요약 { #recap }
`Query`, `Path`(아직 보지 못한 다른 것들도)를 사용하면 [쿼리 매개변수와 문자열 검증](query-params-str-validations.md){.internal-link target=_blank}에서와 마찬가지로 메타데이터와 문자열 검증을 선언할 수 있습니다.
그리고 숫자 검증 또한 선언할 수 있습니다:
-* `gt`: 크거나(`g`reater `t`han)
-* `ge`: 크거나 같은(`g`reater than or `e`qual)
-* `lt`: 작거나(`l`ess `t`han)
-* `le`: 작거나 같은(`l`ess than or `e`qual)
+* `gt`: `g`reater `t`han
+* `ge`: `g`reater than or `e`qual
+* `lt`: `l`ess `t`han
+* `le`: `l`ess than or `e`qual
/// info | 정보
-`Query`, `Path`, 그리고 나중에게 보게될 것들은 (여러분이 사용할 필요가 없는) 공통 `Param` 클래스의 서브 클래스입니다.
+`Query`, `Path`, 그리고 나중에 보게 될 다른 클래스들은 공통 `Param` 클래스의 서브클래스입니다.
-그리고 이들 모두는 여태까지 본 추가 검증과 메타데이터의 동일한 모든 매개변수를 공유합니다.
+이들 모두는 여러분이 본 추가 검증과 메타데이터에 대한 동일한 매개변수를 공유합니다.
///
/// note | 기술 세부사항
-`fastapi`에서 `Query`, `Path` 등을 임포트 할 때, 이것들은 실제로 함수입니다.
+`fastapi`에서 `Query`, `Path` 등을 임포트할 때, 이것들은 실제로 함수입니다.
호출되면 동일한 이름의 클래스의 인스턴스를 반환합니다.
즉, 함수인 `Query`를 임포트한 겁니다. 그리고 호출하면 `Query`라는 이름을 가진 클래스의 인스턴스를 반환합니다.
-편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해 (클래스를 직접 사용하는 대신) 이러한 함수들이 있습니다.
+이 함수들이 있는 이유는(클래스를 직접 사용하는 대신) 편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해서입니다.
이렇게 하면 오류를 무시하기 위한 사용자 설정을 추가하지 않고도 일반 편집기와 코딩 도구를 사용할 수 있습니다.
-# 경로 매개변수
+# 경로 매개변수 { #path-parameters }
파이썬의 포맷 문자열 리터럴에서 사용되는 문법을 이용하여 경로 "매개변수" 또는 "변수"를 선언할 수 있습니다:
-{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
경로 매개변수 `item_id`의 값은 함수의 `item_id` 인자로 전달됩니다.
{"item_id":"foo"}
```
-## 타입이 있는 매개변수
+## 타입이 있는 경로 매개변수 { #path-parameters-with-types }
파이썬 표준 타입 어노테이션을 사용하여 함수에 있는 경로 매개변수의 타입을 선언할 수 있습니다:
-{* ../../docs_src/path_params/tutorial002.py hl[7] *}
+{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
위의 예시에서, `item_id`는 `int`로 선언되었습니다.
///
-## 데이터 <abbr title="다음으로도 알려져 있습니다: 직렬화, 파싱, 마샬링">변환</abbr>
+## 데이터 <abbr title="다음으로도 알려져 있습니다: 직렬화, 파싱, 마샬링">변환</abbr> { #data-conversion }
이 예제를 실행하고 <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>을 열면, 다음 응답을 볼 수 있습니다:
///
-## 데이터 검증
+## 데이터 검증 { #data-validation }
-하지만 브라우저에서 <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>로 이동하면, HTTP 오류가 잘 뜨는 것을 확인할 수 있습니다:
+하지만 브라우저에서 <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>로 이동하면, 다음과 같은 HTTP 오류를 볼 수 있습니다:
```JSON
{
- "detail": [
- {
- "loc": [
- "path",
- "item_id"
- ],
- "msg": "value is not a valid integer",
- "type": "type_error.integer"
- }
- ]
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo"
+ }
+ ]
}
```
-경로 매개변수 `item_id`는 `int`가 아닌 `"foo"` 값이기 때문입니다.
+경로 매개변수 `item_id`가 `int`가 아닌 `"foo"` 값을 가졌기 때문입니다.
-`int`가 아닌 `float`을 전달하는 경우에도 동일한 오류가 나타납니다: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
+`int` 대신 `float`을 제공하면(예: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>) 동일한 오류가 나타납니다.
/// check | 확인
즉, 파이썬 타입 선언을 하면 **FastAPI**는 데이터 검증을 합니다.
-오류에는 정확히 어느 지점에서 검증을 통과하지 못했는지 명시됩니다.
+또한 오류에는 검증을 통과하지 못한 지점이 정확히 명시됩니다.
이는 API와 상호 작용하는 코드를 개발하고 디버깅하는 데 매우 유용합니다.
///
-## 문서화
+## 문서화 { #documentation }
그리고 브라우저에서 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>를 열면, 다음과 같이 자동 대화식 API 문서를 볼 수 있습니다:
/// check | 확인
-그저 파이썬 타입 선언을 하기만 하면 **FastAPI**는 자동 대화형 API 문서(Swagger UI)를 제공합니다.
+다시 한 번, 동일한 파이썬 타입 선언만으로 **FastAPI**는 자동 대화형 문서(Swagger UI 통합)를 제공합니다.
-경로 매개변수가 정수형으로 명시된 것을 확인할 수 있습니다.
+경로 매개변수가 정수형으로 선언된 것을 확인할 수 있습니다.
///
-## 표준 기반의 이점, 대체 문서
+## 표준 기반의 이점, 대체 문서 { #standards-based-benefits-alternative-documentation }
-그리고 생성된 스키마는 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> 표준에서 나온 것이기 때문에 호환되는 도구가 많이 있습니다.
+그리고 생성된 스키마는 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> 표준에서 나온 것이기 때문에 호환되는 도구가 많이 있습니다.
-이 덕분에 **FastAPI**는 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 접속할 수 있는 (ReDoc을 사용하는) 대체 API 문서를 제공합니다:
+이 덕분에 **FastAPI** 자체에서 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 접속할 수 있는 (ReDoc을 사용하는) 대체 API 문서를 제공합니다:
<img src="/img/tutorial/path-params/image02.png">
이와 마찬가지로 다양한 언어에 대한 코드 생성 도구를 포함하여 여러 호환되는 도구가 있습니다.
-## Pydantic
+## Pydantic { #pydantic }
모든 데이터 검증은 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>에 의해 내부적으로 수행되므로 이로 인한 이점을 모두 얻을 수 있습니다. 여러분은 관리를 잘 받고 있음을 느낄 수 있습니다.
이 중 몇 가지는 자습서의 다음 장에 설명되어 있습니다.
-## 순서 문제
+## 순서 문제 { #order-matters }
-*ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\84 ë§\8cë\93¤때 고정 경로를 갖고 있는 상황들을 맞닥뜨릴 수 있습니다.
+*ê²½ë¡\9c ì²\98리*를 ë§\8cë\93¤ 때 고정 경로를 갖고 있는 상황들을 맞닥뜨릴 수 있습니다.
`/users/me`처럼, 현재 사용자의 데이터를 가져온다고 합시다.
사용자 ID를 이용해 특정 사용자의 정보를 가져오는 경로 `/users/{user_id}`도 있습니다.
-*ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\80 ì\88\9cì°¨ì \81ì\9c¼ë¡\9c ì\8b¤í\96\89ë\90\98기 ë\95\8c문ì\97\90 `/users/{user_id}` ì\9d´ì \84ì\97\90 `/users/me`를 먼ì \80 ì\84 ì\96¸í\95´ì\95¼ í\95©ë\8b\88ë\8b¤:
+*ê²½ë¡\9c ì²\98리*ë\8a\94 ì\88\9cì°¨ì \81ì\9c¼ë¡\9c í\8f\89ê°\80ë\90\98기 ë\95\8c문ì\97\90 `/users/{user_id}` ì\9d´ì \84ì\97\90 `/users/me`ì\97\90 ë\8c\80í\95\9c ê²½ë¡\9cê°\80 먼ì \80 ì\84 ì\96¸ë\90\98ì\97\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95´ì\95¼ í\95©ë\8b\88ë\8b¤:
-{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
-그렇지 않으면 `/users/{user_id}`는 `/users/me` 요청 또한 매개변수 `user_id`의 값이 `"me"`인 것으로 "생각하게" 됩니다.
+그렇지 않으면 `/users/{user_id}`에 대한 경로가 `/users/me`에도 매칭되어, 매개변수 `user_id`에 `"me"` 값이 들어왔다고 "생각하게" 됩니다.
-## 사전정의 값
+마찬가지로, 경로 처리를 재정의할 수는 없습니다:
-만약 *경로 매개변수*를 받는 *경로 작동*이 있지만, *경로 매개변수*로 가능한 값들을 미리 정의하고 싶다면 파이썬 표준 <abbr title="열거형(Enumeration)">`Enum`</abbr>을 사용할 수 있습니다.
+{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
-### `Enum` 클래스 생성
+경로가 먼저 매칭되기 때문에 첫 번째 것이 항상 사용됩니다.
-`Enum`을 임포트하고 `str`과 `Enum`을 상속하는 서브 클래스를 만듭니다.
+## 사전정의 값 { #predefined-values }
-`str`을 상속함으로써 API 문서는 값이 `string` 형이어야 하는 것을 알게 되고 이는 문서에 제대로 표시됩니다.
+만약 *경로 매개변수*를 받는 *경로 처리*가 있지만, 가능한 유효한 *경로 매개변수* 값들을 미리 정의하고 싶다면 파이썬 표준 <abbr title="열거형(Enumeration)">`Enum`</abbr>을 사용할 수 있습니다.
-가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다:
+### `Enum` 클래스 생성 { #create-an-enum-class }
-{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
+`Enum`을 임포트하고 `str`과 `Enum`을 상속하는 서브 클래스를 만듭니다.
-/// info | 정보
+`str`을 상속함으로써 API 문서는 값이 `string` 형이어야 하는 것을 알게 되고 이는 문서에 제대로 표시됩니다.
-<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">열거형(또는 enums)</a>은 파이썬 버전 3.4 이후로 사용 가능합니다.
+가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다:
-///
+{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
/// tip | 팁
-혹시 궁금하다면, "AlexNet", "ResNet", 그리고 "LeNet"은 그저 기계 학습 <abbr title="기술적으로 정확히는 딥 러닝 모델 구조">모델</abbr>들의 이름입니다.
+혹시 궁금하다면, "AlexNet", "ResNet", 그리고 "LeNet"은 그저 머신 러닝 <abbr title="기술적으로는 딥 러닝 모델 아키텍처">모델</abbr>들의 이름입니다.
///
-### *경로 매개변수* 선언
+### *경로 매개변수* 선언 { #declare-a-path-parameter }
생성한 열거형 클래스(`ModelName`)를 사용하는 타입 어노테이션으로 *경로 매개변수*를 만듭니다:
-{* ../../docs_src/path_params/tutorial005.py hl[16] *}
+{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
-### 문서 확인
+### 문서 확인 { #check-the-docs }
*경로 매개변수*에 사용할 수 있는 값은 미리 정의되어 있으므로 대화형 문서에서 잘 표시됩니다:
<img src="/img/tutorial/path-params/image03.png">
-### 파이썬 *열거형*으로 작업하기
+### 파이썬 *열거형*으로 작업하기 { #working-with-python-enumerations }
*경로 매개변수*의 값은 *열거형 멤버*가 됩니다.
-#### *열거형 멤버* 비교
+#### *열거형 멤버* 비교 { #compare-enumeration-members }
-ì\97´ê±°í\98\95 `ModelName`ì\9d\98 *ì\97´ê±°í\98\95 멤ë²\84*를 비교할 수 있습니다:
+ì\83\9dì\84±í\95\9c ì\97´ê±°í\98\95 `ModelName`ì\9d\98 *ì\97´ê±°í\98\95 멤ë²\84*ì\99\80 비교할 수 있습니다:
-{* ../../docs_src/path_params/tutorial005.py hl[17] *}
+{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
-#### *열거형 값* 가져오기
+#### *열거형 값* 가져오기 { #get-the-enumeration-value }
`model_name.value` 또는 일반적으로 `your_enum_member.value`를 이용하여 실제 값(위 예시의 경우 `str`)을 가져올 수 있습니다:
-{* ../../docs_src/path_params/tutorial005.py hl[20] *}
+{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
/// tip | 팁
///
-#### *열거형 멤버* 반환
+#### *열거형 멤버* 반환 { #return-enumeration-members }
-*ê²½ë¡\9c ì\9e\91ë\8f\99*ì\97\90ì\84\9c *ì\97´ê±°í\98\95 멤ë²\84*를 ë°\98í\99\98í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ë\8a\94 ì¤\91첩 JSON 본문(ì\98\88: `dict`)ë\82´ì\9d\98 ê°\92ì\9c¼로도 가능합니다.
+*ê²½ë¡\9c ì²\98리*ì\97\90ì\84\9c *enum 멤ë²\84*를 ë°\98í\99\98í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ë\8a\94 JSON 본문(ì\98\88: `dict`) ë\82´ì\97\90 ì¤\91첩ë\90\9c í\98\95í\83\9c로도 가능합니다.
클라이언트에 반환하기 전에 해당 값(이 경우 문자열)으로 변환됩니다:
-{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
+{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
-í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ë\8a\94 ì\95\84ë\9e\98ì\9d\98 JSON ì\9d\91ë\8bµì\9d\84 ì\96»ì\8aµ니다:
+í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ë\8a\94 ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d\80 JSON ì\9d\91ë\8bµì\9d\84 ì\96»ê²\8c ë\90©니다:
```JSON
{
}
```
-## 경로를 포함하는 경로 매개변수
+## 경로를 포함하는 경로 매개변수 { #path-parameters-containing-paths }
-경로를 포함하는 *경로 작동* `/files/{file_path}`이 있다고 해봅시다.
+경로 `/files/{file_path}`를 가진 *경로 처리*가 있다고 해봅시다.
-그런데 이 경우 `file_path` 자체가 `home/johndoe/myfile.txt`와 같은 경로를 포함해야 합니다.
+하지만 `file_path` 자체가 `home/johndoe/myfile.txt`와 같은 *경로*를 포함해야 합니다.
이때 해당 파일의 URL은 다음처럼 됩니다: `/files/home/johndoe/myfile.txt`.
-### OpenAPI 지원
+### OpenAPI 지원 { #openapi-support }
테스트와 정의가 어려운 시나리오로 이어질 수 있으므로 OpenAPI는 *경로*를 포함하는 *경로 매개변수*를 내부에 선언하는 방법을 지원하지 않습니다.
-그럼에도 Starlette의 내부 도구중 하나를 사용하여 **FastAPI**에서는 이가 가능합니다.
+그럼에도 Starlette의 내부 도구 중 하나를 사용하여 **FastAPI**에서는 이가 가능합니다.
-문ì\84\9cì\97\90 매ê°\9cë³\80ì\88\98ì\97\90 ê²½ë¡\9cê°\80 í\8f¬í\95¨ë\90\98ì\96´ì\95¼ í\95\9cë\8b¤ë\8a\94 ì \95ë³´ê°\80 ëª\85ì\8b\9cë\90\98ì§\80ë\8a\94 ì\95\8aì§\80ë§\8c ì\97¬ì \84í\9e\88 ì\9e\91ë\8f\99í\95©니다.
+ë\98\90í\95\9c 문ì\84\9cê°\80 ì\97¬ì \84í\9e\88 ë\8f\99ì\9e\91í\95\98긴 í\95\98ì§\80ë§\8c, 매ê°\9cë³\80ì\88\98ì\97\90 ê²½ë¡\9cê°\80 í\8f¬í\95¨ë\90\98ì\96´ì\95¼ í\95\9cë\8b¤ë\8a\94 ë\82´ì\9a©ì\9d\84 ì¶\94ê°\80ë¡\9c 문ì\84\9cí\99\94í\95\98ì§\80ë\8a\94 ì\95\8aì\8aµ니다.
-### 경로 변환기
+### 경로 변환기 { #path-convertor }
-Starlette의 옵션을 직접 이용하여 다음과 같은 URL을 사용함으로써 *path*를 포함하는 *경로 매개변수*를 선언할 수 있습니다:
+Starlette의 옵션을 직접 이용하여 다음과 같은 URL을 사용함으로써 *경로*를 포함하는 *경로 매개변수*를 선언할 수 있습니다:
```
/files/{file_path:path}
```
-이러한 경우 매개변수의 이름은 `file_path`이며, 마지막 부분 `:path`는 매개변수가 *경로*와 일치해야 함을 명시합니다.
+이러한 경우 매개변수의 이름은 `file_path`이며, 마지막 부분 `:path`는 매개변수가 어떤 *경로*와도 매칭되어야 함을 의미합니다.
따라서 다음과 같이 사용할 수 있습니다:
-{* ../../docs_src/path_params/tutorial004.py hl[6] *}
+{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
/// tip | 팁
-매개변수가 가져야 하는 값이 `/home/johndoe/myfile.txt`와 같이 슬래시로 시작(`/`)해야 할 수 있습니다.
+매개변수가 선행 슬래시(`/`)가 있는 `/home/johndoe/myfile.txt`를 포함해야 할 수도 있습니다.
-이 경우 URL은: `/files//home/johndoe/myfile.txt`이며 `files`과 `home` 사이에 이중 슬래시(`//`)가 생깁니다.
+그 경우 URL은: `/files//home/johndoe/myfile.txt`이며 `files`와 `home` 사이에 이중 슬래시(`//`)가 생깁니다.
///
-## 요약
+## 요약 { #recap }
**FastAPI**를 이용하면 짧고 직관적인 표준 파이썬 타입 선언을 사용하여 다음을 얻을 수 있습니다:
* 편집기 지원: 오류 검사, 자동완성 등
-* 데이터 "<abbr title="HTTP 요청에서 전달되는 문자열을 파이썬 데이터로 변환">파싱</abbr>"
+* 데이터 "<abbr title="HTTP 요청에서 전달되는 문자열을 파이썬 데이터로 변환">parsing</abbr>"
* 데이터 검증
* API 주석(Annotation)과 자동 문서
-단 한번의 선언만으로 위 사항들을 모두 선언할 수 있습니다.
+그리고 한 번만 선언하면 됩니다.
이는 대체 프레임워크와 비교했을 때 (엄청나게 빠른 성능 외에도) **FastAPI**의 주요한 장점일 것입니다.
-# 쿼리 매개변수 모델
+# 쿼리 매개변수 모델 { #query-parameter-models }
-연관된 쿼리 **매개변수** 그룹이 있다면 **Pydantic 모델** 을 사용해 선언할 수 있습니다.
+연관된 **쿼리 매개변수** 그룹이 있다면 이를 선언하기 위해 **Pydantic 모델**을 생성할 수 있습니다.
이렇게 하면 **여러 곳**에서 **모델을 재사용**할 수 있을 뿐만 아니라, 매개변수에 대한 검증 및 메타데이터도 한 번에 선언할 수 있습니다. 😎
/// note | 참고
-ì\9d´ 기ë\8a¥ì\9d\80 FastAPI ë²\84ì \84 `0.115.0`ë¶\80í\84° ì \9cê³µ됩니다. 🤓
+ì\9d´ 기ë\8a¥ì\9d\80 FastAPI ë²\84ì \84 `0.115.0`ë¶\80í\84° ì§\80ì\9b\90됩니다. 🤓
///
-## 쿼리 매개변수와 Pydantic 모델
+## Pydantic 모델과 쿼리 매개변수 { #query-parameters-with-a-pydantic-model }
-í\95\84ì\9a\94í\95\9c **쿼리 매ê°\9cë³\80ì\88\98**를 **Pydantic 모ë\8d¸** ì\95\88ì\97\90 ì\84 ì\96¸í\95\9c ë\8b¤ì\9d\8c, 모ë\8d¸ì\9d\84 `Query`ë¡\9c ì\84 ì\96¸í\95©ë\8b\88ë\8b¤.
+í\95\84ì\9a\94í\95\9c **쿼리 매ê°\9cë³\80ì\88\98**를 **Pydantic 모ë\8d¸** ì\95\88ì\97\90 ì\84 ì\96¸í\95\9c ë\8b¤ì\9d\8c, 매ê°\9cë³\80ì\88\98를 `Query`ë¡\9c ì\84 ì\96¸í\95©ë\8b\88ë\8b¤:
{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
-**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델로 제공합니다.
+**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델을 제공합니다.
-## 문서 확인하기
+## 문서 확인하기 { #check-the-docs }
-`/docs` 경로의 API 문서에서 매개변수를 확인할 수 있습니다.
+`/docs`의 문서 UI에서 쿼리 매개변수를 확인할 수 있습니다:
<div class="screenshot">
<img src="/img/tutorial/query-param-models/image01.png">
</div>
-## 추가 쿼리 매개변수 금지
+## 추가 쿼리 매개변수 금지 { #forbid-extra-query-parameters }
-몇몇의 특이한 경우에 (흔치 않지만), 허용할 쿼리 매개변수를 **제한**해야할 수 있습니다.
+몇몇의 특이한 경우에 (흔치 않지만), 받으려는 쿼리 매개변수를 **제한**하고 싶을 수 있습니다.
-Pydantic 모델 설정에서 `extra` 필드를 `forbid` 로 설정할 수 있습니다.
+Pydantic의 모델 설정을 사용해 어떤 `extra` 필드도 `forbid`할 수 있습니다:
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
-만약 클라이언트가 쿼리 매개변수로 **추가적인** 데이터를 보내려고 하면, 클라이언트는 **에러** 응답을 받게 됩니다.
+클라이언트가 **쿼리 매개변수**로 **추가적인** 데이터를 보내려고 하면 **에러** 응답을 받게 됩니다.
-예를 들어, 아래와 같이 만약 클라이언트가 `tool` 쿼리 매개변수에 `plumbus` 라는 값을 추가해서 보내려고 하면,
+예를 들어, 아래와 같이 클라이언트가 `tool` 쿼리 매개변수에 `plumbus` 값을 보내려고 하면:
```http
https://example.com/items/?limit=10&tool=plumbus
```
-클라이언트는 쿼리 매개변수 `tool` 이 허용되지 않는다는 **에러** 응답을 받게 됩니다.
+쿼리 매개변수 `tool`이 허용되지 않는다는 **에러** 응답을 받게 됩니다:
```json
{
}
```
-## 요약
+## 요약 { #summary }
-**FastAPI** 에서 **쿼리 매개변수** 를 선언할 때 **Pydantic 모델** 을 사용할 수 있습니다. 😎
+**FastAPI**에서 **쿼리 매개변수**를 선언할 때 **Pydantic 모델**을 사용할 수 있습니다. 😎
/// tip | 팁
-ì\8a¤í\8f¬ì\9d¼ë\9f¬ ê²½ê³ : Pydantic 모ë\8d¸ì\9d\84 ì¿ í\82¤ì\99\80 í\97¤ë\8d\94ì\97\90ë\8f\84 ì \81ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ì\97\90 ë\8c\80í\95´ì\84\9cë\8a\94 ì\9d´í\9b\84 í\8a\9cí\86 리ì\96¼ì\97\90ì\84\9c ë\8b¤ë£° ì\98\88ì \95입니다. 🤫
+ì\8a¤í\8f¬ì\9d¼ë\9f¬ ê²½ê³ : Pydantic 모ë\8d¸ì\9d\84 ì¿ í\82¤ì\99\80 í\97¤ë\8d\94ì\97\90ë\8f\84 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì§\80ë§\8c, ì\9d´ì\97\90 ë\8c\80í\95´ì\84\9cë\8a\94 ì\9d´í\9b\84 í\8a\9cí\86 리ì\96¼ì\97\90ì\84\9c ì\9d½ê²\8c ë\90 ê²\83입니다. 🤫
///
-# 쿼리 매개변수와 문자열 검증
+# 쿼리 매개변수와 문자열 검증 { #query-parameters-and-string-validations }
**FastAPI**를 사용하면 매개변수에 대한 추가 정보 및 검증을 선언할 수 있습니다.
이 응용 프로그램을 예로 들어보겠습니다:
-{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
-쿼리 매개변수 `q`는 `Optional[str]` 자료형입니다. 즉, `str` 자료형이지만 `None` 역시 될 수 있음을 뜻하고, 실제로 기본값은 `None`이기 때문에 FastAPI는 이 매개변수가 필수가 아니라는 것을 압니다.
+쿼리 매개변수 `q`는 `str | None` 자료형입니다. 즉, `str` 자료형이지만 `None` 역시 될 수 있음을 뜻하고, 실제로 기본값은 `None`이기 때문에 FastAPI는 이 매개변수가 필수가 아니라는 것을 압니다.
/// note | 참고
FastAPI는 `q`의 기본값이 `= None`이기 때문에 필수가 아님을 압니다.
-`Optional[str]`에 있는 `Optional`은 FastAPI가 사용하는게 아니지만, 편집기에게 더 나은 지원과 오류 탐지를 제공하게 해줍니다.
+`str | None`을 사용하면 편집기가 더 나은 지원과 오류 탐지를 제공하게 해줍니다.
///
-## 추가 검증
+## 추가 검증 { #additional-validation }
-`q`ê°\80 ì\84 í\83\9dì \81ì\9d´ì§\80ë§\8c ê°\92ì\9d´ 주ì\96´ì§\88 ë\95\8cë§\88ë\8b¤ **ê°\92ì\9d´ 50 ê¸\80자를 초과하지 않게** 강제하려 합니다.
+`q`ê°\80 ì\84 í\83\9dì \81ì\9d´ì§\80ë§\8c ê°\92ì\9d´ 주ì\96´ì§\88 ë\95\8cë§\88ë\8b¤ **길ì\9d´ê°\80 50자를 초과하지 않게** 강제하려 합니다.
-### `Query` 임포트
+### `Query`와 `Annotated` 임포트 { #import-query-and-annotated }
-이를 위해 먼저 `fastapi`에서 `Query`를 임포트합니다:
+이를 위해 먼저 다음을 임포트합니다:
-{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
+* `fastapi`에서 `Query`
+* `typing`에서 `Annotated`
-## 기본값으로 `Query` 사용
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
-이제 `Query`를 매개변수의 기본값으로 사용하여 `max_length` 매개변수를 50으로 설정합니다:
+/// info | 정보
-{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
+FastAPI는 0.95.0 버전에서 `Annotated` 지원을 추가했고(그리고 이를 권장하기 시작했습니다).
-기본ê°\92 `None`ì\9d\84 `Query(None)`ì\9c¼ë¡\9c ë°\94ê¿\94ì\95¼ í\95\98ë¯\80ë¡\9c, `Query`ì\9d\98 첫 ë²\88째 매ê°\9cë³\80ì\88\98ë\8a\94 기본ê°\92ì\9d\84 ì \95ì\9d\98í\95\98ë\8a\94 ê²\83ê³¼ ê°\99ì\9d\80 목ì \81ì\9c¼ë¡\9c ì\82¬ì\9a©ë\90©ë\8b\88ë\8b¤.
+ì\9d´ì \84 ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ë©´ `Annotated`를 ì\82¬ì\9a©í\95\98ë ¤ê³ í\95 ë\95\8c ì\98¤ë¥\98ê°\80 ë°\9cì\83\9dí\95©ë\8b\88ë\8b¤.
-그러므로:
+`Annotated`를 사용하기 전에 최소 0.95.1 버전으로 [FastAPI 버전 업그레이드](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}를 진행하세요.
+
+///
+
+## `q` 매개변수의 타입에 `Annotated` 사용하기 { #use-annotated-in-the-type-for-the-q-parameter }
+
+이전에 [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}에서 `Annotated`를 사용해 매개변수에 메타데이터를 추가할 수 있다고 말씀드린 것을 기억하시나요?
+
+이제 FastAPI에서 사용할 차례입니다. 🚀
+
+다음과 같은 타입 어노테이션이 있었습니다:
+
+//// tab | Python 3.10+
```Python
-q: Optional[str] = Query(None)
+q: str | None = None
```
-...위 코드는 아래와 동일하게 매개변수를 선택적으로 만듭니다:
+////
+
+//// tab | Python 3.9+
```Python
-q: Optional[str] = None
+q: Union[str, None] = None
```
-하지만 명시적으로 쿼리 매개변수를 선언합니다.
+////
-/// info | 정보
+여기서 `Annotated`로 감싸서 다음과 같이 만듭니다:
-FastAPI는 다음 부분에 관심이 있습니다:
+//// tab | Python 3.10+
```Python
-= None
+q: Annotated[str | None] = None
```
-또는:
+////
+
+//// tab | Python 3.9+
```Python
-= Query(None)
+q: Annotated[Union[str, None]] = None
```
-그리고 `None`을 사용하여 쿼라 매개변수가 필수적이지 않다는 것을 파악합니다.
+////
+
+두 버전 모두 같은 의미로, `q`는 `str` 또는 `None`이 될 수 있는 매개변수이며 기본값은 `None`입니다.
+
+이제 재미있는 부분으로 넘어가 봅시다. 🎉
-`Optional` 부분은 편집기에게 더 나은 지원을 제공하기 위해서만 사용됩니다.
+## `q` 매개변수의 `Annotated`에 `Query` 추가하기 { #add-query-to-annotated-in-the-q-parameter }
+
+이제 이 `Annotated`에 더 많은 정보를 넣을 수 있으므로(이 경우에는 추가 검증), `Annotated` 안에 `Query`를 추가하고 `max_length` 매개변수를 `50`으로 설정합니다:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
+
+기본값은 여전히 `None`이므로, 매개변수는 여전히 선택적입니다.
+
+하지만 `Annotated` 안에 `Query(max_length=50)`를 넣음으로써, 이 값에 대해 **추가 검증**을 적용하고 최대 50자까지만 허용하도록 FastAPI에 알려줍니다. 😎
+
+/// tip | 팁
+
+여기서는 **쿼리 매개변수**이기 때문에 `Query()`를 사용합니다. 나중에 `Path()`, `Body()`, `Header()`, `Cookie()`와 같이 `Query()`와 동일한 인자를 받는 것들도 보게 될 것입니다.
///
-또한 `Query`로 더 많은 매개변수를 전달할 수 있습니다. 지금의 경우 문자열에 적용되는 `max_length` 매개변수입니다:
+이제 FastAPI는 다음을 수행합니다:
+
+* 최대 길이가 50자인지 확인하도록 데이터를 **검증**합니다
+* 데이터가 유효하지 않을 때 클라이언트에게 **명확한 오류**를 보여줍니다
+* OpenAPI 스키마 *경로 처리*에 매개변수를 **문서화**합니다(따라서 **자동 문서 UI**에 표시됩니다)
+
+## 대안(이전 방식): 기본값으로 `Query` 사용 { #alternative-old-query-as-the-default-value }
+
+이전 FastAPI 버전(<abbr title="before 2023-03">0.95.0</abbr> 이전)에서는 `Annotated`에 넣는 대신, 매개변수의 기본값으로 `Query`를 사용해야 했습니다. 주변에서 이 방식을 사용하는 코드를 볼 가능성이 높기 때문에 설명해 드리겠습니다.
+
+/// tip | 팁
+
+새 코드를 작성할 때와 가능할 때는 위에서 설명한 대로 `Annotated`를 사용하세요. 여러 장점이 있고(아래에서 설명합니다) 단점은 없습니다. 🍰
+
+///
+
+다음은 함수 매개변수의 기본값으로 `Query()`를 사용하면서 `max_length`를 50으로 설정하는 방법입니다:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
+
+이 경우(`Annotated`를 사용하지 않는 경우) 함수에서 기본값 `None`을 `Query()`로 바꿔야 하므로, 이제 `Query(default=None)`로 기본값을 설정해야 합니다. (최소한 FastAPI 입장에서는) 이 인자는 해당 기본값을 정의하는 것과 같은 목적을 수행합니다.
+
+그러므로:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+...위 코드는 기본값이 `None`인 선택적 매개변수를 만들며, 아래와 동일합니다:
+
```Python
-q: str = Query(None, max_length=50)
+q: str | None = None
```
-이는 데이터를 검증할 것이고, 데이터가 유효하지 않다면 명백한 오류를 보여주며, OpenAPI 스키마 *경로 작동*에 매개변수를 문서화 합니다.
+하지만 `Query` 버전은 이것이 쿼리 매개변수임을 명시적으로 선언합니다.
-## 검증 추가
+그 다음, `Query`로 더 많은 매개변수를 전달할 수 있습니다. 지금의 경우 문자열에 적용되는 `max_length` 매개변수입니다:
+
+```Python
+q: str | None = Query(default=None, max_length=50)
+```
-매개변수 `min_length` 또한 추가할 수 있습니다:
+이는 데이터를 검증할 것이고, 데이터가 유효하지 않다면 명백한 오류를 보여주며, OpenAPI 스키마 *경로 처리*에 매개변수를 문서화 합니다.
-{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
+### 기본값으로 `Query` 사용 또는 `Annotated`에 넣기 { #query-as-the-default-value-or-in-annotated }
-## 정규식 추가
+`Annotated` 안에서 `Query`를 사용할 때는 `Query`에 `default` 매개변수를 사용할 수 없다는 점을 기억하세요.
-매개변수와 일치해야 하는 <abbr title="정규표현식(regular expression), regex 또는 regexp는 문자열 조회 패턴을 정의하는 문자들의 순열입니다">정규표현식</abbr>을 정의할 수 있습니다:
+대신 함수 매개변수의 실제 기본값을 사용하세요. 그렇지 않으면 일관성이 깨집니다.
+
+예를 들어, 다음은 허용되지 않습니다:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...왜냐하면 기본값이 `"rick"`인지 `"morty"`인지 명확하지 않기 때문입니다.
+
+따라서 (가능하면) 다음과 같이 사용합니다:
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...또는 오래된 코드베이스에서는 다음과 같은 코드를 찾게 될 것입니다:
+
+```Python
+q: str = Query(default="rick")
+```
-{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
+### `Annotated`의 장점 { #advantages-of-annotated }
-이 특정 정규표현식은 전달 받은 매개변수 값을 검사합니다:
+함수 매개변수의 기본값 방식 대신 **`Annotated`를 사용하는 것을 권장**합니다. 여러 이유로 **더 좋기** 때문입니다. 🤓
-* `^`: 이전에 문자가 없고 뒤따르는 문자로 시작합니다.
-* `fixedquery`: 정확히 `fixedquery` 값을 갖습니다.
-* `$`: 여기서 끝나고 `fixedquery` 이후로 아무 문자도 갖지 않습니다.
+**함수 매개변수**의 **기본값**이 **실제 기본값**이 되므로, 전반적으로 Python에 더 직관적입니다. 😌
-**"정규표현식"** 개념에 대해 상실감을 느꼈다면 걱정하지 않아도 됩니다. 많은 사람에게 어려운 주제입니다. 아직은 정규표현식 없이도 많은 작업들을 할 수 있습니다.
+FastAPI 없이도 **다른 곳에서** 같은 함수를 **호출**할 수 있고, **예상대로 동작**합니다. **필수** 매개변수(기본값이 없는 경우)가 있다면 **편집기**가 오류로 알려줄 것이고, 필수 매개변수를 전달하지 않고 실행하면 **Python**도 오류를 냅니다.
-í\95\98ì§\80ë§\8c ì\96¸ì \9cë\93 ì§\80 ê°\80ì\84\9c ë°°ì\9a¸ì\88\98 ì\9e\88ê³ , **FastAPI**ì\97\90ì\84\9c ì§\81ì \91 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ë\8b¤ë\8a\94 ì\82¬ì\8b¤ì\9d\84 ì\95\8cê³ ì\9e\88ì\96´ì\95¼ í\95©ë\8b\88ë\8b¤.
+`Annotated`를 ì\82¬ì\9a©í\95\98ì§\80 ì\95\8aê³ **(ì\9d´ì \84) 기본ê°\92 ì\8a¤í\83\80ì\9d¼**ì\9d\84 ì\82¬ì\9a©í\95\98ë©´, FastAPI ì\97\86ì\9d´ **ë\8b¤ë¥¸ ê³³ì\97\90ì\84\9c** í\95¨ì\88\98를 í\98¸ì¶\9cí\95 ë\95\8cë\8f\84 ì \9cë\8c\80ë¡\9c ë\8f\99ì\9e\91í\95\98ë\8f\84ë¡\9d í\95¨ì\88\98ì\97\90 ì\9d¸ì\9e\90를 ì \84ë\8b¬í\95´ì\95¼ í\95\9cë\8b¤ë\8a\94 ê²\83ì\9d\84 **기ì\96µ**í\95´ì\95¼ í\95©ë\8b\88ë\8b¤. ê·¸ë \87ì§\80 ì\95\8aì\9c¼ë©´ ê°\92ì\9d´ 기ë\8c\80ì\99\80 ë\8b¤ë¥´ê²\8c ë\90©ë\8b\88ë\8b¤(ì\98\88: `str` ë\8c\80ì\8b `QueryInfo` ê°\99ì\9d\80 ê²\83). ê·¸ë¦¬ê³ í\8e¸ì§\91기ë\8f\84 ê²½ê³ í\95\98ì§\80 ì\95\8aê³ Pythonë\8f\84 ê·¸ í\95¨ì\88\98를 ì\8b¤í\96\89í\95 ë\95\8cë\8a\94 ë¶\88í\8f\89í\95\98ì§\80 ì\95\8aì\9c¼ë©°, ì\98¤ì§\81 ë\82´ë¶\80 ë\8f\99ì\9e\91ì\97\90ì\84\9c ì\98¤ë¥\98ê°\80 ë°\9cì\83\9dí\95 ë\95\8cë§\8c 문ì \9cê°\80 ë\93\9cë\9f¬ë\82©ë\8b\88ë\8b¤.
-## 기본값
+`Annotated`는 하나 이상의 메타데이터 어노테이션을 가질 수 있기 때문에, 이제 <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a> 같은 다른 도구에서도 같은 함수를 사용할 수 있습니다. 🚀
-기본값으로 사용하는 첫 번째 인자로 `None`을 전달하듯이, 다른 값을 전달할 수 있습니다.
+## 검증 더 추가하기 { #add-more-validations }
-`min_length`가 `3`이고, 기본값이 `"fixedquery"`인 쿼리 매개변수 `q`를 선언해봅시다:
+`min_length` 매개변수도 추가할 수 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
+{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
+
+## 정규식 추가 { #add-regular-expressions }
+
+매개변수와 일치해야 하는 <abbr title="문자열에 대한 검색 패턴을 정의하는 문자들의 순열인 정규 표현식(regular expression), regex 또는 regexp입니다.">정규 표현식</abbr> `pattern`을 정의할 수 있습니다:
+
+{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
+
+이 특정 정규표현식 패턴은 전달 받은 매개변수 값이 다음을 만족하는지 검사합니다:
+
+* `^`: 뒤따르는 문자로 시작하며, 앞에는 문자가 없습니다.
+* `fixedquery`: 정확히 `fixedquery` 값을 가집니다.
+* `$`: 여기서 끝나며, `fixedquery` 이후로 더 이상 문자가 없습니다.
+
+**"정규 표현식"** 개념에 대해 상실감을 느꼈다면 걱정하지 않아도 됩니다. 많은 사람에게 어려운 주제입니다. 아직은 정규 표현식 없이도 많은 작업들을 할 수 있습니다.
+
+이제 필요할 때 언제든지 **FastAPI**에서 직접 사용할 수 있다는 사실을 알게 되었습니다.
+
+## 기본값 { #default-values }
+
+물론 `None`이 아닌 다른 기본값을 사용할 수도 있습니다.
+
+`q` 쿼리 매개변수에 `min_length`를 `3`으로 설정하고, 기본값을 `"fixedquery"`로 선언하고 싶다고 해봅시다:
+
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note | 참고
-기본값을 갖는 것만으로 매개변수는 선택적이 됩니다.
+`None`을 포함해 어떤 타입이든 기본값을 가지면 매개변수는 선택적(필수 아님)이 됩니다.
///
-## 필수로 만들기
+## 필수 매개변수 { #required-parameters }
더 많은 검증이나 메타데이터를 선언할 필요가 없는 경우, 다음과 같이 기본값을 선언하지 않고 쿼리 매개변수 `q`를 필수로 만들 수 있습니다:
아래 대신:
```Python
-q: Optional[str] = None
+q: str | None = None
```
-그러나 이제 다음과 같이 `Query`로 선언합니다:
+하지만 이제는 예를 들어 다음과 같이 `Query`로 선언합니다:
```Python
-q: Optional[str] = Query(None, min_length=3)
+q: Annotated[str | None, Query(min_length=3)] = None
```
-그래서 `Query`를 필수값으로 만들어야 할 때면, 첫 번째 인자로 `...`를 사용할 수 있습니다:
+따라서 `Query`를 사용하면서 값을 필수로 선언해야 할 때는, 기본값을 선언하지 않으면 됩니다:
-{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
-/// info | 정보
+### 필수지만 `None` 가능 { #required-can-be-none }
-이전에 `...`를 본적이 없다면: 특별한 단일값으로, <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">파이썬의 일부이며 "Ellipsis"라 부릅니다</a>.
+매개변수가 `None`을 허용하지만 여전히 필수라고 선언할 수 있습니다. 이렇게 하면 값이 `None`이더라도 클라이언트는 값을 반드시 전송해야 합니다.
-///
+이를 위해 `None`이 유효한 타입이라고 선언하되, 기본값은 선언하지 않으면 됩니다:
-이렇게 하면 **FastAPI**가 이 매개변수는 필수임을 알 수 있습니다.
+{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
-## 쿼리 매개변수 리스트 / 다중값
+## 쿼리 매개변수 리스트 / 다중값 { #query-parameter-list-multiple-values }
-쿼리 매개변수를 `Query`와 함께 명시적으로 선언할 때, 값들의 리스트나 다른 방법으로 여러 값을 받도록 선언 할 수도 있습니다.
+`Query`로 쿼리 매개변수를 명시적으로 정의할 때 값들의 리스트를 받도록 선언할 수도 있고, 다른 말로 하면 여러 값을 받도록 선언할 수도 있습니다.
-예를 들어, URL에서 여러번 나오는 `q` 쿼리 매개변수를 선언하려면 다음과 같이 작성할 수 있습니다:
+예를 들어, URL에서 여러 번 나타날 수 있는 `q` 쿼리 매개변수를 선언하려면 다음과 같이 작성할 수 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
-아래와 같은 URL을 사용합니다:
+그 다음, 아래와 같은 URL로:
```
http://localhost:8000/items/?q=foo&q=bar
```
-여러 `q` *쿼리 매개변수* 값들을 (`foo` 및 `bar`) 파이썬 `list`로 *경로 작동 함수* 내 *함수 매개변수* `q`로 전달 받습니다.
+여러 `q` *쿼리 매개변수* 값들(`foo` 및 `bar`)을 파이썬 `list`로 *경로 처리 함수*의 *함수 매개변수* `q`에서 받게 됩니다.
따라서 해당 URL에 대한 응답은 다음과 같습니다:
/// tip | 팁
-위의 예와 같이 `list` 자료형으로 쿼리 매개변수를 선언하려면 `Query`를 명시적으로 사용해야 합니다. 그렇지 않으면 요청 본문으로 해석됩니다.
+위의 예와 같이 `list` 타입으로 쿼리 매개변수를 선언하려면 `Query`를 명시적으로 사용해야 합니다. 그렇지 않으면 요청 본문으로 해석됩니다.
///
<img src="/img/tutorial/query-params-str-validations/image02.png">
-### 쿼리 매ê°\9cë³\80ì\88\98 리ì\8a¤í\8a¸ / 기본ê°\92ì\9d\84 ì\82¬ì\9a©í\95\98ë\8a\94 ë\8b¤ì¤\91ê°\92
+### 쿼리 매ê°\9cë³\80ì\88\98 리ì\8a¤í\8a¸ / 기본ê°\92ì\9d´ ì\9e\88ë\8a\94 ë\8b¤ì¤\91ê°\92 { #query-parameter-list-multiple-values-with-defaults }
-그리고 제공된 값이 없으면 기본 `list` 값을 정의할 수도 있습니다:
+제공된 값이 없으면 기본 `list` 값을 정의할 수도 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
-아래로 이동한다면:
+다음으로 이동하면:
```
http://localhost:8000/items/
```
-`q`의 기본값은: `["foo", "bar"]`이며 응답은 다음이 됩니다:
+`q`의 기본값은 `["foo", "bar"]`가 되고, 응답은 다음이 됩니다:
```JSON
{
}
```
-#### `list` 사용하기
+#### `list`만 사용하기 { #using-just-list }
-`List[str]` 대신 `list`를 직접 사용할 수도 있습니다:
+`list[str]` 대신 `list`를 직접 사용할 수도 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note | 참고
-이 경우 FastAPI는 리스트의 내용을 검사하지 않음을 명심하기 바랍니다.
+이 경우 FastAPI는 리스트의 내용을 검사하지 않음을 명심하세요.
-예를 들어, `List[int]`는 리스트 내용이 정수인지 검사(및 문서화)합니다. 하지만 `list` 단독일 경우는 아닙니다.
+예를 들어, `list[int]`는 리스트 내용이 정수인지 검사(및 문서화)합니다. 하지만 `list` 단독일 경우는 아닙니다.
///
-## 더 많은 메타데이터 선언
+## 더 많은 메타데이터 선언 { #declare-more-metadata }
매개변수에 대한 정보를 추가할 수 있습니다.
/// note | 참고
-도구에 따라 OpenAPI 지원 수준이 다를 수 있음을 명심하기 바랍니다.
+도구에 따라 OpenAPI 지원 수준이 다를 수 있음을 명심하세요.
일부는 아직 선언된 추가 정보를 모두 표시하지 않을 수 있지만, 대부분의 경우 누락된 기능은 이미 개발 계획이 있습니다.
`title`을 추가할 수 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
+{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
그리고 `description`도 추가할 수 있습니다:
-{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
+{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
-## 별칭 매개변수
+## 별칭 매개변수 { #alias-parameters }
매개변수가 `item-query`이길 원한다고 가정해 봅시다.
http://127.0.0.1:8000/items/?item-query=foobaritems
```
-그러나 `item-query`은 유효한 파이썬 변수 이름이 아닙니다.
+그러나 `item-query`는 유효한 파이썬 변수 이름이 아닙니다.
가장 가까운 것은 `item_query`일 겁니다.
-하지만 정확히`item-query`이길 원합니다...
+하지만 정확히 `item-query`이길 원합니다...
이럴 경우 `alias`를 선언할 수 있으며, 해당 별칭은 매개변수 값을 찾는 데 사용됩니다:
-{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
-## 매개변수 사용하지 않게 하기
+## 매개변수 사용 중단하기 { #deprecating-parameters }
-이제는 더이상 이 매개변수를 마음에 들어하지 않는다고 가정해 봅시다.
+이제는 더 이상 이 매개변수를 마음에 들어하지 않는다고 가정해 봅시다.
-이 매개변수를 사용하는 클라이언트가 있기 때문에 한동안은 남겨둬야 하지만, <abbr title="구식이며, 사용하지 않는 것을 추천">사용되지 않는다(deprecated)</abbr>고 확실하게 문서에서 보여주고 싶습니다.
+이 매개변수를 사용하는 클라이언트가 있기 때문에 한동안은 남겨둬야 하지만, 문서에서 <abbr title="obsolete, recommended not to use it – 구식이며, 사용하지 않는 것을 추천">deprecated</abbr>로 명확하게 보여주고 싶습니다.
그렇다면 `deprecated=True` 매개변수를 `Query`로 전달합니다:
-{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
+{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
문서가 아래와 같이 보일겁니다:
<img src="/img/tutorial/query-params-str-validations/image01.png">
-## 요약
+## OpenAPI에서 매개변수 제외 { #exclude-parameters-from-openapi }
+
+생성된 OpenAPI 스키마(따라서 자동 문서화 시스템)에서 쿼리 매개변수를 제외하려면 `Query`의 `include_in_schema` 매개변수를 `False`로 설정하세요:
+
+{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
+
+## 커스텀 검증 { #custom-validation }
+
+위에 나온 매개변수들로는 할 수 없는 **커스텀 검증**이 필요한 경우가 있을 수 있습니다.
+
+그런 경우에는 일반적인 검증(예: 값이 `str`인지 검증한 뒤) 이후에 적용되는 **커스텀 검증 함수**를 사용할 수 있습니다.
+
+`Annotated` 안에서 <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic의 `AfterValidator`</a>를 사용하면 이를 구현할 수 있습니다.
+
+/// tip | 팁
+
+Pydantic에는 <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a>와 같은 다른 것들도 있습니다. 🤓
+
+///
+
+예를 들어, 이 커스텀 validator는 <abbr title="ISBN means International Standard Book Number – 국제 표준 도서 번호">ISBN</abbr> 도서 번호의 경우 아이템 ID가 `isbn-`으로 시작하고, <abbr title="IMDB (Internet Movie Database) is a website with information about movies – 영화에 대한 정보를 제공하는 웹사이트">IMDB</abbr> 영화 URL ID의 경우 `imdb-`로 시작하는지 확인합니다:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
+
+/// info | 정보
+
+이는 Pydantic 2 이상 버전에서 사용할 수 있습니다. 😎
+
+///
+
+/// tip | 팁
+
+데이터베이스나 다른 API 같은 **외부 구성요소**와 통신이 필요한 어떤 종류의 검증이든 해야 한다면, 대신 **FastAPI Dependencies**를 사용해야 합니다. 이에 대해서는 나중에 배우게 됩니다.
+
+이 커스텀 validator는 요청에서 제공된 **같은 데이터만**으로 확인할 수 있는 것들을 위한 것입니다.
+
+///
+
+### 코드 이해하기 { #understand-that-code }
+
+중요한 부분은 **`Annotated` 안에서 함수와 함께 `AfterValidator`를 사용한다는 것**뿐입니다. 이 부분은 건너뛰셔도 됩니다. 🤸
+
+---
+
+하지만 이 특정 코드 예제가 궁금하고 계속 보고 싶다면, 추가 세부사항은 다음과 같습니다.
+
+#### `value.startswith()`를 사용한 문자열 { #string-with-value-startswith }
+
+알고 계셨나요? `value.startswith()`를 사용하는 문자열은 튜플을 받을 수 있으며, 튜플에 있는 각 값을 확인합니다:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
+
+#### 임의의 항목 { #a-random-item }
+
+`data.items()`를 사용하면 각 딕셔너리 항목의 키와 값을 담은 튜플로 구성된 <abbr title="리스트, 세트 등처럼 for 루프로 순회할 수 있는 것">iterable object</abbr>를 얻습니다.
+
+이 iterable object를 `list(data.items())`로 적절한 `list`로 변환합니다.
+
+그 다음 `random.choice()`로 리스트에서 **무작위 값**을 얻어 `(id, name)` 형태의 튜플을 얻습니다. 예를 들어 `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")` 같은 값이 될 것입니다.
+
+그 다음 이 튜플의 **두 값을** 변수 `id`와 `name`에 **할당**합니다.
+
+따라서 사용자가 아이템 ID를 제공하지 않더라도, 무작위 추천을 받게 됩니다.
+
+...이 모든 것을 **단 하나의 간단한 줄**로 합니다. 🤯 Python 정말 좋지 않나요? 🐍
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
+
+## 요약 { #recap }
매개변수에 검증과 메타데이터를 추가 선언할 수 있습니다.
* `description`
* `deprecated`
-특정 문자열 검증:
+문자열에 특화된 검증:
* `min_length`
* `max_length`
-* `regex`
+* `pattern`
+
+`AfterValidator`를 사용하는 커스텀 검증.
예제에서 `str` 값의 검증을 어떻게 추가하는지 살펴보았습니다.
-숫자와 같은 다른 자료형에 대한 검증을 어떻게 선언하는지 확인하려면 다음 장을 확인하기 바랍니다.
+숫자와 같은 다른 타입에 대한 검증을 어떻게 선언하는지 확인하려면 다음 장을 확인하기 바랍니다.
-# 쿼리 매개변수
+# 쿼리 매개변수 { #query-parameters }
경로 매개변수의 일부가 아닌 다른 함수 매개변수를 선언하면 "쿼리" 매개변수로 자동 해석합니다.
-{* ../../docs_src/query_params/tutorial001.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
쿼리는 URL에서 `?` 후에 나오고 `&`으로 구분되는 키-값 쌍의 집합입니다.
경로 매개변수에 적용된 동일한 프로세스가 쿼리 매개변수에도 적용됩니다:
* (당연히) 편집기 지원
-* 데이터 <abbr title="HTTP 요청에서 전달되는 문자열을 파이썬 데이터로 변환">"파싱"</abbr>
+* 데이터 <abbr title="converting the string that comes from an HTTP request into Python data">"파싱"</abbr>
* 데이터 검증
* 자동 문서화
-## 기본값
+## 기본값 { #defaults }
쿼리 매개변수는 경로에서 고정된 부분이 아니기 때문에 선택적일 수 있고 기본값을 가질 수 있습니다.
* `skip=20`: URL에서 지정했기 때문입니다
* `limit=10`: 기본값이기 때문입니다
-## 선택적 매개변수
+## 선택적 매개변수 { #optional-parameters }
같은 방법으로 기본값을 `None`으로 설정하여 선택적 매개변수를 선언할 수 있습니다:
-{* ../../docs_src/query_params/tutorial002.py hl[9] *}
+{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
이 경우 함수 매개변수 `q`는 선택적이며 기본값으로 `None` 값이 됩니다.
-/// check | 확인
+/// check
-**FastAPI**는 `item_id`가 경로 매개변수이고 `q`는 경로 매개변수가 아닌 쿼리 매개변수라는 것을 알 정도로 충분히 똑똑합니다.
+또한 **FastAPI**는 `item_id`가 경로 매개변수이고 `q`는 경로 매개변수가 아니라서 쿼리 매개변수라는 것을 알 정도로 충분히 똑똑하다는 점도 확인하세요.
///
-/// note | 참고
-
-FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다.
-
-`Union[str, None]`에 있는 `Union`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Union[str, None]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다.
-
-///
-
-## 쿼리 매개변수 형변환
+## 쿼리 매개변수 형변환 { #query-parameter-type-conversion }
`bool` 형으로 선언할 수도 있고, 아래처럼 변환됩니다:
-{* ../../docs_src/query_params/tutorial003.py hl[9] *}
+{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
이 경우, 아래로 이동하면:
http://127.0.0.1:8000/items/foo?short=yes
```
-또는 다른 어떤 변형(대문자, 첫글자만 대문자 등)이더라도 함수는 매개변수 `bool`형을 가진 `short`의 값이 `True`임을 압니다. 그렇지 않은 경우 `False`입니다.
+또는 다른 어떤 변형(대문자, 첫글자만 대문자 등)이더라도 함수는 `bool` 값이 `True`인 매개변수 `short`를 보게 됩니다. 그렇지 않은 경우 `False`입니다.
-## 여러 경로/쿼리 매개변수
+## 여러 경로/쿼리 매개변수 { #multiple-path-and-query-parameters }
여러 경로 매개변수와 쿼리 매개변수를 동시에 선언할 수 있으며 **FastAPI**는 어느 것이 무엇인지 알고 있습니다.
매개변수들은 이름으로 감지됩니다:
-{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
+{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
-## 필수 쿼리 매개변수
+## 필수 쿼리 매개변수 { #required-query-parameters }
경로가 아닌 매개변수에 대한 기본값을 선언할 때(지금은 쿼리 매개변수만 보았습니다), 해당 매개변수는 필수적(Required)이지 않았습니다.
그러나 쿼리 매개변수를 필수로 만들려면 단순히 기본값을 선언하지 않으면 됩니다:
-{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
여기 쿼리 매개변수 `needy`는 `str`형인 필수 쿼리 매개변수입니다.
```JSON
{
- "detail": [
- {
- "loc": [
- "query",
- "needy"
- ],
- "msg": "field required",
- "type": "value_error.missing"
- }
- ]
+ "detail": [
+ {
+ "type": "missing",
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "Field required",
+ "input": null
+ }
+ ]
}
```
그리고 물론, 일부 매개변수는 필수로, 다른 일부는 기본값을, 또 다른 일부는 선택적으로 선언할 수 있습니다:
-{* ../../docs_src/query_params/tutorial006.py hl[10] *}
+{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
위 예시에서는 3가지 쿼리 매개변수가 있습니다:
* `skip`, 기본값이 `0`인 `int`.
* `limit`, 선택적인 `int`.
-/// tip | 팁
+/// tip
-[경로 매개변수](path-params.md#_8){.internal-link target=_blank}와 마찬가지로 `Enum`을 사용할 수 있습니다.
+[경로 매개변수](path-params.md#predefined-values){.internal-link target=_blank}와 마찬가지로 `Enum`을 사용할 수 있습니다.
///
-# 파일 요청
+# 파일 요청 { #request-files }
`File`을 사용하여 클라이언트가 업로드할 파일들을 정의할 수 있습니다.
업로드된 파일을 전달받기 위해 먼저 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>를 설치해야합니다.
-예시) `pip install python-multipart`.
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 다음, 예를 들어 다음과 같이 설치하세요:
+
+```console
+$ pip install python-multipart
+```
업로드된 파일들은 "폼 데이터"의 형태로 전송되기 때문에 이 작업이 필요합니다.
///
-## `File` 임포트
+## `File` 임포트 { #import-file }
`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다:
-{* ../../docs_src/request_files/tutorial001.py hl[1] *}
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
-## `File` 매개변수 정의
+## `File` 매개변수 정의 { #define-file-parameters }
`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다:
-{* ../../docs_src/request_files/tutorial001.py hl[7] *}
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
/// info | 정보
파일들은 "폼 데이터"의 형태로 업로드 됩니다.
-*ê²½ë¡\9c ì\9e\91ë\8f\99 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다.
+*ê²½ë¡\9c ì²\98리 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다.
이것은 전체 내용이 메모리에 저장된다는 것을 의미한다는 걸 염두하기 바랍니다. 이는 작은 크기의 파일들에 적합합니다.
어떤 경우에는 `UploadFile` 을 사용하는 것이 더 유리합니다.
-## `File` 매개변수와 `UploadFile`
+## `UploadFile`을 사용하는 `File` 매개변수 { #file-parameters-with-uploadfile }
`File` 매개변수를 `UploadFile` 타입으로 정의합니다:
-{* ../../docs_src/request_files/tutorial001.py hl[12] *}
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
`UploadFile` 을 사용하는 것은 `bytes` 과 비교해 다음과 같은 장점이 있습니다:
+* 매개변수의 기본값에서 `File()`을 사용할 필요가 없습니다.
* "스풀 파일"을 사용합니다.
* 최대 크기 제한까지만 메모리에 저장되며, 이를 초과하는 경우 디스크에 저장됩니다.
* 따라서 이미지, 동영상, 큰 이진코드와 같은 대용량 파일들을 많은 메모리를 소모하지 않고 처리하기에 적합합니다.
* <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `async` 인터페이스를 갖고 있습니다.
* file-like object를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 파이썬 <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> 객체를 반환합니다.
-### `UploadFile`
+### `UploadFile` { #uploadfile }
`UploadFile` 은 다음과 같은 어트리뷰트가 있습니다:
* `filename` : 문자열(`str`)로 된 업로드된 파일의 파일명입니다 (예: `myimage.jpg`).
* `content_type` : 문자열(`str`)로 된 파일 형식(MIME type / media type)입니다 (예: `image/jpeg`).
-* `file` : <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">파일류</a> 객체)입니다. 이것은 "파일류" 객체를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일입니다.
+* `file` : <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> object)입니다. 이것은 "file-like" 객체를 필요로하는 다른 함수나 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일 객체입니다.
`UploadFile` 에는 다음의 `async` 메소드들이 있습니다. 이들은 내부적인 `SpooledTemporaryFile` 을 사용하여 해당하는 파일 메소드를 호출합니다.
상기 모든 메소드들이 `async` 메소드이기 때문에 “await”을 사용하여야 합니다.
-ì\98\88를ë\93¤ì\96´, `async` *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다:
+ì\98\88를ë\93¤ì\96´, `async` *ê²½ë¡\9c ì²\98리 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다:
```Python
contents = await myfile.read()
```
-ë§\8cì\95½ ì\9d¼ë°\98ì \81ì\9d¸ `def` *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*의 내부라면, 다음과 같이 `UploadFile.file` 에 직접 접근할 수 있습니다:
+ë§\8cì\95½ ì\9d¼ë°\98ì \81ì\9d¸ `def` *ê²½ë¡\9c ì²\98리 함수*의 내부라면, 다음과 같이 `UploadFile.file` 에 직접 접근할 수 있습니다:
```Python
contents = myfile.file.read()
```
-/// note | "`async` 기술적 세부사항"
+/// note | `async` 기술 세부사항
`async` 메소드들을 사용할 때 **FastAPI**는 스레드풀에서 파일 메소드들을 실행하고 그들을 기다립니다.
///
-/// note | Starlette 기술적 세부사항
+/// note | Starlette 기술 세부사항
**FastAPI**의 `UploadFile` 은 **Starlette**의 `UploadFile` 을 직접적으로 상속받지만, **Pydantic** 및 FastAPI의 다른 부분들과의 호환성을 위해 필요한 부분들이 추가되었습니다.
///
-## "폼 데이터"란
+## "폼 데이터"란 { #what-is-form-data }
HTML의 폼들(`<form></form>`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다.
**FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다.
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
폼의 데이터는 파일이 포함되지 않은 경우 일반적으로 "미디어 유형" `application/x-www-form-urlencoded` 을 사용해 인코딩 됩니다.
하지만 파일이 포함된 경우, `multipart/form-data`로 인코딩됩니다. `File`을 사용하였다면, **FastAPI**는 본문의 적합한 부분에서 파일을 가져와야 한다는 것을 인지합니다.
-인코딩과 폼 필드에 대해 더 알고싶다면, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><code>POST</code>에 관한<abbr title="Mozilla Developer Network">MDN</abbr>웹 문서</a> 를 참고하기 바랍니다,.
+인코딩과 폼 필드에 대해 더 알고싶다면, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>를 참고하기 바랍니다.
///
/// warning | 경고
-ë\8b¤ì\88\98ì\9d\98 `File` ê³¼ `Form` 매ê°\9cë³\80ì\88\98를 í\95\9c *ê²½ë¡\9c ì\9e\91ë\8f\99*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다.
+ë\8b¤ì\88\98ì\9d\98 `File` ê³¼ `Form` 매ê°\9cë³\80ì\88\98를 í\95\9c *ê²½ë¡\9c ì²\98리*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다.
이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다.
///
-## 다중 파일 업로드
+## 선택적 파일 업로드 { #optional-file-upload }
-여러 파일을 동시에 업로드 할 수 있습니다.
+표준 타입 애너테이션을 사용하고 기본값을 `None`으로 설정하여 파일을 선택적으로 만들 수 있습니다:
-그들은 "폼 데이터"를 사용하여 전송된 동일한 "폼 필드"에 연결됩니다.
+{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
-이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:
+## 추가 메타데이터를 포함한 `UploadFile` { #uploadfile-with-additional-metadata }
-{* ../../docs_src/request_files/tutorial002.py hl[10,15] *}
+추가 메타데이터를 설정하기 위해 예를 들어 `UploadFile`과 함께 `File()`을 사용할 수도 있습니다:
-선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다.
+{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
-/// note | 참고
+## 다중 파일 업로드 { #multiple-file-uploads }
-2019년 4월 14일부터 Swagger UI가 하나의 폼 필드로 다수의 파일을 업로드하는 것을 지원하지 않습니다. 더 많은 정보를 원하면, <a href="https://github.com/swagger-api/swagger-ui/issues/4276" class="external-link" target="_blank">#4276</a>과 <a href="https://github.com/swagger-api/swagger-ui/issues/3641" class="external-link" target="_blank">#3641</a>을 참고하세요.
+여러 파일을 동시에 업로드 할 수 있습니다.
-ê·¸ë\9f¼ì\97\90ë\8f\84, **FastAPI**ë\8a\94 í\91\9cì¤\80 Open API를 ì\82¬ì\9a©í\95´ ì\9d´ë¯¸ í\98¸í\99\98ì\9d´ ê°\80ë\8a¥í\95©ë\8b\88ë\8b¤.
+ê·¸ë\93¤ì\9d\80 "í\8f¼ ë\8d°ì\9d´í\84°"를 ì\82¬ì\9a©í\95\98ì\97¬ ì \84ì\86¡ë\90\9c ë\8f\99ì\9d¼í\95\9c "í\8f¼ í\95\84ë\93\9c"ì\97\90 ì\97°ê²°ë\90©ë\8b\88ë\8b¤.
-따라서 Swagger UI 또는 기타 그 외의 OpenAPI를 지원하는 툴이 다중 파일 업로드를 지원하는 경우, 이들은 **FastAPI**와 호환됩니다.
+이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:
-///
+{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+
+선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다.
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
`from starlette.responses import HTMLResponse` 역시 사용할 수 있습니다.
///
-## 요약
+### 추가 메타데이터를 포함한 다중 파일 업로드 { #multiple-file-uploads-with-additional-metadata }
+
+이전과 같은 방식으로 `UploadFile`에 대해서도 `File()`을 사용해 추가 매개변수를 설정할 수 있습니다:
+
+{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+
+## 요약 { #recap }
-폼 데이터로써 입력 매개변수로 업로드할 파일을 선언할 경우 `File` 을 사용하기 바랍니다.
+`File`, `bytes`, `UploadFile`을 사용하여 폼 데이터로 전송되는 요청에서 업로드할 파일을 선언하세요.
-# 폼 모델
+# 폼 모델 { #form-models }
FastAPI에서 **Pydantic 모델**을 이용하여 **폼 필드**를 선언할 수 있습니다.
/// info | 정보
-폼(Form)을 사용하려면, 먼저 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>를 설치하세요.
+폼을 사용하려면, 먼저 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>를 설치하세요.
-[ê°\80ì\83\81 í\99\98ê²½](../virtual-environments.md){.internal-link target=_blank}ì\9d\84 ì\83\9dì\84±í\95\98ê³ í\99\9cì\84±í\99\94í\95\9c ë\8b¤ì\9d\8c, ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d´ ì\84¤ì¹\98í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
+[ê°\80ì\83\81 í\99\98ê²½](../virtual-environments.md){.internal-link target=_blank}ì\9d\84 ì\83\9dì\84±í\95\98ê³ í\99\9cì\84±í\99\94í\95\9c ë\8b¤ì\9d\8c, ì\98\88를 ë\93¤ì\96´ ì\95\84ë\9e\98ì\99\80 ê°\99ì\9d´ ì\84¤ì¹\98í\95\98ì\84¸ì\9a\94:
```console
$ pip install python-multipart
///
-## Pydantic 모델을 사용한 폼
+## 폼을 위한 Pydantic 모델 { #pydantic-models-for-forms }
**폼 필드**로 받고 싶은 필드를 **Pydantic 모델**로 선언한 다음, 매개변수를 `Form`으로 선언하면 됩니다:
**FastAPI**는 요청에서 받은 **폼 데이터**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
-## 문서 확인하기
+## 문서 확인하기 { #check-the-docs }
문서 UI `/docs`에서 확인할 수 있습니다:
<img src="/img/tutorial/request-form-models/image01.png">
</div>
-## 추가 폼 필드 금지하기
+## 추가 폼 필드 금지하기 { #forbid-extra-form-fields }
-일부 특별한 사용 사례(흔하지는 않겠지만)에서는 Pydantic 모델에서 정의한 폼 필드를 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다.
+일부 특별한 사용 사례(아마도 흔하지는 않겠지만)에서는 Pydantic 모델에서 선언된 폼 필드로만 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다.
/// note | 참고
///
-Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:
+Pydantic의 모델 구성을 사용하여 `extra` 필드를 `forbid`할 수 있습니다:
{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
}
```
-## 요약
+## 요약 { #summary }
Pydantic 모델을 사용하여 FastAPI에서 폼 필드를 선언할 수 있습니다. 😎
-# 폼 및 파일 요청
+# 폼 및 파일 요청 { #request-forms-and-files }
-`File` 과 `Form` 을 사용하여 파일과 폼을 함께 정의할 수 있습니다.
+`File` 과 `Form` 을 사용하여 파일과 폼 필드를 동시에 정의할 수 있습니다.
/// info | 정보
-파일과 폼 데이터를 함께, 또는 각각 업로드하기 위해 먼저 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>를 설치해야합니다.
+업로드된 파일 및/또는 폼 데이터를 받으려면 먼저 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>를 설치해야 합니다.
-예 ) `pip install python-multipart`.
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 다음 설치해야 합니다. 예:
+
+```console
+$ pip install python-multipart
+```
///
-## `File` ë°\8f `Form` ì\97\85ë¡\9cë\93\9c
+## `File` ë°\8f `Form` ì\9e\84í\8f¬í\8a¸ { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001.py hl[1] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
-## `File` 및 `Form` 매개변수 정의
+## `File` 및 `Form` 매개변수 정의 { #define-file-and-form-parameters }
`Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다:
-{* ../../docs_src/request_forms_and_files/tutorial001.py hl[8] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
-파일과 폼 필드는 폼 데이터 형식으로 업로드되어 파일과 폼 필드로 전달됩니다.
+파일과 폼 필드는 폼 데이터로 업로드되며, 파일과 폼 필드를 받게 됩니다.
-어떤 파일들은 `bytes`로, 또 어떤 파일들은 `UploadFile`로 선언할 수 있습니다.
+또한 일부 파일은 `bytes`로, 일부 파일은 `UploadFile`로 선언할 수 있습니다.
/// warning | 경고
-ë\8b¤ì\88\98ì\9d\98 `File`ê³¼ `Form` 매ê°\9cë³\80ì\88\98를 í\95\9c *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\97\90 ì\84 ì\96¸í\95\98ë\8a\94 ê²\83ì\9d´ ê°\80ë\8a¥í\95\98ì§\80ë§\8c, ì\9a\94ì²ì\9d\98 본문ì\9d´ `application/json`ê°\80 ì\95\84ë\8b\8c `multipart/form-data`ë¡\9c ì\9d¸ì½\94ë\94© ë\90\98기 ë\95\8c문ì\97\90 JSONì\9c¼ë¡\9c ë°\9bì\95\84ì\95¼하는 `Body` 필드를 함께 선언할 수는 없습니다.
+ë\8b¤ì\88\98ì\9d\98 `File`ê³¼ `Form` 매ê°\9cë³\80ì\88\98를 í\95\9c *ê²½ë¡\9c ì²\98리*ì\97\90 ì\84 ì\96¸í\95\98ë\8a\94 ê²\83ì\9d´ ê°\80ë\8a¥í\95\98ì§\80ë§\8c, ì\9a\94ì²ì\9d\98 본문ì\9d´ `application/json`ê°\80 ì\95\84ë\8b\8c `multipart/form-data`ë¡\9c ì\9d¸ì½\94ë\94©ë\90\98기 ë\95\8c문ì\97\90 JSONì\9c¼ë¡\9c ë°\9b기를 기ë\8c\80하는 `Body` 필드를 함께 선언할 수는 없습니다.
-ì\9d´ë\8a\94 **FastAPI**ì\9d\98 í\95\9cê³\84ê°\80 ì\95\84ë\8b\88ë\9d¼, HTTP í\94\84ë¡\9cí\86 ì½\9cì\97\90 ì\9d\98í\95\9c ê²\83입니다.
+ì\9d´ë\8a\94 **FastAPI**ì\9d\98 í\95\9cê³\84ê°\80 ì\95\84ë\8b\88ë\9d¼, HTTP í\94\84ë¡\9cí\86 ì½\9cì\9d\98 ì\9d¼ë¶\80입니다.
///
-## 요약
+## 요약 { #recap }
하나의 요청으로 데이터와 파일들을 받아야 할 경우 `File`과 `Form`을 함께 사용하기 바랍니다.
-# 폼 데이터
+# 폼 데이터 { #form-data }
JSON 대신 폼 필드를 받아야 하는 경우 `Form`을 사용할 수 있습니다.
///
-## `Form` 임포트하기
+## `Form` 임포트하기 { #import-form }
`fastapi`에서 `Form`을 임포트합니다:
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
-## `Form` 매개변수 정의하기
+## `Form` 매개변수 정의하기 { #define-form-parameters }
`Body` 또는 `Query`와 동일한 방식으로 폼 매개변수를 만듭니다:
예를 들어, OAuth2 사양을 사용할 수 있는 방법 중 하나("패스워드 플로우"라고 함)로 `username`과 `password`를 폼 필드로 보내야 합니다.
-<abbr title="specification">사양</abbr>에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다.
+<abbr title="specification">spec</abbr>에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다.
`Form`을 사용하면 유효성 검사, 예제, 별칭(예: `username` 대신 `user-name`) 등을 포함하여 `Body`(및 `Query`, `Path`, `Cookie`)와 동일한 구성을 선언할 수 있습니다.
///
-## "폼 필드"에 대해
+## "폼 필드"에 대해 { #about-form-fields }
HTML 폼(`<form></form>`)이 데이터를 서버로 보내는 방식은 일반적으로 해당 데이터에 대해 "특수" 인코딩을 사용하며, 이는 JSON과 다릅니다.
그러나 폼에 파일이 포함된 경우, `multipart/form-data`로 인코딩합니다. 다음 장에서 파일 처리에 대해 읽을 겁니다.
-
-이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><code>POST</code>에 대한 <abbr title="Mozilla Developer Network">MDN</a> 웹 문서를 참조하세요.
+이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><code>POST</code>에 대한 <abbr title="Mozilla Developer Network">MDN</abbr> 웹 문서를 참조하세요</a>.
///
/// warning | 경고
-*ê²½ë¡\9c ì\9e\91ì\97\85*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다.
+*ê²½ë¡\9c ì²\98리*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다.
이는 **FastAPI**의 제한 사항이 아니며 HTTP 프로토콜의 일부입니다.
///
-## 요약
+## 요약 { #recap }
폼 데이터 입력 매개변수를 선언하려면 `Form`을 사용하세요.
-# 응답 모델
+# 응답 모델 - 반환 타입 { #response-model-return-type }
-어떤 *경로 작동*이든 매개변수 `response_model`를 사용하여 응답을 위한 모델을 선언할 수 있습니다:
+*경로 처리 함수*의 **반환 타입**을 어노테이션하여 응답에 사용될 타입을 선언할 수 있습니다.
+
+함수 **매개변수**에서 입력 데이터를 위해 사용하는 것과 동일하게 **타입 어노테이션**을 사용할 수 있으며, Pydantic 모델, 리스트, 딕셔너리, 정수/불리언 같은 스칼라 값 등을 사용할 수 있습니다.
+
+{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
+
+FastAPI는 이 반환 타입을 사용하여:
+
+* 반환된 데이터를 **검증**합니다.
+ * 데이터가 유효하지 않다면(예: 필드가 누락된 경우), 이는 *여러분의* 앱 코드가 깨져서 의도한 값을 반환하지 못한다는 의미이며, 잘못된 데이터를 반환하는 대신 서버 오류를 반환합니다. 이렇게 하면 여러분과 클라이언트는 기대한 데이터와 데이터 형태를 받는다는 것을 확실히 할 수 있습니다.
+* OpenAPI *경로 처리*의 응답에 **JSON Schema**를 추가합니다.
+ * 이는 **자동 문서**에서 사용됩니다.
+ * 또한 자동 클라이언트 코드 생성 도구에서도 사용됩니다.
+
+하지만 가장 중요한 것은:
+
+* 반환 타입에 정의된 내용으로 출력 데이터를 **제한하고 필터링**합니다.
+ * 이는 특히 **보안**에 매우 중요합니다. 아래에서 더 자세히 살펴보겠습니다.
+
+## `response_model` 매개변수 { #response-model-parameter }
+
+타입 선언이 말하는 것과 정확히 일치하지 않는 데이터를 반환해야 하거나 반환하고 싶은 경우가 있습니다.
+
+예를 들어, **딕셔너리**나 데이터베이스 객체를 **반환**하고 싶지만, **Pydantic 모델로 선언**하고 싶을 수 있습니다. 이렇게 하면 Pydantic 모델이 반환한 객체(예: 딕셔너리나 데이터베이스 객체)에 대해 데이터 문서화, 검증 등 모든 작업을 수행합니다.
+
+반환 타입 어노테이션을 추가했다면, 도구와 에디터가 함수가 선언한 타입(예: Pydantic 모델)과 다른 타입(예: dict)을 반환하고 있다는 (올바른) 오류로 불평할 것입니다.
+
+그런 경우에는 반환 타입 대신 *경로 처리 데코레이터*의 매개변수 `response_model`을 사용할 수 있습니다.
+
+`response_model` 매개변수는 모든 *경로 처리*에서 사용할 수 있습니다:
* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
-* 기타.
+* 등.
-{* ../../docs_src/response_model/tutorial001.py hl[17] *}
+{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
/// note | 참고
-`response_model`ì\9d\80 "ë\8d°ì½\94ë \88ì\9d´í\84°" ë©\94ì\86\8cë\93\9c(`get`, `post`, ë\93±)ì\9d\98 매ê°\9cë³\80ì\88\98ì\9e\85ë\8b\88ë\8b¤. 모ë\93 매ê°\9cë³\80ì\88\98ë\93¤ê³¼ 본문(body)ì²\98ë\9f¼ *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*가 아닙니다.
+`response_model`ì\9d\80 "ë\8d°ì½\94ë \88ì\9d´í\84°" ë©\94ì\84\9cë\93\9c(`get`, `post` ë\93±)ì\9d\98 매ê°\9cë³\80ì\88\98ì\9e\85ë\8b\88ë\8b¤. 모ë\93 매ê°\9cë³\80ì\88\98ì\99\80 bodyì²\98ë\9f¼, *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ì\9d\98 매ê°\9cë³\80ì\88\98가 아닙니다.
///
-Pydantic 모델 어트리뷰트를 선언한 것과 동일한 타입을 수신하므로 Pydantic 모델이 될 수 있지만, `List[Item]`과 같이 Pydantic 모델들의 `list`일 수도 있습니다.
+`response_model`은 Pydantic 모델 필드에 선언하는 것과 동일한 타입을 받습니다. 따라서 Pydantic 모델이 될 수도 있고, `List[Item]`처럼 Pydantic 모델의 `list`가 될 수도 있습니다.
-FastAPI는 이 `response_model`를 사용하여:
+FastAPI는 이 `response_model`을 사용해 데이터 문서화, 검증 등을 수행하고, 또한 출력 데이터를 타입 선언에 맞게 **변환하고 필터링**합니다.
-* 출력 데이터를 타입 선언으로 변환.
-* 데이터 검증.
-* OpenAPI *경로 작동*의 응답에 JSON 스키마 추가.
-* 자동 생성 문서 시스템에 사용.
+/// tip | 팁
-하지만 가장 중요한 것은:
+에디터, mypy 등에서 엄격한 타입 체크를 사용하고 있다면, 함수 반환 타입을 `Any`로 선언할 수 있습니다.
-* 해당 모델의 출력 데이터 제한. 이것이 얼마나 중요한지 아래에서 볼 것입니다.
+이렇게 하면 에디터에 의도적으로 어떤 값이든 반환한다고 알려줍니다. 하지만 FastAPI는 여전히 `response_model`을 사용하여 데이터 문서화, 검증, 필터링 등을 수행합니다.
-/// note | 기술 세부사항
+///
-응답 모델은 함수의 타입 어노테이션 대신 이 매개변수로 선언하는데, 경로 함수가 실제 응답 모델을 반환하지 않고 `dict`, 데이터베이스 객체나 기타 다른 모델을 `response_model`을 사용하여 필드 제한과 직렬화를 수행하고 반환할 수 있기 때문입니다
+### `response_model` 우선순위 { #response-model-priority }
-///
+반환 타입과 `response_model`을 둘 다 선언하면, `response_model`이 우선순위를 가지며 FastAPI에서 사용됩니다.
+
+이렇게 하면 응답 모델과 다른 타입을 반환하는 경우에도 에디터와 mypy 같은 도구에서 사용할 올바른 타입 어노테이션을 함수에 추가할 수 있습니다. 그리고 동시에 FastAPI가 `response_model`을 사용하여 데이터 검증, 문서화 등을 수행하게 할 수도 있습니다.
+
+또한 `response_model=None`을 사용해 해당 *경로 처리*에 대한 응답 모델 생성을 비활성화할 수도 있습니다. 이는 유효한 Pydantic 필드가 아닌 것들에 대해 타입 어노테이션을 추가하는 경우에 필요할 수 있으며, 아래 섹션 중 하나에서 예시를 볼 수 있습니다.
+
+## 동일한 입력 데이터 반환 { #return-the-same-input-data }
-## 동일한 입력 데이터 반환
+여기서는 평문 비밀번호를 포함하는 `UserIn` 모델을 선언합니다:
-여기서 우리는 평문 비밀번호를 포함하는 `UserIn` 모델을 선언합니다:
+{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
-{* ../../docs_src/response_model/tutorial002.py hl[9,11] *}
+/// info | 정보
+
+`EmailStr`을 사용하려면 먼저 <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>를 설치하세요.
+
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 다음 설치해야 합니다. 예를 들어:
+
+```console
+$ pip install email-validator
+```
+
+또는 다음과 같이:
+
+```console
+$ pip install "pydantic[email]"
+```
+
+///
그리고 이 모델을 사용하여 입력을 선언하고 같은 모델로 출력을 선언합니다:
-{* ../../docs_src/response_model/tutorial002.py hl[17:18] *}
+{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
이제 브라우저가 비밀번호로 사용자를 만들 때마다 API는 응답으로 동일한 비밀번호를 반환합니다.
-이 경우, 사용자가 스스로 비밀번호를 발신했기 때문에 문제가 되지 않을 수 있습니다.
+이 경우, 동일한 사용자가 비밀번호를 보내는 것이므로 문제가 되지 않을 수도 있습니다.
-그러나 동일한 모델을 다른 *경로 작동*에서 사용할 경우, 모든 클라이언트에게 사용자의 비밀번호를 발신할 수 있습니다.
+하지만 동일한 모델을 다른 *경로 처리*에서 사용하면, 모든 클라이언트에게 사용자의 비밀번호를 보내게 될 수도 있습니다.
/// danger | 위험
-절대로 사용자의 평문 비밀번호를 저장하거나 응답으로 발신하지 마십시오.
+모든 주의사항을 알고 있으며 무엇을 하는지 정확히 알고 있지 않다면, 이런 방식으로 사용자의 평문 비밀번호를 저장하거나 응답으로 보내지 마세요.
///
-## 출력 모델 추가
+## 출력 모델 추가 { #add-an-output-model }
+
+대신 평문 비밀번호를 포함하는 입력 모델과, 비밀번호가 없는 출력 모델을 만들 수 있습니다:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
+
+여기서 *경로 처리 함수*가 비밀번호를 포함하는 동일한 입력 사용자를 반환하더라도:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
+
+...비밀번호를 포함하지 않는 `UserOut` 모델로 `response_model`을 선언했습니다:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
+
+따라서 **FastAPI**는 출력 모델에 선언되지 않은 모든 데이터를 (Pydantic을 사용하여) 필터링합니다.
+
+### `response_model` 또는 반환 타입 { #response-model-or-return-type }
+
+이 경우 두 모델이 서로 다르기 때문에, 함수 반환 타입을 `UserOut`으로 어노테이션하면 에디터와 도구는 서로 다른 클래스인데 잘못된 타입을 반환하고 있다고 불평할 것입니다.
+
+그래서 이 예제에서는 `response_model` 매개변수로 선언해야 합니다.
-대신 평문 비밀번호로 입력 모델을 만들고 해당 비밀번호 없이 출력 모델을 만들 수 있습니다:
+...하지만 아래를 계속 읽으면 이를 극복하는 방법을 볼 수 있습니다.
-{* ../../docs_src/response_model/tutorial003.py hl[9,11,16] *}
+## 반환 타입과 데이터 필터링 { #return-type-and-data-filtering }
-ì\97¬ê¸°ì\84\9c *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*ê°\80 ë¹\84ë°\80ë²\88í\98¸ë¥¼ í\8f¬í\95¨í\95\98ë\8a\94 ë\8f\99ì\9d¼í\95\9c ì\9e\85ë ¥ ì\82¬ì\9a©ì\9e\90를 ë°\98í\99\98í\95 ì§\80ë\9d¼ë\8f\84:
+ì\9d´ì \84 ì\98\88ì \9cì\97\90ì\84\9c ê³\84ì\86\8dí\95´ ë´\85ì\8b\9cë\8b¤. í\95¨ì\88\98ì\97\90 **í\95\98ë\82\98ì\9d\98 í\83\80ì\9e\85ì\9c¼ë¡\9c ì\96´ë\85¸í\85\8cì\9d´ì\85\98**ì\9d\84 í\95\98ê³ ì\8b¶ì§\80ë§\8c, í\95¨ì\88\98ì\97\90ì\84\9c ì\8b¤ì \9cë¡\9cë\8a\94 **ë\8d\94 ë§\8eì\9d\80 ë\8d°ì\9d´í\84°**를 í\8f¬í\95¨í\95\98ë\8a\94 ê²\83ì\9d\84 ë°\98í\99\98í\95 ì\88\98 ì\9e\88길 ì\9b\90í\96\88ì\8aµë\8b\88ë\8b¤.
-{* ../../docs_src/response_model/tutorial003.py hl[24] *}
+FastAPI가 응답 모델을 사용해 데이터를 계속 **필터링**하길 원합니다. 그래서 함수가 더 많은 데이터를 반환하더라도, 응답에는 응답 모델에 선언된 필드만 포함되게 합니다.
-...`response_model`을 `UserOut` 모델로 선언했기 때문에 비밀번호를 포함하지 않습니다:
+이전 예제에서는 클래스가 달랐기 때문에 `response_model` 매개변수를 써야 했습니다. 하지만 이는 에디터와 도구가 함수 반환 타입을 체크해 주는 지원을 받지 못한다는 뜻이기도 합니다.
-{* ../../docs_src/response_model/tutorial003.py hl[22] *}
+하지만 대부분 이런 작업이 필요한 경우에는, 이 예제처럼 모델로 일부 데이터를 **필터링/제거**하길 원하는 경우가 많습니다.
-따라서 **FastAPI**는 출력 모델에서 선언하지 않은 모든 데이터를 (Pydantic을 사용하여) 필터링합니다.
+그리고 그런 경우에는 클래스와 상속을 사용하여 함수 **타입 어노테이션**을 활용해 에디터/도구에서 더 나은 지원을 받으면서도 FastAPI의 **데이터 필터링**을 유지할 수 있습니다.
-## 문서에서 보기
+{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
-자동 생성 문서를 보면 입력 모델과 출력 모델이 각자의 JSON 스키마를 가지고 있음을 확인할 수 있습니다:
+이를 통해 이 코드는 타입 관점에서 올바르므로 에디터와 mypy 등의 도구 지원을 받을 수 있고, 동시에 FastAPI의 데이터 필터링도 받을 수 있습니다.
+
+이게 어떻게 동작할까요? 확인해 봅시다. 🤓
+
+### 타입 어노테이션과 도구 지원 { #type-annotations-and-tooling }
+
+먼저 에디터, mypy 및 기타 도구가 이를 어떻게 보는지 살펴봅시다.
+
+`BaseUser`는 기본 필드를 가집니다. 그리고 `UserIn`은 `BaseUser`를 상속하고 `password` 필드를 추가하므로, 두 모델의 모든 필드를 포함하게 됩니다.
+
+함수 반환 타입을 `BaseUser`로 어노테이션하지만, 실제로는 `UserIn` 인스턴스를 반환합니다.
+
+에디터, mypy 및 기타 도구는 이에 대해 불평하지 않습니다. 타이핑 관점에서 `UserIn`은 `BaseUser`의 서브클래스이므로, `BaseUser`인 어떤 것이 기대되는 곳에서는 *유효한* 타입이기 때문입니다.
+
+### FastAPI 데이터 필터링 { #fastapi-data-filtering }
+
+이제 FastAPI는 반환 타입을 보고, 여러분이 반환하는 값이 해당 타입에 선언된 필드 **만** 포함하도록 보장합니다.
+
+FastAPI는 Pydantic을 내부적으로 여러 방식으로 사용하여, 클래스 상속의 동일한 규칙이 반환 데이터 필터링에는 적용되지 않도록 합니다. 그렇지 않으면 기대한 것보다 훨씬 더 많은 데이터를 반환하게 될 수도 있습니다.
+
+이렇게 하면 **도구 지원**이 있는 타입 어노테이션과 **데이터 필터링**이라는 두 가지 장점을 모두 얻을 수 있습니다.
+
+## 문서에서 보기 { #see-it-in-the-docs }
+
+자동 생성 문서를 보면 입력 모델과 출력 모델이 각자의 JSON Schema를 가지고 있음을 확인할 수 있습니다:
<img src="/img/tutorial/response-model/image01.png">
<img src="/img/tutorial/response-model/image02.png">
-## 응답 모델 인코딩 매개변수
+## 기타 반환 타입 어노테이션 { #other-return-type-annotations }
+
+유효한 Pydantic 필드가 아닌 것을 반환하면서도, 도구(에디터, mypy 등)가 제공하는 지원을 받기 위해 함수에 어노테이션을 달아두는 경우가 있을 수 있습니다.
+
+### 응답을 직접 반환하기 { #return-a-response-directly }
+
+가장 흔한 경우는 [고급 문서에서 나중에 설명하는 대로 Response를 직접 반환하는 것](../advanced/response-directly.md){.internal-link target=_blank}입니다.
+
+{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+
+이 간단한 경우는 반환 타입 어노테이션이 `Response` 클래스(또는 그 서브클래스)이기 때문에 FastAPI에서 자동으로 처리됩니다.
+
+그리고 `RedirectResponse`와 `JSONResponse`는 모두 `Response`의 서브클래스이므로, 타입 어노테이션이 올바르기 때문에 도구들도 만족합니다.
+
+### Response 서브클래스 어노테이션 { #annotate-a-response-subclass }
+
+타입 어노테이션에 `Response`의 서브클래스를 사용할 수도 있습니다:
+
+{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+
+이는 `RedirectResponse`가 `Response`의 서브클래스이기 때문에 동작하며, FastAPI가 이 간단한 경우를 자동으로 처리합니다.
+
+### 유효하지 않은 반환 타입 어노테이션 { #invalid-return-type-annotations }
+
+하지만 유효한 Pydantic 타입이 아닌 다른 임의의 객체(예: 데이터베이스 객체)를 반환하고, 함수에서 그렇게 어노테이션하면, FastAPI는 그 타입 어노테이션으로부터 Pydantic 응답 모델을 만들려고 시도하다가 실패합니다.
+
+또한, 유효한 Pydantic 타입이 아닌 타입이 하나 이상 포함된 여러 타입 간의 <abbr title='여러 타입 간 union은 "이 타입들 중 아무거나"를 의미합니다.'>union</abbr>이 있는 경우에도 동일합니다. 예를 들어, 아래는 실패합니다 💥:
+
+{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
+
+...이는 타입 어노테이션이 Pydantic 타입이 아니고, 단일 `Response` 클래스/서브클래스도 아니며, `Response`와 `dict` 간 union(둘 중 아무거나)이기 때문에 실패합니다.
+
+### 응답 모델 비활성화 { #disable-response-model }
+
+위 예제에서 이어서, FastAPI가 수행하는 기본 데이터 검증, 문서화, 필터링 등을 원하지 않을 수 있습니다.
+
+하지만 에디터나 타입 체커(예: mypy) 같은 도구 지원을 받기 위해 함수에 반환 타입 어노테이션은 유지하고 싶을 수도 있습니다.
+
+이 경우 `response_model=None`으로 설정하여 응답 모델 생성을 비활성화할 수 있습니다:
+
+{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
+
+그러면 FastAPI는 응답 모델 생성을 건너뛰며, FastAPI 애플리케이션에 영향을 주지 않고 필요한 반환 타입 어노테이션을 어떤 것이든 사용할 수 있습니다. 🤓
+
+## 응답 모델 인코딩 매개변수 { #response-model-encoding-parameters }
응답 모델은 아래와 같이 기본값을 가질 수 있습니다:
-{* ../../docs_src/response_model/tutorial004.py hl[11,13:14] *}
+{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
-* `description: Optional[str] = None`은 기본값으로 `None`을 갖습니다.
+* `description: Union[str, None] = None` (또는 Python 3.10에서 `str | None = None`)은 기본값으로 `None`을 갖습니다.
* `tax: float = 10.5`는 기본값으로 `10.5`를 갖습니다.
-* `tags: List[str] = []` 빈 리스트의 기본값으로: `[]`.
+* `tags: List[str] = []`는 기본값으로 빈 리스트 `[]`를 갖습니다.
-그러나 실제로 저장되지 않았을 경우 결과에서 값을 생략하고 싶을 수 있습니다.
+하지만 실제로 저장되지 않았을 경우 결과에서 이를 생략하고 싶을 수 있습니다.
예를 들어, NoSQL 데이터베이스에 많은 선택적 속성이 있는 모델이 있지만, 기본값으로 가득 찬 매우 긴 JSON 응답을 보내고 싶지 않습니다.
-### `response_model_exclude_unset` 매개변수 사용
+### `response_model_exclude_unset` 매개변수 사용 { #use-the-response-model-exclude-unset-parameter }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°* 매ê°\9cë³\80ì\88\98를 `response_model_exclude_unset=True`ë¡\9c ì\84¤ì \95 할 수 있습니다:
+*ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°* 매ê°\9cë³\80ì\88\98 `response_model_exclude_unset=True`ë¡\9c ì\84¤ì \95할 수 있습니다:
-{* ../../docs_src/response_model/tutorial004.py hl[24] *}
+{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
-이러한 기본값은 응답에 포함되지 않고 실제로 설정된 값만 포함됩니다.
+그러면 이러한 기본값은 응답에 포함되지 않고, 실제로 설정된 값만 포함됩니다.
-따라서 해당 *경로 작동*에 ID가 `foo`인 항목(items)을 요청으로 보내면 (기본값을 제외한) 응답은 다음과 같습니다:
+따라서 ID가 `foo`인 항목에 대해 해당 *경로 처리*로 요청을 보내면, (기본값을 제외한) 응답은 다음과 같습니다:
```JSON
{
/// info | 정보
-FastAPI는 이를 위해 Pydantic 모델의 `.dict()`의 <a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank"> `exclude_unset` 매개변수</a>를 사용합니다.
-
-///
-
-/// info | 정보
-
-아래 또한 사용할 수 있습니다:
+다음도 사용할 수 있습니다:
* `response_model_exclude_defaults=True`
* `response_model_exclude_none=True`
-<a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank">Pydantic 문ì\84\9c</a>ì\97\90ì\84\9c `exclude_defaults` ë°\8f `exclude_none`ì\97\90 ë\8c\80í\95´ ì\84¤ëª\85í\95\9c ë\8c\80ë¡\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+`exclude_defaults` ë°\8f `exclude_none`ì\97\90 ë\8c\80í\95´ <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">Pydantic 문ì\84\9c</a>ì\97\90 ì\84¤ëª\85ë\90\9c ë\8c\80ë¡\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
///
-#### 기본값이 있는 필드를 갖는 값의 데이터
+#### 기본값이 있는 필드에 값이 있는 데이터 { #data-with-values-for-fields-with-defaults }
-하지만 모델의 필드가 기본값이 있어도 ID가 `bar`인 항목(items)처럼 데이터가 값을 갖는다면:
+하지만 ID가 `bar`인 항목처럼, 기본값이 있는 모델의 필드에 값이 있다면:
```Python hl_lines="3 5"
{
}
```
-ì\9d\91ë\8bµì\97\90 í\95´ë\8b¹ ê°\92ë\93¤ì\9d´ í\8f¬í\95¨ë\90©ë\8b\88ë\8b¤.
+응답에 포함됩니다.
-#### 기본값과 동일한 값을 갖는 데이터
+#### 기본값과 동일한 값을 갖는 데이터 { #data-with-the-same-values-as-the-defaults }
-If the data has the same values as the default ones, like the item with ID `baz`:
-ID가 `baz`인 항목(items)처럼 기본값과 동일한 값을 갖는다면:
+데이터가 ID가 `baz`인 항목처럼 기본값과 동일한 값을 갖는다면:
```Python hl_lines="3 5-6"
{
}
```
-`description`, `tax` 그리고 `tags`가 기본값과 같더라도 (기본값에서 가져오는 대신) 값들이 명시적으로 설정되었다는 것을 인지할 정도로 FastAPI는 충분히 똑똑합니다(사실, Pydantic이 충분히 똑똑합니다).
+FastAPI는 충분히 똑똑해서(사실, Pydantic이 충분히 똑똑합니다) `description`, `tax`, `tags`가 기본값과 동일하더라도, 기본값에서 가져온 것이 아니라 명시적으로 설정되었다는 것을 알아냅니다.
-따라서 JSON 스키마에 포함됩니다.
+그래서 JSON 응답에 포함됩니다.
/// tip | 팁
-`None` 뿐만 아니라 다른 어떤 것도 기본값이 될 수 있습니다.
+기본값은 `None`뿐만 아니라 어떤 것이든 될 수 있습니다.
리스트(`[]`), `float`인 `10.5` 등이 될 수 있습니다.
///
-### `response_model_include` 및 `response_model_exclude`
+### `response_model_include` 및 `response_model_exclude` { #response-model-include-and-response-model-exclude }
-*ê²½ë¡\9c ì\9e\91ë\8f\99 ë\8d°ì½\94ë \88ì\9d´í\84°* 매ê°\9cë³\80ì\88\98 `response_model_include` ë°\8f `response_model_exclude`를 ì\82¬ì\9a©í\95 ì\88\98 있습니다.
+*ê²½ë¡\9c ì²\98리 ë\8d°ì½\94ë \88ì\9d´í\84°* 매ê°\9cë³\80ì\88\98 `response_model_include` ë°\8f `response_model_exclude`를 ì\82¬ì\9a©í\95 ì\88\98ë\8f\84 있습니다.
-이들은 포함(나머지 생략)하거나 제외(나머지 포함) 할 어트리뷰트의 이름과 `str`의 `set`을 받습니다.
+이들은 포함(나머지 생략)하거나 제외(나머지 포함)할 어트리뷰트 이름을 담은 `str`의 `set`을 받습니다.
-Pydantic 모델이 하나만 있고 출력에서 일부 데이터를 제거하려는 경우 빠른 지름길로 사용할 수 있습니다.
+Pydantic 모델이 하나만 있고 출력에서 일부 데이터를 제거하려는 경우, 빠른 지름길로 사용할 수 있습니다.
/// tip | 팁
-하지만 이러한 매개변수 대신 여러 클래스를 사용하여 위 아이디어를 사용하는 것을 추천합니다.
+하지만 이러한 매개변수 대신, 위에서 설명한 것처럼 여러 클래스를 사용하는 것을 여전히 권장합니다.
-이는 일부 어트리뷰트를 생략하기 위해 `response_model_include` 또는 `response_model_exclude`를 사용하더라도 앱의 OpenAPI(및 문서)가 생성한 JSON 스키마가 여전히 전체 모델에 대한 스키마이기 때문입니다.
+이는 일부 어트리뷰트를 생략하기 위해 `response_model_include` 또는 `response_model_exclude`를 사용하더라도, 앱의 OpenAPI(및 문서)에 생성되는 JSON Schema가 여전히 전체 모델에 대한 스키마이기 때문입니다.
-비슷하게 작동하는 `response_model_by_alias` 역시 마찬가지로 적용됩니다.
+비슷하게 동작하는 `response_model_by_alias`에도 동일하게 적용됩니다.
///
-{* ../../docs_src/response_model/tutorial005.py hl[31,37] *}
+{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
/// tip | 팁
///
-#### `set` 대신 `list` 사용하기
+#### `set` 대신 `list` 사용하기 { #using-lists-instead-of-sets }
-`list` 또는 `tuple` 대신 `set`을 사용하는 법을 잊었더라도, FastAPI는 `set`으로 변환하고 정상적으로 작동합니다:
+`set`을 쓰는 것을 잊고 `list`나 `tuple`을 대신 사용하더라도, FastAPI는 이를 `set`으로 변환하므로 올바르게 동작합니다:
-{* ../../docs_src/response_model/tutorial006.py hl[31,37] *}
+{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
-## 요약
+## 요약 { #recap }
-응답 모델을 정의하고 개인정보가 필터되는 것을 보장하기 위해 *경로 작동 데코레이터*의 매개변수 `response_model`을 사용하세요.
+응답 모델을 정의하고 특히 개인정보가 필터링되도록 보장하려면 *경로 처리 데코레이터*의 매개변수 `response_model`을 사용하세요.
명시적으로 설정된 값만 반환하려면 `response_model_exclude_unset`을 사용하세요.
-# 응답 상태 코드
+# 응답 상태 코드 { #response-status-code }
-응답 모델과 같은 방법으로, 어떤 *경로 작동*이든 `status_code` 매개변수를 사용하여 응답에 대한 HTTP 상태 코드를 선언할 수 있습니다.
+응답 모델을 지정하는 것과 같은 방법으로, 어떤 *경로 처리*에서든 `status_code` 매개변수를 사용하여 응답에 사용할 HTTP 상태 코드를 선언할 수도 있습니다:
* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
-* 기타
+* 등
-{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
/// note | 참고
-`status_code` ë\8a\94 "ë\8d°ì½\94ë \88ì\9d´í\84°" ë©\94ì\86\8cë\93\9c(`get`, `post` ë\93±)ì\9d\98 매ê°\9cë³\80ì\88\98ì\9e\85ë\8b\88ë\8b¤. 모ë\93 매ê°\9cë³\80ì\88\98ë\93¤ê³¼ 본문ì²\98ë\9f¼ *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*가 아닙니다.
+`status_code` ë\8a\94 "ë\8d°ì½\94ë \88ì\9d´í\84°" ë©\94ì\86\8cë\93\9c(`get`, `post` ë\93±)ì\9d\98 매ê°\9cë³\80ì\88\98ì\9e\85ë\8b\88ë\8b¤. 모ë\93 매ê°\9cë³\80ì\88\98ë\93¤ê³¼ 본문ì²\98ë\9f¼ *ê²½ë¡\9c ì²\98리 함수*가 아닙니다.
///
/// info | 정보
-`status_code` 는 파이썬의 `http.HTTPStatus` 와 같은 `IntEnum` 을 입력받을 수도 있습니다.
+`status_code` 는 파이썬의 <a href="https://docs.python.org/3/library/http.html#http.HTTPStatus" class="external-link" target="_blank">`http.HTTPStatus`</a> 와 같은 `IntEnum` 을 입력받을 수도 있습니다.
///
`status_code` 매개변수는:
* 응답에서 해당 상태 코드를 반환합니다.
-* ì\83\81í\83\9c ì½\94ë\93\9c를 OpenAPI ì\8a¤í\82¤ë§\88(ë°\8f ì\82¬ì\9a©ì\9e\90 ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤)ì\97\90 문ì\84\9cí\99\94 í\95©ë\8b\88ë\8b¤.
+* ì\83\81í\83\9c ì½\94ë\93\9c를 OpenAPI ì\8a¤í\82¤ë§\88(ë\94°ë\9d¼ì\84\9c, ì\82¬ì\9a©ì\9e\90 ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤ì\97\90ë\8f\84)ì\97\90 문ì\84\9cí\99\94í\95©ë\8b\88ë\8b¤:
-<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image01.png">
+<img src="/img/tutorial/response-status-code/image01.png">
/// note | 참고
-ì\96´ë\96¤ ì\9d\91ë\8bµ ì½\94ë\93\9cë\93¤ì\9d\80 í\95´ë\8b¹ ì\9d\91ë\8bµì\97\90 본문ì\9d´ ì\97\86ë\8b¤ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95\98기ë\8f\84 í\95©ë\8b\88ë\8b¤ (ë\8b¤ì\9d\8c í\95목 ì°¸ê³ ).
+ì\9d¼ë¶\80 ì\9d\91ë\8bµ ì½\94ë\93\9c(ë\8b¤ì\9d\8c ì\84¹ì\85\98 ì°¸ê³ )ë\8a\94 ì\9d\91ë\8bµì\97\90 본문ì\9d´ ì\97\86ë\8b¤ë\8a\94 ê²\83ì\9d\84 ë\82\98í\83\80ë\83\85ë\8b\88ë\8b¤.
-이에 따라 FastAPI는 응답 본문이 없음을 명시하는 OpenAPI를 생성합니다.
+FastAPI는 이를 알고 있으며, 응답 본문이 없다고 명시하는 OpenAPI 문서를 생성합니다.
///
-## HTTP 상태 코드에 대하여
+## HTTP 상태 코드에 대하여 { #about-http-status-codes }
/// note | 참고
-만약 HTTP 상태 코드에 대하여 이미 알고있다면, 다음 항목으로 넘어가십시오.
+만약 HTTP 상태 코드가 무엇인지 이미 알고 있다면, 다음 섹션으로 넘어가세요.
///
-HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다.
+HTTP에서는 응답의 일부로 3자리 숫자 상태 코드를 보냅니다.
-이 상태 코드들은 각자를 식별할 수 있도록 지정된 이름이 있으나, 중요한 것은 숫자 코드입니다.
+이 상태 코드들은 이를 식별할 수 있도록 이름이 연결되어 있지만, 중요한 부분은 숫자입니다.
요약하자면:
-* `1xx` 상태 코드는 "정보"용입니다. 이들은 직접적으로는 잘 사용되지는 않습니다. 이 상태 코드를 갖는 응답들은 본문을 가질 수 없습니다.
-* **`2xx`** 상태 코드는 "성공적인" 응답을 위해 사용됩니다. 가장 많이 사용되는 유형입니다.
- * `200` 은 디폴트 상태 코드로, 모든 것이 "성공적임"을 의미합니다.
- * 다른 예로는 `201` "생성됨"이 있습니다. 일반적으로 데이터베이스에 새로운 레코드를 생성한 후 사용합니다.
- * 단, `204` "내용 없음"은 특별한 경우입니다. 이것은 클라이언트에게 반환할 내용이 없는 경우 사용합니다. 따라서 응답은 본문을 가질 수 없습니다.
-* **`3xx`** 상태 코드는 "리다이렉션"용입니다. 본문을 가질 수 없는 `304` "수정되지 않음"을 제외하고, 이 상태 코드를 갖는 응답에는 본문이 있을 수도, 없을 수도 있습니다.
-* **`4xx`** 상태 코드는 "클라이언트 오류" 응답을 위해 사용됩니다. 이것은 아마 가장 많이 사용하게 될 두번째 유형입니다.
- * ì\9d¼ë¡\80ë¡\9c `404` 는 "찾을 수 없음" 응답을 위해 사용합니다.
- * 일반적인 클라이언트 오류의 경우 `400` 을 사용할 수 있습니다.
-* `5xx` 상태 코드는 서버 오류에 사용됩니다. 이것들을 직접 사용할 일은 거의 없습니다. 응용 프로그램 코드나 서버의 일부에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다.
+* `100 - 199` 는 "정보"용입니다. 직접 사용할 일은 거의 없습니다. 이 상태 코드를 갖는 응답은 본문을 가질 수 없습니다.
+* **`200 - 299`** 는 "성공적인" 응답을 위한 것입니다. 가장 많이 사용하게 될 유형입니다.
+ * `200` 은 기본 상태 코드로, 모든 것이 "OK"임을 의미합니다.
+ * 다른 예로는 `201` "생성됨"이 있습니다. 일반적으로 데이터베이스에 새 레코드를 생성한 후 사용합니다.
+ * 특별한 경우로 `204` "내용 없음"이 있습니다. 이 응답은 클라이언트에게 반환할 내용이 없을 때 사용되며, 따라서 응답은 본문을 가지면 안 됩니다.
+* **`300 - 399`** 는 "리다이렉션"용입니다. 이 상태 코드를 갖는 응답은 본문이 있을 수도 없을 수도 있으며, 본문이 없어야 하는 `304` "수정되지 않음"을 제외합니다.
+* **`400 - 499`** 는 "클라이언트 오류" 응답을 위한 것입니다. 아마 두 번째로 가장 많이 사용하게 될 유형입니다.
+ * ì\98\88를 ë\93¤ì\96´ `404` 는 "찾을 수 없음" 응답을 위해 사용합니다.
+ * 클라이언트의 일반적인 오류에는 `400` 을 그냥 사용할 수 있습니다.
+* `500 - 599` 는 서버 오류에 사용됩니다. 직접 사용할 일은 거의 없습니다. 애플리케이션 코드의 일부나 서버에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다.
/// tip | 팁
-각각의 상태 코드와 이들이 의미하는 내용에 대해 더 알고싶다면 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> HTTP 상태 코드에 관한 문서</a> 를 확인하십시오.
+각 상태 코드와 어떤 코드가 어떤 용도인지 더 알고 싶다면 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr>의 HTTP 상태 코드에 관한 문서</a>를 확인하세요.
///
-## 이름을 기억하는 쉬운 방법
+## 이름을 기억하는 쉬운 방법 { #shortcut-to-remember-the-names }
-ì\83\81기 ì\98\88ì\8b\9c ì°¸ê³ :
+ì\9d´ì \84 ì\98\88ì\8b\9c를 ë\8b¤ì\8b\9c í\99\95ì\9d¸í\95´ë³´ê² ì\8aµë\8b\88ë\8b¤:
-{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
-`201` 은 "생성됨"를 의미하는 상태 코드입니다.
+`201` 은 "생성됨"을 위한 상태 코드입니다.
-하지만 모든 상태 코드들이 무엇을 의미하는지 외울 필요는 없습니다.
+하지만 각각의 코드가 무엇을 의미하는지 외울 필요는 없습니다.
`fastapi.status` 의 편의 변수를 사용할 수 있습니다.
-{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
-이것은 단순히 작업을 편리하게 하기 위한 것으로, HTTP 상태 코드와 동일한 번호를 갖고있지만, 이를 사용하면 편집기의 자동완성 기능을 사용할 수 있습니다:
+이것들은 단지 편의를 위한 것으로, 동일한 숫자를 갖고 있지만, 이를 통해 편집기의 자동완성 기능으로 찾을 수 있습니다:
-<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image02.png">
+<img src="/img/tutorial/response-status-code/image02.png">
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
`from starlette import status` 역시 사용할 수 있습니다.
///
-## 기본값 변경
+## 기본값 변경 { #changing-the-default }
-추후 여기서 선언하는 기본 상태 코드가 아닌 다른 상태 코드를 반환하는 방법을 [숙련된 사용자 지침서](https://fastapi.tiangolo.com/ko/advanced/response-change-status-code/){.internal-link target=_blank}에서 확인할 수 있습니다.
+나중에 [고급 사용자 지침서](../advanced/response-change-status-code.md){.internal-link target=_blank}에서, 여기서 선언하는 기본값과 다른 상태 코드를 반환하는 방법을 확인할 수 있습니다.
-# 요청 예제 데이터 선언
+# 요청 예제 데이터 선언 { #declare-request-example-data }
여러분의 앱이 받을 수 있는 데이터 예제를 선언할 수 있습니다.
여기 이를 위한 몇가지 방식이 있습니다.
-## Pydantic 모델 속 추가 JSON 스키마 데이터
+## Pydantic 모델 속 추가 JSON 스키마 데이터 { #extra-json-schema-data-in-pydantic-models }
생성된 JSON 스키마에 추가될 Pydantic 모델을 위한 `examples`을 선언할 수 있습니다.
-//// tab | Pydantic v2
-
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
-////
-
-//// tab | Pydantic v1
-
-{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
-
-////
-
추가 정보는 있는 그대로 해당 모델의 **JSON 스키마** 결과에 추가되고, API 문서에서 사용합니다.
-//// tab | Pydantic v2
-
-Pydantic 버전 2에서 <a href="https://docs.pydantic.dev/latest/usage/model_config/" class="external-link" target="_blank">Pydantic 공식 문서: Model Config</a>에 나와 있는 것처럼 `dict`를 받는 `model_config` 어트리뷰트를 사용할 것입니다.
+<a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Pydantic 문서: Configuration</a>에 설명된 것처럼 `dict`를 받는 `model_config` 어트리뷰트를 사용할 수 있습니다.
`"json_schema_extra"`를 생성된 JSON 스키마에서 보여주고 싶은 별도의 데이터와 `examples`를 포함하는 `dict`으로 설정할 수 있습니다.
-////
-
-//// tab | Pydantic v1
-
-Pydantic v1에서 <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic 공식 문서: Schema customization</a>에서 설명하는 것처럼, 내부 클래스인 `Config`와 `schema_extra`를 사용할 것입니다.
-
-`schema_extra`를 생성된 JSON 스키마에서 보여주고 싶은 별도의 데이터와 `examples`를 포함하는 `dict`으로 설정할 수 있습니다.
-
-////
-
/// tip | 팁
JSON 스키마를 확장하고 여러분의 별도의 자체 데이터를 추가하기 위해 같은 기술을 사용할 수 있습니다.
그 전에는, 하나의 예제만 가능한 `example` 키워드만 지원했습니다. 이는 아직 OpenAPI 3.1.0에서 지원하지만, 지원이 종료될 것이며 JSON 스키마 표준에 포함되지 않습니다. 그렇기에 `example`을 `examples`으로 이전하는 것을 추천합니다. 🤓
-이 문서 끝에 더 많은 읽을거리가 있습니다.
+이 페이지 끝에서 더 많은 내용을 읽을 수 있습니다.
///
-## `Field` 추가 인자
+## `Field` 추가 인자 { #field-additional-arguments }
Pydantic 모델과 같이 `Field()`를 사용할 때 추가적인 `examples`를 선언할 수 있습니다:
{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
-## JSON Schema에서의 `examples` - OpenAPI
+## JSON Schema에서의 `examples` - OpenAPI { #examples-in-json-schema-openapi }
-이들 중에서 사용합니다:
+다음 중 하나를 사용할 때:
* `Path()`
* `Query()`
* `Form()`
* `File()`
-**OpenAPI**의 **JSON 스키마**에 추가될 부가적인 정보를 포함한 `examples` 모음을 선언할 수 있습니다.
+**OpenAPI** 안의 **JSON 스키마**에 추가될 부가적인 정보를 포함한 `examples` 모음을 선언할 수도 있습니다.
-### `examples`를 포함한 `Body`
+### `examples`를 포함한 `Body` { #body-with-examples }
여기, `Body()`에 예상되는 예제 데이터 하나를 포함한 `examples`를 넘겼습니다:
{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
-### 문서 UI 예시
+### 문서 UI 예시 { #example-in-the-docs-ui }
위의 어느 방법과 함께라면 `/docs`에서 다음과 같이 보일 것입니다:
<img src="/img/tutorial/body-fields/image01.png">
-### 다중 `examples`를 포함한 `Body`
+### 다중 `examples`를 포함한 `Body` { #body-with-multiple-examples }
물론 여러 `examples`를 넘길 수 있습니다:
{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
-ì\9d´ì\99\80 ê°\99ì\9d´ í\95\98ë©´ ì\9d´ ì\98\88ì \9cë\8a\94 ê·¸ 본문 ë\8d°ì\9d´í\84°ë¥¼ ì\9c\84í\95\9c 내부 **JSON 스키마**의 일부가 될 것입니다.
+ì\9d´ì\99\80 ê°\99ì\9d´ í\95\98ë©´ ì\98\88ì \9cë\93¤ì\9d\80 ê·¸ 본문 ë\8d°ì\9d´í\84°ì\9d\98 내부 **JSON 스키마**의 일부가 될 것입니다.
그럼에도 불구하고, 지금 <abbr title="2023-08-26">이 문서를 작성하는 시간</abbr>에, 문서 UI를 보여주는 역할을 맡은 Swagger UI는 **JSON 스키마** 속 데이터를 위한 여러 예제의 표현을 지원하지 않습니다. 하지만 해결 방안을 밑에서 읽어보세요.
-### OpenAPI-특화 `examples`
+### OpenAPI-특화 `examples` { #openapi-specific-examples }
-**JSON 스키마**가 `examples`를 지원하기 전 부터, OpenAPI는 `examples`이라 불리는 다른 필드를 지원해 왔습니다.
+**JSON 스키마**가 `examples`를 지원하기 전부터 OpenAPI는 `examples`이라 불리는 다른 필드를 지원해 왔습니다.
-ì\9d´ **OpenAPI-í\8a¹í\99\94** `examples`ë\8a\94 OpenAPI ëª\85ì\84¸ì\84\9cì\9d\98 ë\8b¤ë¥¸ 구ì\97ì\9c¼ë¡\9c ë\93¤ì\96´ê°\91ë\8b\88ë\8b¤. ê°\81 JSON ì\8a¤í\82¤ë§\88 ë\82´ë¶\80ê°\80 ì\95\84ë\8b\88ë\9d¼ **ê°\81 *ê²½ë¡\9c ì\9e\91ë\8f\99* 세부 정보**에 포함됩니다.
+ì\9d´ **OpenAPI-í\8a¹í\99\94** `examples`ë\8a\94 OpenAPI ëª\85ì\84¸ì\84\9cì\9d\98 ë\8b¤ë¥¸ 구ì\97ì\9c¼ë¡\9c ë\93¤ì\96´ê°\91ë\8b\88ë\8b¤. ê°\81 JSON ì\8a¤í\82¤ë§\88 ë\82´ë¶\80ê°\80 ì\95\84ë\8b\88ë\9d¼ **ê°\81 *ê²½ë¡\9c ì²\98리* 세부 정보**에 포함됩니다.
그리고 Swagger UI는 이 특정한 `examples` 필드를 한동안 지원했습니다. 그래서, 이를 다른 **문서 UI에 있는 예제**를 **표시**하기 위해 사용할 수 있습니다.
-이 OpenAPI-특화 필드인 `examples`의 형태는 (`list`대신에) **다중 예제**가 포함된 `dict`이며, 각각의 별도 정보 또한 **OpenAPI**에 추가될 것입니다.
+이 OpenAPI-특화 필드인 `examples`의 형태는 (`list` 대신에) **다중 예제**가 포함된 `dict`이며, 각각의 별도 정보 또한 **OpenAPI**에 추가될 것입니다.
-이는 OpenAPI에 포함된 JSON 스키마 안으로 포함되지 않으며, *경로 작동*에 직접적으로 포함됩니다.
+이는 OpenAPI에 포함된 각 JSON 스키마 안으로 포함되지 않으며, *경로 처리*에 직접적으로 포함됩니다.
-### `openapi_examples` 매개변수 사용하기
+### `openapi_examples` 매개변수 사용하기 { #using-the-openapi-examples-parameter }
-다음 예시 속에 OpenAPI-특화 `examples`를 FastAPI 안에서 매개변수 `openapi_examples` 매개변수와 함께 선언할 수 있습니다:
+다음에 대해 FastAPI에서 매개변수 `openapi_examples`로 OpenAPI-특화 `examples`를 선언할 수 있습니다:
* `Path()`
* `Query()`
* `Form()`
* `File()`
-`dict`의 키가 또 다른 `dict`인 각 예제와 값을 구별합니다.
+`dict`의 키는 각 예제를 식별하고, 각 값은 또 다른 `dict`입니다.
-ê°\81ê°\81ì\9d\98 í\8a¹ì \95 `examples` ì\86\8d `dict` ì\98\88ì \9cë\8a\94 ë\8b¤ì\9d\8cì\9d\84 í\8f¬í\95¨í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
+`examples` ì\95\88ì\9d\98 ê°\81 í\8a¹ì \95 ì\98\88ì \9c `dict`ì\97\90ë\8a\94 ë\8b¤ì\9d\8cì\9d´ í\8f¬í\95¨ë\90 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
* `summary`: 예제에 대한 짧은 설명문.
* `description`: 마크다운 텍스트를 포함할 수 있는 긴 설명문.
* `value`: 실제로 보여지는 예시, 예를 들면 `dict`.
-* `externalValue`: `value`ì\9d\98 ë\8c\80ì\95\88ì\9d´ë©° ì\98\88ì \9c를 ê°\80르키는 URL. 비록 `value`처럼 많은 도구를 지원하지 못할 수 있습니다.
+* `externalValue`: `value`ì\9d\98 ë\8c\80ì\95\88ì\9d´ë©° ì\98\88ì \9c를 ê°\80리키는 URL. 비록 `value`처럼 많은 도구를 지원하지 못할 수 있습니다.
이를 다음과 같이 사용할 수 있습니다:
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
-### 문서 UI에서의 OpenAPI 예시
+### 문서 UI에서의 OpenAPI 예시 { #openapi-examples-in-the-docs-ui }
-`Body()`에 추가된 `openapi_examples`를 포함한 `/docs`는 다음과 같이 보일 것입니다:
+`Body()`에 `openapi_examples`가 추가되면 `/docs`는 다음과 같이 보일 것입니다:
<img src="/img/tutorial/body-fields/image02.png">
-## 기술적 세부 사항
+## 기술적 세부 사항 { #technical-details }
/// tip | 팁
OpenAPI는 또한 `example`과 `examples` 필드를 명세서의 다른 부분에 추가했습니다:
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`(명세서에 있는) Parameter Object`</a>는 FastAPI의 다음 기능에서 쓰였습니다:
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (명세서에 있는)</a>는 FastAPI의 다음 기능에서 쓰였습니다:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">(명세서에 있는)`Media Type Object`속 `content`에 있는 `Request Body Object`</a>는 FastAPI의 다음 기능에서 쓰였습니다:
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, `Media Type Object` (명세서에 있는)의 `content` 필드에 있는</a>는 FastAPI의 다음 기능에서 쓰였습니다:
* `Body()`
* `File()`
* `Form()`
///
-### JSON 스키마의 `examples` 필드
+### JSON 스키마의 `examples` 필드 { #json-schemas-examples-field }
-하지만, 후에 JSON 스키마는 <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>필드를 명세서의 새 버전에 추가했습니다.
+하지만, 후에 JSON 스키마는 <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> 필드를 명세서의 새 버전에 추가했습니다.
그리고 새로운 OpenAPI 3.1.0은 이 새로운 `examples` 필드가 포함된 최신 버전 (JSON 스키마 2020-12)을 기반으로 했습니다.
-이제 새로운 `examples` 필드는 이전의 단일 (그리고 커스텀) `example` 필드보다 우선되며, `example`은 사용하지 않는 것이 좋습니다.
+그리고 이제 이 새로운 `examples` 필드는 이제 지원 중단된, 예전의 단일 (그리고 커스텀) `example` 필드보다 우선됩니다.
-JSON 스키마의 새로운 `examples` 필드는 예제 속 **단순한 `list`**이며, (위에서 상술한 것처럼) OpenAPI의 다른 곳에 존재하는 dict으로 된 추가적인 메타데이터가 아닙니다.
+JSON 스키마의 새로운 `examples` 필드는 예제의 **단순한 `list`**일 뿐이며, (위에서 상술한 것처럼) OpenAPI의 다른 곳에 존재하는 추가 메타데이터가 있는 dict가 아닙니다.
/// info | 정보
///
-### Pydantic과 FastAPI `examples`
+### Pydantic과 FastAPI `examples` { #pydantic-and-fastapi-examples }
-`examples`를 Pydantic 모델 속에 추가할 때, `schema_extra` 혹은 `Field(examples=["something"])`를 사용하면 Pydantic 모델의 **JSON 스키마**에 해당 예시가 추가됩니다.
+Pydantic 모델 안에 `examples`를 추가할 때, `schema_extra` 또는 `Field(examples=["something"])`를 사용하면 그 예제는 해당 Pydantic 모델의 **JSON 스키마**에 추가됩니다.
그리고 Pydantic 모델의 **JSON 스키마**는 API의 **OpenAPI**에 포함되고, 그 후 문서 UI 속에서 사용됩니다.
-FastAPI 0.99.0 이전 버전에서 (0.99.0 이상 버전은 새로운 OpenAPI 3.1.0을 사용합니다), `example` 혹은 `examples`를 다른 유틸리티(`Query()`, `Body()` 등)와 함께 사용했을 때, 저러한 예시는 데이터를 설명하는 JSON 스키마에 추가되지 않으며 (심지어 OpenAPI의 자체 JSON 스키마에도 포함되지 않습니다), OpenAPI의 *경로 작동* 선언에 직접적으로 추가됩니다 (JSON 스키마를 사용하는 OpenAPI 부분 외에도).
+FastAPI 0.99.0 이전 버전에서 (0.99.0 이상 버전은 새로운 OpenAPI 3.1.0을 사용합니다), 다른 유틸리티(`Query()`, `Body()` 등)와 함께 `example` 또는 `examples`를 사용했을 때, 그러한 예제는 그 데이터를 설명하는 JSON 스키마에 추가되지 않고 (OpenAPI 자체의 JSON 스키마에도 포함되지 않습니다), OpenAPI의 *경로 처리* 선언에 직접적으로 추가됩니다 (JSON 스키마를 사용하는 OpenAPI 부분 밖에서).
-í\95\98ì§\80ë§\8c ì§\80ê¸\88ì\9d\80 FastAPI 0.99.0 ë°\8f ì\9d´í\9b\84 ë²\84ì \84ì\97\90ì\84\9cë\8a\94 JSON ì\8a¤í\82¤ë§\88 2020-12를 ì\82¬ì\9a©í\95\98ë\8a\94 OpenAPI 3.1.0ê³¼ Swagger UI 5.0.0 ë°\8f ì\9d´í\9b\84 ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98ë©°, 모ë\93 ê²\83ì\9d´ ë\8d\94 ì\9d¼ê´\80ì\84±ì\9d\84 ë\9d\84ê³ ì\98\88ì\8b\9cë\8a\94 JSON 스키마에 포함됩니다.
+í\95\98ì§\80ë§\8c ì\9d´ì \9c FastAPI 0.99.0 ë°\8f ì\9d´í\9b\84 ë²\84ì \84ì\97\90ì\84\9cë\8a\94 JSON ì\8a¤í\82¤ë§\88 2020-12를 ì\82¬ì\9a©í\95\98ë\8a\94 OpenAPI 3.1.0ê³¼ Swagger UI 5.0.0 ë°\8f ì\9d´í\9b\84 ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95\98기 ë\95\8c문ì\97\90, 모ë\93 ê²\83ì\9d´ ë\8d\94 ì\9d¼ê´\80ì\84±ì\9d\84 ë\9d\84ê³ ì\98\88ì \9cë\8f\84 JSON 스키마에 포함됩니다.
-### Swagger UI와 OpenAPI-특화 `examples`
+### Swagger UI와 OpenAPI-특화 `examples` { #swagger-ui-and-openapi-specific-examples }
-현재 (2023-08-26), Swagger UI가 다중 JSON 스키마 예시를 지원하지 않으며, 사용자는 다중 예시를 문서에 표시하는 방법이 없었습니다.
+Swagger UI는 다중 JSON 스키마 예제를 지원하지 않았기 때문에(2023-08-26 기준), 사용자는 문서에 여러 예제를 표시할 방법이 없었습니다.
-ì\9d´ë¥¼ í\95´ê²°í\95\98기 ì\9c\84í\95´, FastAPI `0.103.0`ì\9d\80 ì\83\88ë¡\9cì\9a´ 매ê°\9cë³\80ì\88\98ì\9d¸ `openapi_examples`를 í\8f¬í\95¨í\95\98ë\8a\94 ì\98\88ì \84 **OpenAPI-í\8a¹í\99\94** `examples` í\95\84ë\93\9c를 ì\84 ì\96¸í\95\98기 ì\9c\84í\95\9c **ì§\80ì\9b\90ì\9d\84 ì¶\94ê°\80**했습니다. 🤓
+ì\9d´ë¥¼ í\95´ê²°í\95\98기 ì\9c\84í\95´, FastAPI `0.103.0`ì\9d\80 ì\83\88ë¡\9cì\9a´ 매ê°\9cë³\80ì\88\98ì\9d¸ `openapi_examples`ë¡\9c ë\8f\99ì\9d¼í\95\9c ì\98\88ì \84 **OpenAPI-í\8a¹í\99\94** `examples` í\95\84ë\93\9c를 ì\84 ì\96¸í\95\98ë\8a\94 **ì§\80ì\9b\90**ì\9d\84 ì¶\94ê°\80했습니다. 🤓
-### 요약
+### 요약 { #summary }
-저는 역사를 그다지 좋아하는 편이 아니라고 말하고는 했지만... "기술 역사" 강의를 가르치는 지금의 저를 보세요.
+저는 역사를 그다지 좋아하는 편이 아니라고 말하고는 했지만... "기술 역사" 강의를 하는 지금의 저를 보세요. 😅
-ì\9a\94ì\95½í\95\98ì\9e\90ë©´ **FastAPI 0.99.0 í\98¹ì\9d\80 ê·¸ ì\9d´ì\83\81ì\9d\98 ë²\84ì \84**ì\9c¼ë¡\9c ì\97\85ê·¸ë \88ì\9d´ë\93\9cí\95\98ë\8a\94 ê²\83ì\9d\80 ë§\8eì\9d\80 ê²\83ë\93¤ì\9d´ ë\8d\94 **ì\89½ê³ , ì\9d¼ê´\80ì \81ì\9d´ë©° ì§\81ê´\80ì \81ì\9d´ê²\8c** 되며, 여러분은 이 모든 역사적 세부 사항을 알 필요가 없습니다. 😎
+ì\9a\94ì\95½í\95\98ì\9e\90ë©´ **FastAPI 0.99.0 í\98¹ì\9d\80 ê·¸ ì\9d´ì\83\81ì\9d\98 ë²\84ì \84**ì\9c¼ë¡\9c ì\97\85ê·¸ë \88ì\9d´ë\93\9cí\95\98ë©´, ë§\8eì\9d\80 ê²\83ë\93¤ì\9d´ í\9b¨ì\94¬ ë\8d\94 **ë\8b¨ì\88\9cí\95\98ê³ , ì\9d¼ê´\80ì \81ì\9d´ë©° ì§\81ê´\80ì \81**ì\9d´ 되며, 여러분은 이 모든 역사적 세부 사항을 알 필요가 없습니다. 😎
-# 현재 사용자 가져오기
+# 현재 사용자 가져오기 { #get-current-user }
-이전 장에서 (의존성 주입 시스템을 기반으로 한)보안 시스템은 *경로 작동 함수*에서 `str`로 `token`을 제공했습니다:
+이전 장에서 (의존성 주입 시스템을 기반으로 한) 보안 시스템은 *경로 처리 함수*에 `str`로 `token`을 제공했습니다:
-{* ../../docs_src/security/tutorial001.py hl[10] *}
+{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
-그러나 아직도 유용하지 않습니다.
+하지만 이는 여전히 그다지 유용하지 않습니다.
-í\98\84ì\9e¬ ì\82¬ì\9a©ì\9e\90를 ì \9cê³µí\95\98ë\8f\84ë¡\9d í\95©시다.
+í\98\84ì\9e¬ ì\82¬ì\9a©ì\9e\90를 ì \9cê³µí\95\98ë\8f\84ë¡\9d í\95´ë´\85시다.
-## ì\9c ì \80 모ë\8d¸ ì\83\9dì\84±í\95\98기
+## ì\82¬ì\9a©ì\9e\90 모ë\8d¸ ì\83\9dì\84±í\95\98기 { #create-a-user-model }
-먼ì \80 Pydantic ì\9c ì \80 모ë\8d¸ì\9d\84 ë§\8cë\93¤ì\96´ ë³´ê² ì\8aµë\8b\88다.
+먼ì \80 Pydantic ì\82¬ì\9a©ì\9e\90 모ë\8d¸ì\9d\84 ë§\8cë\93¤ì\96´ ë´\85ì\8b\9c다.
-Pydanticì\9d\84 ì\82¬ì\9a©í\95\98ì\97¬ 본문ì\9d\84 ì\84 ì\96¸í\95\98ë\8a\94 ê²\83ê³¼ ê°\99ì\9d\80 ë°©ì\8b\9dì\9c¼ë¡\9c ë\8b¤ë¥¸ ê³³ì\97\90ì\84\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+Pydanticì\9d\84 ì\82¬ì\9a©í\95´ 본문ì\9d\84 ì\84 ì\96¸í\95\98ë\8a\94 ê²\83ê³¼ ê°\99ì\9d\80 ë°©ì\8b\9dì\9c¼ë¡\9c, ë\8b¤ë¥¸ ê³³ì\97\90ì\84\9cë\8f\84 ì\96´ë\94\94ì\84\9cë\93 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
-{* ../../docs_src/security/tutorial002.py hl[5,12:16] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
-## `get_current_user` 의존성 생성하기
+## `get_current_user` 의존성 생성하기 { #create-a-get-current-user-dependency }
의존성 `get_current_user`를 만들어 봅시다.
-ì\9d\98ì¡´ì\84±ì\9d´ í\95\98ì\9c\84 ì\9d\98ì¡´ì\84±ì\9d\84 ê°\80ì§\88 ì\88\98 ì\9e\88ë\8b¤ë\8a\94 ê²\83ì\9d\84 기ì\96µí\95\98ì\8bë\8b\88ê¹\8c?
+ì\9d\98ì¡´ì\84±ì\9d´ í\95\98ì\9c\84 ì\9d\98ì¡´ì\84±ì\9d\84 ê°\80ì§\88 ì\88\98 ì\9e\88ë\8b¤ë\8a\94 ê²\83ì\9d\84 기ì\96µí\95\98ì\8b\9cë\82\98ì\9a\94?
-`get_current_user`는 이전에 생성한 것과 동일한 `oauth2_scheme`과 종속성을 갖게 됩니다.
+`get_current_user`는 이전에 생성한 것과 동일한 `oauth2_scheme`에 대한 의존성을 갖게 됩니다.
-ì\9d´ì \84ì\97\90 *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\97\90ì\84\9c ì§\81ì \91 ì\88\98í\96\89í\96\88ë\8d\98 ê²\83ê³¼ ë\8f\99ì\9d¼í\95\98ê²\8c ì\83\88 ì¢\85ì\86\8dì\84± `get_current_user`ë\8a\94 í\95\98ì\9c\84 ì¢\85ì\86\8dì\84± `oauth2_scheme`ì\97\90ì\84\9c `str`ë¡\9c `token`ì\9d\84 ì\88\98ì\8b í\95©ë\8b\88ë\8b¤.
+ì\9d´ì \84ì\97\90 *ê²½ë¡\9c ì²\98리*ì\97\90ì\84\9c ì§\81ì \91 ì\88\98í\96\89í\96\88ë\8d\98 ê²\83ê³¼ ë\8f\99ì\9d¼í\95\98ê²\8c, ì\83\88 ì\9d\98ì¡´ì\84± `get_current_user`ë\8a\94 í\95\98ì\9c\84 ì\9d\98ì¡´ì\84± `oauth2_scheme`ë¡\9cë¶\80í\84° `str`ë¡\9c `token`ì\9d\84 ë°\9bê²\8c ë\90©ë\8b\88ë\8b¤:
-{* ../../docs_src/security/tutorial002.py hl[25] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
-## ì\9c ì \80 ê°\80ì ¸ì\98¤ê¸°
+## ì\82¬ì\9a©ì\9e\90 ê°\80ì ¸ì\98¤ê¸° { #get-the-user }
-`get_current_user`는 토큰을 `str`로 취하고 Pydantic `User` 모델을 반환하는 우리가 만든 (가짜) 유틸리티 함수를 사용합니다.
+`get_current_user`는 우리가 만든 (가짜) 유틸리티 함수를 사용합니다. 이 함수는 `str`로 토큰을 받아 Pydantic `User` 모델을 반환합니다:
-{* ../../docs_src/security/tutorial002.py hl[19:22,26:27] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
-## í\98\84ì\9e¬ ì\9c ì \80 주ì\9e\85í\95\98기
+## í\98\84ì\9e¬ ì\82¬ì\9a©ì\9e\90 주ì\9e\85í\95\98기 { #inject-the-current-user }
-ì\9d´ì \9c *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\97\90ì\84\9c `get_current_user`ì\99\80 ë\8f\99ì\9d¼í\95\9c `Depends`를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\9d´ì \9c *ê²½ë¡\9c ì²\98리*ì\97\90ì\84\9c `get_current_user`ì\99\80 í\95¨ê»\98 ê°\99ì\9d\80 `Depends`를 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
-{* ../../docs_src/security/tutorial002.py hl[31] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
-Pydantic 모델인 `User`로 `current_user`의 타입을 선언하는 것을 알아야 합니다.
+`current_user`의 타입을 Pydantic 모델 `User`로 선언한다는 점에 주목하세요.
-이것은 모든 완료 및 타입 검사를 통해 함수 내부에서 우리를 도울 것입니다.
+이는 함수 내부에서 자동 완성과 타입 체크에 도움을 줍니다.
/// tip | 팁
-ì\9a\94ì² ë³¸ë¬¸ë\8f\84 Pydantic 모ë\8d¸ë¡\9c ì\84 ì\96¸ë\90\9cë\8b¤ë\8a\94 ê²\83ì\9d\84 기ì\96µí\95 ê²\83ì\9e\85ë\8b\88ë\8b¤.
+ì\9a\94ì² ë³¸ë¬¸ë\8f\84 Pydantic 모ë\8d¸ë¡\9c ì\84 ì\96¸ë\90\9cë\8b¤ë\8a\94 ê²\83ì\9d\84 기ì\96µí\95\98ì\8b¤ì§\80ë\8f\84 모ë¦\85ë\8b\88ë\8b¤.
-여기서 **FastAPI**는 `Depends`를 사용하고 있기 때문에 혼동ë\90\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
+여기서 **FastAPI**는 `Depends`를 사용하고 있기 때문에 혼동í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
///
/// check | 확인
-이 의존성 시스템이 설계된 방식은 모두 `User` 모델을 반환하는 다양한 의존성(다른 "의존적인")을 가질 수 있도록 합니다.
+이 의존성 시스템이 설계된 방식은 모두 `User` 모델을 반환하는 서로 다른 의존성(서로 다른 "dependables")을 가질 수 있도록 합니다.
-해당 타입의 데이터를 반환할 수 있는 의존성이 하나만 있는 것으로 제한되지 않습니다.
+해당 타입의 데이터를 반환할 수 있는 의존성이 하나만 있어야 하는 것으로 제한되지 않습니다.
///
-## 다른 모델
+## 다른 모델 { #other-models }
-ì\9d´ì \9c *ê²½ë¡\9c ì\9e\91ë\8f\99 í\95¨ì\88\98*ì\97\90ì\84\9c í\98\84ì\9e¬ ì\82¬ì\9a©ì\9e\90를 ì§\81ì \91 ê°\80ì ¸ì\98¬ ì\88\98 ì\9e\88ì\9c¼ë©° `Depends`를 ì\82¬ì\9a©í\95\98ì\97¬ **의존성 주입** 수준에서 보안 메커니즘을 처리할 수 있습니다.
+ì\9d´ì \9c *ê²½ë¡\9c ì²\98리 í\95¨ì\88\98*ì\97\90ì\84\9c í\98\84ì\9e¬ ì\82¬ì\9a©ì\9e\90를 ì§\81ì \91 ê°\80ì ¸ì\98¬ ì\88\98 ì\9e\88ì\9c¼ë©°, `Depends`를 ì\82¬ì\9a©í\95´ **의존성 주입** 수준에서 보안 메커니즘을 처리할 수 있습니다.
-ê·¸ë¦¬ê³ ë³´ì\95\88 ì\9a\94구 ì\82¬í\95ì\97\90 ë\8c\80í\95\9c 모ë\93 모ë\8d¸ ë\98\90ë\8a\94 ë\8d°ì\9d´í\84°ë¥¼ 사용할 수 있습니다(이 경우 Pydantic 모델 `User`).
+ê·¸ë¦¬ê³ ë³´ì\95\88 ì\9a\94구 ì\82¬í\95ì\9d\84 ì\9c\84í\95´ ì\96´ë\96¤ 모ë\8d¸ì\9d´ë\82\98 ë\8d°ì\9d´í\84°ë\93 사용할 수 있습니다(이 경우 Pydantic 모델 `User`).
-그러나 일부 특정 데이터 모델, 클래스 또는 타입을 사용하도록 제한되지 않습니다.
+하지만 특정 데이터 모델, 클래스 또는 타입만 사용해야 하는 것은 아닙니다.
-모ë\8d¸ì\97\90 `id`ì\99\80 `email`ì\9d´ ì\9e\88ê³ `username`ì\9d´ ì\97\86길 ì\9b\90í\95\98ì\8bë\8b\88ê¹\8c? ë§\9eì\8aµë\8b\88ë\8b¤. ì\9d´ë\93¤ì\9d\80 ë\8f\99ì\9d¼í\95\9c 도구를 사용할 수 있습니다.
+모ë\8d¸ì\97\90 `id`ì\99\80 `email`ì\9d´ ì\9e\88ê³ `username`ì\9d\80 ì\97\86ê²\8c í\95\98ê³ ì\8b¶ì\9c¼ì\8b ê°\80ì\9a\94? ë¬¼ë¡ ì\9e\85ë\8b\88ë\8b¤. ê°\99ì\9d\80 도구를 사용할 수 있습니다.
-`str`ë§\8c ê°\96ê³ ì\8b¶ì\8aµë\8b\88ê¹\8c? ì\95\84ë\8b\88ë©´ ê·¸ë\83¥ `dict`를 ê°\96ê³ ì\8b¶ì\8aµë\8b\88ê¹\8c? ì\95\84ë\8b\88ë©´ ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ í\81´ë\9e\98ì\8a¤ 모ë\8d¸ ì\9d¸ì\8a¤í\84´ì\8a¤ë¥¼ ì§\81ì \91 ê°\96ê³ ì\8b¶ì\8aµë\8b\88ê¹\8c? ê·¸ë\93¤ì\9d\80 모ë\91\90 ê°\99ì\9d\80 ë°©ì\8b\9dì\9c¼ë¡\9c ì\9e\91ë\8f\99합니다.
+`str`ë§\8c ê°\96ê³ ì\8b¶ì\9c¼ì\8b ê°\80ì\9a\94? ì\95\84ë\8b\88ë©´ `dict`ë§\8cì\9a\94? ë\98\90ë\8a\94 ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ í\81´ë\9e\98ì\8a¤ 모ë\8d¸ ì\9d¸ì\8a¤í\84´ì\8a¤ë¥¼ ì§\81ì \91 ì\93°ê³ ì\8b¶ì\9c¼ì\8b ê°\80ì\9a\94? 모ë\91\90 ê°\99ì\9d\80 ë°©ì\8b\9dì\9c¼ë¡\9c ë\8f\99ì\9e\91합니다.
-ì\8b¤ì \9cë¡\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90 ë¡\9cê·¸ì\9d¸í\95\98ë\8a\94 ì\82¬ì\9a©ì\9e\90ê°\80 ì\97\86ì§\80ë§\8c ì\95¡ì\84¸ì\8a¤ í\86 í\81°ë§\8c ì\9e\88ë\8a\94 ë¡\9cë´\87, ë´\87 ë\98\90ë\8a\94 기í\83\80 ì\8b\9cì\8a¤í\85\9cì\9d´ ì\9e\88ì\8aµë\8b\88ê¹\8c? ë\8b¤ì\8b\9c ë§\90í\95\98ì§\80ë§\8c 모ë\91\90 ë\8f\99ì\9d¼í\95\98ê²\8c ì\9e\91ë\8f\99합니다.
+ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90 ë¡\9cê·¸ì\9d¸í\95\98ë\8a\94 ì\82¬ì\9a©ì\9e\90ë\8a\94 ì\97\86ê³ , ì\95¡ì\84¸ì\8a¤ í\86 í\81°ë§\8c ê°\80ì§\84 ë¡\9cë´\87, ë´\87 ë\98\90ë\8a\94 ë\8b¤ë¥¸ ì\8b\9cì\8a¤í\85\9cë§\8c ì\9e\88ë\82\98ì\9a\94? ì\9d´ê²\83ë\8f\84 ë§\88ì°¬ê°\80ì§\80ë¡\9c 모ë\91\90 ë\8f\99ì\9d¼í\95\98ê²\8c ë\8f\99ì\9e\91합니다.
-애플리케이션에 필요한 모든 종류의 모델, 모든 종류의 클래스, 모든 종류의 데이터베이스를 사용하십시오. **FastAPI**는 의존성 주입 시스템을 다루었습니다.
+애플리케이션에 필요한 어떤 종류의 모델, 어떤 종류의 클래스, 어떤 종류의 데이터베이스든 사용하세요. **FastAPI**는 의존성 주입 시스템으로 이를 지원합니다.
-## 코드 사이즈
+## 코드 크기 { #code-size }
-이 예는 장황해 보일 수 있습니다. 동일한 파일에서 보안, 데이터 모델, 유틸리티 기능 및 *경로 작동*을 혼합하고 있음을 염두에 두십시오.
+이 예시는 장황해 보일 수 있습니다. 동일한 파일에서 보안, 데이터 모델, 유틸리티 함수 및 *경로 처리*를 섞어서 사용하고 있다는 점을 기억하세요.
-그러나 이게 키포인트입니다.
+하지만 여기 핵심이 있습니다.
-ë³´ì\95\88ê³¼ ì¢\85ì\86\8dì\84± 주ì\9e\85 í\95목ì\9d\84 í\95\9c ë²\88ë§\8c ì\9e\91ì\84±í\95\98ë©´ ë\90©ë\8b\88ë\8b¤.
+ë³´ì\95\88ê³¼ ì\9d\98ì¡´ì\84± 주ì\9e\85 ê´\80ë ¨ ì½\94ë\93\9cë\8a\94 í\95\9c ë²\88ë§\8c ì\9e\91ì\84±í\95©ë\8b\88ë\8b¤.
-ê·¸ë¦¬ê³ ì\9b\90í\95\98ë\8a\94 ë§\8cí\81¼ ë³µì\9e¡í\95\98ê²\8c ë§\8cë\93¤ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë\9e\98ë\8f\84 ì\9c ì\97°ì\84±ê³¼ í\95¨ê»\98 í\95\9c ê³³ì\97\90 í\95\9c ë²\88ì\97\90 ì\9e\91ì\84±í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ê·¸ë¦¬ê³ ì\9b\90í\95\98ë\8a\94 ë§\8cí\81¼ ë³µì\9e¡í\95\98ê²\8c ë§\8cë\93¤ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë\9f¼ì\97\90ë\8f\84 ì\97¬ì \84í\9e\88 í\95\9c ë²\88ë§\8c, í\95\9c ê³³ì\97\90ë§\8c ì\9e\91ì\84±í\95\98ë©´ ë\90©ë\8b\88ë\8b¤. ì\9c ì\97°ì\84±ì\9d\84 모ë\91\90 ì\9c ì§\80í\95\98ë©´ì\84\9cì\9a\94.
-그러나 동일한 보안 시스템을 사용하여 수천 개의 엔드포인트(*경로 작동*)를 가질 수 있습니다.
+하지만 같은 보안 시스템을 사용해 수천 개의 엔드포인트(*경로 처리*)를 가질 수 있습니다.
-그리고 그들 모두(또는 원하는 부분)는 이러한 의존성 또는 생성한 다른 의존성을 재사용하는 이점을 얻을 수 있습니다.
+그리고 그들 모두(또는 원하는 일부)는 이러한 의존성 또는 여러분이 생성한 다른 의존성을 재사용하는 이점을 얻을 수 있습니다.
-ê·¸ë¦¬ê³ ì\9d´ ì\88\98ì²\9c ê°\9cì\9d\98 *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\80 모ë\91\90 3ì¤\84 ì \95ë\8f\84ë¡\9c ì¤\84ì\9d¼ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ê·¸ë¦¬ê³ ì\9d´ ì\88\98ì²\9c ê°\9cì\9d\98 *ê²½ë¡\9c ì²\98리*ë\8a\94 3ì¤\84 ì \95ë\8f\84ë¡\9cë\8f\84 ë§\8cë\93¤ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤:
-{* ../../docs_src/security/tutorial002.py hl[30:32] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
-## 요약
+## 요약 { #recap }
-ì\9d´ì \9c *ê²½ë¡\9c ì\9e\91ë\8f\99 함수*에서 현재 사용자를 직접 가져올 수 있습니다.
+ì\9d´ì \9c *ê²½ë¡\9c ì²\98리 함수*에서 현재 사용자를 직접 가져올 수 있습니다.
-ì\9a°ë¦¬ë\8a\94 ì\9d´ë¯¸ ì\9d´ë\93¤ ì\82¬ì\9d´ì\97\90 ì\9e\88습니다.
+ì\9a°ë¦¬ë\8a\94 ì\9d´ë¯¸ ì \88ë°\98ì\9d\80 ì\99\94습니다.
-ì\82¬ì\9a©ì\9e\90/í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\8b¤ì \9cë¡\9c `username`ê³¼ `password`를 ë³´ë\82´ë ¤ë©´ *ê²½ë¡\9c ì\9e\91ë\8f\99*ì\9d\84 ì¶\94ê°\80í\95\98기ë§\8c 하면 됩니다.
+ì\82¬ì\9a©ì\9e\90/í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\8b¤ì \9cë¡\9c `username`ê³¼ `password`를 ë³´ë\82´ë\8f\84ë¡\9d í\95\98ë\8a\94 *ê²½ë¡\9c ì²\98리*ë§\8c ì¶\94ê°\80하면 됩니다.
-다음 장을 확인해 봅시다.
+다음에 이어집니다.
-# 패스워드 해싱을 이용한 OAuth2, JWT 토큰을 사용하는 Bearer 인증
+# 패스워드(해싱 포함)를 사용하는 OAuth2, JWT 토큰을 사용하는 Bearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
-모든 보안 흐름을 구성했으므로, 이제 <abbr title="JSON Web Tokens">JWT</abbr> 토큰과 패스워드 해싱을 사용해 애플리케이션을 안전하게 만들 것입니다.
+모든 보안 흐름을 구성했으므로, 이제 <abbr title="JSON Web Tokens">JWT</abbr> 토큰과 안전한 패스워드 해싱을 사용해 애플리케이션을 실제로 안전하게 만들겠습니다.
-이 코드는 실제로 애플리케이션에서 패스워드를 해싱하여 DB에 저장하는 등의 작업에 활용할 수 있습니다.
+이 코드는 실제로 애플리케이션에서 사용할 수 있으며, 패스워드 해시를 데이터베이스에 저장하는 등의 작업에 활용할 수 있습니다.
-이전 장에 이어서 시작해 봅시다.
+이전 장에서 멈춘 지점부터 시작해 내용을 확장해 나가겠습니다.
-## JWT
+## JWT 알아보기 { #about-jwt }
-JWT 는 "JSON Web Tokens" 을 의미합니다.
+JWT는 "JSON Web Tokens"를 의미합니다.
-JSON ê°\9d체를 공백ì\9d´ ì\97\86ë\8a\94 긴 문ì\9e\90ì\97´ë¡\9c ì\9d¸ì½\94ë\94©í\95\98ë\8a\94 í\91\9cì¤\80ì\9d´ë©°, 다음과 같은 형태입니다:
+JSON ê°\9d체를 공백ì\9d´ ì\97\86ë\8a\94 ê¸¸ê³ ë°\80ì§\91ë\90\9c 문ì\9e\90ì\97´ë¡\9c ë¶\80í\98¸í\99\94í\95\98ë\8a\94 í\91\9cì¤\80ì\9e\85ë\8b\88ë\8b¤. 다음과 같은 형태입니다:
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```
-JWT는 암호화되지 않아 누구든지 토큰에서 정보를 복원할 수 있습니다.
+암호화된 것이 아니므로, 누구나 내용에서 정보를 복원할 수 있습니다.
-하지만 JWT는 서명되어 있습니다. 그래서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한게 맞는지 검증할 수 있습니다.
+하지만 서명되어 있습니다. 따라서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한 것이 맞는지 검증할 수 있습니다.
-만료 기간이 일주일인 토큰을 발행했다고 가정해 봅시다. 다음 날 사용자가 토큰을 가져왔을 때, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다.
+예를 들어 만료 기간이 1주일인 토큰을 생성할 수 있습니다. 그리고 사용자가 다음 날 토큰을 가지고 돌아오면, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다.
-일주일 뒤에는 토큰이 만료될 것이고, 사용자는 인가되지 않아 새 토큰을 받기 위해 다시 로그인해야 할 것입니다. 만약 사용자(또는 제3자)가 토큰을 수정하거나 만료일을 변경하면, 서명이 일치하지 않기 때문에 알아챌 수 있을 것입니다.
+1주일 뒤에는 토큰이 만료되고 사용자는 인가되지 않으므로 새 토큰을 받기 위해 다시 로그인해야 합니다. 그리고 사용자(또는 제3자)가 만료 시간을 바꾸기 위해 토큰을 수정하려고 하면, 서명이 일치하지 않기 때문에 이를 알아챌 수 있습니다.
-만약 JWT 토큰을 다뤄보고, 작동 방식도 알아보고 싶다면 <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a> 을 확인하십시오.
+JWT 토큰을 직접 다뤄보고 동작 방식을 확인해보고 싶다면 <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>를 확인하십시오.
-## `PyJWT` 설치
+## `PyJWT` 설치 { #install-pyjwt }
-파이썬으로 JWT 토큰을 생성하고 검증하려면 `PyJWT` 를 설치해야 합니다.
+Python에서 JWT 토큰을 생성하고 검증하려면 `PyJWT`를 설치해야 합니다.
-[가상환경](../../virtual-environments.md){.internal-link target=_blank} 을 만들고 활성화한 다음 `pyjwt` 를 설치하십시오:
+[가상환경](../../virtual-environments.md){.internal-link target=_blank}을 만들고 활성화한 다음 `pyjwt`를 설치하십시오:
<div class="termy">
</div>
-/// info | 참고
+/// info
-RSAë\82\98 ECDSA ê°\99ì\9d\80 ì \84ì\9e\90 ì\84\9cëª\85 ì\95\8cê³ ë¦¬ì¦\98ì\9d\84 ì\82¬ì\9a©í\95\98ë ¤ë©´, `pyjwt[crypto]`ë\9d¼ë\8a\94 ì\95\94í\98¸í\99\94 ë\9d¼ì\9d´ë¸\8cë\9f¬ë¦¬ ì\9d\98ì¡´ì\84±ì\9d\84 설치해야 합니다.
+RSAë\82\98 ECDSA ê°\99ì\9d\80 ì \84ì\9e\90 ì\84\9cëª\85 ì\95\8cê³ ë¦¬ì¦\98ì\9d\84 ì\82¬ì\9a©í\95 ê³\84í\9a\8dì\9d´ë\9d¼ë©´, cryptography ë\9d¼ì\9d´ë¸\8cë\9f¬ë¦¬ ì\9d\98ì¡´ì\84±ì\9d¸ `pyjwt[crypto]`를 설치해야 합니다.
-더 자세한 내용은 <a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">PyJWT 설치</a> 에서 확인할 수 있습니다.
+자세한 내용은 <a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">PyJWT Installation docs</a>에서 확인할 수 있습니다.
///
-## 패스워드 해싱
+## 패스워드 해싱 { #password-hashing }
-"해싱(Hashing)"은 어떤 내용(여기서는 패스워드)을 해석할 수 없는 일련의 바이트 집합(단순 문자열)으로 변환하는 것을 의미합니다.
+"해싱(Hashing)"은 어떤 내용(여기서는 패스워드)을 알아볼 수 없는 바이트 시퀀스(그냥 문자열)로 변환하는 것을 의미합니다.
-ë\8f\99ì\9d¼í\95\9c ë\82´ì\9a©(ë\98\91ê°\99ì\9d\80 í\8c¨ì\8a¤ì\9b\8cë\93\9c)ì\9d\84 í\95´ì\8b±í\95\98ë©´ ë\8f\99ì\9d¼í\95\9c 문ì\9e\90ì\97´ì\9d\84 ì\96»ì\8aµë\8b\88ë\8b¤.
+ì \95í\99\95í\9e\88 ê°\99ì\9d\80 ë\82´ì\9a©(ì \95í\99\95í\9e\88 ê°\99ì\9d\80 í\8c¨ì\8a¤ì\9b\8cë\93\9c)ì\9d\84 ë\84£ì\9c¼ë©´ ì \95í\99\95í\9e\88 ê°\99ì\9d\80 ì\95\8cì\95\84ë³¼ ì\88\98 ì\97\86ë\8a\94 문ì\9e\90ì\97´ì\9d´ ë\82\98ì\98µë\8b\88ë\8b¤.
-하지만 그 문자열을 다시 패스워드로 되돌릴 수는 없습니다.
+하지만 그 알아볼 수 없는 문자열에서 다시 패스워드로 되돌릴 수는 없습니다.
-### 패스워드를 해싱하는 이유
+### 패스워드 해싱을 사용하는 이유 { #why-use-password-hashing }
-데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시 값만 얻을 수 있습니다.
+데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시만 얻게 됩니다.
-따라서 침입자는 훔친 사용자 패스워드를 다른 시스템에서 활용할 수 없습니다. (대다수 사용자가 여러 시스템에서 동일한 패스워드를 사용하기 때문에 평문 패스워드가 유출되면 위험합니다.)
+따라서 침입자는 그 패스워드를 다른 시스템에서 사용해 보려고 시도할 수 없습니다(많은 사용자가 어디서나 같은 패스워드를 사용하므로, 이는 위험합니다).
-## `passlib` 설치
+## `pwdlib` 설치 { #install-pwdlib }
-PassLib는 패스워드 해시를 다루는 훌륭한 파이썬 패키지입니다.
+pwdlib는 패스워드 해시를 다루기 위한 훌륭한 Python 패키지입니다.
-ë§\8eì\9d\80 ì\95\88ì \84í\95\9c í\95´ì\8b\9c ì\95\8cê³ ë¦¬ì¦\98ê³¼ ë\8f\84구ë\93¤ì\9d\84 지원합니다.
+ë§\8eì\9d\80 ì\95\88ì \84í\95\9c í\95´ì\8b± ì\95\8cê³ ë¦¬ì¦\98ê³¼ ì\9d´ë¥¼ ë\8b¤ë£¨ê¸° ì\9c\84í\95\9c ì\9c í\8b¸ë¦¬í\8b°ë¥¼ 지원합니다.
-추천하는 알고리즘은 "Bcrypt"입니다.
+추천 알고리즘은 "Argon2"입니다.
-[가상환경](../../virtual-environments.md){.internal-link target=_blank} 을 만들고 활성화한 다음 PassLib와 Bcrypt를 설치하십시오:
+[가상환경](../../virtual-environments.md){.internal-link target=_blank}을 만들고 활성화한 다음 Argon2와 함께 pwdlib를 설치하십시오:
<div class="termy">
```console
-$ pip install "passlib[bcrypt]"
+$ pip install "pwdlib[argon2]"
---> 100%
```
</div>
-/// tip | 팁
+/// tip
-`passlib`를 사용하여, **Django**, **Flask** 의 보안 플러그인이나 다른 도구로 생성한 패스워드를 읽을 수 있도록 설정할 수도 있습니다.
+`pwdlib`를 사용하면 **Django**, **Flask** 보안 플러그인 또는 다른 여러 도구로 생성한 패스워드를 읽을 수 있도록 설정할 수도 있습니다.
-예를 들자면, FastAPI 애플리케이션과 Django 애플리케이션이 같은 데이터베이스에서 데이터를 공유할 수 있습니다. 또는 같은 데이터베이스를 사용하여 Django 애플리케이션을 점진적으로 마이그레이션 할 수도 있습니다.
+따라서 예를 들어, FastAPI 애플리케이션과 Django 애플리케이션이 같은 데이터베이스에서 동일한 데이터를 공유할 수 있습니다. 또는 같은 데이터베이스를 사용하면서 Django 애플리케이션을 점진적으로 마이그레이션할 수도 있습니다.
-그리고 사용자는 FastAPI 애플리케이션과 Django 애플리케이션에 동시에 로그인할 수 있습니다.
+그리고 사용자는 Django 앱 또는 **FastAPI** 앱에서 동시에 로그인할 수 있습니다.
///
-## 패스워드의 해시와 검증
+## 패스워드 해시 및 검증 { #hash-and-verify-the-passwords }
-필요한 도구를 `passlib`에서 임포트합니다.
+`pwdlib`에서 필요한 도구를 임포트합니다.
-PassLib "컨í\85\8dì\8a¤í\8a¸(context)"를 ì\83\9dì\84±í\95©ë\8b\88ë\8b¤. ì\9d´ê²\83ì\9d\80 í\8c¨ì\8a¤ì\9b\8cë\93\9c를 í\95´ì\8b±í\95\98ê³ ê²\80ì¦\9dí\95\98ë\8a\94ë\8d° ì\82¬ì\9a©í\95©ë\8b\88ë\8b¤.
+ê¶\8cì\9e¥ ì\84¤ì \95ì\9c¼ë¡\9c PasswordHash ì\9d¸ì\8a¤í\84´ì\8a¤ë¥¼ ì\83\9dì\84±í\95©ë\8b\88ë\8b¤. ì\9d´ë\8a\94 í\8c¨ì\8a¤ì\9b\8cë\93\9c를 í\95´ì\8b±í\95\98ê³ ê²\80ì¦\9dí\95\98ë\8a\94 ë\8d° ì\82¬ì\9a©ë\90©ë\8b\88ë\8b¤.
-/// tip | 팁
+/// tip
-PassLib 컨텍스트는 다양한 해싱 알고리즘을 사용할 수 있는 기능을 제공하며, 더 이상 사용이 권장되지 않는 오래된 해싱 알고리즘을 검증하는 기능도 포함되어 있습니다.
+pwdlib는 bcrypt 해싱 알고리즘도 지원하지만 레거시 알고리즘은 포함하지 않습니다. 오래된 해시로 작업해야 한다면 passlib 라이브러리를 사용하는 것을 권장합니다.
-ì\98\88를 ë\93¤ì\96´, ë\8b¤ë¥¸ ì\8b\9cì\8a¤í\85\9c(Django ê°\99ì\9d\80)ì\97\90ì\84\9c ì\83\9dì\84±í\95\9c í\8c¨ì\8a¤ì\9b\8cë\93\9c를 ì\9d½ê³ ê²\80ì¦\9dí\95 ì\88\98 ì\9e\88ì\9c¼ë©°, ì\83\88ë¡\9cì\9a´ í\8c¨ì\8a¤ì\9b\8cë\93\9c를 Bcrypt ê°\99ì\9d\80 ë\8b¤ë¥¸ ì\95\8cê³ ë¦¬ì¦\98ì\9c¼ë¡\9c í\95´ì\8b±í\95 ì\88\98ë\8f\84 있습니다.
+ì\98\88를 ë\93¤ì\96´, ë\8b¤ë¥¸ ì\8b\9cì\8a¤í\85\9c(Django ê°\99ì\9d\80)ì\97\90ì\84\9c ì\83\9dì\84±í\95\9c í\8c¨ì\8a¤ì\9b\8cë\93\9c를 ì\9d½ê³ ê²\80ì¦\9dí\95\98ë\90\98, ì\83\88 í\8c¨ì\8a¤ì\9b\8cë\93\9cë\8a\94 Argon2ë\82\98 Bcrypt ê°\99ì\9d\80 ë\8b¤ë¥¸ ì\95\8cê³ ë¦¬ì¦\98ì\9c¼ë¡\9c í\95´ì\8b±í\95\98ë\8f\84ë¡\9d í\95 ì\88\98 있습니다.
-그리고 동시에 그런 모든 알고리즘과 호환성을 유지합니다.
+그리고 동시에 그 모든 것과 호환되게 만들 수 있습니다.
///
사용자로부터 받은 패스워드를 해싱하는 유틸리티 함수를 생성합니다.
-그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티 함수도 생성합니다.
+그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티도 생성합니다.
그리고 사용자를 인증하고 반환하는 또 다른 함수도 생성합니다.
/// note
-새로운 (가짜) 데이터베이스 `fake_users_db`를 확인하면, 해시 처리된 패스워드가 어떻게 생겼는지 볼 수 있습니다: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+새로운 (가짜) 데이터베이스 `fake_users_db`를 확인하면, 이제 해시 처리된 패스워드가 어떻게 생겼는지 볼 수 있습니다: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
///
-## JWT 토큰 처리
+## JWT 토큰 처리 { #handle-jwt-tokens }
-설치된 모듈을 임포트 합니다.
+설치된 모듈을 임포트합니다.
-JWT 토큰 서명에 사용될 임의의 비밀키를 생성합니다.
+JWT 토큰을 서명하는 데 사용할 임의의 비밀 키를 생성합니다.
-안전한 임의의 비밀키를 생성하려면 다음 명령어를 사용하십시오:
+안전한 임의의 비밀 키를 생성하려면 다음 명령을 사용하십시오:
<div class="termy">
</div>
-ê·¸ë¦¬ê³ ì\83\9dì\84±í\95\9c ë¹\84ë°\80í\82¤ë¥¼ ë³µì\82¬í\95´ ë³\80ì\88\98 `SECRET_KEY`ì\97\90 ë\8c\80ì\9e\85í\95©ë\8b\88ë\8b¤. (ì\9d´ ì\98\88ì \9cì\9d\98 ë³\80ì\88\98 ê°\92ì\9d\84 ê·¸ë\8c\80ë¡\9c ì\82¬ì\9a©í\95\98ì§\80 ë§\88ì\8bì\8b\9cì\98¤.)
+ê·¸ë¦¬ê³ ì¶\9cë ¥ 결과를 ë³\80ì\88\98 `SECRET_KEY`ì\97\90 ë³µì\82¬í\95©ë\8b\88ë\8b¤(ì\98\88ì \9cì\9d\98 ê°\92ì\9d\84 ì\82¬ì\9a©í\95\98ì§\80 ë§\88ì\8bì\8b\9cì\98¤).
-JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM` 을 생성하고 `"HS256"` 으로 설정합니다.
+JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM`을 생성하고 `"HS256"`으로 설정합니다.
-토큰 만료 기간을 위한 변수를 생성합니다.
+토큰 만료를 위한 변수를 생성합니다.
-ì\9d\91ë\8bµì\9d\84 ì\9c\84í\95\9c í\86 í\81° ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸ì\97\90 사용될 Pydantic 모델을 정의합니다.
+ì\9d\91ë\8bµì\9d\84 ì\9c\84í\95´ í\86 í\81° ì\97\94ë\93\9cí\8f¬ì\9d¸í\8a¸ì\97\90ì\84\9c 사용될 Pydantic 모델을 정의합니다.
새 액세스 토큰을 생성하기 위한 유틸리티 함수를 생성합니다.
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
-## ì\9d\98ì¡´ì\84± ì\88\98ì \95
+## ì\9d\98ì¡´ì\84± ì\97\85ë\8d°ì\9d´í\8a¸ { #update-the-dependencies }
-`get_current_user` 함수를 이전과 동일한 토큰을 받도록 수정하되, 이번에는 JWT 토큰을 사용하도록 합니다.
+`get_current_user`가 이전과 동일한 토큰을 받도록 업데이트하되, 이번에는 JWT 토큰을 사용하도록 합니다.
-받은 토큰을 디코딩하여 검증한 후 현재 사용자를 반환합니다.
+받은 토큰을 디코딩하고 검증한 뒤 현재 사용자를 반환합니다.
-토큰이 유효하지 않다면 HTTP 오류를 반환합니다.
+토큰이 유효하지 않다면 즉시 HTTP 오류를 반환합니다.
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
-## `/token` 경로 작업 수정
+## `/token` *경로 처리* 업데이트 { #update-the-token-path-operation }
-í\86 í\81°ì\9d\98 ë§\8cë£\8c ì\8b\9cê°\81ì\9d\84 ì\84¤ì \95í\95\98기 ì\9c\84í\95´ `timedelta` 를 생성합니다.
+í\86 í\81°ì\9d\98 ë§\8cë£\8c ì\8b\9cê°\84ì\9c¼ë¡\9c `timedelta`를 생성합니다.
실제 JWT 액세스 토큰을 생성하여 반환합니다.
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
-### JWT "주체(subject)" `sub`에 대한 기술 세부 사항
+### JWT "주체(subject)" `sub`에 대한 기술 세부사항 { #technical-details-about-the-jwt-subject-sub }
-JWT 명세에 따르면 토큰의 주체를 포함하는 `sub`라는 키가 있습니다.
+JWT 명세에 따르면 토큰의 주체를 담는 `sub` 키가 있습니다.
-ì\82¬ì\9a© ì\97¬ë¶\80ë\8a\94 ì\84 í\83\9dì\82¬í\95ì\9d´ì§\80ë§\8c, ì\82¬ì\9a©ì\9e\90ì\9d\98 ì\8b\9dë³\84 ì \95보를 ì \80ì\9e¥í\95 ì\88\98 ì\9e\88ì\9c¼므로 여기서는 이를 사용합니다.
+ì\84 í\83\9dì \81ì\9c¼ë¡\9c ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì§\80ë§\8c, ì\97¬ê¸°ì\97\90 ì\82¬ì\9a©ì\9e\90 ì\8b\9dë³\84 ì \95보를 ë\84£ê²\8c ë\90\98므로 여기서는 이를 사용합니다.
-JWT는 사용자를 식별하고 사용자가 API를 직접 사용할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수도 있습니다.
+JWT는 사용자를 식별하고 사용자가 API에서 직접 작업을 수행할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수 있습니다.
-ì\98\88를 ë\93¤ì\96´ "ì\9e\90ë\8f\99ì°¨"ë\82\98 "ë¸\94ë¡\9cê·¸ ê²\8cì\8b\9c물"ì\9d\84 ì\8b\9dë³\84í\95\98ë\8a\94 ë\8d° ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+예를 들어 "자동차"나 "블로그 게시물"을 식별할 수 있습니다.
-ê·¸ë¦¬ê³ "ì\9e\90ë\8f\99차를 ì\9a´ì \84í\95\98ë\8b¤"ë\82\98 "ë¸\94ë¡\9cê·¸ ê²\8cì\8b\9c물ì\9d\84 ì\88\98ì \95í\95\98ë\8b¤"ì²\98ë\9f¼ í\95´ë\8b¹ ì\97\94í\84°í\8b°ì\97\90 ë\8c\80í\95\9c ê¶\8cí\95\9c을 추가할 수 있습니다.
+ê·¸ë\9f° ë\8b¤ì\9d\8c í\95´ë\8b¹ ì\97\94í\84°í\8b°ì\97\90 ë\8c\80í\95\9c ê¶\8cí\95\9c(ì\9e\90ë\8f\99ì°¨ì\9d\98 ê²½ì\9a° "drive", ë¸\94ë¡\9cê·¸ì\9d\98 ê²½ì\9a° "edit" ë\93±)을 추가할 수 있습니다.
-그 후 이 JWT 토큰을 사용자(또는 봇)에게 제공하면, 그들은 계정을 따로 만들 필요 없이 API가 생성한 JWT 토큰만으로 작업(자동차 운전 또는 블로그 게시물 편집)을 수행할 수 있습니다.
+그리고 그 JWT 토큰을 사용자(또는 봇)에게 제공하면, 계정이 없어도 API가 생성한 JWT 토큰만으로 그 동작들(자동차 운전, 블로그 편집)을 수행할 수 있습니다.
-이러한 ê°\9cë\85\90ì\9d\84 í\99\9cì\9a©í\95\98ë©´ JWTë\8a\94 í\9b¨ì\94¬ ë\8d\94 ë³µì\9e¡í\95\9c ì\8b\9cë\82\98리ì\98¤ì\97\90ë\8f\84 ì\82¬ì\9a©í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+이러한 ì\95\84ì\9d´ë\94\94ì\96´ë¥¼ í\99\9cì\9a©í\95\98ë©´ JWTë\8a\94 í\9b¨ì\94¬ ë\8d\94 ì \95êµ\90í\95\9c ì\8b\9cë\82\98리ì\98¤ì\97\90ë\8f\84 ì\82¬ì\9a©ë\90 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
-이 경우 여러 엔터티가 동일한 ID를 가질 수 있습니다. 예를 들어 foo라는 ID를 가진 사용자, 자동차, 블로그 게시물이 있을 수 있습니다.
+그런 경우 여러 엔터티가 동일한 ID(예: `foo`)를 가질 수도 있습니다(사용자 `foo`, 자동차 `foo`, 블로그 게시물 `foo`).
-그래서 ID 충돌을 방지하기 위해, 사용자의 JWT 토큰을 생성할 때 접두사로 `sub` 키를 추가할 수 있습니다. 예를 들어 `username:` 을 붙이는 방식입니다. 이 예제에서는 `sub` 값이 `username:johndoe`이 될 수 있습니다.
+따라서 ID 충돌을 방지하기 위해, 사용자에 대한 JWT 토큰을 생성할 때 `sub` 키의 값에 접두사를 붙일 수 있습니다. 예를 들어 `username:` 같은 것입니다. 그러면 이 예제에서 `sub` 값은 `username:johndoe`가 될 수 있습니다.
-ê°\80ì\9e¥ ì¤\91ì\9a\94í\95\9c ì \90ì\9d\80 `sub` í\82¤ë\8a\94 ì \84ì²´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90ì\84\9c ê³ ì\9c í\95\9c ì\8b\9dë³\84ì\9e\90ê°\80 ë\90\98ì\96´ì\95¼ í\95\98ë©° 문ì\9e\90ì\97´ì\9d´ì\96´ì\95¼ í\95\9cë\8b¤ë\8a\94 ì \90입니다.
+기ì\96µí\95´ì\95¼ í\95 ì¤\91ì\9a\94í\95\9c ì \90ì\9d\80 `sub` í\82¤ê°\80 ì \84ì²´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90ì\84\9c ê³ ì\9c í\95\9c ì\8b\9dë³\84ì\9e\90ì\97¬ì\95¼ í\95\98ê³ , 문ì\9e\90ì\97´ì\9d´ì\96´ì\95¼ í\95\9cë\8b¤ë\8a\94 ê²\83입니다.
-## í\99\95ì\9d¸í\95´ë´\85ì\8b\9cë\8b¤
+## í\99\95ì\9d¸í\95\98기 { #check-it }
서버를 실행하고 문서로 이동하십시오: <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/security/image07.png">
-ì\9d´ì \84ê³¼ ê°\99ì\9d\80 ë°©ë²\95ì\9c¼ë¡\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\97\90 ì\9d¸ì¦\9d하십시오.
+ì\9d´ì \84ê³¼ ê°\99ì\9d\80 ë°©ë²\95ì\9c¼ë¡\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\9d¸ê°\80하십시오.
다음 인증 정보를 사용하십시오:
/// check
-코드 어디에도 평문 패스워드 "`secret`" ì\9d´ ì\97\86ë\8b¤ë\8a\94 ì \90ì\97\90 ì\9c ì\9d\98í\95\98ì\8bì\8b\9cì\98¤. í\95´ì\8b\9cë\90\9c ë²\84ì \84ë§\8c ì\9e\88ì\8aµë\8b\88ë\8b¤.
+코드 어디에도 평문 패스워드 "`secret`"ì\9d\80 ì\97\86ê³ , í\95´ì\8b\9cë\90\9c ë²\84ì \84ë§\8c ì\9e\88ë\8b¤ë\8a\94 ì \90ì\97\90 ì\9c ì\9d\98í\95\98ì\8bì\8b\9cì\98¤.
///
<img src="/img/tutorial/security/image08.png">
-`/users/me/` 를 호출하면 다음과 같은 응답을 얻을 수 있습니다:
+엔드포인트 `/users/me/`를 호출하면 다음과 같은 응답을 받게 됩니다:
```JSON
{
<img src="/img/tutorial/security/image09.png">
-개발자 도구를 열어보면 전송된 데이터에 토큰만 포함된 것을 확인할 수 있습니다. 패스워드는 사용자를 인증하고 액세스 토큰을 받기 위한 첫 번째 요청에만 전송되며, 이후에는 전송되지 않습니다:
+개발자 도구를 열어보면 전송된 데이터에는 토큰만 포함되어 있고, 패스워드는 사용자를 인증하고 해당 액세스 토큰을 얻기 위한 첫 번째 요청에서만 전송되며 이후에는 전송되지 않는 것을 확인할 수 있습니다:
<img src="/img/tutorial/security/image10.png">
/// note
-`Bearer `로 시작하는 `Authorization` 헤더에 주목하십시오.
+`Bearer `로 시작하는 값을 가진 `Authorization` 헤더에 주목하십시오.
///
-## `scopes` 의 고급 사용법
+## `scopes`의 고급 사용법 { #advanced-usage-with-scopes }
-OAuth2는 "스코프(scopes)" 라는 개념을 갖고 있습니다.
+OAuth2에는 "scopes"라는 개념이 있습니다.
-ì\9d´ë¥¼ ì\82¬ì\9a©í\95\98ì\97¬ JWT 토큰에 특정 권한 집합을 추가할 수 있습니다.
+ì\9d´ë¥¼ ì\82¬ì\9a©í\95´ JWT 토큰에 특정 권한 집합을 추가할 수 있습니다.
-그 후 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에있는 API와 통신하도록 할 수 있습니다.
+그런 다음 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에서 API와 상호작용하도록 할 수 있습니다.
-**FastAPI** 에서의 사용 방법과 통합 방식은 **심화 사용자 안내서** 에서 자세히 배울 수 있습니다.
+어떻게 사용하는지, 그리고 **FastAPI**에 어떻게 통합되는지는 이후 **심화 사용자 안내서**에서 배울 수 있습니다.
-## 요약
+## 요약 { #recap }
-ì§\80ê¸\88ê¹\8cì§\80 ì\82´í\8e´ë³¸ ë\82´ì\9a©ì\9d\84 ë°\94í\83\95ì\9c¼ë¡\9c, OAuth2ì\99\80 JWT ê°\99ì\9d\80 í\91\9cì¤\80ì\9d\84 ì\82¬ì\9a©í\95\98ì\97¬ ì\95\88ì \84í\95\9c **FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ë§\8cë\93¤ 수 있습니다.
+ì§\80ê¸\88ê¹\8cì§\80 ì\82´í\8e´ë³¸ ë\82´ì\9a©ì\9d\84 ë°\94í\83\95ì\9c¼ë¡\9c, OAuth2ì\99\80 JWT ê°\99ì\9d\80 í\91\9cì¤\80ì\9d\84 ì\82¬ì\9a©í\95´ ì\95\88ì \84í\95\9c **FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\84¤ì \95í\95 수 있습니다.
-거의 모든 프레임워크에서 보안 처리는 상당히 복잡한 주제입니다.
+거의 모든 프레임워크에서 보안 처리는 꽤 빠르게 복잡한 주제가 됩니다.
-이를 단순화하는 많은 패키지는 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 여러 제약이 있습니다. 그리고 지나치게 단순화하는 일부 패키지들은 심각한 보안 결함을 가질 수도 있습니다.
+이를 크게 단순화하는 많은 패키지들은 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 많은 타협을 해야 합니다. 그리고 지나치게 단순화하는 일부 패키지들은 실제로 내부에 보안 결함이 있기도 합니다.
---
-**FastAPI** 는 어떤 데이터베이스, 데이터 모델, 도구도 강요하지 않습니다.
+**FastAPI**는 어떤 데이터베이스, 데이터 모델, 도구에도 타협하지 않습니다.
-í\94\84ë¡\9cì \9dí\8a¸ì\97\90 ê°\80ì\9e¥ ì \81í\95©í\95\9c ê²\83ì\9d\84 ì\84 í\83\9dí\95 ì\88\98 ì\9e\88ë\8a\94 유연성을 제공합니다.
+í\94\84ë¡\9cì \9dí\8a¸ì\97\90 ê°\80ì\9e¥ ì\9e\98 ë§\9eë\8a\94 ê²\83ë\93¤ì\9d\84 ì\84 í\83\9dí\95 ì\88\98 ì\9e\88ë\8a\94 모ë\93 유연성을 제공합니다.
-그리고 `passlib` 와 `PyJWT` 처럼 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다. **FastAPI** 는 외부 패키지 통합을 위해 복잡한 메커니즘이 필요하지 않기 때문입니다.
+그리고 **FastAPI**는 외부 패키지를 통합하기 위해 복잡한 메커니즘을 요구하지 않기 때문에 `pwdlib`와 `PyJWT` 같은 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다.
-그러나 유연성, 견고성, 보안성을 해치지 않으면서 과정을 단순화할 수 있는 도구들을 제공합니다.
+하지만 유연성, 견고성, 보안성을 해치지 않으면서 과정을 가능한 한 단순화할 수 있도록 도구들을 제공합니다.
-그리고 OAuth2와 같은 표준 프로토콜을 비교적 간단한 방법으로 구현하고 사용할 수 있습니다.
+또한 OAuth2 같은 안전한 표준 프로토콜을 비교적 간단한 방식으로 사용하고 구현할 수 있습니다.
-ë\8d\94 ì\84¸ë¶\84í\99\94ë\90\9c ê¶\8cí\95\9c ì²´ê³\84를 ì\9c\84í\95´ OAuth2ì\9d\98 "ì\8a¤ì½\94í\94\84"를 ì\82¬ì\9a©í\95\98ë\8a\94 ë°©ë²\95ì\9d\80 **ì\8b¬í\99\94 ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c**ì\97\90ì\84\9c ë\8d\94 ì\9e\90ì\84¸í\9e\88 ë°°ì\9a¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. OAuth2ì\9d\98 ì\8a¤ì½\94í\94\84ë\8a\94 ì \9c3ì\9e\90 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì\82¬ì\9a©ì\9e\90를 ë\8c\80ì\8b í\95´ ê·¸ë\93¤ì\9d\98 APIì\99\80 ì\83\81í\98¸ì\9e\91ì\9a©í\95\98ë\8f\84ë¡\9d ê¶\8cí\95\9cì\9d\84 ë¶\80ì\97¬í\95\98기 ì\9c\84í\95´, Facebook, Google, GitHub, Microsoft, X (Twitter) ë\93±ì\9d\98 ë§\8eì\9d\80 ë\8c\80í\98\95 ì\9d¸ì¦\9d ì \9cê³µì\97\85ì²´ë\93¤ì\9d´ 사용하는 메커니즘입니다.
+ë\8d\94 ì\84¸ë¶\84í\99\94ë\90\9c ê¶\8cí\95\9c ì\8b\9cì\8a¤í\85\9cì\9d\84 ì\9c\84í\95´ OAuth2 "scopes"를 ì\82¬ì\9a©í\95\98ë\8a\94 ë°©ë²\95ì\9d\80, ê°\99ì\9d\80 í\91\9cì¤\80ì\9d\84 ë\94°ë¥´ë\8a\94 ë°©ì\8b\9dì\9c¼ë¡\9c **ì\8b¬í\99\94 ì\82¬ì\9a©ì\9e\90 ì\95\88ë\82´ì\84\9c**ì\97\90ì\84\9c ë\8d\94 ì\9e\90ì\84¸í\9e\88 ë°°ì\9a¸ ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\8a¤ì½\94í\94\84를 ì\82¬ì\9a©í\95\98ë\8a\94 OAuth2ë\8a\94 Facebook, Google, GitHub, Microsoft, X (Twitter) ë\93± ë§\8eì\9d\80 ë\8c\80í\98\95 ì\9d¸ì¦\9d ì \9cê³µì\97\85ì²´ë\93¤ì\9d´ ì \9c3ì\9e\90 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì\82¬ì\9a©ì\9e\90 ë\8c\80ì\8b ê·¸ë\93¤ì\9d\98 APIì\99\80 ì\83\81í\98¸ì\9e\91ì\9a©í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d ì\9d¸ê°\80í\95\98ë\8a\94 ë\8d° 사용하는 메커니즘입니다.
-# 패스워드와 Bearer를 이용한 간단한 OAuth2
+# 패스워드와 Bearer를 이용한 간단한 OAuth2 { #simple-oauth2-with-password-and-bearer }
이제 이전 장에서 빌드하고 누락된 부분을 추가하여 완전한 보안 흐름을 갖도록 하겠습니다.
-## `username`와 `password` 얻기
+## `username`와 `password` 얻기 { #get-the-username-and-password }
**FastAPI** 보안 유틸리티를 사용하여 `username` 및 `password`를 가져올 것입니다.
그리고 데이터베이스 모델은 원하는 다른 이름을 사용할 수 있습니다.
-ê·¸ë\9f¬ë\82\98 ë¡\9cê·¸ì\9d¸ *ê²½ë¡\9c ì\9e\91ë\8f\99*의 경우 사양과 호환되도록 이러한 이름을 사용해야 합니다(예를 들어 통합 API 문서 시스템을 사용할 수 있어야 합니다).
+ê·¸ë\9f¬ë\82\98 ë¡\9cê·¸ì\9d¸ *ê²½ë¡\9c ì²\98리*의 경우 사양과 호환되도록 이러한 이름을 사용해야 합니다(예를 들어 통합 API 문서 시스템을 사용할 수 있어야 합니다).
사양에는 또한 `username`과 `password`가 폼 데이터로 전송되어야 한다고 명시되어 있습니다(따라서 여기에는 JSON이 없습니다).
-### `scope`
+### `scope` { #scope }
사양에는 클라이언트가 다른 폼 필드 "`scope`"를 보낼 수 있다고 나와 있습니다.
///
-## `username`과 `password`를 가져오는 코드
+## `username`과 `password`를 가져오는 코드 { #code-to-get-the-username-and-password }
이제 **FastAPI**에서 제공하는 유틸리티를 사용하여 이를 처리해 보겠습니다.
-### `OAuth2PasswordRequestForm`
+### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }
-먼ì \80 `OAuth2PasswordRequestForm`ì\9d\84 ê°\80ì ¸ì\99\80 `/token`ì\97\90 ë\8c\80í\95\9c *ê²½ë¡\9c ì\9e\91ë\8f\99*에서 `Depends`의 의존성으로 사용합니다.
+먼ì \80 `OAuth2PasswordRequestForm`ì\9d\84 ê°\80ì ¸ì\99\80 `/token`ì\97\90 ë\8c\80í\95\9c *ê²½ë¡\9c ì²\98리*에서 `Depends`의 의존성으로 사용합니다.
-{* ../../docs_src/security/tutorial003.py hl[4,76] *}
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
`OAuth2PasswordRequestForm`은 다음을 사용하여 폼 본문을 선언하는 클래스 의존성입니다:
///
-### 폼 데이터 사용하기
+### 폼 데이터 사용하기 { #use-the-form-data }
/// tip | 팁
오류의 경우 `HTTPException` 예외를 사용합니다:
-{* ../../docs_src/security/tutorial003.py hl[3,77:79] *}
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
-### 패스워드 확인하기
+### 패스워드 확인하기 { #check-the-password }
이 시점에서 데이터베이스의 사용자 데이터 형식을 확인했지만 암호를 확인하지 않았습니다.
두 패스워드가 일치하지 않으면 동일한 오류가 반환됩니다.
-#### 패스워드 해싱
+#### 패스워드 해싱 { #password-hashing }
"해싱"은 일부 콘텐츠(이 경우 패스워드)를 횡설수설하는 것처럼 보이는 일련의 바이트(문자열)로 변환하는 것을 의미합니다.
그러나 횡설수설에서 암호로 다시 변환할 수는 없습니다.
-##### 패스워드 해싱을 사용해야 하는 이유
+##### 패스워드 해싱을 사용해야 하는 이유 { #why-use-password-hashing }
데이터베이스가 유출된 경우 해커는 사용자의 일반 텍스트 암호가 아니라 해시만 갖게 됩니다.
따라서 해커는 다른 시스템에서 동일한 암호를 사용하려고 시도할 수 없습니다(많은 사용자가 모든 곳에서 동일한 암호를 사용하므로 이는 위험할 수 있습니다).
-//// tab | 파이썬 3.7 이상
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
-{* ../../docs_src/security/tutorial003.py hl[80:83] *}
-
-////
-
-{* ../../docs_src/security/tutorial003_py310.py hl[78:81] *}
-
-#### `**user_dict`에 대해
+#### `**user_dict`에 대해 { #about-user-dict }
`UserInDB(**user_dict)`는 다음을 의미한다:
/// info | 정보
-`**user_dict`에 대한 자세한 설명은 [**추가 모델** 문서](../extra-models.md#about-user_indict){.internal-link target=_blank}를 다시 읽어봅시다.
+`**user_dict`에 대한 자세한 설명은 [**추가 모델** 문서](../extra-models.md#about-user-in-dict){.internal-link target=_blank}를 다시 확인해보세요.
///
-## 토큰 반환하기
+## 토큰 반환하기 { #return-the-token }
`token` 엔드포인트의 응답은 JSON 객체여야 합니다.
///
-{* ../../docs_src/security/tutorial003.py hl[85] *}
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
/// tip | 팁
///
-## 의존성 업데이트하기
+## 의존성 업데이트하기 { #update-the-dependencies }
이제 의존성을 업데이트를 할 겁니다.
이 사용자가 활성화되어 있는 *경우에만* `current_user`를 가져올 겁니다.
-ë\94°ë\9d¼ì\84\9c `get_current_user`를 ì\9d\98ì¡´ì\84±ì\9c¼ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 ì¶\94ê°\80 ì¢\85ì\86\8d성 `get_current_active_user`를 만듭니다.
+ë\94°ë\9d¼ì\84\9c `get_current_user`를 ì\9d\98ì¡´ì\84±ì\9c¼ë¡\9c ì\82¬ì\9a©í\95\98ë\8a\94 ì¶\94ê°\80 ì\9d\98ì¡´성 `get_current_active_user`를 만듭니다.
이러한 의존성 모두, 사용자가 존재하지 않거나 비활성인 경우 HTTP 오류를 반환합니다.
따라서 엔드포인트에서는 사용자가 존재하고 올바르게 인증되었으며 활성 상태인 경우에만 사용자를 얻습니다:
-{* ../../docs_src/security/tutorial003.py hl[58:66,69:72,90] *}
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
/// info | 정보
///
-## 확인하기
+## 확인하기 { #see-it-in-action }
대화형 문서 열기: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
-### 인증하기
+### 인증하기 { #authenticate }
"Authorize" 버튼을 눌러봅시다.
<img src="/img/tutorial/security/image05.png">
-### 자신의 유저 데이터 가져오기
+### 자신의 유저 데이터 가져오기 { #get-your-own-user-data }
이제 `/users/me` 경로에 `GET` 작업을 진행합시다.
}
```
-### 비활성된 유저
+### 비활성된 유저 { #inactive-user }
이제 비활성된 사용자로 시도하고, 인증해봅시다:
}
```
-## 요약
+## 요약 { #recap }
이제 API에 대한 `username` 및 `password`를 기반으로 완전한 보안 시스템을 구현할 수 있는 도구가 있습니다.
-# SQL (관계형) 데이터베이스
+# SQL (관계형) 데이터베이스 { #sql-relational-databases }
-**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다.
+**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 하지만 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다.
여기서는 <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>을 사용하는 예제를 살펴보겠습니다.
-**SQLModel**은 <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a>와 Pydantic을 기반으로 구축되었습니다.SQLModel은 **SQL 데이터베이스**를 사용하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**의 제작자가 설계한 도구입니다.
+**SQLModel**은 <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a>와 Pydantic을 기반으로 구축되었습니다. **SQL 데이터베이스**를 사용해야 하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**와 같은 제작자가 만든 도구입니다.
/// tip | 팁
-다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 <abbr title="객체 관계 매퍼(Object Relational Mapper), SQL 테이블을 나타내는 클래스를 제공하고 테이블의 행을 인스턴스로 표현하는 라이브러리를 지칭하는 용어">"ORM"</abbr>이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎
+다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 <abbr title="Object Relational Mapper: a fancy term for a library where some classes represent SQL tables and instances represent rows in those tables">"ORMs"</abbr>이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎
///
-SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(SQLModel에서도 동일하게 지원됩니다). 예를 들면:
+SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(이것들은 SQLModel에서도 지원됩니다). 예를 들면:
* PostgreSQL
* MySQL
* Oracle
* Microsoft SQL Server 등.
-이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 파이썬에서 기본적으로 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다.
+이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 Python에서 통합 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다.
-나중에 실제 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다.
+나중에 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다.
/// tip | 팁
-**FastAPI**와 **PostgreSQL**를 포함하여 프론트엔드와 다양한 도구를 제공하는 공식 프로젝트 생성기가 있습니다: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
+프론트엔드와 더 많은 도구를 포함하여 **FastAPI**와 **PostgreSQL**을 포함한 공식 프로젝트 생성기가 있습니다: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
///
-이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 복잡한 기능에 대해 배우고 싶다면, <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel 문서</a>를 참고하세요.
+이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 고급 기능에 대해 배우고 싶다면, <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel 문서</a>를 참고하세요.
-## `SQLModel` 설치하기
+## `SQLModel` 설치하기 { #install-sqlmodel }
먼저, [가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `sqlmodel`을 설치하세요:
</div>
-## 단일 모델로 애플리케이션 생성하기
+## 단일 모델로 애플리케이션 생성하기 { #create-the-app-with-a-single-model }
우선 단일 **SQLModel** 모델을 사용하여 애플리케이션의 가장 간단한 첫 번째 버전을 생성해보겠습니다.
-이후 **다중 모델**을 추가하여 보안과 유연성을 강화할 것입니다. 🤓
+이후 아래에서 **여러 모델**로 보안과 유연성을 강화하며 개선하겠습니다. 🤓
-### 모델 생성하기
+### 모델 생성하기 { #create-models }
`SQLModel`을 가져오고 데이터베이스 모델을 생성합니다:
몇 가지 차이점이 있습니다:
-* `table=True`는 SQLModel에 이 모델이 *테이블 모델*이며, 단순한 데이터 모델이 아니라 SQL 데이터베이스의 **테이블**을 나타낸다는 것을 알려줍니다. (다른 일반적인 Pydantic 클래스처럼) 단순한 *데이터 모델*이 아닙니다.
+* `table=True`는 SQLModel에 이 모델이 *테이블 모델*이며, SQL 데이터베이스의 **테이블**을 나타내야 한다는 것을 알려줍니다. (다른 일반적인 Pydantic 클래스처럼) 단순한 *데이터 모델*이 아닙니다.
* `Field(primary_key=True)`는 SQLModel에 `id`가 SQL 데이터베이스의 **기본 키**임을 알려줍니다 (SQL 기본 키에 대한 자세한 내용은 SQLModel 문서를 참고하세요).
- `int | None` 유형으로 설정하면, SQLModel은 해당 열이 SQL 데이터베이스에서 `INTEGER` 유형이며 `NULLABLE` 값이어야 한다는 것을 알 수 있습니다.
+ **참고:** 기본 키 필드에 `int | None`을 사용하는 이유는, Python 코드에서 *`id` 없이 객체를 생성*할 수 있게 하기 위해서입니다(`id=None`). 데이터베이스가 *저장할 때 생성해 줄 것*이라고 가정합니다. SQLModel은 데이터베이스가 `id`를 제공한다는 것을 이해하고, 데이터베이스 스키마에서 *해당 열을 null이 아닌 `INTEGER`*로 정의합니다. 자세한 내용은 <a href="https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id" class="external-link" target="_blank">기본 키에 대한 SQLModel 문서</a>를 참고하세요.
-* `Field(index=True)`는 SQLModel에 해당 열에 대해 **SQL 인덱스**를 생성하도록 지시합니다. 이를 통해 데이터베이스에서 이 열으로 필터링된 데이터를 읽을 때 더 빠르게 조회할 수 있습니다.
+* `Field(index=True)`는 SQLModel에 해당 열에 대해 **SQL 인덱스**를 생성하도록 지시합니다. 이를 통해 데이터베이스에서 이 열로 필터링된 데이터를 읽을 때 더 빠르게 조회할 수 있습니다.
SQLModel은 `str`으로 선언된 항목이 SQL 데이터베이스에서 `TEXT` (또는 데이터베이스에 따라 `VARCHAR`) 유형의 열로 저장된다는 것을 인식합니다.
-### 엔진 생성하기
+### 엔진 생성하기 { #create-an-engine }
SQLModel의 `engine` (내부적으로는 SQLAlchemy `engine`)은 데이터베이스에 대한 **연결을 유지**하는 역할을 합니다.
-**하나의 단일 engine 객체**를 통해 코드 전체에서 동일한 데이터베이스에 연결할 수 있습니다.
+코드 전체에서 동일한 데이터베이스에 연결하기 위해 **하나의 단일 `engine` 객체**를 사용합니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
-`check_same_thread=False`를 사용하면 FastAPI에서 여러 스레드에서 동일한 SQLite 데이터베이스를 사용할 수 있습니다. 이는 **하나의 단일 요청**이 **여러 스레드**를 사용할 수 있기 때문에 필요합니다(예: 의존성에서 사용되는 경우).
+`check_same_thread=False`를 사용하면 FastAPI에서 여러 스레드에서 동일한 SQLite 데이터베이스를 사용할 수 있습니다. 이는 **하나의 단일 요청**이 **둘 이상의 스레드**를 사용할 수 있기 때문에 필요합니다(예: 의존성에서 사용되는 경우).
-걱정하지 마세요. 코드가 구조화된 방식으로 인해, 이후에 **각 요청마다 단일 SQLModel *세션*을 사용**하도록 보장할 것입니다. 실제로 그것이 `check_same_thread`가 하려는 것입니다.
+걱정하지 마세요. 코드가 구조화된 방식으로 인해, 이후에 **각 요청마다 단일 SQLModel *세션*을 사용**하도록 보장할 것입니다. 실제로 이것이 `check_same_thread`가 하려는 것입니다.
-### 테이블 생성하기
+### 테이블 생성하기 { #create-the-tables }
그 다음 `SQLModel.metadata.create_all(engine)`을 사용하여 모든 *테이블 모델*의 **테이블을 생성**하는 함수를 추가합니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
-### 세션 의존성 생성하기
+### 세션 의존성 생성하기 { #create-a-session-dependency }
**`Session`**은 **메모리에 객체**를 저장하고 데이터에 필요한 모든 변경 사항을 추적한 후, **`engine`을 통해** 데이터베이스와 통신합니다.
`yield`를 사용해 FastAPI의 **의존성**을 생성하여 각 요청마다 새로운 `Session`을 제공합니다. 이는 요청당 하나의 세션만 사용되도록 보장합니다. 🤓
-그런 다음 이 의존성을 사용하는 코드를 간소화하기 위해 `Annotated` 의존성 `SessionDep`을 생성합니다.
+그런 다음 이 의존성을 사용하는 나머지 코드를 간소화하기 위해 `Annotated` 의존성 `SessionDep`을 생성합니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
-### 시작 시 데이터베이스 테이블 생성하기
+### 시작 시 데이터베이스 테이블 생성하기 { #create-database-tables-on-startup }
애플리케이션 시작 시 데이터베이스 테이블을 생성합니다.
///
-### Hero 생성하기
+### Hero 생성하기 { #create-a-hero }
-각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 **타입 어노테이**션에서 동일하게 사용할 수 있습니다.
+각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 동일한 **타입 어노테이션**에서 사용할 수 있습니다.
예를 들어, 파라미터를 `Hero` 타입으로 선언하면 **JSON 본문**에서 값을 읽어옵니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
-</details>
+여기서는 `SessionDep` 의존성(`Session`)을 사용하여 새로운 `Hero`를 `Session` 인스턴스에 추가하고, 데이터베이스에 변경 사항을 커밋하고, `hero` 데이터의 최신 상태를 갱신한 다음 이를 반환합니다.
-여기서 `SessionDep` 의존성 (즉, `Session`)을 사용하여 새로운 `Hero`를 `Session` 인스턴스에 추가하고, 데이터베이스에 변경 사항을 커밋하고, `hero` 데이터의 최신 상태를 갱신한 다음 이를 반환합니다.
-
-### Heroes 조회하기
+### Heroes 조회하기 { #read-heroes }
`select()`를 사용하여 데이터베이스에서 `Hero`를 **조회**할 수 있습니다. 결과에 페이지네이션을 적용하기 위해 `limit`와 `offset`을 포함할 수 있습니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
-### 단일 Hero 조회하기
+### 단일 Hero 조회하기 { #read-one-hero }
단일 `Hero`를 **조회**할 수도 있습니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
-### Hero 삭제하기
+### Hero 삭제하기 { #delete-a-hero }
`Hero`를 **삭제**하는 것도 가능합니다.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
-### 애플리케이션 실행하기
+### 애플리케이션 실행하기 { #run-the-app }
-ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\8b¤í\96\89í\95\98ë ¤ë©´ ë\8b¤ì\9d\8c ëª\85ë ¹ì\9d\84 ì\82¬ì\9a©í\95©니다:
+ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\8b¤í\96\89í\95 ì\88\98 ì\9e\88ì\8aµ니다:
<div class="termy">
</div>
-그런 다음 `/docs` UI로 이동하면, **FastAPI**가 해당 **model들**을 사용하여 API **문서를 생성**하는 것으르 확인할 수 있습니다. 또한 이 모델들은 데이터를 직렬화하고 검증하는 데에도 사용됩니다.
+그런 다음 `/docs` UI로 이동하면, **FastAPI**가 이 **모델**들을 사용해 API를 **문서화**하고, 데이터를 **직렬화**하고 **검증**하는 데에도 사용하는 것을 확인할 수 있습니다.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image01.png">
</div>
-## 여러 모델로 애플리케이션 업데이트
+## 여러 모델로 애플리케이션 업데이트 { #update-the-app-with-multiple-models }
-ì\9d´ì \9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\95½ê°\84 **리í\8c©í\86 링**하여 **보안**과 **유연성**을 개선해 보겠습니다.
+ì\9d´ì \9c ì\9d´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì\95½ê°\84 **리í\8c©í\84°링**하여 **보안**과 **유연성**을 개선해 보겠습니다.
-ì\9d´ì \84 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 UI를 ë³´ë©´, ì§\80ê¸\88ê¹\8cì§\80ë\8a\94 í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\83\9dì\84±í\95 `Hero`ì\9d\98 `id`를 ì§\81ì \91 ì§\80ì \95í\95 ì\88\98 ì\9e\88ë\8b¤ë\8a\94 ê²\83ì\9d\84 ì\95\8c 수 있습니다. 😱
+ì\9d´ì \84 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 í\99\95ì\9d¸í\95´ ë³´ë©´, ì§\80ê¸\88ê¹\8cì§\80ë\8a\94 UIì\97\90ì\84\9c í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\83\9dì\84±í\95 `Hero`ì\9d\98 `id`를 ê²°ì \95í\95 ì\88\98 ì\9e\88ê²\8c ë\90\98ì\96´ ì\9e\88ë\8a\94 ê²\83ì\9d\84 ë³¼ 수 있습니다. 😱
-ì\9d´ë\8a\94 í\97\88ì\9a©ë\90\98ì\96´ì\84 ì\95\88 ë\90©ë\8b\88ë\8b¤. í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\9d´ë¯¸ ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ì\97\90 ì \80ì\9e¥ë\90\9c `id`를 ë\8d®ì\96´ì\93¸ ì\9c\84í\97\98ì\9d´ ì\9e\88기 ë\95\8c문ì\9e\85ë\8b\88ë\8b¤. `id`ë\8a\94 **ë°±ì\97\94ë\93\9c** ë\98\90ë\8a\94 **ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤**ê°\80 ê²°ì \95í\95´ì\95¼ í\95\98ë©°, **í\81´ë\9d¼ì\9d´ì\96¸í\8a¸**ê°\80 ê²°ì \95해서는 안 됩니다.
+ì\9d´ë \87ê²\8c í\95´ì\84\9cë\8a\94 ì\95\88 ë\90©ë\8b\88ë\8b¤. í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 DBì\97\90 ì\9d´ë¯¸ í\95 ë\8b¹ë\90\98ì\96´ ì\9e\88ë\8a\94 `id`를 ë\8d®ì\96´ì\93¸ ì\88\98 ì\9e\88기 ë\95\8c문ì\9e\85ë\8b\88ë\8b¤. `id`를 ê²°ì \95í\95\98ë\8a\94 ê²\83ì\9d\80 **ë°±ì\97\94ë\93\9c** ë\98\90ë\8a\94 **ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤**ê°\80 í\95´ì\95¼ í\95\98ë©°, **í\81´ë\9d¼ì\9d´ì\96¸í\8a¸**ê°\80 해서는 안 됩니다.
-ë\98\90í\95\9c heroì\9d\98 `secret_name`ì\9d\84 ì\83\9dì\84±í\95\98긴 í\96\88지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅
+ë\98\90í\95\9c heroì\97\90 ë\8c\80í\95\9c `secret_name`ì\9d\84 ì\83\9dì\84±í\95\98지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅
-ì\9d´ë\9f¬í\95\9c 문ì \9c를 í\95´ê²°í\95\98기 ì\9c\84í\95´ ëª\87 ê°\80ì§\80 **ì¶\94ê°\80 모ë\8d¸**ì\9d\84 ì¶\94ê°\80í\95 ê²\83ì\9e\85니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨
+ì\9d´ë\9f¬í\95\9c 문ì \9cë\8a\94 ëª\87 ê°\80ì§\80 **ì¶\94ê°\80 모ë\8d¸**ì\9d\84 ì¶\94ê°\80í\95´ í\95´ê²°í\95\98ê² ì\8aµ니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨
-### 여러 모델 생성하기
+### 여러 모델 생성하기 { #create-multiple-models }
**SQLModel**에서 `table=True`가 설정된 모델 클래스는 **테이블 모델**입니다.
-`table=True`가 없는 모델 클래스는 **데이터 모델**로, 이는 실제로 몇 가지 추가 기능이 포함된 Pydantic 모델에 불과합니다. 🤓
+그리고 `table=True`가 없는 모델 클래스는 **데이터 모델**인데, 이것들은 실제로는 (몇 가지 작은 추가 기능이 있는) Pydantic 모델일 뿐입니다. 🤓
SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중복 선언하지 않아도** 됩니다.
-#### `HeroBase` - 기본 클래스
+#### `HeroBase` - 기본 클래스 { #herobase-the-base-class }
모든 모델에서 **공유되는 필드**를 가진 `HeroBase` 모델을 시작해 봅시다:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
-#### `Hero` - *테이블 모델*
+#### `Hero` - *테이블 모델* { #hero-the-table-model }
다음으로 실제 *테이블 모델*인 `Hero`를 생성합니다. 이 모델은 다른 모델에는 항상 포함되는 건 아닌 **추가 필드**를 포함합니다:
* `id`
* `secret_name`
-`Hero`는 `HeroBase`를 상속하므로 `HeroBase`에 선언된 필드도 포함합니다. 따라서 `Hero`는 다음 **필드들도** 가지게 됩니다:
+`Hero`는 `HeroBase`를 상속하므로 `HeroBase`에 선언된 필드도 **또한** 포함합니다. 따라서 `Hero`의 모든 필드는 다음과 같습니다:
* `id`
* `name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
-#### `HeroPublic` - 공개 *데이터 모델*
+#### `HeroPublic` - 공개 *데이터 모델* { #heropublic-the-public-data-model }
다음으로 `HeroPublic` 모델을 생성합니다. 이 모델은 API 클라이언트에 **반환**되는 모델입니다.
-`HeroPublic`ì\9d\80 `HeroBase`ì\99\80 ë\8f\99ì\9d¼í\95\9c í\95\84ë\93\9c를 ê°\80ì§\80ë©°, `secret_name`은 포함하지 않습니다.
+`HeroPublic`ì\9d\80 `HeroBase`ì\99\80 ë\8f\99ì\9d¼í\95\9c í\95\84ë\93\9c를 ê°\80ì§\80ë¯\80ë¡\9c, `secret_name`은 포함하지 않습니다.
마침내 우리의 heroes의 정체가 보호됩니다! 🥷
/// tip | 팁
-반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API와 통신하는 개발자가 훨씬 더 간단한 코드를 작성할 수 있습니다.
+반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API 클라이언트는 이런 확신을 바탕으로 훨씬 더 간단한 코드를 작성할 수 있습니다.
-또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 훨씬 수월하게 작업할 수 있습니다. 😎
+또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 API를 사용하면서 훨씬 더 좋은 경험을 할 수 있습니다. 😎
///
* `id`
* `name`
* `age`
-* `secret_name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
-#### `HeroCreate` - hero 생성용 *데이터 모델*
+#### `HeroCreate` - hero 생성용 *데이터 모델* { #herocreate-the-data-model-to-create-a-hero }
이제 `HeroCreate` 모델을 생성합니다. 이 모델은 클라이언트로부터 받은 데이터를 **검증**하는 역할을 합니다.
-`HeroCreate`는 `HeroBase와` 동일한 필드를 가지며, 추가로 `secret_name을` 포함합니다.
+`HeroCreate`는 `HeroBase`와 동일한 필드를 가지며, `secret_name`도 포함합니다.
-클라이언트가 **새 hero을 생성**할 때 `secret_name`을 보내고, 이는 데이터베이스에 저장되지만, 해당 비밀 이름은 API를 통해 클라이언트에게 반환되지 않습니다.
+이제 클라이언트가 **새 hero를 생성**할 때 `secret_name`을 보내면, 데이터베이스에 저장되지만, 그 비밀 이름은 API를 통해 클라이언트에게 반환되지 않습니다.
/// tip | 팁
이 방식은 **비밀번호**를 처리하는 방법과 동일합니다. 비밀번호를 받지만, 이를 API에서 반환하지는 않습니다.
-비밀번호 값을 저장하기 전에 **해싱**하여 저장하고, **평문으로 저장하지 마십시오**.
+ë\98\90í\95\9c ë¹\84ë°\80ë²\88í\98¸ ê°\92ì\9d\84 ì \80ì\9e¥í\95\98기 ì \84ì\97\90 **í\95´ì\8b±**í\95\98ì\97¬ ì \80ì\9e¥í\95\98ê³ , **í\8f\89문ì\9c¼ë¡\9c ì \80ì\9e¥í\95\98ì§\80 ë§\88ì\8bì\8b\9cì\98¤**.
///
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
-#### `HeroUpdate` - hero 수정용 *데이터 모델*
+#### `HeroUpdate` - hero 수정용 *데이터 모델* { #heroupdate-the-data-model-to-update-a-hero }
-이전 애플리케이션에서는 **hero를 수정**할 방법이 없었지만, 이제 **다중 모델**을 통해 수정 기능을 추가할 수 있습니다. 🎉
+이전 버전의 애플리케이션에서는 **hero를 수정**할 방법이 없었지만, 이제 **여러 모델**로 이를 할 수 있습니다. 🎉
-`HeroUpdate` *데이터 모델*은 약간 특별한데, 새 hero을 생성할 때 필요한 **모든 동일한 필드**를 가지지만, 모든 필드가 **선택적**(기본값이 있음)입니다. 이렇게 하면 hero을 수정할 때 수정하려는 필드만 보낼 수 있습니다.
+`HeroUpdate` *데이터 모델*은 약간 특별한데, 새 hero를 생성할 때 필요한 **모든 동일한 필드**를 가지지만, 모든 필드가 **선택적**(기본값이 있음)입니다. 이렇게 하면 hero를 수정할 때 수정하려는 필드만 보낼 수 있습니다.
-모든 **필드가 변경되기** 때문에(타입이 `None`을 포함하고, 기본값이 `None`으로 설정됨), 모든 필드를 **다시 선언**해야 합니다.
+모든 **필드가 실제로 변경**되기 때문에(타입이 이제 `None`을 포함하고, 기본값도 이제 `None`이 됨), 우리는 필드를 **다시 선언**해야 합니다.
-엄밀히 말하면 `HeroBase`를 상속할 필요는 없습니다. 모든 필드를 다시 선언하기 때문입니다. 일관성을 위해 상속을 유지하긴 했지만, 필수는 아닙니다. 이는 개인적인 취향의 문제입니다. 🤷
+`HeroBase`를 상속할 필요는 없습니다. 모든 필드를 다시 선언하기 때문입니다. 일관성을 위해 상속을 유지하긴 했지만, 필수는 아닙니다. 이는 개인적인 취향의 문제입니다. 🤷
`HeroUpdate`의 필드는 다음과 같습니다:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
-### `HeroCreate`로 생성하고 `HeroPublic` 반환하기
+### `HeroCreate`로 생성하고 `HeroPublic` 반환하기 { #create-with-herocreate-and-return-a-heropublic }
-이제 **다중 모델**을 사용하므로 애플리케이션의 관련 부분을 업데이트할 수 있습니다.
+이제 **여러 모델**을 사용하므로 애플리케이션의 관련 부분을 업데이트할 수 있습니다.
요청에서 `HeroCreate` *데이터 모델*을 받아 이를 기반으로 `Hero` *테이블 모델*을 생성합니다.
이 새 *테이블 모델* `Hero`는 클라이언트에서 보낸 필드를 가지며, 데이터베이스에서 생성된 `id`도 포함합니다.
-그런 다음 함수를 통해 동일한 *테이블 모델* `Hero`를 반환합니다. 하지만 `response_model`로 `HeroPublic` *데이터 모델*을 선언했기 때문에, **FastAPI**는 `HeroPublic`을 사용하여 데이터를 검증하고 직렬화합니다.
+그런 다음 함수를 통해 동일한 *테이블 모델* `Hero`를 그대로 반환합니다. 하지만 `response_model`로 `HeroPublic` *데이터 모델*을 선언했기 때문에, **FastAPI**는 `HeroPublic`을 사용하여 데이터를 검증하고 직렬화합니다.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
/// tip | 팁
-ì\9d´ì \9c **ë°\98í\99\98 í\83\80ì\9e\85 주ì\84\9d** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다.
+ì\9d´ì \9c **ë°\98í\99\98 í\83\80ì\9e\85 ì\96´ë\85¸í\85\8cì\9d´ì\85\98** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다.
-만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 반환값이 `HeroPublic`이 아니라 `Hero`라고 경고했을 것입니다. 이는 적절한 경고입니다.
+만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 `HeroPublic` 대신 `Hero`를 반환한다고 (당연히) 불평할 것입니다.
-`response_model`ì\97\90 ì\84 ì\96¸í\95¨ì\9c¼ë¡\9cì\8d¨ **FastAPI**ê°\80 ì\9d´ë¥¼ ì²\98리í\95\98ë\8f\84ë¡\9d í\95\98ê³ , í\83\80ì\9e\85 ì\96´ë\85¸í\85\8cì\9d´ì\85\98ê³¼ ì\97\90ë\94\94í\84° ë°\8f ë\8b¤ë¥¸ ë\8f\84구ì\9d\98 ë\8f\84ì\9b\80ì\97\90ë\8a\94 ì\98\81í\96¥ì\9d\84 미ì¹\98ì§\80 ì\95\8aë\8f\84ë¡\9d ì\84¤ì \95합니다.
+`response_model`ì\97\90 ì\84 ì\96¸í\95¨ì\9c¼ë¡\9cì\8d¨ **FastAPI**ê°\80 ì²\98리í\95\98ë\8f\84ë¡\9d í\95\98ê³ , í\83\80ì\9e\85 ì\96´ë\85¸í\85\8cì\9d´ì\85\98ê³¼ ì\97\90ë\94\94í\84° ë°\8f ë\8b¤ë¥¸ ë\8f\84구ì\9d\98 ë\8f\84ì\9b\80ì\97\90ë\8a\94 ì\98\81í\96¥ì\9d\84 미ì¹\98ì§\80 ì\95\8aë\8f\84ë¡\9d 합니다.
///
-### `HeroPublic`으로 Heroes 조회하기
+### `HeroPublic`으로 Heroes 조회하기 { #read-heroes-with-heropublic }
이전과 동일하게 `Hero`를 **조회**할 수 있습니다. 이번에도 `response_model=list[HeroPublic]`을 사용하여 데이터가 올바르게 검증되고 직렬화되도록 보장합니다.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
-### `HeroPublic`으로 단일 Hero 조회하기
+### `HeroPublic`으로 단일 Hero 조회하기 { #read-one-hero-with-heropublic }
-단일 hero을 **조회**할 수도 있습니다:
+단일 hero를 **조회**할 수도 있습니다:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
-### `HeroUpdate`로 Hero 수정하기
+### `HeroUpdate`로 Hero 수정하기 { #update-a-hero-with-heroupdate }
**hero를 수정**할 수도 있습니다. 이를 위해 HTTP `PATCH` 작업을 사용합니다.
-코드에서는 클라이언트가 보낸 데이터를 딕셔너리 형태(`dict`)로 가져옵니다. 이는 **클라이언트가 보낸 데이터만 포함**하며, 기본값으로 들어가는 값은 제외합니다. 이를 위해 `exclude_unset=True`를 사용합니다. 이것이 주요 핵심입니다. 🪄
+그리고 코드에서는 클라이언트가 보낸 모든 데이터가 담긴 `dict`를 가져오는데, **클라이언트가 보낸 데이터만** 포함하고, 기본값이어서 들어가 있는 값은 제외합니다. 이를 위해 `exclude_unset=True`를 사용합니다. 이것이 주요 핵심입니다. 🪄
-ê·¸ë\9f° ë\8b¤ì\9d\8c, `hero_db.sqlmodel_update(hero_data)`를 ì\82¬ì\9a©í\95\98ì\97¬ `hero_data`ì\9d\98 ë\8d°ì\9d´í\84°ë¥¼ `hero_db`ì\97\90 업데이트합니다.
+ê·¸ë\9f° ë\8b¤ì\9d\8c, `hero_db.sqlmodel_update(hero_data)`를 ì\82¬ì\9a©í\95\98ì\97¬ `hero_data`ì\9d\98 ë\8d°ì\9d´í\84°ë¡\9c `hero_db`를 업데이트합니다.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
-### Hero 다시 삭제하기
+### Hero 다시 삭제하기 { #delete-a-hero-again }
hero **삭제**는 이전과 거의 동일합니다.
-ì\9d´ë²\88ì\97\90ë\8a\94 모ë\93 ê²\83ì\9d\84 리í\8c©í\86 ë§\81í\95\98ê³ ì\8b¶ì\9d\80 ì\9a\95구를 ë§\8c족ì\8b\9cí\82¤ì§\80 못í\95 ê²\83 ê°\99습니다. 😅
+ì\9d´ë²\88ì\97\90ë\8a\94 모ë\93 ê²\83ì\9d\84 리í\8c©í\84°ë§\81í\95\98ê³ ì\8b¶ì\9d\80 ì\9a\95구를 ë§\8c족ì\8b\9cí\82¤ì§\80 못í\95\98ê² 습니다. 😅
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
-### 애플리케이션 다시 실행하기
+### 애플리케이션 다시 실행하기 { #run-the-app-again }
-다음 명령을 사용해 애플리케이션을 다시 실행할 수 있습니다:
+애플리케이션을 다시 실행할 수 있습니다:
<div class="termy">
</div>
-`/docs` API UIë¡\9c ì\9d´ë\8f\99í\95\98ë©´ ì\97\85ë\8d°ì\9d´í\8a¸ë\90\9c ê²\83ì\9d\84 í\99\95ì\9d¸í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 ì\98\81ì\9b\85ì\9d\84 ì\83\9dì\84±í\95 ë\95\8c `id`를 ì \9cê³µí\95 í\95\84ì\9a\94ê°\80 ì\97\86ê²\8c ë\90\98ë\8a\94 ë\93±ì\9d\98 ë³\80í\99\94ë\8f\84 ë³´ì\9e\85니다.
+`/docs` API UIë¡\9c ì\9d´ë\8f\99í\95\98ë©´ ì\9d´ì \9c ì\97\85ë\8d°ì\9d´í\8a¸ë\90\98ì\96´ ì\9e\88ê³ , hero를 ì\83\9dì\84±í\95 ë\95\8c í\81´ë\9d¼ì\9d´ì\96¸í\8a¸ê°\80 `id`를 ë³´ë\82¼ ê²\83ì\9d´ë\9d¼ê³ 기ë\8c\80í\95\98ì§\80 ì\95\8aë\8a\94 ê²\83 ë\93±ì\9d\84 í\99\95ì\9d¸í\95 ì\88\98 ì\9e\88ì\8aµ니다.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
</div>
-## 요약
+## 요약 { #recap }
<a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a>을 사용하여 SQL 데이터베이스와 상호작용하고, *데이터 모델* 및 *테이블 모델*로 코드를 간소화할 수 있습니다.
-더 많은 내용을 배우고 싶다면, **SQLModel** 문서를 참고하세요. <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">SQLModel을 **FastAPI**와 함께 사용하는 것에 대한 더 긴 미니 튜토리얼</a>도 제공합니다. 🚀
+더 많은 내용을 배우려면 **SQLModel** 문서를 참고하세요. **FastAPI**와 함께 SQLModel을 사용하는 더 긴 미니 <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">튜토리얼</a>도 있습니다. 🚀
-# 정적 파일
+# 정적 파일 { #static-files }
-'StaticFiles'를 사용하여 디렉토리에서 정적 파일을 자동으로 제공할 수 있습니다.
+`StaticFiles`를 사용하면 디렉터리에서 정적 파일을 자동으로 제공할 수 있습니다.
-## `StaticFiles` 사용
+## `StaticFiles` 사용 { #use-staticfiles }
-* `StaticFiles` 임포트합니다.
-* 특정 경로에 `StaticFiles()` 인스턴스를 "마운트" 합니다.
+* `StaticFiles`를 임포트합니다.
+* 특정 경로에 `StaticFiles()` 인스턴스를 "마운트"합니다.
-{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
-/// note | 기술적 세부사항
+/// note | 기술 세부사항
-`from starlette.staticfiles import StaticFiles` 를 사용할 수도 있습니다.
+`from starlette.staticfiles import StaticFiles`를 사용할 수도 있습니다.
-**FastAPI**는 단지 개발자인, 당신에게 편의를 제공하기 위해 `fastapi.static files` 와 동일한 `starlett.static files`를 제공합니다. 하지만 사실 이것은 Starlett에서 직접 온 것입니다.
+**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.staticfiles`로 `starlette.staticfiles`와 동일한 것을 제공합니다. 하지만 실제로는 Starlette에서 직접 가져온 것입니다.
///
-### "마운팅" 이란
+### "마운팅"이란 { #what-is-mounting }
-"ë§\88ì\9a´í\8c\85"ì\9d\80 í\8a¹ì \95 ê²½ë¡\9cì\97\90 ì\99\84ì \84í\9e\88 "ë\8f\85립ì \81ì\9d¸" ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì¶\94ê°\80í\95\98ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95\98ë\8a\94ë\8d°, ê·¸ í\9b\84 모ë\93 í\95\98ì\9c\84 ê²½ë¡\9cì\97\90 ë\8c\80í\95´ì\84\9cë\8f\84 ì \81ì\9a©ë\90©ë\8b\88ë\8b¤.
+"ë§\88ì\9a´í\8c\85"ì\9d\80 í\8a¹ì \95 ê²½ë¡\9cì\97\90 ì\99\84ì \84í\95\9c "ë\8f\85립ì \81ì\9d¸" ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì¶\94ê°\80í\95\98ê³ , ê·¸ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ 모ë\93 í\95\98ì\9c\84 ê²½ë¡\9c를 ì²\98리í\95\98ë\8f\84ë¡\9d í\95\98ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95©ë\8b\88ë\8b¤.
-ë§\88ì\9a´í\8a¸ë\90\9c ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 ì\99\84ì \84í\9e\88 ë\8f\85립ì \81ì\9d´ê¸° ë\95\8c문ì\97\90 `APIRouter`를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ê³¼ë\8a\94 ë\8b¤ë¦\85ë\8b\88ë\8b¤. OpenAPI ë°\8f ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 문ì\84\9cë\8a\94 ë§\88ì\9a´í\8a¸ë\90\9c ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ ë\93±ì\97\90ì\84\9c ì\96´ë\96¤ ê²\83ë\8f\84 í\8f¬í\95¨í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
+ë§\88ì\9a´í\8a¸ë\90\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\80 ì\99\84ì \84í\9e\88 ë\8f\85립ì \81ì\9d´ë¯\80ë¡\9c `APIRouter`를 ì\82¬ì\9a©í\95\98ë\8a\94 ê²\83ê³¼ë\8a\94 ë\8b¤ë¦\85ë\8b\88ë\8b¤. ë©\94ì\9d¸ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 OpenAPI ë°\8f 문ì\84\9cì\97\90ë\8a\94 ë§\88ì\9a´í\8a¸ë\90\9c ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\98 ë\82´ì\9a© ë\93±ì\9d´ í\8f¬í\95¨ë\90\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤.
-자세한 내용은 **숙련된 사용자 안내서**에서 확인할 수 있습니다.
+자세한 내용은 [고급 사용자 가이드](../advanced/index.md){.internal-link target=_blank}에서 확인할 수 있습니다.
-## 세부사항
+## 세부사항 { #details }
-첫 ë²\88째 `"/static"`ì\9d\80 ì\9d´ "í\95\98ì\9c\84 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨"ì\9d´ "ë§\88ì\9a´í\8a¸"ë\90 í\95\98ì\9c\84 ê²½ë¡\9c를 ê°\80리í\82µë\8b\88ë\8b¤. ë\94°ë\9d¼ì\84\9c `"/static"`ì\9c¼ë¡\9c ì\8b\9cì\9e\91í\95\98ë\8a\94 모ë\93 ê²½ë¡\9cë\8a\94 `"/static"`ì\9c¼ë¡\9c ì²\98리ë\90©ë\8b\88ë\8b¤.
+첫 ë²\88째 `"/static"`ì\9d\80 ì\9d´ "í\95\98ì\9c\84 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98"ì\9d´ "ë§\88ì\9a´í\8a¸"ë\90 í\95\98ì\9c\84 ê²½ë¡\9c를 ê°\80리í\82µë\8b\88ë\8b¤. ë\94°ë\9d¼ì\84\9c `"/static"`ì\9c¼ë¡\9c ì\8b\9cì\9e\91í\95\98ë\8a\94 모ë\93 ê²½ë¡\9cë\8a\94 ì\9d´ ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d´ ì²\98리í\95©ë\8b\88ë\8b¤.
-`'directory="static"`은 정적 파일이 들어 있는 디렉토리의 이름을 나타냅니다.
+`directory="static"`은 정적 파일이 들어 있는 디렉터리의 이름을 나타냅니다.
`name="static"`은 **FastAPI**에서 내부적으로 사용할 수 있는 이름을 제공합니다.
-ì\9d´ 모ë\93 매ê°\9cë³\80ì\88\98ë\8a\94 "`static`"ê³¼ ë\8b¤ë¥¼ ì\88\98 ì\9e\88ì\9c¼ë©°, ì\82¬ì\9a©ì\9e\90 ì\9d\91ì\9a© í\94\84ë¡\9cê·¸ë\9e¨ì\9d\98 ì\9a\94구 ì\82¬í\95 ë°\8f 구체ì \81ì\9d¸ ì\84¸ë¶\80 ì \95ë³´ì\97\90 ë\94°ë\9d¼ 매ê°\9cë³\80ì\88\98를 ì¡°ì \95í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤.
+ì\9d´ 모ë\93 매ê°\9cë³\80ì\88\98ë\8a\94 "`static`"ê³¼ ë\8b¤ë¥¼ ì\88\98 ì\9e\88ì\9c¼ë©°, ì\97¬ë\9f¬ë¶\84ì\9d\98 ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98 ì\9a\94구 ì\82¬í\95 ë°\8f 구체ì \81ì\9d¸ ì\84¸ë¶\80 ì \95ë³´ì\97\90 ë§\9eê²\8c ì¡°ì \95í\95\98ì\84¸ì\9a\94.
+## 추가 정보 { #more-info }
-## 추가 정보
-
-자세한 내용과 선택 사항을 보려면 <a href="https://www.starlette.dev/staticfiles/" class="external-link" target="_blank">Starlette의 정적 파일에 관한 문서</a>를 확인하십시오.
+자세한 내용과 옵션은 <a href="https://www.starlette.dev/staticfiles/" class="external-link" target="_blank">Starlette의 정적 파일 문서</a>를 확인하세요.
-# 테스팅
+# 테스팅 { #testing }
-<a href="https://www.starlette.dev/testclient/" class="external-link" target="_blank">Starlette</a> 덕분에 **FastAPI** 를 테스트하는 일은 쉽고 즐거운 일이 되었습니다.
+<a href="https://www.starlette.dev/testclient/" class="external-link" target="_blank">Starlette</a> 덕분에 **FastAPI** 애플리케이션을 테스트하는 일은 쉽고 즐거운 일이 되었습니다.
-Starlette는 <a href="https://www.python-httpx.org\" class="external-link" target="_blank">HTTPX</a>를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다.
+Starlette는 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다.
-이를 사용하면 FastAPI에서 <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a>를 직접 사용할 수 있습니다.
+이를 사용하면 **FastAPI**에서 <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a>를 직접 사용할 수 있습니다.
-## `TestClient` 사용하기
+## `TestClient` 사용하기 { #using-testclient }
/// info | 정보
-`TestClient` 사용하려면, 우선 <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a> 를 설치해야 합니다.
+`TestClient` 사용하려면, 우선 <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>를 설치해야 합니다.
-[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
+[virtual environment](../virtual-environments.md){.internal-link target=_blank}를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
```console
$ pip install httpx
///
-`TestClient` 를 임포트하세요.
+`TestClient`를 임포트하세요.
-**FastAPI** ì\96´í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì \84ë\8b¬í\95\98ì\97¬ `TestClient` 를 만드세요.
+**FastAPI** ì\95 í\94\8c리ì¼\80ì\9d´ì\85\98ì\9d\84 ì \84ë\8b¬í\95\98ì\97¬ `TestClient`를 만드세요.
-이름이 `test_` 로 시작하는 함수를 만드세요(`pytest` 의 표준적인 관례입니다).
+이름이 `test_`로 시작하는 함수를 만드세요(`pytest`의 표준적인 관례입니다).
-`httpx` 를 사용하는 것과 같은 방식으로 `TestClient` 객체를 사용하세요.
+`httpx`를 사용하는 것과 같은 방식으로 `TestClient` 객체를 사용하세요.
-표준적인 파이썬 문법을 이용하여 확인이 필요한 곳에 간단한 `assert` 문장을 작성하세요(역시 표준적인 `pytest` 관례입니다).
+표준적인 파이썬 표현식으로 확인이 필요한 곳에 간단한 `assert` 문장을 작성하세요(역시 표준적인 `pytest` 관례입니다).
-{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
/// tip | 팁
-테스트를 위한 함수는 `async def` 가 아니라 `def` 로 작성됨에 주의하세요.
+테스트를 위한 함수는 `async def`가 아니라 `def`로 작성됨에 주의하세요.
-그리고 클라이언트에 대한 호출도 `await` 를 사용하지 않는 일반 호출입니다.
+그리고 클라이언트에 대한 호출도 `await`를 사용하지 않는 일반 호출입니다.
-이렇게 하여 복잡한 과정 없이 `pytest` 를 직접적으로 사용할 수 있습니다.
+이렇게 하여 복잡한 과정 없이 `pytest`를 직접적으로 사용할 수 있습니다.
///
-/// note | 기술 세부사항
+/// note Technical Details | 기술 세부사항
`from starlette.testclient import TestClient` 역시 사용할 수 있습니다.
-**FastAPI** 는 개발자의 편의를 위해 `starlette.testclient` 를 `fastapi.testclient` 로도 제공할 뿐입니다. 이는 단지 `Starlette` 에서 직접 가져오는지의 차이일 뿐입니다.
+**FastAPI**는 개발자의 편의를 위해 `starlette.testclient`를 `fastapi.testclient`로도 제공할 뿐입니다. 하지만 이는 Starlette에서 직접 가져옵니다.
///
/// tip | 팁
-FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 `async` 함수를 호출하고 싶다면 (예: 비동기 데이터베이스 함수), 심화 튜토리얼의 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} 를 참조하세요.
+FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 `async` 함수를 호출하고 싶다면 (예: 비동기 데이터베이스 함수), 심화 튜토리얼의 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank}를 참조하세요.
///
-## 테스트 분리하기
+## 테스트 분리하기 { #separating-tests }
실제 애플리케이션에서는 테스트를 별도의 파일로 나누는 경우가 많습니다.
-
그리고 **FastAPI** 애플리케이션도 여러 파일이나 모듈 등으로 구성될 수 있습니다.
-### **FastAPI** app 파일
+### **FastAPI** app 파일 { #fastapi-app-file }
-[Bigger Applications](bigger-applications.md){.internal-link target=_blank} 에 묘사된 파일 구조를 가지고 있는 것으로 가정해봅시다.
+[Bigger Applications](bigger-applications.md){.internal-link target=_blank}에 묘사된 파일 구조를 가지고 있는 것으로 가정해봅시다.
```
.
`main.py` 파일 안에 **FastAPI** app 을 만들었습니다:
-{* ../../docs_src/app_testing/main.py *}
-### 테스트 파일
+{* ../../docs_src/app_testing/app_a_py39/main.py *}
+
+### 테스트 파일 { #testing-file }
-테스트를 위해 `test_main.py` 라는 파일을 생성할 수 있습니다. 이 파일은 동일한 Python 패키지(즉, `__init__.py` 파일이 있는 동일한 디렉터리)에 위치할 수 있습니다.
+테스트를 위해 `test_main.py`라는 파일을 생성할 수 있습니다. 이 파일은 동일한 Python 패키지(즉, `__init__.py` 파일이 있는 동일한 디렉터리)에 위치할 수 있습니다.
``` hl_lines="5"
.
│ └── test_main.py
```
-í\8c\8cì\9d¼ë\93¤ì\9d´ ë\8f\99ì\9d¼í\95\9c í\8c¨í\82¤ì§\80ì\97\90 ì\9c\84ì¹\98í\95´ ì\9e\88ì\9c¼ë¯\80ë¡\9c, ì\83\81ë\8c\80 참조를 ì\82¬ì\9a©í\95\98ì\97¬ `main` 에서 `app` 객체를 임포트 해올 수 있습니다.
+í\8c\8cì\9d¼ë\93¤ì\9d´ ë\8f\99ì\9d¼í\95\9c í\8c¨í\82¤ì§\80ì\97\90 ì\9c\84ì¹\98í\95´ ì\9e\88ì\9c¼ë¯\80ë¡\9c, ì\83\81ë\8c\80 ì\9e\84í\8f¬í\8a¸ë¥¼ ì\82¬ì\9a©í\95\98ì\97¬ `main` 모ë\93\88(`main.py`)에서 `app` 객체를 임포트 해올 수 있습니다.
-{* ../../docs_src/app_testing/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
...그리고 이전에 작성했던 것과 같은 테스트 코드를 작성할 수 있습니다.
-## 테스트: 확장된 예시
+## 테스트: 확장된 예시 { #testing-extended-example }
이제 위의 예시를 확장하고 더 많은 세부 사항을 추가하여 다양한 부분을 어떻게 테스트하는지 살펴보겠습니다.
-### 확장된 FastAPI 애플리케이션 파일
+### 확장된 **FastAPI** app 파일 { #extended-fastapi-app-file }
이전과 같은 파일 구조를 계속 사용해 보겠습니다.
│ └── test_main.py
```
-ì\9d´ì \9c **FastAPI** ì\95±ì\9d´ ì\9e\88ë\8a\94 `main.py` í\8c\8cì\9d¼ì\97\90 ëª\87 ê°\80ì§\80 ë\8b¤ë¥¸ **ê²½ë¡\9c ì\9e\91ì\97\85** ì\9d´ 추가된 경우를 생각해봅시다.
+ì\9d´ì \9c **FastAPI** ì\95±ì\9d´ ì\9e\88ë\8a\94 `main.py` í\8c\8cì\9d¼ì\97\90 ëª\87 ê°\80ì§\80 ë\8b¤ë¥¸ **ê²½ë¡\9c ì²\98리**ê°\80 추가된 경우를 생각해봅시다.
단일 오류를 반환할 수 있는 `GET` 작업이 있습니다.
여러 다른 오류를 반환할 수 있는 `POST` 작업이 있습니다.
-두 *경로 작업* 모두 `X-Token` 헤더를 요구합니다.
-
-//// tab | Python 3.10+
-
-```Python
-{!> ../../docs_src/app_testing/app_b_an_py310/main.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python
-{!> ../../docs_src/app_testing/app_b_an_py39/main.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python
-{!> ../../docs_src/app_testing/app_b_an/main.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | 팁
-
-될 수 있으면 `Annotated` 버전 사용을 권장합나다.
-
-///
-
-```Python
-{!> ../../docs_src/app_testing/app_b_py310/main.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | 팁
-
-될 수 있으면 `Annotated` 버전 사용을 권장합나다.
-
-///
-
-```Python
-{!> ../../docs_src/app_testing/app_b/main.py!}
-```
+두 *경로 처리* 모두 `X-Token` 헤더를 요구합니다.
-////
+{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
-### 확장된 테스트 파일
+### 확장된 테스트 파일 { #extended-testing-file }
-이제는 `test_main.py` 를 확장된 테스트들로 수정할 수 있습니다:
+이제는 `test_main.py`를 확장된 테스트들로 수정할 수 있습니다:
-{* ../../docs_src/app_testing/app_b/test_main.py *}
+{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
-클라이언트가 요청에 정보를 전달해야 하는데 방법을 모르겠다면, `httpx`에서 해당 작업을 수행하는 방법을 검색(Google)하거나, `requests`에서의 방법을 검색해보세요. HTTPX는 Requests의 디자인을 기반으로 설계되었습니다.
+클라이언트가 요청에 정보를 전달해야 하는데 방법을 모르겠다면, Requests의 디자인을 기반으로 설계된 HTTPX처럼 `httpx`에서 해당 작업을 수행하는 방법을 검색(Google)하거나, `requests`에서의 방법을 검색해보세요.
그 후, 테스트에서도 동일하게 적용하면 됩니다.
예시:
* *경로* 혹은 *쿼리* 매개변수를 전달하려면, URL 자체에 추가한다.
-* JSON 본문을 전달하려면, 파이썬 객체 (예를들면 `dict`) 를 `json` 파라미터로 전달한다.
-* JSON 대신 *폼 데이터* 를 보내야한다면, `data` 파라미터를 대신 전달한다.
-* *헤더* 를 전달하려면, `headers` 파라미터에 `dict` 를 전달한다.
-* *쿠키* 를 전달하려면, `cookies` 파라미터에 `dict` 를 전달한다.
+* JSON 본문을 전달하려면, 파이썬 객체 (예를들면 `dict`)를 `json` 파라미터로 전달한다.
+* JSON 대신 *폼 데이터*를 보내야한다면, `data` 파라미터를 대신 전달한다.
+* *헤더*를 전달하려면, `headers` 파라미터에 `dict`를 전달한다.
+* *쿠키*를 전달하려면, `cookies` 파라미터에 `dict`를 전달한다.
-백엔드로 데이터를 어떻게 보내는지 정보를 더 얻으려면 (`httpx` 혹은 `TestClient` 를 이용해서) <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX documentation</a> 를 확인하세요.
+백엔드로 데이터를 어떻게 보내는지 정보를 더 얻으려면 (`httpx` 혹은 `TestClient`를 이용해서) <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX documentation</a>를 확인하세요.
/// info | 정보
-`TestClient` 는 Pydantic 모델이 아니라 JSON 으로 변환될 수 있는 데이터를 받습니다.
+`TestClient`는 Pydantic 모델이 아니라 JSON으로 변환될 수 있는 데이터를 받습니다.
-만약 테스트중 Pydantic 모델을 어플리케이션으로에 보내고 싶다면, [JSON 호환 가능 인코더](encoder.md){.internal-link target=_blank} 에 설명되어 있는 `jsonable_encoder` 를 사용할 수 있습니다.
+만약 테스트 중 Pydantic 모델을 가지고 있고 테스트 중에 애플리케이션으로 해당 데이터를 보내고 싶다면, [JSON Compatible Encoder](encoder.md){.internal-link target=_blank}에 설명되어 있는 `jsonable_encoder`를 사용할 수 있습니다.
///
-## 실행하기
+## 실행하기 { #run-it }
-í\85\8cì\8a¤í\8a¸ ì½\94ë\93\9c를 ì\9e\91ì\84±í\95\98ê³ , `pytest` 를 ì\84¤ì¹\98í\95´ì\95¼í\95©ë\8b\88ë\8b¤.
+ê·¸ í\9b\84ì\97\90ë\8a\94 `pytest`를 ì\84¤ì¹\98í\95\98기ë§\8c í\95\98ë©´ ë\90©ë\8b\88ë\8b¤.
-[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
+[virtual environment](../virtual-environments.md){.internal-link target=_blank}를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
<div class="termy">
</div>
-`pytest` 파일과 테스트를 자동으로 감지하고 실행한 다음, 결과를 보고할 것입니다.
+`pytest`는 파일과 테스트를 자동으로 감지하고 실행한 다음, 결과를 보고할 것입니다.
테스트를 다음 명령어로 실행하세요.
-# 가상 환경
+# 가상 환경 { #virtual-environments }
-Python 프로젝트를 작업할 때는 **가상 환경** (또는 이와 유사한 도구)을 사용하는 것이 좋습니다. 각 프로젝트 마다 설치하는 패키지를 분리하여 관리할 수 있습니다.
+Python 프로젝트를 작업할 때는 **가상 환경**(또는 이와 유사한 메커니즘)을 사용해 각 프로젝트마다 설치하는 패키지를 분리하는 것이 좋습니다.
-/// info | 정보
+/// info
-ì\9d´ë¯¸ ê°\80ì\83\81 í\99\98ê²½ì\97\90 ë\8c\80í\95´ ì\9e\98 ì\95\8cê³ ì\9e\88ë\8b¤ë©´, ì\9d´ ì\84¹ì\85\98ì\9d\80 ê±´ë\84\88 뛰어도 괜찮습니다. 🤓
+ì\9d´ë¯¸ ê°\80ì\83\81 í\99\98ê²½ì\97\90 ë\8c\80í\95´ ì\95\8cê³ ì\9e\88ê³ , ì\96´ë\96»ê²\8c ì\83\9dì\84±í\95\98ê³ ì\82¬ì\9a©í\95\98ë\8a\94ì§\80ë\8f\84 ì\95\8cê³ ì\9e\88ë\8b¤ë©´, ì\9d´ ì\84¹ì\85\98ì\9d\80 ê±´ë\84\88뛰어도 괜찮습니다. 🤓
///
-/// tip | 팁
+/// tip
-**가상 환경(Virtual Environment)** 은 **환경 변수(Environment Variable)** 와 다릅니다.
+**가상 환경**은 **환경 변수**와 다릅니다.
**환경 변수**는 시스템에 존재하며, 프로그램이 사용할 수 있는 변수입니다.
///
-/// info | 정보
+/// info
-ì\9d´ í\8e\98ì\9d´ì§\80ì\97\90ì\84\9cë\8a\94 **ê°\80ì\83\81 í\99\98ê²½**ì\9d\98 ì\82¬ì\9a© ë°©ë²\95ê³¼ ì\9e\91ë\8f\99 ë°©ì\8b\9dì\9d\84 ì\84¤ëª\85í\95©니다.
+ì\9d´ í\8e\98ì\9d´ì§\80ì\97\90ì\84\9cë\8a\94 **ê°\80ì\83\81 í\99\98ê²½**ì\9d\84 ì\82¬ì\9a©í\95\98ë\8a\94 ë°©ë²\95ê³¼ ì\9e\91ë\8f\99 ë°©ì\8b\9dì\9d\84 ì\95\8cë ¤ë\93\9c립니다.
-만약 **모든 것을 관리해주는 도구** (Python 설치까지 포함)를 사용하고 싶다면 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>를 사용해보세요.
+Python 설치까지 포함해 **모든 것을 관리해주는 도구**를 도입할 준비가 되었다면 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>를 사용해 보세요.
///
-## 프로젝트 생성
+## 프로젝트 생성 { #create-a-project }
먼저, 프로젝트를 위한 디렉터리를 하나 생성합니다.
-보통 사용자 홈 디렉터리 안에 `code`라는 디렉터리를 만들고, 그 안에 프로젝트마다 하나씩 디렉터리를 만들어 관리합니다.
+제가 보통 하는 방법은 사용자 홈/유저 디렉터리 안에 `code`라는 디렉터리를 만드는 것입니다.
+
+그리고 그 안에 프로젝트마다 디렉터리를 하나씩 만듭니다.
<div class="termy">
```console
-// 홈 디렉터리로 이동
+// Go to the home directory
$ cd
-// 모든 코드 프로젝트를 위한 디렉터리 생성
+// Create a directory for all your code projects
$ mkdir code
-// code 디렉터리로 이동
+// Enter into that code directory
$ cd code
-// 이번 프로젝트를 위한 디렉터리 생성
+// Create a directory for this project
$ mkdir awesome-project
-// 해당 프로젝트 디렉터리로 이동
+// Enter into that project directory
$ cd awesome-project
```
</div>
-## 가상 환경 생성
+## 가상 환경 생성 { #create-a-virtual-environment }
-Python 프로젝트를 **처음 시작할 때**, 가상 환경을 **<abbr title="다른 방법들도 있지만, 이건 간단한 가이드라인입니다">프로젝트 내부</abbr>**에 생성합니다.
+Python 프로젝트를 **처음 시작할 때**, **<abbr title="다른 옵션도 있지만, 이것은 간단한 가이드라인입니다">프로젝트 내부</abbr>**에 가상 환경을 생성하세요.
-/// tip | 팁
+/// tip
-ì\9d´ ì\9e\91ì\97\85ì\9d\80 **í\94\84ë¡\9cì \9dí\8a¸ë¥¼ ì²\98ì\9d\8c ì\84¤ì \95í\95 ë\95\8c í\95\9cë²\88ë§\8c** í\95´ì£¼ë©´ ë\90©ë\8b\88ë\8b¤. ì\9d´í\9b\84 ì\9e\91ì\97\85í\95 ë\95\8c ë°\98ë³µ할 필요는 없습니다.
+ì\9d´ ì\9e\91ì\97\85ì\9d\80 **í\94\84ë¡\9cì \9dí\8a¸ë\8b¹ í\95\9c ë²\88ë§\8c** í\95\98ë©´ ë\90\98ë©°, ì\9e\91ì\97\85í\95 ë\95\8cë§\88ë\8b¤ 할 필요는 없습니다.
///
//// tab | `venv`
-Python 표준 라이브러리에 포함된 venv 모듈을 사용해 가상 환경을 생성할 수 있습니다.
+가상 환경을 만들려면 Python에 포함된 `venv` 모듈을 사용할 수 있습니다.
<div class="termy">
</div>
-/// details | ëª\85ë ¹ì\96´ ì\83\81ì\84¸ ì\84¤ëª\85
+/// details | ëª\85ë ¹ì\96´ ì\9d\98미
-* `python`: `python` 프로그램을 실행합니다.
-* `-m`: 특정 모듈을 스크립트처럼 실행합니다. 대상 모듈을 바로 뒤에 지정합니다.
-* `venv`: Python 표준 라이브러리에 포함된 `venv` 모듈을 실행합니다.
-* `.venv`: 가상 환경을 `.venv` 디렉터리에 생성합니다.
+* `python`: `python`이라는 프로그램을 사용합니다
+* `-m`: 모듈을 스크립트로 호출합니다. 다음에 어떤 모듈인지 지정합니다
+* `venv`: 보통 Python에 기본으로 설치되어 있는 `venv` 모듈을 사용합니다
+* `.venv`: 새 디렉터리인 `.venv`에 가상 환경을 생성합니다
///
//// tab | `uv`
-<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>가 설치되어 있다면, uv를 통해 가상 환경을 생성할 수 있습니다.
+<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>가 설치되어 있다면, 이를 사용해 가상 환경을 생성할 수 있습니다.
<div class="termy">
</div>
-/// tip | 팁
+/// tip
-`uv`는 기본적으로 `.venv` 디렉터리에 가상 환경을 생성합니다.
+기본적으로 `uv`는 `.venv`라는 디렉터리에 가상 환경을 생성합니다.
-별도로 디렉터리 이름을 추가 인자로 넘겨 주면 경로를 지정 할 수 있습니다.
+하지만 디렉터리 이름을 추가 인자로 전달해 이를 커스터마이즈할 수 있습니다.
///
////
-해당 명령어는 `.venv` 디렉터리에 새로운 가상 환경을 생성합니다.
+해당 명령어는 `.venv`라는 디렉터리에 새로운 가상 환경을 생성합니다.
/// details | `.venv` 또는 다른 이름
-가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv` 디렉터리 이름을 사용합니다.
+가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv`라는 이름을 사용합니다.
///
-## 가상 환경 활성화
+## 가상 환경 활성화 { #activate-the-virtual-environment }
-이후 실행하는 Python 명령어와 패키지 설치가 가상 환경을 따르도록, 가상 환경을 활성화하세요.
+이후 실행하는 Python 명령어와 설치하는 패키지가 새 가상 환경을 사용하도록, 새 가상 환경을 활성화하세요.
-/// tip | 팁
+/// tip
-**터미널을 새로 열고** 프로젝트 작업을 시작할 때는, **항상 이 작업을** 해주세요.
+프로젝트 작업을 위해 **새 터미널 세션**을 시작할 때마다 **매번** 이 작업을 하세요.
///
//// tab | Windows Bash
-Windows에서 Bash(예: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>)를 사용하는 경우:
+또는 Windows에서 Bash(예: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>)를 사용하는 경우:
<div class="termy">
////
-/// tip | 팁
+/// tip
-가상 환경에 새로운 패키지를 설치할 때마다, 해당 환경을 다시 활성화하세요.
+해당 환경에 **새 패키지**를 설치할 때마다, 환경을 다시 **활성화**하세요.
-이렇게 하면 해당 패키지ë¡\9c ì\84¤ì¹\98ë\90\9c **í\84°ë¯¸ë\84\90(<abbr title="command line interface">CLI</abbr>) í\94\84ë¡\9cê·¸ë\9e¨**ì\9d\84 ì\82¬ì\9a©í\95 ë\95\8c, ì \84ì\97ì\97\90 ì\84¤ì¹\98ë\90\9c ë\8b¤ë¥¸ ë²\84ì \84ì\9d´ ì\95\84ë\8b\88ë\9d¼, ê°\80ì\83\81 í\99\98ê²½ ì\95\88ì\97\90 ì\84¤ì¹\98ë\90\9c ì \95í\99\95í\95\9c ë²\84ì \84ì\9d\84 ì\82¬ì\9a©í\95©ë\8b\88ë\8b¤.
+이렇게 하면 해당 패키지ê°\80 ì\84¤ì¹\98í\95\9c **í\84°ë¯¸ë\84\90(<abbr title="command line interface">CLI</abbr>) í\94\84ë¡\9cê·¸ë\9e¨**ì\9d\84 ì\82¬ì\9a©í\95 ë\95\8c, ì \84ì\97ì\9c¼ë¡\9c ì\84¤ì¹\98ë\90\98ì\96´ ì\9e\88ì\9d\84 ì\88\98ë\8f\84 ì\9e\88ë\8a\94(ì\95\84ë§\88 í\95\84ì\9a\94í\95\9c ë²\84ì \84ê³¼ë\8a\94 ë\8b¤ë¥¸ ë²\84ì \84ì\9d¸) ë\8b¤ë¥¸ í\94\84ë¡\9cê·¸ë\9e¨ì\9d´ ì\95\84ë\8b\88ë\9d¼ ê°\80ì\83\81 í\99\98ê²½ì\97\90 ì\9e\88ë\8a\94 ê²\83ì\9d\84 ì\82¬ì\9a©í\95\98ê²\8c ë\90©ë\8b\88ë\8b¤.
///
-## 가상 환경이 활성화 여부 확인
+## 가상 환경 활성화 여부 확인 { #check-the-virtual-environment-is-active }
-ê°\80ì\83\81 í\99\98ê²½ì\9d´ í\99\9cì\84±í\99\94ë\90\98ì\97\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95©ë\8b\88ë\8b¤. (ì\9d´ì \84 ëª\85ë ¹ì\96´ê°\80 ì \9cë\8c\80ë¡\9c ì\9e\91ë\8f\99í\96\88ë\8a\94ì§\80 í\99\95ì\9d¸í\95©ë\8b\88ë\8b¤).
+ê°\80ì\83\81 í\99\98ê²½ì\9d´ í\99\9cì\84±í\99\94ë\90\98ì\96´ ì\9e\88ë\8a\94ì§\80(ì\9d´ì \84 ëª\85ë ¹ì\96´ê°\80 ì\9e\91ë\8f\99í\96\88ë\8a\94ì§\80) í\99\95ì\9d¸í\95©ë\8b\88ë\8b¤.
-/// tip | 팁
+/// tip
-ì\9d´ ë\8b¨ê³\84ë\8a\94 **ì\84 í\83\9d ì\82¬í\95**ì\9d´ì§\80ë§\8c, 모ë\93 ê²\83ì\9d´ ì\98\88ì\83\81ë\8c\80ë¡\9c ì\9e\91ë\8f\99í\95\98ê³ ì\9e\88ë\8a\94ì§\80, ê·¸ë¦¬ê³ ì\9d\98ë\8f\84í\95\9c ê°\80ì\83\81 í\99\98ê²½ì\9d´ í\99\9cì\84±í\99\94 ë\90\98ì\97\88ë\8a\94 지 **확인**하는 좋은 방법입니다.
+ì\9d´ ë\8b¨ê³\84ë\8a\94 **ì\84 í\83\9d ì\82¬í\95**ì\9d´ì§\80ë§\8c, 모ë\93 ê²\83ì\9d´ ì\98\88ì\83\81ë\8c\80ë¡\9c ì\9e\91ë\8f\99í\95\98ê³ ì\9e\88ë\8a\94ì§\80, ê·¸ë¦¬ê³ ì\9d\98ë\8f\84í\95\9c ê°\80ì\83\81 í\99\98ê²½ì\9d\84 ì\82¬ì\9a©í\95\98ê³ ì\9e\88ë\8a\94지 **확인**하는 좋은 방법입니다.
///
</div>
-`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv/bin/python` 경로로 표시된다면 성공입니다. 🎉
+프로젝트 내부(이 경우 `awesome-project`)의 `.venv/bin/python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉
////
</div>
-`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv\bin\python` 경로로 표시된다면 성공입니다. 🎉
+프로젝트 내부(이 경우 `awesome-project`)의 `.venv\Scripts\python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉
////
-## pip 업그레이드
+## `pip` 업그레이드 { #upgrade-pip }
-/// tip | 팁
+/// tip
-<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>를 사용한다면, `pip` 대신 `uv`로 패키지를 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎
+<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>를 사용한다면, `pip` 대신 `uv`로 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎
///
-`pip`을 사용하여 패키지를 설치하는 경우 (Python 표준 라이브러리에 포함되어 있습니다), **최신 버전으로 업그레이드**하는 것이 좋습니다.
+`pip`로 패키지를 설치한다면(Python에 기본으로 포함되어 있습니다) 최신 버전으로 **업그레이드**하는 것이 좋습니다.
-í\8c¨í\82¤ì§\80 ì\84¤ì¹\98 ì¤\91 ë°\9cì\83\9dí\95\98ë\8a\94 ë\8b¤ì\96\91í\95\98ê³ í\8a¹ì\9d´í\95\9c ì\97\90ë\9f¬ë\93¤ì\9d\80 `pip` ì\97\85ê·¸ë \88ì\9d´ë\93\9cë¡\9c ì\89½ê²\8c 해결되는 경우가 많습니다.
+í\8c¨í\82¤ì§\80 ì\84¤ì¹\98 ì¤\91 ë°\9cì\83\9dí\95\98ë\8a\94 ë\8b¤ì\96\91í\95\9c í\8a¹ì\9d´í\95\9c ì\98¤ë¥\98ë\8a\94 먼ì \80 `pip`를 ì\97\85ê·¸ë \88ì\9d´ë\93\9cí\95\98ë\8a\94 ê²\83ë§\8cì\9c¼ë¡\9c 해결되는 경우가 많습니다.
-/// tip | 팁
+/// tip
-이 작업은 보통 가상 환경을 생성한 **직후 한 번만** 하면 됩니다.
+보통 이 작업은 가상 환경을 만든 직후 **한 번만** 하면 됩니다.
///
-가상 환경이 활성화된 상태인지 확인한 후(앞서 설명한 명령어 사용), 아래 명령어를 실행하세요:
+가상 환경이 활성화된 상태인지 확인한 다음(위의 명령어 사용) 아래를 실행하세요:
<div class="termy">
</div>
-## `.gitignore` 추가하기
+/// tip
+
+때로는 pip를 업그레이드하려고 할 때 **`No module named pip`** 오류가 발생할 수 있습니다.
+
+이 경우 아래 명령어로 pip를 설치하고 업그레이드하세요:
+
+<div class="termy">
+
+```console
+$ python -m ensurepip --upgrade
-**Git**을 사용하고 있다면 (사용하는 것이 좋습니다), `.gitignore` 파일을 추가해서 `.venv` 디렉터리 전체를 Git에서 제외하세요.
+---> 100%
+```
-/// tip | 팁
+</div>
-<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>를 사용해 가상 환경을 생성했다면, 이미 이 작업이 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎
+이 명령어는 pip가 아직 설치되어 있지 않다면 설치하며, 설치된 pip 버전이 `ensurepip`에서 제공 가능한 버전만큼 최신임을 보장합니다.
///
-/// tip | 팁
+## `.gitignore` 추가하기 { #add-gitignore }
-이 작업도 마찬가지로, 가상 환경을 생성한 **직후 한 번만** 하면 됩니다.
+**Git**을 사용하고 있다면(사용하는 것이 좋습니다), `.venv`의 모든 내용을 Git에서 제외하도록 `.gitignore` 파일을 추가하세요.
+
+/// tip
+
+<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>로 가상 환경을 만들었다면, 이미 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎
+
+///
+
+/// tip
+
+가상 환경을 만든 직후 **한 번만** 하면 됩니다.
///
</div>
-/// details | 명령어 상세 설명
-
-* `echo "*"`: 터미널에 `*` 텍스트를 "출력"합니다 (다음 설명에서 조금 바뀝니다)
-* `>`: 왼쪽 명령어의 출력 내용을 터미널에 출력하지 않고, 오른쪽에 지정된 파일로 **기록(write)** 하라는 의미입니다.
-* `.gitignore`: 출력된 텍스트가 기록될 파일 이름입니다.
+/// details | 명령어 의미
-그리고 Git에서 `*`는 "모든 것"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시하게 됩니다.
+* `echo "*"`: 터미널에 `*` 텍스트를 "출력"합니다(다음 부분이 이를 약간 변경합니다)
+* `>`: `>` 왼쪽 명령어가 터미널에 출력한 내용을 터미널에 출력하지 않고, `>` 오른쪽에 있는 파일에 기록하라는 의미입니다
+* `.gitignore`: 텍스트가 기록될 파일 이름입니다
-이 명령어는 다음과 같은 내용을 가진 `.gitignore` 파일을 생성합니다:
+그리고 Git에서 `*`는 "모든 것"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시합니다.
+이 명령어는 다음 내용을 가진 `.gitignore` 파일을 생성합니다:
```gitignore
*
///
-## 패키지 설치
+## 패키지 설치 { #install-packages }
-가상 환경을 활성화한 후, 그 안에 필요한 패키지들을 설치할 수 있습니다.
+환경을 활성화한 뒤, 그 안에 패키지를 설치할 수 있습니다.
-/// tip | 팁
+/// tip
-프로젝트에서 필요한 패키지를 설치하거나 업그레이드할 때는 이 작업을 **한 번만** 하면 됩니다.
+프로젝트에 필요한 패키지를 설치하거나 업그레이드할 때는 **한 번**만 하면 됩니다.
-ë§\8cì\95½ í\8a¹ì \95 í\8c¨í\82¤ì§\80ì\9d\98 ë²\84ì \84ì\9d\84 ì\97\85ê·¸ë \88ì\9d´ë\93\9cí\95\98ê±°ë\82\98, ì\83\88ë¡\9cì\9a´ í\8c¨í\82¤ì§\80를 ì¶\94ê°\80í\95 í\95\84ì\9a\94ê°\80 ì\83\9d기면 **ë\8b¤ì\8b\9c ì\9d´ ì\9e\91ì\97\85ì\9d\84 ë°\98ë³µ**í\95\98ë©´ 됩니다.
+ë²\84ì \84ì\9d\84 ì\97\85ê·¸ë \88ì\9d´ë\93\9cí\95\98ê±°ë\82\98 ì\83\88 í\8c¨í\82¤ì§\80를 ì¶\94ê°\80í\95´ì\95¼ í\95\9cë\8b¤ë©´ **ë\8b¤ì\8b\9c ì\9d´ ì\9e\91ì\97\85ì\9d\84** í\95\98ê²\8c 됩니다.
///
-### 패키지 직접 설치
+### 패키지 직접 설치 { #install-packages-directly }
-급하게 작업하거나, 프로젝트에 필요한 패키지 목록을 따로 파일로 관리하고 싶지 않은 경우, 패키지를 직접 설치할 수도 있습니다.
+급하게 작업 중이고 프로젝트의 패키지 요구사항을 선언하는 파일을 사용하고 싶지 않다면, 패키지를 직접 설치할 수 있습니다.
-/// tip | 팁
+/// tip
-í\8c¨í\82¤ì§\80 ì\9d´ë¦\84ê³¼ ë²\84ì \84 ì \95보를 í\8c\8cì\9d¼ì\97\90 ì \95리í\95´ë\91\90ë\8a\94 ê²\83(ì\98\88: `requirements.txt` ë\98\90ë\8a\94 `pyproject.toml`)은 (매우) 좋은 생각입니다.
+í\94\84ë¡\9cê·¸ë\9e¨ì\97\90 í\95\84ì\9a\94í\95\9c í\8c¨í\82¤ì§\80ì\99\80 ë²\84ì \84ì\9d\84 í\8c\8cì\9d¼(ì\98\88: `requirements.txt` ë\98\90ë\8a\94 `pyproject.toml`)ì\97\90 ì \81ì\96´ë\91\90ë\8a\94 ê²\83은 (매우) 좋은 생각입니다.
///
//// tab | `uv`
-<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>를 사용하는 경우:
+<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>가 있다면:
<div class="termy">
////
-### `requirements.txt`에서 설치
+### `requirements.txt`에서 설치 { #install-from-requirements-txt }
-`requirements.txt` 파일이 있다면, 그 안에 명시된 패키지들을 한 번에 설치할 수 있습니다.
+`requirements.txt`가 있다면, 이제 이를 사용해 그 안의 패키지를 설치할 수 있습니다.
//// tab | `pip`
//// tab | `uv`
-<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>를 사용하는 경우:
+<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>가 있다면:
<div class="termy">
/// details | `requirements.txt`
-다음은 몇 가지 패키지를 포함한 `requirements.txt`의 예시입니다:
+일부 패키지가 있는 `requirements.txt`는 다음과 같이 생겼을 수 있습니다:
```requirements.txt
fastapi[standard]==0.113.0
///
-## 프로그램 실행
+## 프로그램 실행 { #run-your-program }
-가상 환경을 활성화한 후에는 프로그램을 실행할 수 있습니다. 이때 해당 가상 환경에 설치된 Python과 패키지들이 사용됩니다.
+가상 환경을 활성화한 뒤에는 프로그램을 실행할 수 있으며, 설치한 패키지가 들어있는 가상 환경 내부의 Python을 사용하게 됩니다.
<div class="termy">
</div>
-## 에디터 설정
+## 에디터 설정 { #configure-your-editor }
-에디터를 사용할 경우, 앞서 만든 가상 환경을 사용하도록 설정하는 것이 좋습니다. (대부분의 에디터는 자동으로 감지하기도 합니다.)
-이렇게 하면 자동 완성 기능이나 코드 내 오류 표시 기능을 제대로 사용할 수 있습니다.
+아마 에디터를 사용할 텐데, 자동 완성과 인라인 오류 표시를 받을 수 있도록 생성한 가상 환경을 사용하도록 설정하세요(대부분 자동 감지합니다).
-예시:
+예를 들면:
* <a href="https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment" class="external-link" target="_blank">VS Code</a>
* <a href="https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html" class="external-link" target="_blank">PyCharm</a>
-/// tip | 팁
+/// tip
-이 설정은 보통 가상 환경을 **처음 만들었을 때 한 번만** 해주면 됩니다.
+보통 이 설정은 가상 환경을 만들 때 **한 번만** 하면 됩니다.
///
-## 가상 환경 비활성화
+## 가상 환경 비활성화 { #deactivate-the-virtual-environment }
-í\94\84ë¡\9cì \9dí\8a¸ ì\9e\91ì\97\85ì\9d´ ë\81\9dë\82¬ë\8b¤ë©´, 가상 환경을 **비활성화**할 수 있습니다.
+í\94\84ë¡\9cì \9dí\8a¸ ì\9e\91ì\97\85ì\9d\84 ë§\88쳤ë\8b¤ë©´ 가상 환경을 **비활성화**할 수 있습니다.
<div class="termy">
</div>
-이렇게 하면 이후에 `python` 명령어를 실행했을 때, 가상 환경의 Python이나 그 안에 설치된 패키지들을 사용하지 않게 됩니다.
+이렇게 하면 `python`을 실행할 때, 해당 가상 환경과 그 안에 설치된 패키지에서 실행하려고 하지 않습니다.
-## ì\9d´ì \9c ì\9e\91ì\97\85í\95 ì¤\80ë¹\84ê°\80 ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤
+## ì\9e\91ì\97\85í\95 ì¤\80ë¹\84 ì\99\84ë£\8c { #ready-to-work }
-이제 프로젝트 작업을 시작할 준비가 완료되었습니다.
+이제 프로젝트 작업을 시작할 준비가 되었습니다.
-/// tip | 팁
-위 내용을 더 깊이 이해하고 싶으신가요?
+/// tip
-그렇다면 계속 읽어 주세요. 👇🤓
+위의 내용이 무엇인지 더 이해하고 싶으신가요?
+
+계속 읽어보세요. 👇🤓
///
-## ê°\80ì\83\81 í\99\98ê²½ì\9d\84 ì\99\9c ì\82¬ì\9a©í\95\98ë\8a\94ê°\80
+## ê°\80ì\83\81 í\99\98ê²½ì\9d\84 ì\99\9c ì\82¬ì\9a©í\95\98ë\82\98ì\9a\94 { #why-virtual-environments }
-FastAPI를 ì\82¬ì\9a©í\95\98ë ¤ë©´ 먼ì \80 <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>을 설치해야 합니다.
+FastAPIë¡\9c ì\9e\91ì\97\85í\95\98ë ¤ë©´ <a href="https://www.python.org/" class="external-link" target="_blank">Python</a>을 설치해야 합니다.
-그 후에는 FastAPI와 함께 사용할 **기타 패키지들**을 **설치**해야 합니다.
+그 다음 FastAPI와 사용하려는 다른 **패키지**를 **설치**해야 합니다.
-패키지를 설치할 때 보통 Python에 기본 포함된 `pip` 명령어(또는 유사한 도구)를 사용합니다.
+패키지를 설치할 때는 보통 Python에 포함된 `pip` 명령어(또는 유사한 대안)를 사용합니다.
-하지만 `pip`을 그냥 직접 사용하면, 해당 패키지들은 **전역 Python 환경**(시스템 전체에 설치된 Python)에 설치됩니다.
+하지만 `pip`를 그대로 직접 사용하면, 패키지는 **전역 Python 환경**(전역 Python 설치)에 설치됩니다.
-### 문제점
+### 문제점 { #the-problem }
-그렇다면, 전역 Python 환경에 패키지를 설치하면 어떤 문제가 발생할까요?
+그렇다면, 전역 Python 환경에 패키지를 설치하면 어떤 문제가 있을까요?
-어느 시점이 되면, **서로 다른 패키지들**에 의존하는 여러 개의 프로그램을 작성하게 될 것입니다. 그리고 이들 중 일부는 **같은 패키지의 서로 다른 버전**을 필요로 할 수 있습니다. 😱
+어느 시점이 되면 **서로 다른 패키지**에 의존하는 다양한 프로그램을 작성하게 될 것입니다. 그리고 작업하는 프로젝트 중 일부는 같은 패키지의 **서로 다른 버전**에 의존할 수도 있습니다. 😱
-예를 들어, `마법사의 돌(philosophers-stone)` 프로젝트를 만들었다고 가정해봅시다. 이 프로그램은 `해리 포터(harry)`라는 패키지의 `v1` 버전을 **의존**합니다. 따라서 `harry`를 설치해야 합니다.
+예를 들어 `philosophers-stone`이라는 프로젝트를 만들 수 있습니다. 이 프로그램은 **`harry`라는 다른 패키지의 버전 `1`**에 의존합니다. 그래서 `harry`를 설치해야 합니다.
```mermaid
flowchart LR
stone(philosophers-stone) -->|requires| harry-1[harry v1]
```
-ê·¸ë\9f°ë\8d° ë\82\98ì¤\91ì\97\90 `ì\95\84ì¦\88ì¹´ë°\98ì\9d\98 ì£\84ì\88\98(prisoner-of-azkaban)`ì\9d´ë\9d¼ë\8a\94 ë\98\90 ë\8b¤ë¥¸ í\94\84ë¡\9cì \9dí\8a¸ë¥¼ ë§\8cë\93¤ê²\8c ë\90\98ì\97\88ê³ , ì\9d´ í\94\84ë¡\9cì \9dí\8a¸ë\8f\84 ì\97ì\8b\9c `harry` í\8c¨í\82¤ì§\80를 ì\82¬ì\9a©í\95©ë\8b\88ë\8b¤. ê·¸ë\9f°ë\8d° ì\9d´ í\94\84ë¡\9cì \9dí\8a¸ë\8a\94 `harry`ì\9d\98 `v3` ë²\84ì \84이 필요합니다.
+ê·¸ë\8b¤ì\9d\8c, ë\82\98ì¤\91ì\97\90 `prisoner-of-azkaban`ì\9d´ë\9d¼ë\8a\94 ë\98\90 ë\8b¤ë¥¸ í\94\84ë¡\9cì \9dí\8a¸ë¥¼ ë§\8cë\93¤ê³ , ì\9d´ í\94\84ë¡\9cì \9dí\8a¸ë\8f\84 `harry`ì\97\90 ì\9d\98ì¡´í\95\98ì§\80ë§\8c, ì\9d´ í\94\84ë¡\9cì \9dí\8a¸ë\8a\94 **`harry` ë²\84ì \84 `3`**이 필요합니다.
```mermaid
flowchart LR
azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
```
-하지만 이제 문제가 생깁니다. 로컬 가상 환경 대신에 전역 환경에 패키지를 설치하게 되면, 어떤 버전의 `harry`를 설치할지를 선택해야 하기 때문입니다.
+하지만 이제 문제가 생깁니다. 로컬 **가상 환경**이 아니라 전역(전역 환경)에 패키지를 설치한다면, 어떤 버전의 `harry`를 설치할지 선택해야 합니다.
-예를 들어, `마법사의 돌(philosophers-stone)`을 실행하고 싶다면 먼저 `harry` `v1` 버전을 다음과 같이 설치 해야 합니다:
+`philosophers-stone`을 실행하고 싶다면, 먼저 `harry` 버전 `1`을 다음과 같이 설치해야 합니다:
<div class="termy">
</div>
-ê·¸ë\9f¬ë©´ ê²°êµ ì \84ì\97 Python í\99\98ê²½ì\97\90ë\8a\94 `harry` `v1`ë²\84ì \84이 설치된 상태가 됩니다.
+ê·¸ë¦¬ê³ ì \84ì\97 Python í\99\98ê²½ì\97\90 `harry` ë²\84ì \84 `1`이 설치된 상태가 됩니다.
```mermaid
flowchart LR
end
```
-하지만 이제 `아즈카반의 죄수(prisoner-of-azkaban)`을 실행하고 싶다면, `harry` `v1`버전을 제거하고 `harry` `v3`버전을 설치해야 합니다. (또는 단순히 `v3`버전을 설치하는 것만으로도 기존의 `v1`버전이 자동으로 제거됩니다.)
+하지만 `prisoner-of-azkaban`을 실행하려면 `harry` 버전 `1`을 제거하고 `harry` 버전 `3`을 설치해야 합니다(또는 버전 `3`을 설치하기만 해도 버전 `1`이 자동으로 제거됩니다).
<div class="termy">
</div>
-ê·¸ë \87ê²\8c í\95\98ë©´ ì\9d´ì \9c ì \84ì\97 Python í\99\98ê²½ì\97\90ë\8a\94 `harry` `v3`ë²\84ì \84이 설치된 상태가 됩니다.
+ê·¸ë\9f¬ë©´ ì \84ì\97 Python í\99\98ê²½ì\97\90 `harry` ë²\84ì \84 `3`이 설치된 상태가 됩니다.
-그리고 다시 `마법사의 돌(philosophers-stone)`을 실행하려고 하면, **작동하지** 않을 수 있습니다. 왜냐하면 이 프로그램은 `harry` `v1`버전을 필요로 하기 때문입니다.
+그리고 `philosophers-stone`을 다시 실행하려고 하면, `harry` 버전 `1`이 필요하기 때문에 **작동하지 않을** 가능성이 있습니다.
```mermaid
flowchart LR
end
```
-/// tip | 팁
+/// tip
-Python 패키지들은 **새 버전**에서 **호환성 문제(breaking changes)**가 발생하지 않도록 최대한 노력하는 것이 일반적입니다. 하지만 그래도 안전하게 작업하려면, 테스트를 실행해보면서 새 버전을 의도적으로 설치하는 것이 좋습니다.
+Python 패키지에서는 **새 버전**에서 **호환성을 깨뜨리는 변경(breaking changes)**을 **피하려고** 최선을 다하는 것이 매우 일반적이지만, 안전을 위해 더 최신 버전은 의도적으로 설치하고, 테스트를 실행해 모든 것이 올바르게 작동하는지 확인할 수 있을 때 설치하는 것이 좋습니다.
///
-이제, 이런 일이 여러분의 **모든 프로젝트**가 사용하는 **수많은 패키지들**에서 동시에 발생한다고 상상해보세요. 이는 매우 관리하기 어려우며, 결국 **서로 호환되지 않는 버전**의 패키지로 프로젝트를 실행하게 될 가능성이 높고, 그로 인해 어떤 문제가 왜 발생하는지 알 수 없게 될 수 있습니다.
+이제 이런 일이 여러분의 **모든 프로젝트가 의존하는** **많은** 다른 **패키지**에서도 일어난다고 상상해 보세요. 이는 관리하기가 매우 어렵습니다. 그리고 결국 일부 프로젝트는 패키지의 **호환되지 않는 버전**으로 실행하게 될 가능성이 높으며, 왜 무언가가 작동하지 않는지 알지 못하게 될 수 있습니다.
-ë\98\90í\95\9c ì\82¬ì\9a©í\95\98ë\8a\94 ì\9a´ì\98\81ì²´ì \9c(Linux, Windows, macOS ë\93±)ì\97\90 ë\94°ë\9d¼ Pythonì\9d´ **미리 ì\84¤ì¹\98ë\90\98ì\96´ ì\9e\88ì\9d\84 ì\88\98ë\8f\84** ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ë\9f° ê²½ì\9a°ì\97\90ë\8a\94 ì\9a´ì\98\81ì²´ì \9cì\9d\98 ë\8f\99ì\9e\91ì\97\90 í\95\84ì\9a\94í\95\9c í\8a¹ì \95 ë²\84ì \84ì\9d\98 í\8c¨í\82¤ì§\80ë\93¤ì\9d´ í\95¨ê»\98 ì\84¤ì¹\98ë\90\98ì\96´ ì\9e\88ì\9d\84 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\9d´ ì\83\81í\83\9cì\97\90ì\84\9c ì \84ì\97 Python í\99\98ê²½ì\97\90 ì\9e\84ì\9d\98ì\9d\98 í\8c¨í\82¤ì§\80를 ì\84¤ì¹\98í\95\98ë©´, ì\9a´ì\98\81ì²´ì \9cì\97\90 í\8f¬í\95¨ë\90\9c í\94\84ë¡\9cê·¸ë\9e¨ ì\9d¼ë¶\80ê°\80 **깨ì§\88 ì\9c\84í\97\98**ë\8f\84 있습니다.
+ë\98\90í\95\9c ì\9a´ì\98\81ì²´ì \9c(Linux, Windows, macOS ë\93±)ì\97\90 ë\94°ë\9d¼ Pythonì\9d´ ì\9d´ë¯¸ ì\84¤ì¹\98ë\90\98ì\96´ ì\9e\88ì\9d\84 ì\88\98ë\8f\84 ì\9e\88ì\8aµë\8b\88ë\8b¤. ê·¸ë\9f° ê²½ì\9a°ì\97\90ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\97\90 **í\95\84ì\9a\94í\95\9c í\8a¹ì \95 ë²\84ì \84**ì\9d\98 í\8c¨í\82¤ì§\80ê°\80 ì\9d¼ë¶\80 미리 ì\84¤ì¹\98ë\90\98ì\96´ ì\9e\88ì\9d\84 ê°\80ë\8a¥ì\84±ì\9d´ í\81½ë\8b\88ë\8b¤. ì \84ì\97 Python í\99\98ê²½ì\97\90 í\8c¨í\82¤ì§\80를 ì\84¤ì¹\98í\95\98ë©´, ì\9a´ì\98\81ì²´ì \9cì\97\90 í\8f¬í\95¨ë\90\9c í\94\84ë¡\9cê·¸ë\9e¨ ì\9d¼ë¶\80ê°\80 **깨ì§\88** ì\88\98 있습니다.
-## í\8c¨í\82¤ì§\80ë\93¤ì\9d\80 ì\96´ë\94\94ì\97\90 ì\84¤ì¹\98ë\90\98ë\8a\94ê°\80
+## í\8c¨í\82¤ì§\80ë\8a\94 ì\96´ë\94\94ì\97\90 ì\84¤ì¹\98ë\90\98ë\82\98ì\9a\94 { #where-are-packages-installed }
-Python을 설치하면, 컴퓨터에 여러 디렉터리와 파일들이 생성됩니다.
+Python을 설치하면 컴퓨터에 몇몇 파일이 들어 있는 디렉터리가 생성됩니다.
-이 중 일부 디렉터리는 사용자가 설치한 패키지들을 보관하는 역할을 합니다.
+이 디렉터리 중 일부는 설치한 모든 패키지를 담는 역할을 합니다.
-예를 들어, 아래 명령어를 실행하면:
+다음을 실행하면:
<div class="termy">
```console
-// 지금 실행하지 않아도 됩니다, 그냥 예제일 뿐이에요 🤓
+// Don't run this now, it's just an example 🤓
$ pip install "fastapi[standard]"
---> 100%
```
</div>
-해당 명령어는 FastAPI 코드를 포함한 압축 파일을 다운로드합니다. 이 파일은 보통 <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>에서 받아옵니다.
-
-또한 FastAPI가 의존하는 다른 패키지들도 함께 **다운로드**됩니다.
+FastAPI 코드를 담은 압축 파일을 다운로드합니다. 보통 <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a>에서 받습니다.
-그리고 그 모든 파일들을 **압축 해제**한 뒤, 컴퓨터의 특정 디렉터리에 저장합니다.
+또한 FastAPI가 의존하는 다른 패키지들의 파일도 **다운로드**합니다.
-기본ì \81ì\9c¼ë¡\9c ì\9d´ í\8c\8cì\9d¼ë\93¤ì\9d\80 Pythonì\9d´ ì\84¤ì¹\98ë\90\9c ë\94\94ë \89í\84°ë¦¬ ì\95\88, ì¦\89 **ì \84ì\97 í\99\98ê²½**ì\97\90 ë\82´ì\9d\98 ë\94\94ë \89í\84°ë¦¬ì\97\90 ì \80ì\9e¥ë\90©니다.
+ê·¸ ë\8b¤ì\9d\8c 모ë\93 í\8c\8cì\9d¼ì\9d\84 **ì\95\95ì¶\95 í\95´ì \9c**í\95\98ê³ ì»´í\93¨í\84°ì\9d\98 í\95\9c ë\94\94ë \89í\84°ë¦¬ì\97\90 ë\84£ì\8aµ니다.
-## 가상 환경이란
+기본적으로, 다운로드하고 압축 해제한 파일들은 Python 설치와 함께 제공되는 디렉터리, 즉 **전역 환경**에 저장됩니다.
-전역 환경에 모든 패키지를 설치하면서 발생하는 문제에 대한 해결책은, 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다.
+## 가상 환경이란 무엇인가요 { #what-are-virtual-environments }
-가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 그 안에 해당 프로젝트를 위한 패키지들을 설치할 수 있습니다.
+전역 환경에 모든 패키지를 두는 문제에 대한 해결책은 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다.
-이렇게 하면 각 프로젝트는 자체적인 가상 환경(`.venv` 디렉터리)을 가지게 되며, 그 안에 해당 프로젝트 전용 패키지들을 보유하게 됩니다.
+가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 프로젝트의 패키지를 설치할 수 있습니다.
+이렇게 하면 각 프로젝트는 자체 가상 환경(`.venv` 디렉터리)과 자체 패키지를 갖게 됩니다.
```mermaid
flowchart TB
stone-project ~~~ azkaban-project
```
-## 가상 환경 활성화 의미
+## 가상 환경을 활성화한다는 것은 무엇을 의미하나요 { #what-does-activating-a-virtual-environment-mean }
-ê°\80ì\83\81 í\99\98ê²½ì\9d\84 í\99\9cì\84±í\99\94í\95\9cë\8b¤ë\8a\94 ê²\83ì\9d\80, ì\98\88를 ë\93¤ì\96´ ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\80 ëª\85ë ¹ì\96´ë¥¼ ì\8b¤í\96\89í\95\98ë\8a\94 ê²\83ì\9d\84 ì\9d\98미í\95©ë\8b\88ë\8b¤:
+ê°\80ì\83\81 í\99\98ê²½ì\9d\84 í\99\9cì\84±í\99\94í\95\9cë\8b¤ë\8a\94 ê²\83ì\9d\80, ì\98\88를 ë\93¤ì\96´ ë\8b¤ì\9d\8cê³¼ ê°\99ì\9d\80 ëª\85ë ¹ì\96´ë¡\9c:
//// tab | Linux, macOS
//// tab | Windows Bash
-Windows에서 Bash(예: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>)를 사용하는 경우:
+또는 Windows에서 Bash(예: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>)를 사용하는 경우:
<div class="termy">
////
-이 명령어는 이후에 실행될 명령어에서 사용될 [환경 변수](environment-variables.md){.internal-link target=_blank} 몇 개를 생성하거나 수정합니다.
+다음 명령어들에서 사용할 수 있는 몇몇 [환경 변수](environment-variables.md){.internal-link target=_blank}를 생성하거나 수정하는 것을 의미합니다.
-이 변수들 중 하나가 바로 `PATH` 변수입니다.
+그 변수 중 하나가 `PATH` 변수입니다.
-/// tip | 팁
+/// tip
-`PATH` 환경 변수에 대해 더 알고 싶다면 [환경 변수 문서의 PATH 환경 변수 섹션](environment-variables.md#path-environment-variable){.internal-link target=_blank}을 참고하세요.
+`PATH` 환경 변수에 대해 더 알아보려면 [환경 변수](environment-variables.md#path-environment-variable){.internal-link target=_blank} 섹션을 참고하세요.
///
-가상 환경을 활성화하면, ê°\80ì\83\81 í\99\98ê²½ì\9d\98 ê²½ë¡\9cì\9d¸ `.venv/bin` (Linuxì\99\80 macOS) ë\98\90ë\8a\94 `.venv\Scripts`(Windows)를 `PATH` í\99\98ê²½ ë³\80ì\88\98ì\97\90 ì¶\94ê°\80ë\90©ë\8b\88ë\8b¤.
+가상 환경을 활성화하면 ê°\80ì\83\81 í\99\98ê²½ì\9d\98 ê²½ë¡\9cì\9d¸ `.venv/bin`(Linuxì\99\80 macOS) ë\98\90ë\8a\94 `.venv\Scripts`(Windows)를 `PATH` í\99\98ê²½ ë³\80ì\88\98ì\97\90 ì¶\94ê°\80í\95©ë\8b\88ë\8b¤.
-예를 들어, 가상 환경을 활성화하기 전의 `PATH` 변수는 다음과 같았다고 가정해봅시다:
+가령 환경을 활성화하기 전에는 `PATH` 변수가 다음과 같았다고 해보겠습니다:
//// tab | Linux, macOS
/usr/bin:/bin:/usr/sbin:/sbin
```
-ì\8b\9cì\8a¤í\85\9cì\9d\80 ë\8b¤ì\9d\8c ê²½ë¡\9cë\93¤ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ì°¾ê²\8c ë\90©니다:
+ì\9d´ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\9d´ ë\8b¤ì\9d\8c ì\9c\84ì¹\98ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ì°¾ë\8a\94ë\8b¤ë\8a\94 ë\9c»ì\9e\85니다:
* `/usr/bin`
* `/bin`
C:\Windows\System32
```
-ì\8b\9cì\8a¤í\85\9cì\9d\80 ë\8b¤ì\9d\8c ê²½ë¡\9cë\93¤ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ì°¾ê²\8c ë\90©니다:
+ì\9d´ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\9d´ ë\8b¤ì\9d\8c ì\9c\84ì¹\98ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ì°¾ë\8a\94ë\8b¤ë\8a\94 ë\9c»ì\9e\85니다:
* `C:\Windows\System32`
////
-가상 환경을 활성화한 후에는, `PATH` 변수는 다음과 같은 형태가 됩니다:
+가상 환경을 활성화한 뒤에는 `PATH` 변수가 다음과 같이 보일 수 있습니다:
//// tab | Linux, macOS
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
-ì\8b\9cì\8a¤í\85\9cì\9d\80 ê°\80ì\9e¥ 먼ì \80 ë\8b¤ì\9d\8c ê²½ë¡\9cì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 찾기 ì\8b\9cì\9e\91í\95©니다:
+ì\9d´ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\9d´ ì\9d´ì \9c ë\8b¤ì\9d\8c ì\9c\84ì¹\98ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ê°\80ì\9e¥ 먼ì \80 찾기 ì\8b\9cì\9e\91í\95\9cë\8b¤ë\8a\94 ë\9c»ì\9e\85니다:
```plaintext
/home/user/code/awesome-project/.venv/bin
```
-그 후에 다른 디렉터리들을 탐색합니다.
+그리고 나서 다른 디렉터리들을 탐색합니다.
-따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에 있는 Python 프로그램을 찾게 됩니다:
+따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에서 Python 프로그램을 찾고:
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
-그리고 해당 Python을 사용하게 됩니다.
+그것을 사용하게 됩니다.
////
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
-ì\8b\9cì\8a¤í\85\9cì\9d\80 ê°\80ì\9e¥ 먼ì \80 ë\8b¤ì\9d\8c ê²½ë¡\9cì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 찾기 ì\8b\9cì\9e\91í\95©니다:
+ì\9d´ë\8a\94 ì\8b\9cì\8a¤í\85\9cì\9d´ ì\9d´ì \9c ë\8b¤ì\9d\8c ì\9c\84ì¹\98ì\97\90ì\84\9c í\94\84ë¡\9cê·¸ë\9e¨ì\9d\84 ê°\80ì\9e¥ 먼ì \80 찾기 ì\8b\9cì\9e\91í\95\9cë\8b¤ë\8a\94 ë\9c»ì\9e\85니다:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
```
-그 후에 다른 디렉터리들을 탐색합니다.
+그리고 나서 다른 디렉터리들을 탐색합니다.
-따라서 터미널에 `python`을 입력하면, 시스템은 다음 경로에 있는 Python 프로그램을 찾게 됩니다:
+따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에서 Python 프로그램을 찾고:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
-그리고 해당 Python을 사용하게 됩니다.
+그것을 사용하게 됩니다.
////
-중요한 세부 사항 중 하나는, 가상 환경의 경로가 `PATH` 변수의 가장 **앞**에 추가된다는 점입니다. 시스템은 사용 가능한 다른 Python들보다 **먼저** 이 경로를 찾습니다. 그래서 터미널에서 `python`을 실행하면, 전역 환경의 Python이 아닌 **가상 환경에 있는** Python이 사용됩니다. (예: 전역 환경에 설치된 `python`이 있더라도 그보다 우선합니다.)
+중요한 세부 사항은 가상 환경 경로가 `PATH` 변수의 **맨 앞**에 들어간다는 점입니다. 시스템은 다른 어떤 Python보다도 **먼저** 이를 찾게 됩니다. 이렇게 하면 `python`을 실행할 때, 다른 어떤 `python`(예: 전역 환경의 `python`)이 아니라 **가상 환경의 Python**을 사용하게 됩니다.
-가상 환경을 활성화하면 이 외에도 몇 가지 다른 것들이 변경되지만, 이는 그중에서도 가장 중요한 변화 중 하나입니다.
+가상 환경을 활성화하면 다른 몇 가지도 변경되지만, 이것이 그중 가장 중요한 것 중 하나입니다.
-## 가상 환경 확인하기
+## 가상 환경 확인하기 { #checking-a-virtual-environment }
-가상 환경이 활성화 되었는지 확인하려면, 아래 명령어를 사용할 수 있습니다:
+가상 환경이 활성화되어 있는지 확인할 때는, 예를 들어 다음을 사용합니다:
//// tab | Linux, macOS, Windows Bash
////
-ì¦\89, í\98\84ì\9e¬ ì\82¬ì\9a©ë\90\98ë\8a\94 `python` í\94\84ë¡\9cê·¸ë\9e¨ì\9d\80 **ê°\80ì\83\81 í\99\98ê²½ ë\82´ë¶\80ì\97\90 ì\9e\88ë\8a\94 ê²\83**입니다.
+ì\9d´ë\8a\94 ì\82¬ì\9a©ë\90 `python` í\94\84ë¡\9cê·¸ë\9e¨ì\9d´ **ê°\80ì\83\81 í\99\98ê²½ ë\82´ë¶\80ì\97\90 ì\9e\88ë\8a\94 ê²\83**ì\9d´ë\9d¼ë\8a\94 ë\9c»입니다.
-Linux와 macOS에서는 `which`, Windows PowerShell에서는 `Get-Command` 명령어를 사용합니다.
+Linux와 macOS에서는 `which`, Windows PowerShell에서는 `Get-Command`를 사용합니다.
-이 명령어는 `PATH` 환경 변수에 지정된 경로들을 **순서대로 탐색**하면서 `python`이라는 이름의 프로그램을 찾습니다.
-찾는 즉시, 해당 프로그램의 **경로를 출력**합니다.
+이 명령어는 `PATH` 환경 변수에 있는 경로를 **순서대로** 확인하면서 `python`이라는 프로그램을 찾습니다. 찾는 즉시, 그 프로그램의 **경로를 보여줍니다**.
-중요한 점은 터미널에서 `python`을 실행했을 때, 실제로 실행되는 "`python`"이 어떤 것인지 정확히 알 수 있다는 것입니다.
+가장 중요한 부분은 `python`을 호출했을 때, 실행될 정확한 "`python`"이 무엇인지 알 수 있다는 점입니다.
-따라서 현재 올바른 가상 환경에 있는지 확인할 수 있습니다.
+따라서 올바른 가상 환경에 있는지 확인할 수 있습니다.
-/// tip | 팁
+/// tip
-하나의 가상 환경을 활성화한 뒤, 해당 Python을 가진 상태에서 **또 다른 프로젝트**로 이동하는 것은 흔히 발생합니다.
+가상 환경을 하나 활성화해서 Python을 사용한 다음, **다른 프로젝트로 이동**하기 쉽습니다.
-하지만 이때 이전 프로젝트의 가상 환경에 있는 **잘못된 Python 실행 파일**을 사용하게 되어 새 프로젝트가 **정상 작동하지 않을 수 있습니다.**
+그리고 두 번째 프로젝트는 다른 프로젝트의 가상 환경에서 온 **잘못된 Python**을 사용하고 있기 때문에 **작동하지 않을** 수 있습니다.
-그래서 현재 어떤 `python`이 사용되고 있는지 확인할 수 있는 능력은 매우 유용합니다. 🤓
+어떤 `python`이 사용되고 있는지 확인할 수 있으면 유용합니다. 🤓
///
-## 가상 환경을 비활성화하는 이유
+## 가상 환경을 왜 비활성화하나요 { #why-deactivate-a-virtual-environment }
-예를 들어 `마법사의 돌(philosophers-stone)`이라는 프로젝트에서 작업 중이라고 해보겠습니다. 이때 해당 **가상 환경을 활성화**하고, 필요한 패키지를 설치하며 작업을 진행합니다.
+예를 들어 `philosophers-stone` 프로젝트에서 작업하면서, **그 가상 환경을 활성화**하고, 패키지를 설치하고, 그 환경으로 작업하고 있다고 해보겠습니다.
-그런데 이제는 **다른 프로젝트**인 `아즈카반의 죄수(prisoner-of-azkaban)`을 작업하고 싶어졌습니다.
+그런데 이제 **다른 프로젝트**인 `prisoner-of-azkaban`에서 작업하고 싶습니다.
-그래서 그 프로젝트 디렉터리로 이동합니다:
+해당 프로젝트로 이동합니다:
<div class="termy">
</div>
-만약 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화하지 않았다면, 터미널에서 `python`을 실행할 때 여전히 `마법사의 돌(philosophers-stone)` 가상 환경의 Python을 사용하게 됩니다.
+`philosophers-stone`의 가상 환경을 비활성화하지 않으면, 터미널에서 `python`을 실행할 때 `philosophers-stone`의 Python을 사용하려고 할 것입니다.
<div class="termy">
$ python main.py
-// sirius를 임포트하는 데 실패했습니다. 설치되어 있지 않아요 😱
+// Error importing sirius, it's not installed 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius
</div>
-하지만 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화한 다음, `아즈카반의 죄수(prisoner-of-azkaban)` 프로젝트의 가상 환경을 활성화하면, 이제 `python` 명령어는 `아즈카반의 죄수(prisoner-of-azkaban)` 가상 환경의 Python을 사용하게 됩니다.
+하지만 가상 환경을 비활성화하고 `prisoner-of-askaban`에 대한 새 가상 환경을 활성화하면, `python`을 실행할 때 `prisoner-of-azkaban`의 가상 환경에 있는 Python을 사용하게 됩니다.
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
-// 이전 디렉터리에 있을 필요 없이, 어디서든 가상 환경을 비활성화할 수 있습니다. 다른 프로젝트 디렉터리로 이동한 후에도 괜찮아요 😎
+// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎
$ deactivate
-// prisoner-of-azkaban/.venv 가상 환경을 활성화합니다 🚀
+// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀
$ source .venv/bin/activate
-// 이제 python을 실행하면, 이 가상 환경에 설치된 sirius 패키지를 찾게 됩니다 ✨
+// Now when you run python, it will find the package sirius installed in this virtual environment ✨
$ python main.py
-못된 짓을 꾸미고 있음을 엄숙히 맹세합니다.🧙
-ImportError는 이제 없습니다. 🐺
+I solemnly swear 🐺
```
</div>
-## 대안들
+## 대안들 { #alternatives }
-ì\9d´ 문ì\84\9cë\8a\94 ì\97¬ë\9f¬ë¶\84ì\9d´ Python í\94\84ë¡\9cì \9dí\8a¸ë¥¼ ì\8b\9cì\9e\91í\95\98ê³ , **ê·¸ ë\82´ë¶\80ì\97\90ì\84\9c** ì\96´ë\96»ê²\8c ë\8f\8cì\95\84ê°\80는지 알려주는 간단한 가이드입니다.
+ì\9d´ 문ì\84\9cë\8a\94 ì\8b\9cì\9e\91ì\9d\84 ë\8f\95ê³ , ë\82´ë¶\80ì\97\90ì\84\9c 모ë\93 ê²\83ì\9d´ ì\96´ë\96»ê²\8c ì\9e\91ë\8f\99í\95\98는지 알려주는 간단한 가이드입니다.
-가상 환경, 패키지 의존성(Requirements), 프로젝트를 관리하는 방법에는 이 외에도 다양한 **대안**들이 존재합니다.
+가상 환경, 패키지 의존성(requirements), 프로젝트를 관리하는 방법에는 많은 **대안**이 있습니다.
-만약 준비가 되었다면, **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 통합적으로 **관리**할 수 있는 도구를 써보는 것도 좋습니다. 그럴 때 추천하는 도구가 바로 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>입니다.
+준비가 되었고 **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 **관리**하는 도구를 사용하고 싶다면 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>를 사용해 보시길 권합니다.
-`uv`ë\8a\94 ë\8b¤ì\96\91í\95\9c 기ë\8a¥ì\9d\84 ì§\80ì\9b\90í\95©ë\8b\88ë\8b¤:
+`uv`ë\8a\94 ë§\8eì\9d\80 ì\9d¼ì\9d\84 í\95 ì\88\98 ì\9e\88ì\8aµë\8b\88ë\8b¤. ì\98\88를 ë\93¤ì\96´:
-* 다양한 버전의 **Python 설치**
-* 각 프로젝트 별 **가상 환경 관리**
-* **패키지 설치**
-* 프로젝트의 **의존성과 버전** 관리
-* ì\84¤ì¹\98ë\90\9c í\8c¨í\82¤ì§\80ë\93¤ê³¼ ê·¸ ë²\84ì \84ì\9d\84 **ì \95í\99\95í\9e\88 ê³ ì \95(lock)**í\95´ì\84\9c,ê°\9cë°\9c í\99\98경과 ì\9a´ì\98\81 í\99\98ê²½ì\9d´ ì\99\84ì \84í\9e\88 ë\8f\99ì\9d¼í\95\98ê²\8c ì\9e\91ë\8f\99í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d ë³´ì\9e¥
-* 이 외에도 다양한 기능을 지원
+* 여러 버전을 포함해 **Python을 설치**
+* 프로젝트의 **가상 환경** 관리
+* **패키지** 설치
+* 프로젝트의 패키지 **의존성과 버전** 관리
+* ì\9d\98ì¡´ì\84±ì\9d\84 í\8f¬í\95¨í\95´ ì\84¤ì¹\98í\95 í\8c¨í\82¤ì§\80ì\99\80 ë²\84ì \84ì\9d\98 **ì \95í\99\95í\95\9c** ì\84¸í\8a¸ë¥¼ ë³´ì\9e¥í\95\98ì\97¬, ê°\9cë°\9c ì¤\91ì\9d¸ ì»´í\93¨í\84°ì\99\80 ë\8f\99ì\9d¼í\95\98ê²\8c í\94\84ë¡\9cë\8d\95ì\85\98ì\97\90ì\84\9c ì\8b¤í\96\89í\95 ì\88\98 ì\9e\88ë\8f\84ë¡\9d í\95©ë\8b\88ë\8b¤. ì\9d´ë¥¼ **locking**ì\9d´ë\9d¼ê³ í\95©ë\8b\88ë\8b¤
+* 그 외에도 많은 기능이 있습니다
-## 결론
+## 결론 { #conclusion }
-ì\97¬ê¸°ê¹\8cì§\80 모ë\91\90 ì\9d½ê³ ì\9d´í\95´í\96\88ë\8b¤ë©´, ì\9d´ì \9c ë§\8eì\9d\80 ê°\9cë°\9cì\9e\90ë\93¤ë³´ë\8b¤ ê°\80ì\83\81 í\99\98ê²½ì\9d\84 **í\9b¨ì\94¬ ë\8d\94 ê¹\8aì\9d´ ì\9e\88ê²\8c ì\9d´í\95´**í\95\98ê²\8c ë\90\98ì\85¨ì\8aµ니다. 🤓
+ì\97¬ê¸°ê¹\8cì§\80 모ë\91\90 ì\9d½ê³ ì\9d´í\95´í\96\88ë\8b¤ë©´, ì\9d´ì \9c ë§\8eì\9d\80 ê°\9cë°\9cì\9e\90ë\93¤ë³´ë\8b¤ ê°\80ì\83\81 í\99\98ê²½ì\97\90 ë\8c\80í\95´ **í\9b¨ì\94¬ ë\8d\94 ë§\8eì\9d´** ì\95\8cê²\8c ë\90\9c ê²\83ì\9e\85니다. 🤓
-이런 세부적인 내용을 알고 있으면, 언젠가 복잡해 보이는 문제를 디버깅할 때 분명히 큰 도움이 될 것입니다. 이제는 **이 모든 것들이 내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎
+이 세부 사항을 알고 있으면, 나중에 복잡해 보이는 무언가를 디버깅할 때 아마도 도움이 될 것입니다. **내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎
"en",
"de",
"es",
+ "ko",
"pt",
"ru",
"uk",