From: Sebastián Ramírez Date: Sun, 11 Jan 2026 00:15:26 +0000 (-0800) Subject: 🌐 Update translations for ko (update-outdated) (#14589) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf8dc98aadc07d28c8f3dc0497324128e782c358;p=thirdparty%2Ffastapi%2Ffastapi.git 🌐 Update translations for ko (update-outdated) (#14589) Co-authored-by: github-actions[bot] Co-authored-by: Yurii Motov --- diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 84255f0f80..1c29546198 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -317,6 +317,8 @@ extra: name: de - Deutsch - link: /es/ name: es - español + - link: /ko/ + name: ko - 한국어 - link: /pt/ name: pt - português - link: /ru/ diff --git a/docs/ko/docs/about/index.md b/docs/ko/docs/about/index.md index ee7804d323..dc2c728740 100644 --- a/docs/ko/docs/about/index.md +++ b/docs/ko/docs/about/index.md @@ -1,3 +1,3 @@ -# 소개 +# 소개 { #about } -FastAPI에 대한 디자인, 영감 등에 대해 🤓 +FastAPI, ê·¸ 디자인, 영감 등에 대해 🤓 diff --git a/docs/ko/docs/advanced/additional-status-codes.md b/docs/ko/docs/advanced/additional-status-codes.md index da06cb778a..64a7eabd5e 100644 --- a/docs/ko/docs/advanced/additional-status-codes.md +++ b/docs/ko/docs/advanced/additional-status-codes.md @@ -1,16 +1,16 @@ -# 추가 상태 코드 +# 추가 상태 코드 { #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`를 설정하여 콘텐츠를 직접 반환합니다: @@ -26,7 +26,7 @@ /// -/// note | 기술적 세부 정보 +/// note | 기술 세부사항 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다. @@ -34,7 +34,7 @@ /// -## OpenAPI 및 API 문서 +## OpenAPI 및 API 문서 { #openapi-and-api-docs } 추가 상태 코드와 응답을 직접 반환하는 경우, FastAPI는 반환할 내용을 미리 알 수 있는 방법이 없기 때문에 OpenAPI 스키마(API 문서)에 포함되지 않습니다. diff --git a/docs/ko/docs/advanced/advanced-dependencies.md b/docs/ko/docs/advanced/advanced-dependencies.md index 7fa043fa3a..04e557d15b 100644 --- a/docs/ko/docs/advanced/advanced-dependencies.md +++ b/docs/ko/docs/advanced/advanced-dependencies.md @@ -1,6 +1,6 @@ -# 고급 의존성 +# 고급 의존성 { #advanced-dependencies } -## 매개변수화된 의존성 +## 매개변수화된 의존성 { #parameterized-dependencies } 지금까지 본 모든 의존성은 고정된 함수 또는 클래스입니다. @@ -10,7 +10,7 @@ 이때 해당 고정된 내용을 매개변수화할 수 있길 바랍니다. -## "호출 가능한" 인스턴스 +## "호출 가능한" 인스턴스 { #a-callable-instance } Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법이 있습니다. @@ -21,9 +21,9 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법 {* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *} 이 경우, **FastAPI**는 추가 매개변수와 하위 의존성을 확인하기 위해 `__call__`을 사용하게 되며, -나중에 *경로 연산 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다. +나중에 *경로 처리 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다. -## 인스턴스 매개변수화하기 +## 인스턴스 매개변수화하기 { #parameterize-the-instance } 이제 `__init__`을 사용하여 의존성을 "매개변수화"할 수 있는 인스턴스의 매개변수를 선언할 수 있습니다: @@ -31,7 +31,7 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법 이 경우, **FastAPI**는 `__init__`에 전혀 관여하지 않으며, 우리는 이 메서드를 코드에서 직접 사용하게 됩니다. -## 인스턴스 생성하기 +## 인스턴스 생성하기 { #create-an-instance } 다음과 같이 이 클래스의 인스턴스를 생성할 수 있습니다: @@ -39,10 +39,9 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법 이렇게 하면 `checker.fixed_content` 속성에 `"bar"`라는 값을 담아 의존성을 "매개변수화"할 수 있습니다. -## 인스턴스를 의존성으로 사용하기 +## 인스턴스를 의존성으로 사용하기 { #use-the-instance-as-a-dependency } -그런 다음, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있으며, -클래스 자체가 아닌 인스턴스 `checker`가 의존성이 됩니다. +그런 다음, 클래스 자체가 아닌 인스턴스 `checker`가 의존성이 되므로, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있습니다. 의존성을 해결할 때 **FastAPI**는 이 `checker`를 다음과 같이 호출합니다: @@ -50,18 +49,116 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법 checker(q="somequery") ``` -...그리고 이때 반환되는 값을 *경로 연산 함수*의 `fixed_content_included` 매개변수로 전달합니다: +...그리고 이때 반환되는 값을 *경로 처리 함수*의 의존성 값으로, `fixed_content_included` 매개변수에 전달합니다: {* ../../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`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 GitHub Discussion Question을 생성해 주세요. + +`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를 전달한 다음 백그라운드 태스크 함수 내부에서 객체를 다시 가져오면 됩니다. diff --git a/docs/ko/docs/advanced/async-tests.md b/docs/ko/docs/advanced/async-tests.md index 37dfe29792..6c85936812 100644 --- a/docs/ko/docs/advanced/async-tests.md +++ b/docs/ko/docs/advanced/async-tests.md @@ -1,31 +1,26 @@ -# 비동기 테스트 코드 작성 +# 비동기 테스트 { #async-tests } -이전 장에서 `TestClient` 를 이용해 **FastAPI** 어플리케이션 테스트를 작성하는 법을 배우셨을텐데요. -지금까지는 `async` 키워드 사용없이 동기 함수의 테스트 코드를 작성하는 법만 익혔습니다. +제공된 `TestClient`를 사용하여 **FastAPI** 애플리케이션을 테스트하는 방법을 이미 살펴보았습니다. 지금까지는 `async` 함수를 사용하지 않고, 동기 테스트를 작성하는 방법만 보았습니다. -하지만 비동기 함수를 사용하여 테스트 코드를 작성하는 것은 매우 유용할 수 있습니다. -예를 들면 데이터베이스에 비동기로 쿼리하는 경우를 생각해봅시다. -FastAPI 애플리케이션에 요청을 보내고, 비동기 데이터베이스 라이브러리를 사용하여 백엔드가 데이터베이스에 올바르게 데이터를 기록했는지 확인하고 싶을 때가 있을 겁니다. +테스트에서 비동기 함수를 사용할 수 있으면 유용할 수 있습니다. 예를 들어 데이터베이스를 비동기로 쿼리하는 경우를 생각해 보세요. FastAPI 애플리케이션에 요청을 보낸 다음, async 데이터베이스 라이브러리를 사용하면서 백엔드가 데이터베이스에 올바른 데이터를 성공적으로 기록했는지 검증하고 싶을 수 있습니다. -이런 경우의 테스트 코드를 어떻게 비동기로 작성하는지 알아봅시다. +어떻게 동작하게 만들 수 있는지 살펴보겠습니다. -## 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`는 HTTPX를 기반으로 하며, 다행히 HTTPX를 직접 사용해 API를 테스트할 수 있습니다. -`TestClient`는 HTTPX를 기반으로 하고 있으며, 다행히 이를 직접 사용하여 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}에서 설명한 것과 비슷한 파일 구조를 살펴보겠습니다: ``` . @@ -35,17 +30,17 @@ AnyIO는 특정 테스트 함수를 비동기 함수로 호출 할 수 있는 │   └── 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` 파일은 `main.py`에 대한 테스트가 있을 텐데, 다음과 같을 수 있습니다: +`test_main.py` 파일에는 `main.py`에 대한 테스트가 있으며, 이제 다음과 같이 보일 수 있습니다: -{* ../../docs_src/async_tests/test_main.py *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py *} -## 실행하기 +## 실행하기 { #run-it } -아래의 명령어로 테스트 코드를 실행합니다: +다음과 같이 평소처럼 테스트를 실행할 수 있습니다:
@@ -57,52 +52,48 @@ $ pytest
-## 자세히 보기 +## 자세히 보기 { #in-detail } -`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 함을 알려줍니다: +`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 한다고 알려줍니다: -{* ../../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] *} -위의 코드는: +이는 다음과 동등합니다: ```Python response = client.get('/') ``` -`TestClient` 에 요청을 보내던 것과 동일합니다. +`TestClient`로 요청을 보내기 위해 사용하던 코드입니다. /// tip | 팁 -새로운 `AsyncClient`를 사용할 때 async/await를 사용하고 있다는 점에 주목하세요. 이 요청은 비동기적으로 처리됩니다. +새 `AsyncClient`와 함께 async/await를 사용하고 있다는 점에 주목하세요. 요청은 비동기입니다. /// /// warning | 경고 -만약의 어플리케이션이 Lifespan 이벤트에 의존성을 갖고 있다면 `AsyncClient` 가 이러한 이벤트를 실행시키지 않습니다. -`AsyncClient` 가 테스트를 실행시켰다는 것을 확인하기 위해 -`LifespanManager` from florimondmanca/asgi-lifespan.확인해주세요. - +애플리케이션이 lifespan 이벤트에 의존한다면, `AsyncClient`는 이러한 이벤트를 트리거하지 않습니다. 이벤트가 트리거되도록 하려면 florimondmanca/asgi-lifespan의 `LifespanManager`를 사용하세요. /// -## 그 외의 비동기 함수 호출 +## 기타 비동기 함수 호출 { #other-asynchronous-function-calls } -테스트 함수가 이제 비동기 함수이므로, FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 호출하고 `await` 키워드를 사용 할 수 있습니다. +테스트 함수가 이제 비동기이므로, 테스트에서 FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 코드의 다른 곳에서 호출하듯이 동일하게 호출하고 (`await`) 사용할 수도 있습니다. /// tip | 팁 -테스트에 비동기 함수 호출을 통합할 때 (예: MongoDB의 MotorClient를 사용할 때) `RuntimeError: Task attached to a different loop` 오류가 발생한다면, 이벤트 루프가 필요한 객체는 반드시 비동기 함수 내에서만 인스턴스화해야 한다는 점을 주의하세요! -예를 들어 `@app.on_event("startup")` 콜백 내에서 인스턴스화하는 것이 좋습니다. +테스트에 비동기 함수 호출을 통합할 때(예: MongoDB의 MotorClient를 사용할 때) `RuntimeError: Task attached to a different loop`를 마주친다면, 이벤트 루프가 필요한 객체는 async 함수 안에서만 인스턴스화해야 한다는 점을 기억하세요. 예를 들어 `@app.on_event("startup")` 콜백에서 인스턴스화할 수 있습니다. /// diff --git a/docs/ko/docs/advanced/custom-response.md b/docs/ko/docs/advanced/custom-response.md index 2001956fa2..55dc2a4be1 100644 --- a/docs/ko/docs/advanced/custom-response.md +++ b/docs/ko/docs/advanced/custom-response.md @@ -1,4 +1,4 @@ -# 사용자 정의 응답 - HTML, Stream, 파일, 기타 +# 사용자 정의 응답 - HTML, Stream, 파일, 기타 { #custom-response-html-stream-file-others } 기본적으로, **FastAPI** 응답을 `JSONResponse`를 사용하여 반환합니다. @@ -6,11 +6,11 @@ 그러나 `Response` (또는 `JSONResponse`와 같은 하위 클래스)를 직접 반환하면, 데이터가 자동으로 변환되지 않으며 (심지어 `response_model`을 선언했더라도), 문서화가 자동으로 생성되지 않습니다(예를 들어, 생성된 OpenAPI의 일부로 HTTP 헤더 `Content-Type`에 특정 "미디어 타입"을 포함하는 경우). -하지만 *경로 작업 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다. +하지만 *경로 처리 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다. -*경로 작업 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다. +*경로 처리 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다. -그리고 만약 그 `Response`가 `JSONResponse`와 `UJSONResponse`의 경우 처럼 JSON 미디어 타입(`application/json`)을 가지고 있다면, *경로 작업 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다. +그리고 만약 그 `Response`가 `JSONResponse`와 `UJSONResponse`의 경우 처럼 JSON 미디어 타입(`application/json`)을 가지고 있다면, *경로 처리 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다. /// note | 참고 @@ -18,11 +18,11 @@ /// -## `ORJSONResponse` 사용하기 +## `ORJSONResponse` 사용하기 { #use-orjsonresponse } -예를 들어, 성능을 극대화하려는 경우, orjson을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다. +예를 들어, 성능을 극대화하려는 경우, `orjson`을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다. -사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, **경로 작업 데코레이터*에서 선언하세요. +사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, *경로 처리 데코레이터*에서 선언하세요. 대규모 응답의 경우, 딕셔너리를 반환하는 것보다 `Response`를 반환하는 것이 훨씬 빠릅니다. @@ -30,7 +30,7 @@ 하지만 반환하는 내용이 **JSON으로 직렬화 가능**하다고 확신하는 경우, 해당 내용을 응답 클래스에 직접 전달할 수 있으며, FastAPI가 반환 내용을 `jsonable_encoder`를 통해 처리한 뒤 응답 클래스에 전달하는 오버헤드를 피할 수 있습니다. -{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} /// info | 정보 @@ -48,14 +48,14 @@ /// -## HTML 응답 +## HTML 응답 { #html-response } **FastAPI**에서 HTML 응답을 직접 반환하려면 `HTMLResponse`를 사용하세요. * `HTMLResponse`를 임포트 합니다. -* *경로 작업 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다. +* *경로 처리 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다. -{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} /// info | 정보 @@ -67,17 +67,17 @@ /// -### `Response` 반환하기 +### `Response` 반환하기 { #return-a-response } -[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것 처럼, *경로 작업*에서 응답을 직접 반환하여 재정의할 수도 있습니다. +[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것 처럼, *경로 처리*에서 응답을 직접 반환하여 재정의할 수도 있습니다. 위의 예제와 동일하게 `HTMLResponse`를 반환하는 코드는 다음과 같을 수 있습니다: -{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} /// warning | 경고 -*경로 작업 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다. +*경로 처리 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다. /// @@ -87,27 +87,27 @@ /// -### OpenAPI에 문서화하고 `Response` 재정의 하기 +### OpenAPI에 문서화하고 `Response` 재정의 하기 { #document-in-openapi-and-override-response } 함수 내부에서 응답을 재정의하면서 동시에 OpenAPI에서 "미디어 타입"을 문서화하고 싶다면, `response_class` 매게변수를 사용하면서 `Response` 객체를 반환할 수 있습니다. -이 경우 `response_class`는 OpenAPI *경로 작업*을 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다. +이 경우 `response_class`는 OpenAPI *경로 처리*를 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `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을 문서화 하는 방법을 알 수 있습니다. -## 사용 가능한 응답들 +## 사용 가능한 응답들 { #available-responses } 다음은 사용할 수 있는 몇가지 응답들 입니다. @@ -121,7 +121,7 @@ /// -### `Response` +### `Response` { #response } 기본 `Response` 클래스는 다른 모든 응답 클래스의 부모 클래스 입니다. @@ -134,27 +134,27 @@ * `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 } `orjson`을 사용하여 빠른 JSON 응답을 제공하는 대안입니다. 위에서 설명한 내용과 같습니다. @@ -164,13 +164,13 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포 /// -### `UJSONResponse` +### `UJSONResponse` { #ujsonresponse } `ujson`을 사용한 또 다른 JSON 응답 형식입니다. /// info | 정보 -이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: 'pip install ujson`. +이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: `pip install ujson`. /// @@ -180,7 +180,7 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포 /// -{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} /// tip | 팁 @@ -188,22 +188,22 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포 /// -### `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] *} -이 경우, *경로 작업* 함수에서 URL을 직접 반환할 수 있습니다. +이 경우, *경로 처리* 함수에서 URL을 직접 반환할 수 있습니다. 이 경우, 사용되는 `status_code`는 `RedirectResponse`의 기본값인 `307` 입니다. @@ -211,23 +211,23 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30 `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)하는 제너레이터 함수를 만들 수 있습니다. +file-like 객체(예: `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` 블록을 사용함으로써, 제너레이터 함수가 완료된 후 파일과 같은 객체가 닫히도록 합니다. 즉, 응답 전송이 끝난 후 닫힙니다. @@ -235,15 +235,15 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30 이렇게 하면 "생성(generating)" 작업을 내부적으로 다른 무언가에 위임하는 제너레이터 함수가 됩니다. - 이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다. + 이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다. /// tip | 팁 -여기서 표준 `open()`을 사용하고 있기 때문에 `async`와 `await`를 지원하지 않습니다. 따라서 경로 작업은 일반 `def`로 선언합니다. +여기서 표준 `open()`을 사용하고 있기 때문에 `async`와 `await`를 지원하지 않습니다. 따라서 경로 처리는 일반 `def`로 선언합니다. /// -### `FileResponse` +### `FileResponse` { #fileresponse } 파일을 비동기로 스트리밍하여 응답합니다. @@ -256,25 +256,25 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30 파일 응답에는 적절한 `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] *} -이 경우, 경로 작업 함수에서 파일 경로를 직접 반환할 수 있습니다. +이 경우, 경로 처리 함수에서 파일 경로를 직접 반환할 수 있습니다. -## 사용자 정의 응답 클래스 +## 사용자 정의 응답 클래스 { #custom-response-class } `Response`를 상속받아 사용자 정의 응답 클래스를 생성하고 사용할 수 있습니다. -예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 orjson을 사용하고 싶다고 가정해봅시다. +예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 `orjson`을 사용하고 싶다고 가정해봅시다. 만약 들여쓰기 및 포맷된 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] *} 이제 다음 대신: @@ -282,7 +282,7 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30 {"message": "Hello World"} ``` -이 응답은 이렇게 반환됩니다: +...이 응답은 이렇게 반환됩니다: ```json { @@ -292,22 +292,22 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30 물론 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 | 팁 -여전히 이전처럼 *경로 작업*에서 `response_class`를 재정의할 수 있습니다. +여전히 이전처럼 *경로 처리*에서 `response_class`를 재정의할 수 있습니다. /// -## 추가 문서화 +## 추가 문서화 { #additional-documentation } OpenAPI에서 `responses`를 사용하여 미디어 타입 및 기타 세부 정보를 선언할 수도 있습니다: [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/ko/docs/advanced/events.md b/docs/ko/docs/advanced/events.md index 4318ada54e..35223eaf39 100644 --- a/docs/ko/docs/advanced/events.md +++ b/docs/ko/docs/advanced/events.md @@ -1,67 +1,66 @@ -# Lifespan 이벤트 +# Lifespan 이벤트 { #lifespan-events } -애플리케이션 **시작 전**에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, **애플리케이션이 요청을 받기 시작하기 전**에 실행된다는 의미입니다. +애플리케이션이 **시작**하기 전에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, 애플리케이션이 **요청을 받기 시작하기 전**에 실행된다는 의미입니다. -마찬가지로, 애플리케이션이 **종료될 때** 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다. +마찬가지로, 애플리케이션이 **종료**될 때 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다. -이 코드가 애플리케이션이 **요청을 받기 시작하기 전에** 실행되고, 요청 처리가 끝난 후 **종료 직전에** 실행되기 때문에 전체 애플리케이션의 **수명(Lifespan)**을 다룹니다. (잠시 후 "수명"이라는 단어가 중요해집니다 😉) +이 코드는 애플리케이션이 요청을 받기 **시작**하기 전에 실행되고, 요청 처리를 **끝낸 직후**에 실행되기 때문에 전체 애플리케이션의 **수명(lifespan)**을 다룹니다(잠시 후 "lifespan"이라는 단어가 중요해집니다 😉). -이 방법은 전체 애플리케이션에서 사용해야 하는 **자원**을 설정하거나 요청 간에 **공유되는** 자원을 설정하고, 또는 그 후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유되는 머신러닝 모델을 로드하는 경우입니다. +이는 전체 앱에서 사용해야 하는 **자원**을 설정하고, 요청 간에 **공유되는** 자원을 설정하고, 그리고/또는 이후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유 머신러닝 모델을 로드하는 경우입니다. +## 사용 사례 { #use-case } -## 사용 사례 +먼저 **사용 사례** 예시로 시작한 다음, 이를 어떻게 해결할지 살펴보겠습니다. -먼저 **사용 사례**를 예로 들어보고, 이를 어떻게 해결할 수 있는지 살펴보겠습니다. +요청을 처리하는 데 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖 -우리가 요청을 처리하기 위해 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖 +동일한 모델이 요청 간에 공유되므로, 요청마다 모델이 하나씩 있거나 사용자마다 하나씩 있는 등의 방식이 아닙니다. -이 모델들은 요청 간에 공유되므로, 요청마다 모델이 하나씩 있는 것이 아니라, 여러 요청에서 동일한 모델을 사용합니다. +모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 그래서 모든 요청마다 이를 수행하고 싶지는 않습니다. -모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 따라서 모든 요청에 대해 모델을 매번 로드하고 싶지 않습니다. +모듈/파일의 최상위에서 로드할 수도 있지만, 그러면 단순한 자동화된 테스트를 실행하는 경우에도 **모델을 로드**하게 되고, 테스트가 코드의 독립적인 부분을 실행하기 전에 모델이 로드될 때까지 기다려야 하므로 **느려집니다**. -모듈/파일의 최상위에서 모델을 로드할 수도 있지만, 그러면 **모델을 로드하는데** 시간이 걸리기 때문에, 단순한 자동화된 테스트를 실행할 때도 모델이 로드될 때까지 기다려야 해서 **테스트 속도가 느려집니다**. +이것이 우리가 해결할 문제입니다. 요청을 처리하기 전에 모델을 로드하되, 코드가 로드되는 동안이 아니라 애플리케이션이 요청을 받기 시작하기 직전에만 로드하겠습니다. -이 문제를 해결하려고 하는 것입니다. 요청을 처리하기 전에 모델을 로드하되, 애플리케이션이 요청을 받기 시작하기 직전에만 로드하고, 코드가 로드되는 동안은 로드하지 않도록 하겠습니다. +## 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`은 애플리케이션을 **종료**할 때 발생합니다. +`shutdown`은 애플리케이션을 **중지**할 때 발생합니다. -새로운 버전을 시작해야 하거나, 그냥 실행을 멈추고 싶을 수도 있습니다. 🤷 +새 버전을 시작해야 할 수도 있고, 그냥 실행하는 게 지겨워졌을 수도 있습니다. 🤷 /// -### 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` 이후의 부분은 애플리케이션이 완료된 후 **나중에** 실행됩니다. +그리고 `yield` 이후의 부분은 애플리케이션이 종료된 **후에** 실행됩니다. -### 비동기 컨텍스트 매니저 +### 비동기 컨텍스트 매니저 { #async-context-manager } -함수를 확인해보면, `@asynccontextmanager`로 장식되어 있습니다. +확인해 보면, 함수는 `@asynccontextmanager`로 데코레이션되어 있습니다. -이것은 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환시킵니다. +이는 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환합니다. -{* ../../docs_src/events/tutorial003.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} 파이썬에서 **컨텍스트 매니저**는 `with` 문에서 사용할 수 있는 것입니다. 예를 들어, `open()`은 컨텍스트 매니저로 사용할 수 있습니다: @@ -69,97 +68,98 @@ with open("file.txt") as file: file.read() ``` -최근 버전의 파이썬에서는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다: + +최근 버전의 파이썬에는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다: ```Python async with lifespan(app): await do_stuff() ``` -컨텍스트 매니저나 위와 같은 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드가 실행되고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드가 실행됩니다. +위와 같은 컨텍스트 매니저 또는 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드를 실행하고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드를 실행합니다. -위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 사용하도록 합니다. +위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 FastAPI가 이를 사용하도록 합니다. -`FastAPI` 애플리케이션의 `lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받기 때문에, 새로운 `lifespan` 비동기 컨텍스트 매니저를 FastAPI에 전달할 수 있습니다. +`FastAPI` 앱의 `lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받으므로, 새 `lifespan` 비동기 컨텍스트 매니저를 전달할 수 있습니다. -{* ../../docs_src/events/tutorial003.py hl[22] *} +{* ../../docs_src/events/tutorial003_py39.py hl[22] *} -## 대체 이벤트 (사용 중단) +## 대체 이벤트(사용 중단) { #alternative-events-deprecated } /// warning | 경고 -*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` 애플리케이션의 `lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup`과 `shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`을 사용할지, 모든 이벤트를 사용할지 선택해야 하며 둘 다 사용할 수는 없습니다. +*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` 앱의 `lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup`과 `shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`만 쓰거나 이벤트만 쓰거나 둘 중 하나이지, 둘 다는 아닙니다. -이 부분은 건너뛰셔도 좋습니다. +이 부분은 아마 건너뛰셔도 됩니다. /// *시작*과 *종료* 동안 실행될 이 로직을 정의하는 대체 방법이 있습니다. -애플리케이션이 시작되기 전에 또는 종료될 때 실행해야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다. +애플리케이션이 시작되기 전에 또는 애플리케이션이 종료될 때 실행되어야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다. 이 함수들은 `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`) 항목을 일부 값으로 초기화합니다. 여러 개의 이벤트 핸들러 함수를 추가할 수 있습니다. -애플리케이션은 모든 `startup` 이벤트 핸들러가 완료될 때까지 요청을 받기 시작하지 않습니다. +그리고 모든 `startup` 이벤트 핸들러가 완료될 때까지 애플리케이션은 요청을 받기 시작하지 않습니다. -### `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`를 사용하지 않습니다. -그래서 우리는 이벤트 핸들러 함수를 `async def` 대신 일반 `def`로 선언합니다. +그래서 이벤트 핸들러 함수는 `async def` 대신 표준 `def`로 선언합니다. /// -### `startup`과 `shutdown`을 함께 사용 +### `startup`과 `shutdown`을 함께 { #startup-and-shutdown-together } -*시작*과 *종료* 로직이 연결될 가능성이 높습니다. 예를 들어, 무언가를 시작한 후 끝내거나, 자원을 획득한 후 해제하는 등의 작업을 할 수 있습니다. +*시작*과 *종료* 로직은 연결되어 있을 가능성이 높습니다. 무언가를 시작했다가 끝내거나, 자원을 획득했다가 해제하는 등의 작업이 필요할 수 있습니다. -이러한 작업을 별도의 함수로 처리하면 서로 로직이나 변수를 공유하지 않기 때문에 더 어려워집니다. 값들을 전역 변수에 저장하거나 비슷한 트릭을 사용해야 할 수 있습니다. +로직이나 변수를 함께 공유하지 않는 분리된 함수에서 이를 처리하면, 전역 변수에 값을 저장하거나 비슷한 트릭이 필요해져 더 어렵습니다. -그렇기 때문에 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다. +그 때문에, 이제는 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다. -## 기술적 세부사항 +## 기술적 세부사항 { #technical-details } 호기심 많은 분들을 위한 기술적인 세부사항입니다. 🤓 -ASGI 기술 사양에 따르면, 이는 Lifespan Protocol의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다. +내부적으로 ASGI 기술 사양에서는 이것이 Lifespan Protocol의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다. /// info | 정보 -Starlette의 `lifespan` 핸들러에 대해 더 읽고 싶다면 Starlette의 Lifespan 문서에서 확인할 수 있습니다. +Starlette `lifespan` 핸들러에 대해서는 Starlette의 Lifespan 문서에서 더 읽어볼 수 있습니다. -이 문서에는 코드의 다른 영역에서 사용할 수 있는 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}에는 실행되지 않음을 유의하세요. diff --git a/docs/ko/docs/advanced/index.md b/docs/ko/docs/advanced/index.md index 31704727ca..78ef5ffece 100644 --- a/docs/ko/docs/advanced/index.md +++ b/docs/ko/docs/advanced/index.md @@ -1,6 +1,6 @@ -# 심화 사용자 안내서 - 도입부 +# 심화 사용자 안내서 - 도입부 { #advanced-user-guide } -## 추가 기능 +## 추가 기능 { #additional-features } 메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}는 여러분이 **FastAPI**의 모든 주요 기능을 둘러보시기에 충분할 것입니다. @@ -14,14 +14,8 @@ /// -## 자습서를 먼저 읽으십시오 +## 자습서를 먼저 읽으십시오 { #read-the-tutorial-first } 여러분은 메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}의 지식으로 **FastAPI**의 대부분의 기능을 사용하실 수 있습니다. 이어지는 장들은 여러분이 메인 자습서 - 사용자 안내서를 이미 읽으셨으며 주요 아이디어를 알고 계신다고 가정합니다. - -## TestDriven.io 강좌 - -여러분이 문서의 이 부분을 보완하시기 위해 심화-기초 강좌 수강을 희망하신다면 다음을 참고 하시기를 바랍니다: **TestDriven.io**의 FastAPI와 Docker를 사용한 테스트 주도 개발. - -그들은 현재 전체 수익의 10퍼센트를 **FastAPI** 개발에 기부하고 있습니다. 🎉 😄 diff --git a/docs/ko/docs/advanced/response-change-status-code.md b/docs/ko/docs/advanced/response-change-status-code.md index 1ba9aa3ccb..4dfadde9df 100644 --- a/docs/ko/docs/advanced/response-change-status-code.md +++ b/docs/ko/docs/advanced/response-change-status-code.md @@ -1,31 +1,31 @@ -# 응답 - 상태 코드 변경 +# 응답 - 상태 코드 변경 { #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 } -*경로 작동 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게) +*경로 처리 함수*에 `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` 파라미터를 선언하고 그 안에서 상태 코드를 설정할 수 있습니다. 단, 마지막으로 설정된 상태 코드가 우선 적용된다는 점을 유의하세요. diff --git a/docs/ko/docs/advanced/response-cookies.md b/docs/ko/docs/advanced/response-cookies.md index 50da713fe6..eef74276fd 100644 --- a/docs/ko/docs/advanced/response-cookies.md +++ b/docs/ko/docs/advanced/response-cookies.md @@ -1,49 +1,51 @@ -# 응답 쿠키 +# 응답 쿠키 { #response-cookies } -## `Response` 매개변수 사용하기 +## `Response` 매개변수 사용하기 { #use-a-response-parameter } -*경로 작동 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다. +*경로 처리 함수*에서 `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`로도 제공합니다. /// -사용 가능한 모든 매개변수와 옵션은 Starlette 문서에서 확인할 수 있습니다. +사용 가능한 모든 매개변수와 옵션은 Starlette의 문서에서 확인할 수 있습니다. diff --git a/docs/ko/docs/advanced/response-directly.md b/docs/ko/docs/advanced/response-directly.md index 08d63c43ce..abf06bb18b 100644 --- a/docs/ko/docs/advanced/response-directly.md +++ b/docs/ko/docs/advanced/response-directly.md @@ -1,20 +1,20 @@ -# 응답을 직접 반환하기 +# 응답을 직접 반환하기 { #return-a-response-directly } -**FastAPI**에서 *경로 작업(path operation)*을 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다. +**FastAPI**에서 *경로 처리(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 호환 데이터(예: `dict`)를 `JSONResponse`에 넣어 사용자의 응답을 전송하는 방식으로 처리됩니다. +그런 다음, 내부적으로는 JSON 호환 데이터(예: `dict`)를 `JSONResponse`에 넣어 클라이언트로 응답을 전송하는 데 사용합니다. -그러나 *경로 작업*에서 `JSONResponse`를 직접 반환할 수도 있습니다. +하지만 *경로 처리*에서 `JSONResponse`를 직접 반환할 수도 있습니다. 예를 들어, 사용자 정의 헤더나 쿠키를 반환해야 하는 경우에 유용할 수 있습니다. -## `Response` 반환하기 +## `Response` 반환하기 { #return-a-response } 사실, `Response` 또는 그 하위 클래스를 반환할 수 있습니다. -/// tip +/// tip | 팁 `JSONResponse` 자체도 `Response`의 하위 클래스입니다. @@ -26,38 +26,40 @@ Pydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른 이로 인해 많은 유연성을 얻을 수 있습니다. 어떤 데이터 유형이든 반환할 수 있고, 데이터 선언이나 유효성 검사를 재정의할 수 있습니다. -## `Response`에서 `jsonable_encoder` 사용하기 +## `Response`에서 `jsonable_encoder` 사용하기 { #using-the-jsonable-encoder-in-a-response } -**FastAPI**는 반환하는 `Response`에 아무런 변환을 하지 않으므로, 그 내용이 준비되어 있어야 합니다. +**FastAPI**는 반환하는 `Response`에 아무런 변경도 하지 않으므로, 그 내용이 준비되어 있는지 확인해야 합니다. -예를 들어, 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 } -이제, 사용자 정의 응답을 반환하는 방법을 알아보겠습니다. +위 예제는 필요한 모든 부분을 보여주지만, 아직은 그다지 유용하지 않습니다. `item`을 그냥 직접 반환했어도 **FastAPI**가 기본으로 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등의 작업을 모두 수행해 주었을 것이기 때문입니다. -예를 들어 XML 응답을 반환하고 싶다고 가정해보겠습니다. +이제, 이를 사용해 사용자 정의 응답을 반환하는 방법을 알아보겠습니다. + +예를 들어 XML 응답을 반환하고 싶다고 가정해 보겠습니다. 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`를 사용하는/선언하는 방법을 확인할 수 있습니다. diff --git a/docs/ko/docs/advanced/response-headers.md b/docs/ko/docs/advanced/response-headers.md index e4e022c9b7..1c36db9b95 100644 --- a/docs/ko/docs/advanced/response-headers.md +++ b/docs/ko/docs/advanced/response-headers.md @@ -1,12 +1,12 @@ -# 응답 헤더 +# 응답 헤더 { #response-headers } -## `Response` 매개변수 사용하기 +## `Response` 매개변수 사용하기 { #use-a-response-parameter } -여러분은 *경로 작동 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다). +여러분은 *경로 처리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다). 그런 다음, 여러분은 해당 *임시* 응답 객체에서 헤더를 설정할 수 있습니다. -{* ../../docs_src/response_headers/tutorial002.py hl[1,7:8] *} +{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *} 그 후, 일반적으로 사용하듯이 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다. @@ -16,26 +16,26 @@ 또한, 종속성에서 `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 } -‘X-’ 접두어를 사용하여 커스텀 사설 헤더를 추가할 수 있습니다. +`X-` 접두어를 사용하여 커스텀 사설 헤더를 추가할 수 있다는 점을 기억하세요. -하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). `expose_headers` 매개변수를 사용하여 Starlette의 CORS 설명서에 문서화된 대로 설정할 수 있습니다. +하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). Starlette의 CORS 문서에 문서화된 `expose_headers` 매개변수를 사용하세요. diff --git a/docs/ko/docs/advanced/sub-applications.md b/docs/ko/docs/advanced/sub-applications.md index c5835de15c..e1554ca5d6 100644 --- a/docs/ko/docs/advanced/sub-applications.md +++ b/docs/ko/docs/advanced/sub-applications.md @@ -1,67 +1,67 @@ -# 하위 응용프로그램 - 마운트 +# 하위 응용프로그램 - 마운트 { #sub-applications-mounts } -만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)을 “마운트"해서 사용할 수 있습니다. +각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 애플리케이션이 필요하다면, 메인 앱을 두고 하나(또는 그 이상)의 하위 응용프로그램을 "마운트"할 수 있습니다. -## **FastAPI** 응용프로그램 마운트 +## **FastAPI** 애플리케이션 마운트 { #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 } -다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다: +그 다음, 하위 응용프로그램과 그 *경로 처리*를 생성합니다. -이 하위 응용프로그램은 또 다른 표준 FastAPI 응용프로그램입니다. 다만 이것은 “마운트”될 것입니다: +이 하위 응용프로그램은 또 다른 표준 FastAPI 애플리케이션이지만, "마운트"될 애플리케이션입니다: -{* ../../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` 명령을 실행하세요:
```console -$ uvicorn main:app --reload +$ fastapi dev main.py INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ```
-그리고 http://127.0.0.1:8000/docs에서 문서를 여십시오. +그리고 http://127.0.0.1:8000/docs에서 문서를 여세요. -메인 응용프로그램의 *경로 동작*만을 포함하는, 메인 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다: +메인 앱의 자동 API 문서를 보게 될 것이며, 메인 앱 자체의 _경로 처리_만 포함됩니다: - + -다음으로, http://127.0.0.1:8000/subapi/docs에서 하위 응용프로그램의 문서를 여십시오. +그 다음, http://127.0.0.1:8000/subapi/docs에서 하위 응용프로그램의 문서를 여세요. -하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다: +하위 응용프로그램의 자동 API 문서를 보게 될 것이며, 하위 경로 접두사 `/subapi` 아래에 올바르게 포함된 하위 응용프로그램 자체의 _경로 처리_만 포함됩니다: - + -두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저는 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다. +두 사용자 인터페이스 중 어느 것과 상호작용을 시도하더라도 올바르게 동작할 것입니다. 브라우저가 각 특정 앱 또는 하위 앱과 통신할 수 있기 때문입니다. -### 기술적 세부사항: `root_path` +### 기술적 세부사항: `root_path` { #technical-details-root-path } -위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다. +위에서 설명한 대로 하위 응용프로그램을 마운트하면, FastAPI는 ASGI 명세의 메커니즘인 `root_path`를 사용해 하위 응용프로그램에 대한 마운트 경로를 전달하는 작업을 처리합니다. -이를 통해, 하위 응용프로그램은 문서 UI를 위해 경로 접두사를 사용해야 한다는 사실을 인지합니다. +이렇게 하면 하위 응용프로그램은 문서 UI를 위해 해당 경로 접두사를 사용해야 한다는 것을 알게 됩니다. -하위 응용프로그램에도 역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 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} 섹션에서 더 알아볼 수 있습니다. diff --git a/docs/ko/docs/advanced/templates.md b/docs/ko/docs/advanced/templates.md index 6126357132..fffffa6a54 100644 --- a/docs/ko/docs/advanced/templates.md +++ b/docs/ko/docs/advanced/templates.md @@ -1,4 +1,4 @@ -# 템플릿 +# 템플릿 { #templates } **FastAPI**와 함께 원하는 어떤 템플릿 엔진도 사용할 수 있습니다. @@ -6,10 +6,9 @@ 설정을 쉽게 할 수 있는 유틸리티가 있으며, 이를 **FastAPI** 애플리케이션에서 직접 사용할 수 있습니다(Starlette 제공). -## 의존성 설치 - -가상 환경을 생성하고(virtual environment{.internal-link target=_blank}), 활성화한 후 jinja2를 설치해야 합니다: +## 의존성 설치 { #install-dependencies } +[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 후 `jinja2`를 설치해야 합니다:
@@ -21,39 +20,38 @@ $ pip install jinja2
-## 사용하기 `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`에 템플릿을 작성할 수 있습니다. 예를 들면: @@ -61,7 +59,7 @@ FastAPI 0.108.0 이전과 Starlette 0.29.0에서는 `name`이 첫 번째 매개 {!../../docs_src/templates/templates/item.html!} ``` -### 템플릿 컨텍스트 값 +### 템플릿 컨텍스트 값 { #template-context-values } 다음과 같은 HTML에서: @@ -85,9 +83,9 @@ Item ID: {{ id }} Item ID: 42 ``` -### 템플릿 `url_for` 인수 +### 템플릿 `url_for` 인수 { #template-url-for-arguments } -템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 작업 함수*에서 사용될 인수와 동일한 인수를 받습니다. +템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 처리 함수*에서 사용될 인수와 동일한 인수를 받습니다. 따라서 다음과 같은 부분에서: @@ -99,14 +97,15 @@ Item ID: 42 {% endraw %} -...이는 *경로 작업 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다. +...이는 *경로 처리 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다. 예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다: + ```html ``` -## 템플릿과 정적 파일 +## 템플릿과 정적 파일 { #templates-and-static-files } 템플릿 내에서 `url_for()`를 사용할 수 있으며, 예를 들어 `name="static"`으로 마운트한 `StaticFiles`와 함께 사용할 수 있습니다. @@ -114,7 +113,7 @@ Item ID: 42 {!../../docs_src/templates/templates/item.html!} ``` -이 예제에서는 `static/styles.css`에 있는 CSS 파일에 연결될 것입니다: +이 예제에서는 다음을 통해 `static/styles.css`에 있는 CSS 파일에 링크합니다: ```CSS hl_lines="4" {!../../docs_src/templates/static/styles.css!} @@ -122,6 +121,6 @@ Item ID: 42 그리고 `StaticFiles`를 사용하고 있으므로, 해당 CSS 파일은 **FastAPI** 애플리케이션에서 `/static/styles.css` URL로 자동 제공됩니다. -## 더 많은 세부 사항 +## 더 많은 세부 사항 { #more-details } 템플릿 테스트를 포함한 더 많은 세부 사항은 Starlette의 템플릿 문서를 확인하세요. diff --git a/docs/ko/docs/advanced/testing-dependencies.md b/docs/ko/docs/advanced/testing-dependencies.md index 780e19431f..ed90fe472d 100644 --- a/docs/ko/docs/advanced/testing-dependencies.md +++ b/docs/ko/docs/advanced/testing-dependencies.md @@ -1,14 +1,14 @@ -# 테스트 의존성 오버라이드 +# 오버라이드로 의존성 테스트하기 { #testing-dependencies-with-overrides } -## 테스트 중 의존성 오버라이드하기 +## 테스트 중 의존성 오버라이드하기 { #overriding-dependencies-during-testing } -테스트를 진행하다 보면 의존성을 오버라이드해야 하는 경우가 있습니다. +테스트를 진행하다 보면 테스트 중에 의존성을 오버라이드해야 하는 경우가 있습니다. 원래 의존성을 실행하고 싶지 않을 수도 있습니다(또는 그 의존성이 가지고 있는 하위 의존성까지도 실행되지 않길 원할 수 있습니다). 대신, 테스트 동안(특정 테스트에서만) 사용될 다른 의존성을 제공하고, 원래 의존성이 사용되던 곳에서 사용할 수 있는 값을 제공하기를 원할 수 있습니다. -### 사용 사례: 외부 서비스 +### 사용 사례: 외부 서비스 { #use-cases-external-service } 예를 들어, 외부 인증 제공자를 호출해야 하는 경우를 생각해봅시다. @@ -18,11 +18,11 @@ 외부 제공자를 한 번만 테스트하고 싶을 수도 있지만 테스트를 실행할 때마다 반드시 호출할 필요는 없습니다. -이 경우 해당 공급자를 호출하는 종속성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 종속성을 사용할 수 있습니다. +이 경우 해당 공급자를 호출하는 의존성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 의존성을 사용할 수 있습니다. -### `app.dependency_overrides` 속성 사용하기 +### `app.dependency_overrides` 속성 사용하기 { #use-the-app-dependency-overrides-attribute } -이런 경우를 위해 **FastAPI** 응용 프로그램에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다. +이런 경우를 위해 **FastAPI** 애플리케이션에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다. 테스트를 위해 의존성을 오버라이드하려면, 원래 의존성(함수)을 키로 설정하고 오버라이드할 의존성(다른 함수)을 값으로 설정합니다. @@ -34,7 +34,7 @@ **FastAPI** 애플리케이션 어디에서든 사용된 의존성에 대해 오버라이드를 설정할 수 있습니다. -원래 의존성은 *경로 동작 함수*, *경로 동작 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다. +원래 의존성은 *경로 처리 함수*, *경로 처리 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다. FastAPI는 여전히 이를 오버라이드할 수 있습니다. @@ -42,7 +42,7 @@ FastAPI는 여전히 이를 오버라이드할 수 있습니다. 그런 다음, `app.dependency_overrides`를 빈 `dict`로 설정하여 오버라이드를 재설정(제거)할 수 있습니다: -```python +```Python app.dependency_overrides = {} ``` diff --git a/docs/ko/docs/advanced/testing-events.md b/docs/ko/docs/advanced/testing-events.md index 502762f23b..8dbd4f6e66 100644 --- a/docs/ko/docs/advanced/testing-events.md +++ b/docs/ko/docs/advanced/testing-events.md @@ -1,5 +1,12 @@ -# 이벤트 테스트: 시작 - 종료 +# 이벤트 테스트: 라이프스팬 및 시작 - 종료 { #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] *} diff --git a/docs/ko/docs/advanced/testing-websockets.md b/docs/ko/docs/advanced/testing-websockets.md index 9b67824295..1cb3cad67e 100644 --- a/docs/ko/docs/advanced/testing-websockets.md +++ b/docs/ko/docs/advanced/testing-websockets.md @@ -1,13 +1,13 @@ -# 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의 WebSocket 테스트에 관한 설명서를 참고하시길 바랍니다. +자세한 내용은 Starlette의 testing WebSockets 문서를 확인하세요. /// diff --git a/docs/ko/docs/advanced/using-request-directly.md b/docs/ko/docs/advanced/using-request-directly.md index b88a83bf42..e0a5e99f88 100644 --- a/docs/ko/docs/advanced/using-request-directly.md +++ b/docs/ko/docs/advanced/using-request-directly.md @@ -1,10 +1,10 @@ -# `Request` 직접 사용하기 +# `Request` 직접 사용하기 { #using-the-request-directly } 지금까지 요청에서 필요한 부분을 각 타입으로 선언하여 사용해 왔습니다. 다음과 같은 곳에서 데이터를 가져왔습니다: -* 경로의 파라미터로부터. +* 경로를 매개변수로. * 헤더. * 쿠키. * 기타 등등. @@ -13,29 +13,29 @@ 하지만 `Request` 객체에 직접 접근해야 하는 상황이 있을 수 있습니다. -## `Request` 객체에 대한 세부 사항 +## `Request` 객체에 대한 세부 사항 { #details-about-the-request-object } **FastAPI**는 실제로 내부에 **Starlette**을 사용하며, 그 위에 여러 도구를 덧붙인 구조입니다. 따라서 여러분이 필요할 때 Starlette의 `Request` 객체를 직접 사용할 수 있습니다. -`Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기)에는 FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 문서 자동화(로 생성된) API 사용자 인터페이스)도 되지 않습니다. +또한 이는 `Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기) FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 자동 API 사용자 인터페이스용)도 되지 않는다는 의미이기도 합니다. 그러나 다른 매개변수(예: Pydantic 모델을 사용한 본문)는 여전히 검증, 변환, 주석 추가 등이 이루어집니다. -하지만 특정한 경우에는 `Request` 객체에 직접 접근하는 것이 유용할 수 있습니다. +하지만 특정한 경우에는 `Request` 객체를 가져오는 것이 유용할 수 있습니다. -## `Request` 객체를 직접 사용하기 +## `Request` 객체를 직접 사용하기 { #use-the-request-object-directly } -여러분이 클라이언트의 IP 주소/호스트 정보를 *경로 작동 함수* 내부에서 가져와야 한다고 가정해 보겠습니다. +여러분이 클라이언트의 IP 주소/호스트 정보를 *경로 처리 함수* 내부에서 가져와야 한다고 가정해 보겠습니다. 이를 위해서는 요청에 직접 접근해야 합니다. -{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *} +{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *} -*경로 작동 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request` 객체를 전달하는 것을 알게 됩니다. +*경로 처리 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request`를 전달하는 것을 알게 됩니다. /// tip | 팁 -이 경우, 요청 매개변수와 함께 경로 매개변수를 선언한 것을 볼 수 있습니다. +이 경우, 요청 매개변수 옆에 경로 매개변수를 선언하고 있다는 점을 참고하세요. 따라서, 경로 매개변수는 추출되고 검증되며 지정된 타입으로 변환되고 OpenAPI로 주석이 추가됩니다. @@ -43,14 +43,14 @@ /// -## `Request` 설명서 +## `Request` 설명서 { #request-documentation } -여러분은 `Request` 객체에 대한 더 자세한 내용을 공식 Starlette 설명서 사이트에서 읽어볼 수 있습니다. +여러분은 공식 Starlette 설명서 사이트의 `Request` 객체에 대한 더 자세한 내용을 읽어볼 수 있습니다. /// note | 기술 세부사항 `from starlette.requests import Request`를 사용할 수도 있습니다. -**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, 실제로는 Starlette에서 가져온 것입니다. +**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, Starlette에서 직접 가져온 것입니다. /// diff --git a/docs/ko/docs/advanced/websockets.md b/docs/ko/docs/advanced/websockets.md index d9d0dd95c4..b6817870b7 100644 --- a/docs/ko/docs/advanced/websockets.md +++ b/docs/ko/docs/advanced/websockets.md @@ -1,10 +1,10 @@ -# WebSockets +# WebSockets { #websockets } 여러분은 **FastAPI**에서 WebSockets를 사용할 수 있습니다. -## `WebSockets` 설치 +## `websockets` 설치 { #install-websockets } -[가상 환경](../virtual-environments.md){.internal-link target=_blank)를 생성하고 활성화한 다음, `websockets`를 설치하세요: +[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `websockets`("WebSocket" 프로토콜을 쉽게 사용할 수 있게 해주는 Python 라이브러리)를 설치하세요:
@@ -16,13 +16,13 @@ $ pip install websockets
-## WebSockets 클라이언트 +## WebSockets 클라이언트 { #websockets-client } -### 프로덕션 환경에서 +### 프로덕션 환경에서 { #in-production } 여러분의 프로덕션 시스템에서는 React, Vue.js 또는 Angular와 같은 최신 프레임워크로 생성된 프런트엔드를 사용하고 있을 가능성이 높습니다. -백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다. +그리고 백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다. 또는 네이티브 코드로 WebSocket 백엔드와 직접 통신하는 네이티브 모바일 응용 프로그램을 가질 수도 있습니다. @@ -30,23 +30,23 @@ $ pip install websockets --- -하지만 이번 예제에서는 일부 자바스크립트를 포함한 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다. +하지만 이번 예제에서는 일부 자바스크립트를 포함한 매우 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다. 물론, 이는 최적의 방법이 아니며 프로덕션 환경에서는 사용하지 않을 것입니다. -프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용하는 것이 좋습니다. +프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용할 것입니다. 그러나 이는 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`을 사용할 수도 있습니다. @@ -54,17 +54,17 @@ $ pip install websockets /// -## 메시지를 대기하고 전송하기 +## 메시지를 대기하고 전송하기 { #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`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
@@ -76,7 +76,7 @@ $ fastapi dev main.py
-브라우저에서 http://127.0.0.1:8000을 열어보세요. +브라우저에서 http://127.0.0.1:8000을 여세요. 간단한 페이지가 나타날 것입니다: @@ -86,7 +86,7 @@ $ fastapi dev main.py -**FastAPI** WebSocket 응용 프로그램이 응답을 돌려줄 것입니다: +그리고 WebSockets가 포함된 **FastAPI** 응용 프로그램이 응답을 돌려줄 것입니다: @@ -94,9 +94,9 @@ $ fastapi dev main.py -모든 메시지는 동일한 WebSocket 연결을 사용합니다. +그리고 모든 메시지는 동일한 WebSocket 연결을 사용합니다. -## `Depends` 및 기타 사용하기 +## `Depends` 및 기타 사용하기 { #using-depends-and-others } WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 수 있습니다: @@ -107,21 +107,21 @@ WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 * `Path` * `Query` -이들은 다른 FastAPI 엔드포인트/*경로 작동*과 동일하게 동작합니다: +이들은 다른 FastAPI 엔드포인트/*경로 처리*와 동일하게 동작합니다: {* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *} /// info | 정보 -WebSocket에서는 `HTTPException`을 발생시키는 것이 적합하지 않습니다. 대신 `WebSocketException`을 발생시킵니다. +WebSocket이기 때문에 `HTTPException`을 발생시키는 것은 적절하지 않습니다. 대신 `WebSocketException`을 발생시킵니다. 명세서에 정의된 유효한 코드를 사용하여 종료 코드를 설정할 수 있습니다. /// -### 종속성을 가진 WebSockets 테스트 +### 종속성을 가진 WebSockets 시도해보기 { #try-the-websockets-with-dependencies } -파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다: +파일 이름이 `main.py`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
@@ -133,9 +133,9 @@ $ fastapi dev main.py
-브라우저에서 http://127.0.0.1:8000을 열어보세요. +브라우저에서 http://127.0.0.1:8000을 여세요. -다음과 같은 값을 설정할 수 있습니다: +여기에서 다음을 설정할 수 있습니다: * 경로에 사용된 "Item ID". * 쿼리 매개변수로 사용된 "Token". @@ -146,13 +146,13 @@ $ fastapi dev main.py /// -이제 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다: +이렇게 하면 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다: -## 연결 해제 및 다중 클라이언트 처리 +## 연결 해제 및 다중 클라이언트 처리 { #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] *} @@ -160,7 +160,7 @@ WebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDis * 여러 브라우저 탭에서 앱을 엽니다. * 각 탭에서 메시지를 작성합니다. -* 한 탭을 닫아보세요. +* 그런 다음 탭 중 하나를 닫아보세요. `WebSocketDisconnect` 예외가 발생하며, 다른 모든 클라이언트가 다음과 같은 메시지를 수신합니다: @@ -170,17 +170,17 @@ Client #1596980209979 left the chat /// tip | 팁 -위 응용 프로그램은 여러 WebSocket 연결에 메시지를 브로드캐스트하는 방법을 보여주는 간단한 예제입니다. +위 앱은 여러 WebSocket 연결에 메시지를 처리하고 브로드캐스트하는 방법을 보여주는 최소한의 간단한 예제입니다. -그러나 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동합니다. +하지만 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동한다는 점을 기억하세요. -FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구를 찾고 있다면, encode/broadcaster를 확인하세요. +FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구가 필요하다면, encode/broadcaster를 확인하세요. /// -## 추가 정보 +## 추가 정보 { #more-info } -다음 옵션에 대한 자세한 내용을 보려면 Starlette의 문서를 확인하세요: +다음 옵션에 대해 더 알아보려면 Starlette의 문서를 확인하세요: * `WebSocket` 클래스. * 클래스 기반 WebSocket 처리. diff --git a/docs/ko/docs/advanced/wsgi.md b/docs/ko/docs/advanced/wsgi.md index 3e9de3e6ca..89cf57cfef 100644 --- a/docs/ko/docs/advanced/wsgi.md +++ b/docs/ko/docs/advanced/wsgi.md @@ -1,10 +1,10 @@ -# WSGI 포함하기 - Flask, Django 그 외 +# WSGI 포함하기 - Flask, Django 그 외 { #including-wsgi-flask-django-others } -[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 다음과 같이 마운트 할 수 있습니다. +[서브 응용 프로그램 - 마운트](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`를 불러와야 합니다. @@ -12,9 +12,9 @@ 그 후, 해당 경로에 마운트합니다. -{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *} +{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *} -## 확인하기 +## 확인하기 { #check-it } 이제 `/v1/` 경로에 있는 모든 요청은 Flask 응용 프로그램에서 처리됩니다. @@ -26,7 +26,7 @@ Hello, World from Flask! ``` -그리고 다음으로 이동하면 http://localhost:8000/v2 Flask의 응답을 볼 수 있습니다: +그리고 다음으로 이동하면 http://localhost:8000/v2 **FastAPI**의 응답을 볼 수 있습니다: ```JSON { diff --git a/docs/ko/docs/benchmarks.md b/docs/ko/docs/benchmarks.md index aff8ae70ef..2d4fdbeddb 100644 --- a/docs/ko/docs/benchmarks.md +++ b/docs/ko/docs/benchmarks.md @@ -1,10 +1,10 @@ -# 벤치마크 +# 벤치마크 { #benchmarks } -독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 가장 빠른 Python 프레임워크 중 하나로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다. +독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 사용 가능한 가장 빠른 Python 프레임워크 중 하나로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다. 그러나 벤치마크와 비교를 확인할 때 다음 사항을 염두에 두어야 합니다. -## 벤치마크와 속도 +## 벤치마크와 속도 { #benchmarks-and-speed } 벤치마크를 확인할 때, 일반적으로 여러 가지 유형의 도구가 동등한 것으로 비교되는 것을 볼 수 있습니다. @@ -16,7 +16,7 @@ * **Uvicorn**: ASGI 서버 * **Starlette**: (Uvicorn 사용) 웹 마이크로 프레임워크 - * **FastAPI**: (Starlette 사용) API 구축을 위한 데이터 검증 등 여러 추가 기능이 포함된 API 마이크로 프레임워크 + * **FastAPI**: (Starlette 사용) 데이터 검증 등 API를 구축하기 위한 여러 추가 기능이 포함된 API 마이크로 프레임워크 * **Uvicorn**: * 서버 자체 외에는 많은 추가 코드가 없기 때문에 최고의 성능을 발휘합니다. @@ -29,6 +29,6 @@ * **FastAPI**: * Starlette가 Uvicorn을 사용하므로 Uvicorn보다 빨라질 수 없는 것과 마찬가지로, **FastAPI**는 Starlette를 사용하므로 더 빠를 수 없습니다. * FastAPI는 Starlette에 추가적으로 더 많은 기능을 제공합니다. API를 구축할 때 거의 항상 필요한 데이터 검증 및 직렬화와 같은 기능들이 포함되어 있습니다. 그리고 이를 사용하면 문서 자동화 기능도 제공됩니다(문서 자동화는 응용 프로그램 실행 시 오버헤드를 추가하지 않고 시작 시 생성됩니다). - * FastAPI를 사용하지 않고 직접 Starlette(또는 Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다. - * 따라서 FastAPI를 사용함으로써 개발 시간, 버그, 코드 라인을 줄일 수 있으며, FastAPI를 사용하지 않았을 때와 동일하거나 더 나은 성능을 얻을 수 있습니다(코드에서 모두 구현해야 하기 때문에). - * FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화가 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 웹 응용 프로그램 프레임워크(또는 도구 집합)와 비교하세요. + * FastAPI를 사용하지 않고 직접 Starlette(또는 다른 도구, 예: Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다. + * 따라서 FastAPI를 사용함으로써 개발 시간, 버그, 코드 라인을 줄일 수 있으며, FastAPI를 사용하지 않았을 때와 동일한 성능(또는 더 나은 성능)을 얻을 수 있을 것입니다(코드에서 모두 구현해야 하기 때문에). + * FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화를 제공하는 웹 애플리케이션 프레임워크(또는 도구 집합)와 비교하세요. 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 프레임워크입니다. diff --git a/docs/ko/docs/deployment/cloud.md b/docs/ko/docs/deployment/cloud.md index dbc814bbdb..0705e120c4 100644 --- a/docs/ko/docs/deployment/cloud.md +++ b/docs/ko/docs/deployment/cloud.md @@ -1,13 +1,24 @@ -# FastAPI를 클라우드 제공업체에서 배포하기 +# 클라우드 제공업체에서 FastAPI 배포하기 { #deploy-fastapi-on-cloud-providers } 사실상 거의 **모든 클라우드 제공업체**를 사용하여 여러분의 FastAPI 애플리케이션을 배포할 수 있습니다. 대부분의 경우, 주요 클라우드 제공업체에서는 FastAPI를 배포할 수 있도록 가이드를 제공합니다. -## 클라우드 제공업체 - 후원자들 +## FastAPI Cloud { #fastapi-cloud } -몇몇 클라우드 제공업체들은 [**FastAPI를 후원하며**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, 이를 통해 FastAPI와 FastAPI **생태계**가 지속적이고 건전한 **발전**을 할 수 있습니다. +**FastAPI Cloud**는 **FastAPI**를 만든 동일한 작성자와 팀이 구축했습니다. -이는 FastAPI와 **커뮤니티** (여러분)에 대한 진정한 헌신을 보여줍니다. 그들은 여러분에게 **좋은 서비스**를 제공할 뿐 만이 아니라 여러분이 **훌륭하고 건강한 프레임워크인** FastAPI 를 사용하길 원하기 때문입니다. 🙇 +최소한의 노력으로 API를 **구축**, **배포**, **접근**하는 과정을 간소화합니다. -아래와 같은 서비스를 사용해보고 각 서비스의 가이드를 따를 수도 있습니다. +FastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데에도 제공합니다. 🎉 + +FastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 후원자이자 자금 제공자입니다. ✨ + +## 클라우드 제공업체 - 후원자들 { #cloud-providers-sponsors } + +다른 몇몇 클라우드 제공업체들도 ✨ [**FastAPI를 후원합니다**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨. 🙇 + +가이드를 따라 하고 서비스를 사용해보기 위해 이들도 고려해볼 수 있습니다: + +* Render +* Railway diff --git a/docs/ko/docs/deployment/docker.md b/docs/ko/docs/deployment/docker.md index e8b2746c5f..be04c923a5 100644 --- a/docs/ko/docs/deployment/docker.md +++ b/docs/ko/docs/deployment/docker.md @@ -1,17 +1,17 @@ -# 컨테이너의 FastAPI - 도커 +# 컨테이너의 FastAPI - 도커 { #fastapi-in-containers-docker } -FastAPI 어플리케이션을 배포할 때 일반적인 접근 방법은 **리눅스 컨테이너 이미지**를 생성하는 것입니다. 이 방법은 주로 **도커**를 사용해 이루어집니다. 그런 다음 해당 컨테이너 이미지를 몇가지 방법으로 배포할 수 있습니다. +FastAPI 애플리케이션을 배포할 때 일반적인 접근 방법은 **리눅스 컨테이너 이미지**를 빌드하는 것입니다. 보통 **Docker**를 사용해 수행합니다. 그런 다음 해당 컨테이너 이미지를 몇 가지 가능한 방법 중 하나로 배포할 수 있습니다. -리눅스 컨테이너를 사용하는 데에는 **보안**, **반복 가능성**, **단순함** 등의 장점이 있습니다. +리눅스 컨테이너를 사용하면 **보안**, **재현 가능성**, **단순함** 등 여러 장점이 있습니다. /// tip | 팁 -시간에 쫓기고 있고 이미 이런것들을 알고 있다면 [`Dockerfile`👇](#build-a-docker-image-for-fastapi)로 점프할 수 있습니다. +시간이 없고 이미 이런 내용들을 알고 계신가요? 아래의 [`Dockerfile` 👇](#build-a-docker-image-for-fastapi)로 이동하세요. ///
-도커파일 미리보기 👀 +Dockerfile Preview 👀 ```Dockerfile FROM python:3.9 @@ -24,128 +24,125 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt COPY ./app /code/app -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +CMD ["fastapi", "run", "app/main.py", "--port", "80"] # 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"] ```
-## 컨테이너란 +## 컨테이너란 { #what-is-a-container } -컨테이너(주로 리눅스 컨테이너)는 어플리케이션의 의존성과 필요한 파일들을 모두 패키징하는 매우 **가벼운** 방법입니다. 컨테이너는 같은 시스템에 있는 다른 컨테이너(다른 어플리케이션이나 요소들)와 독립적으로 유지됩니다. +컨테이너(주로 리눅스 컨테이너)는 모든 의존성과 필요한 파일을 포함해 애플리케이션을 패키징하면서, 같은 시스템의 다른 컨테이너(다른 애플리케이션이나 컴포넌트)와는 분리된 상태로 유지할 수 있는 매우 **가벼운** 방법입니다. -리눅스 컨테이너는 호스트(머신, 가상 머신, 클라우드 서버 등)와 같은 리눅스 커널을 사용해 실행됩니다. 이말은 리눅스 컨테이너가 (전체 운영체제를 모방하는 다른 가상 머신과 비교했을 때) 매우 가볍다는 것을 의미합니다. +리눅스 컨테이너는 호스트(머신, 가상 머신, 클라우드 서버 등)와 같은 리눅스 커널을 사용해 실행됩니다. 즉, 전체 운영체제를 에뮬레이션하는 완전한 가상 머신에 비해 매우 가볍습니다. -이 방법을 통해, 컨테이너는 직접 프로세스를 실행하는 것과 비슷한 정도의 **적은 자원**을 소비합니다 (가상 머신은 훨씬 많은 자원을 소비할 것입니다). +이 방식으로 컨테이너는 프로세스를 직접 실행하는 것과 비슷한 수준의 **적은 자원**을 소비합니다(가상 머신은 훨씬 더 많은 자원을 소비합니다). -컨테이너는 또한 그들만의 **독립된** 실행 프로세스 (일반적으로 하나의 프로세스로 충분합니다), 파일 시스템, 그리고 네트워크를 가지므로 배포, 보안, 개발 및 기타 과정을 단순화 합니다. +또한 컨테이너는 자체적인 **격리된** 실행 프로세스(보통 하나의 프로세스), 파일 시스템, 네트워크를 가지므로 배포, 보안, 개발 등을 단순화합니다. -## 컨테이너 이미지란 +## 컨테이너 이미지란 { #what-is-a-container-image } -**컨테이너**는 **컨테이너 이미지**를 실행한 것 입니다. +**컨테이너**는 **컨테이너 이미지**에서 실행됩니다. -컨테이너 이미지란 컨테이너에 필요한 모든 파일, 환경 변수 그리고 디폴트 명령/프로그램의 **정적** 버전입니다. 여기서 **정적**이란 말은 컨테이너 **이미지**가 작동되거나 실행되지 않으며, 단지 패키지 파일과 메타 데이터라는 것을 의미합니다. +컨테이너 이미지는 컨테이너에 있어야 하는 모든 파일, 환경 변수, 기본 명령/프로그램의 **정적** 버전입니다. 여기서 **정적**이라는 것은 컨테이너 **이미지**가 실행 중이거나 수행되는 것이 아니라, 패키징된 파일과 메타데이터일 뿐이라는 뜻입니다. -저장된 정적 컨텐츠인 **컨테이너 이미지**와 대조되게, **컨테이너**란 보통 실행될 수 있는 작동 인스턴스를 의미합니다. +저장된 정적 콘텐츠인 "**컨테이너 이미지**"와 달리, "**컨테이너**"는 보통 실행 중인 인스턴스, 즉 **실행되는** 대상을 의미합니다. -**컨테이너**가 (**컨테이너 이미지**로 부터) 시작되고 실행되면, 컨테이너는 파일이나 환경 변수를 생성하거나 변경할 수 있습니다. 이러한 변화는 오직 컨테이너에서만 존재하며, 그 기반이 되는 컨테이너 이미지에는 지속되지 않습니다 (즉 디스크에는 저장되지 않습니다). +**컨테이너**가 시작되어 실행 중이면(**컨테이너 이미지**로부터 시작됨) 파일, 환경 변수 등을 생성하거나 변경할 수 있습니다. 이러한 변경은 해당 컨테이너에만 존재하며, 기반이 되는 컨테이너 이미지에는 지속되지 않습니다(디스크에 저장되지 않습니다). -컨테이너 이미지는 **프로그램** 파일과 컨텐츠, 즉 `python`과 어떤 파일 `main.py`에 비교할 수 있습니다. +컨테이너 이미지는 **프로그램** 파일과 그 콘텐츠, 예를 들어 `python`과 어떤 파일 `main.py`에 비유할 수 있습니다. -그리고 (**컨테이너 이미지**와 대비해서) **컨테이너**는 이미지의 실제 실행 인스턴스로 **프로세스**에 비교할 수 있습니다. 사실, 컨테이너는 **프로세스 러닝**이 있을 때만 실행됩니다 (그리고 보통 하나의 프로세스 입니다). 컨테이너는 내부에서 실행되는 프로세스가 없으면 종료됩니다. +그리고 **컨테이너** 자체는(**컨테이너 이미지**와 달리) 이미지의 실제 실행 인스턴스로서 **프로세스**에 비유할 수 있습니다. 실제로 컨테이너는 **실행 중인 프로세스**가 있을 때만 실행됩니다(보통 단일 프로세스입니다). 컨테이너 내부에 실행 중인 프로세스가 없으면 컨테이너는 중지됩니다. -## 컨테이너 이미지 +## 컨테이너 이미지 { #container-images } -도커는 **컨테이너 이미지**와 **컨테이너**를 생성하고 관리하는데 주요 도구 중 하나가 되어왔습니다. +Docker는 **컨테이너 이미지**와 **컨테이너**를 생성하고 관리하는 주요 도구 중 하나입니다. -그리고 도커 허브에 다양한 도구, 환경, 데이터베이스, 그리고 어플리케이션에 대해 미리 만들어진 **공식 컨테이너 이미지**가 공개되어 있습니다. +또한 Docker Hub에는 다양한 도구, 환경, 데이터베이스, 애플리케이션을 위한 미리 만들어진 **공식 컨테이너 이미지**가 공개되어 있습니다. -예를 들어, 공식 파이썬 이미지가 있습니다. +예를 들어, 공식 Python Image가 있습니다. -또한 다른 대상, 예를 들면 데이터베이스를 위한 이미지들도 있습니다: +그리고 데이터베이스 등 다양한 용도의 다른 이미지도 많이 있습니다. 예를 들면: * PostgreSQL * MySQL * MongoDB * Redis 등 -미리 만들어진 컨테이너 이미지를 사용하면 서로 다른 도구들을 **결합**하기 쉽습니다. 대부분의 경우에, **공식 이미지들**을 사용하고 환경 변수를 통해 설정할 수 있습니다. +미리 만들어진 컨테이너 이미지를 사용하면 서로 다른 도구를 **결합**하고 사용하기가 매우 쉽습니다. 예를 들어 새로운 데이터베이스를 시험해 볼 때도 그렇습니다. 대부분의 경우 **공식 이미지**를 사용하고, 환경 변수로 설정만 하면 됩니다. -이런 방법으로 대부분의 경우에 컨테이너와 도커에 대해 배울 수 있으며 다양한 도구와 요소들에 대한 지식을 재사용할 수 있습니다. +이렇게 하면 많은 경우 컨테이너와 Docker를 학습하고, 그 지식을 여러 다른 도구와 컴포넌트에 재사용할 수 있습니다. -따라서, 서로 다른 **다중 컨테이너**를 생성한 다음 이들을 연결할 수 있습니다. 예를 들어 데이터베이스, 파이썬 어플리케이션, 리액트 프론트엔드 어플리케이션을 사용하는 웹 서버에 대한 컨테이너를 만들어 이들의 내부 네트워크로 각 컨테이너를 연결할 수 있습니다. +따라서 데이터베이스, Python 애플리케이션, React 프론트엔드 애플리케이션이 있는 웹 서버 등 서로 다른 것들을 담은 **여러 컨테이너**를 실행하고 내부 네트워크를 통해 연결할 수 있습니다. -모든 컨테이너 관리 시스템(도커나 쿠버네티스)은 이러한 네트워킹 특성을 포함하고 있습니다. +Docker나 Kubernetes 같은 모든 컨테이너 관리 시스템에는 이러한 네트워킹 기능이 통합되어 있습니다. -## 컨테이너와 프로세스 +## 컨테이너와 프로세스 { #containers-and-processes } -**컨테이너 이미지**는 보통 **컨테이너**를 시작하기 위해 필요한 메타데이터와 디폴트 커맨드/프로그램과 그 프로그램에 전달하기 위한 파라미터들을 포함합니다. 이는 커맨드 라인에서 프로그램을 실행할 때 필요한 값들과 유사합니다. +**컨테이너 이미지**는 보통 **컨테이너**가 시작될 때 실행되어야 하는 기본 프로그램/명령과 해당 프로그램에 전달할 매개변수를 메타데이터에 포함합니다. 커맨드 라인에서 실행할 때와 매우 유사합니다. -**컨테이너**가 시작되면, 해당 커맨드/프로그램이 실행됩니다 (그러나 다른 커맨드/프로그램을 실행하도록 오버라이드 할 수 있습니다). +**컨테이너**가 시작되면 해당 명령/프로그램을 실행합니다(다만 오버라이드하여 다른 명령/프로그램을 실행하게 할 수도 있습니다). -컨테이너는 **메인 프로세스**(커맨드 또는 프로그램)이 실행되는 동안 실행됩니다. +컨테이너는 **메인 프로세스**(명령 또는 프로그램)가 실행되는 동안 실행됩니다. -컨테이너는 일반적으로 **단일 프로세스**를 가지고 있지만, 메인 프로세스의 서브 프로세스를 시작하는 것도 가능하며, 이 방법으로 하나의 컨테이너에 **다중 프로세스**를 가질 수 있습니다. +컨테이너는 보통 **단일 프로세스**를 가지지만, 메인 프로세스에서 서브프로세스를 시작할 수도 있으며, 그러면 같은 컨테이너에 **여러 프로세스**가 존재하게 됩니다. -그러나 **최소한 하나의 실행중인 프로세스**를 가지지 않고서는 실행중인 컨테이너를 가질 수 없습니다. 만약 메인 프로세스가 중단되면, 컨테이너도 중단됩니다. +하지만 **최소 하나의 실행 중인 프로세스** 없이 실행 중인 컨테이너를 가질 수는 없습니다. 메인 프로세스가 중지되면 컨테이너도 중지됩니다. -## FastAPI를 위한 도커 이미지 빌드하기 +## FastAPI를 위한 도커 이미지 빌드하기 { #build-a-docker-image-for-fastapi } -이제 무언가를 만들어 봅시다! 🚀 +좋습니다, 이제 무언가를 만들어 봅시다! 🚀 -**공식 파이썬** 이미지에 기반하여, FastAPI를 위한 **도커 이미지**를 **맨 처음부터** 생성하는 방법을 보이겠습니다. +**공식 Python** 이미지에 기반하여 FastAPI용 **Docker 이미지**를 **처음부터** 빌드하는 방법을 보여드리겠습니다. -**대부분의 경우**에 다음과 같은 것들을 하게 됩니다. 예를 들면: +이는 **대부분의 경우**에 하고 싶은 방식입니다. 예를 들면: -* **쿠버네티스** 또는 유사한 도구 사용하기 -* **라즈베리 파이**로 실행하기 -* 컨테이너 이미지를 실행할 클라우드 서비스 사용하기 등 +* **Kubernetes** 또는 유사한 도구를 사용할 때 +* **Raspberry Pi**에서 실행할 때 +* 컨테이너 이미지를 대신 실행해주는 클라우드 서비스를 사용할 때 등 -### 요구 패키지 +### 패키지 요구사항 { #package-requirements } -일반적으로는 어플리케이션의 특정 파일을 위한 **패키지 요구 조건**이 있을 것입니다. +보통 애플리케이션의 **패키지 요구사항**을 어떤 파일에 적어 둡니다. -그 요구 조건을 **설치**하는 방법은 여러분이 사용하는 도구에 따라 다를 것입니다. +이는 주로 그 요구사항을 **설치**하는 데 사용하는 도구에 따라 달라집니다. -가장 일반적인 방법은 패키지 이름과 버전이 줄 별로 기록된 `requirements.txt` 파일을 만드는 것입니다. +가장 일반적인 방법은 패키지 이름과 버전을 한 줄에 하나씩 적어 둔 `requirements.txt` 파일을 사용하는 것입니다. -버전의 범위를 설정하기 위해서는 [FastAPI 버전들에 대하여](versions.md){.internal-link target=_blank}에 쓰여진 것과 같은 아이디어를 사용합니다. +버전 범위를 설정할 때는 [FastAPI 버전들에 대하여](versions.md){.internal-link target=_blank}에서 읽은 것과 같은 아이디어를 사용하면 됩니다. -예를 들어, `requirements.txt` 파일은 다음과 같을 수 있습니다: +예를 들어 `requirements.txt`는 다음과 같을 수 있습니다: ``` -fastapi>=0.68.0,<0.69.0 -pydantic>=1.8.0,<2.0.0 -uvicorn>=0.15.0,<0.16.0 +fastapi[standard]>=0.113.0,<0.114.0 +pydantic>=2.7.0,<3.0.0 ``` -그리고 일반적으로 패키지 종속성은 `pip`로 설치합니다. 예를 들어: +그리고 보통 `pip`로 패키지 의존성을 설치합니다. 예를 들면:
```console $ pip install -r requirements.txt ---> 100% -Successfully installed fastapi pydantic uvicorn +Successfully installed fastapi pydantic ```
/// info | 정보 -패키지 종속성을 정의하고 설치하기 위한 방법과 도구는 다양합니다. - -나중에 아래 세션에서 Poetry를 사용한 예시를 보이겠습니다. 👇 +패키지 의존성을 정의하고 설치하는 다른 형식과 도구도 있습니다. /// -### **FastAPI** 코드 생성하기 +### **FastAPI** 코드 생성하기 { #create-the-fastapi-code } -* `app` 디렉터리를 생성하고 이동합니다. -* 빈 파일 `__init__.py`을 생성합니다. -* 다음과 같은 `main.py`을 생성합니다: +* `app` 디렉터리를 만들고 들어갑니다. +* 빈 파일 `__init__.py`를 만듭니다. +* 다음 내용으로 `main.py` 파일을 만듭니다: ```Python from typing import Union @@ -165,79 +162,109 @@ def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` -### 도커파일 +### Dockerfile { #dockerfile } -이제 같은 프로젝트 디렉터리에 다음과 같은 파일 `Dockerfile`을 생성합니다: +이제 같은 프로젝트 디렉터리에 다음 내용으로 `Dockerfile` 파일을 만듭니다: ```{ .dockerfile .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. 현재 워킹 디렉터리를 `/code`로 설정합니다. +2. 현재 작업 디렉터리를 `/code`로 설정합니다. - 여기에 `requirements.txt` 파일과 `app` 디렉터리를 위치시킬 것입니다. + 여기에 `requirements.txt` 파일과 `app` 디렉터리를 둘 것입니다. -3. 요구 조건과 파일을 `/code` 디렉터리로 복사합니다. +3. 요구사항 파일을 `/code` 디렉터리로 복사합니다. - 처음에는 **오직** 요구 조건이 필요한 파일만 복사하고, 이외의 코드는 그대로 둡니다. + 처음에는 요구사항 파일만 **단독으로** 복사하고, 나머지 코드는 복사하지 않습니다. - 이 파일이 **자주 바뀌지 않기 때문에**, 도커는 파일을 탐지하여 이 단계의 **캐시**를 사용하여 다음 단계에서도 캐시를 사용할 수 있도록 합니다. + 이 파일은 **자주 바뀌지 않기** 때문에 Docker는 이를 감지하여 이 단계에서 **캐시**를 사용하고, 다음 단계에서도 캐시를 사용할 수 있게 해줍니다. -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 지시어 `CMD`는 두 가지 형식으로 작성할 수 있습니다: + +✅ **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을 사용하세요. + +자세한 내용은 shell and exec form에 대한 Docker 문서를 참고하세요. + +이는 `docker compose`를 사용할 때 꽤 눈에 띌 수 있습니다. 좀 더 기술적인 상세 내용은 Docker Compose FAQ 섹션을 참고하세요: Why do my services take 10 seconds to recreate or stop?. + +#### 디렉터리 구조 { #directory-structure } + +이제 다음과 같은 디렉터리 구조가 되어야 합니다: ``` . @@ -248,51 +275,51 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] └── 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와 유사한 도구들은 이미지를 빌드할 때 **내부 캐시**도 사용합니다. 어떤 파일이 마지막으로 컨테이너 이미지를 빌드했을 때부터 바뀌지 않았다면, 파일을 다시 복사하고 새 레이어를 처음부터 만드는 대신, 이전에 만든 **같은 레이어를 재사용**합니다. -단지 파일 복사를 지양하는 것으로 효율이 많이 향상되는 것은 아니지만, 그 단계에서 캐시를 사용했기 때문에, **다음 단계에서도 마찬가지로 캐시를 사용**할 수 있습니다. 예를 들어, 다음과 같은 의존성을 설치하는 지시 사항을 위한 캐시를 사용할 수 있습니다: +파일 복사를 피하는 것만으로 큰 개선이 생기지는 않을 수 있지만, 해당 단계에서 캐시를 사용했기 때문에 **다음 단계에서도 캐시를 사용할 수** 있습니다. 예를 들어 다음과 같이 의존성을 설치하는 지시어에서 캐시를 사용할 수 있습니다: ```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 이미지를 빌드합니다:
@@ -307,13 +334,13 @@ $ docker build -t myimage . /// tip | 팁 -맨 끝에 있는 `.` 에 주목합시다. 이는 `./`와 동등하며, 도커에게 컨테이너 이미지를 빌드하기 위한 디렉터리를 알려줍니다. +끝에 있는 `.`에 주목하세요. 이는 `./`와 동일하며, Docker에게 컨테이너 이미지를 빌드할 때 사용할 디렉터리를 알려줍니다. -이 경우에는 현재 디렉터리(`.`)와 같습니다. +이 경우 현재 디렉터리(`.`)입니다. /// -### 도커 컨테이너 시작하기 +### 도커 컨테이너 시작하기 { #start-the-docker-container } * 여러분의 이미지에 기반하여 컨테이너를 실행합니다: @@ -325,35 +352,35 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-## 체크하기 +## 확인하기 { #check-it } -여러분의 도커 컨테이너 URL에서 실행 사항을 체크할 수 있습니다. 예를 들어: http://192.168.99.100/items/5?q=somequery 또는 http://127.0.0.1/items/5?q=somequery (또는 동일하게, 여러분의 도커 호스트를 이용해서 체크할 수도 있습니다). +Docker 컨테이너의 URL에서 확인할 수 있어야 합니다. 예를 들어: http://192.168.99.100/items/5?q=somequery 또는 http://127.0.0.1/items/5?q=somequery(또는 Docker 호스트를 사용해 동등하게 확인할 수 있습니다). -아래와 비슷한 것을 보게 될 것입니다: +아래와 같은 것을 보게 될 것입니다: ```JSON {"item_id": 5, "q": "somequery"} ``` -## 인터랙티브 API 문서 +## 인터랙티브 API 문서 { #interactive-api-docs } -이제 여러분은 http://192.168.99.100/docs 또는 http://127.0.0.1/docs로 이동할 수 있습니다(또는, 여러분의 도커 호스트를 이용할 수 있습니다). +이제 http://192.168.99.100/docs 또는 http://127.0.0.1/docs(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수 있습니다. -여러분은 자동으로 생성된 인터랙티브 API(Swagger UI에서 제공된)를 볼 수 있습니다: +자동으로 생성된 인터랙티브 API 문서(Swagger UI 제공)를 볼 수 있습니다: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -## 대안 API 문서 +## 대안 API 문서 { #alternative-api-docs } -또한 여러분은 http://192.168.99.100/redoc 또는 http://127.0.0.1/redoc으로 이동할 수 있습니다(또는, 여러분의 도커 호스트를 이용할 수 있습니다). +또한 http://192.168.99.100/redoc 또는 http://127.0.0.1/redoc(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수도 있습니다. -여러분은 자동으로 생성된 대안 문서(ReDoc에서 제공된)를 볼 수 있습니다: +대안 자동 문서(ReDoc 제공)를 볼 수 있습니다: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## 단일 파일 FastAPI로 도커 이미지 생성하기 +## 단일 파일 FastAPI로 도커 이미지 빌드하기 { #build-a-docker-image-with-a-single-file-fastapi } -만약 여러분의 FastAPI가 하나의 파일이라면, 예를 들어 `./app` 디렉터리 없이 `main.py` 파일만으로 이루어져 있다면, 파일 구조는 다음과 유사할 것입니다: +FastAPI가 단일 파일(예: `./app` 디렉터리 없이 `main.py`만 있는 경우)이라면, 파일 구조는 다음과 같을 수 있습니다: ``` . @@ -362,7 +389,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage └── requirements.txt ``` -그러면 여러분들은 `Dockerfile` 내에 있는 파일을 복사하기 위해 그저 상응하는 경로를 바꾸기만 하면 됩니다: +그런 다음 `Dockerfile`에서 해당 파일을 복사하도록 경로만 맞게 변경하면 됩니다: ```{ .dockerfile .annotate hl_lines="10 13" } FROM python:3.9 @@ -373,359 +400,221 @@ COPY ./requirements.txt /code/requirements.txt RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt -# (1) +# (1)! COPY ./main.py /code/ -# (2) -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] +# (2)! +CMD ["fastapi", "run", "main.py", "--port", "80"] ``` -1. `main.py` 파일을 `/code` 디렉터리로 곧바로 복사합니다(`./app` 디렉터리는 고려하지 않습니다). +1. `main.py` 파일을 `/code` 디렉터리로 직접 복사합니다(`./app` 디렉터리 없이). -2. Uvicorn을 실행해 `app` 객체를 (`app.main` 대신) `main`으로 부터 불러오도록 합니다. +2. 단일 파일 `main.py`에 있는 애플리케이션을 제공(serve)하기 위해 `fastapi run`을 사용합니다. -그 다음 Uvicorn 커맨드를 조정해서 FastAPI 객체를 불러오는데 `app.main` 대신에 새로운 모듈 `main`을 사용하도록 합니다. +`fastapi run`에 파일을 전달하면, 이것이 패키지의 일부가 아닌 단일 파일이라는 것을 자동으로 감지하고, 어떻게 임포트해서 FastAPI 앱을 제공할지 알아냅니다. 😎 -## 배포 개념 +## 배포 개념 { #deployment-concepts } -이제 컨테이너의 측면에서 [배포 개념](concepts.md){.internal-link target=_blank}에서 다루었던 것과 같은 배포 개념에 대해 이야기해 보겠습니다. +컨테이너 관점에서 같은 [배포 개념](concepts.md){.internal-link target=_blank}들을 다시 이야기해 봅시다. -컨테이너는 주로 어플리케이션을 빌드하고 배포하기 위한 과정을 단순화하는 도구이지만, **배포 개념**에 대한 특정한 접근법을 강요하지 않기 때문에 가능한 배포 전략에는 여러가지가 있습니다. +컨테이너는 주로 애플리케이션의 **빌드 및 배포** 과정을 단순화하는 도구이지만, 이러한 **배포 개념**을 처리하는 특정 접근 방식을 강제하지는 않으며, 가능한 전략은 여러 가지입니다. -**좋은 소식**은 서로 다른 전략들을 포괄하는 배포 개념이 있다는 점입니다. 🎉 +**좋은 소식**은 각 전략마다 모든 배포 개념을 다룰 수 있는 방법이 있다는 점입니다. 🎉 -컨테이너 측면에서 **배포 개념**을 리뷰해 보겠습니다: +컨테이너 관점에서 이 **배포 개념**들을 살펴봅시다: * HTTPS -* 구동하기 +* 시작 시 자동 실행 * 재시작 -* 복제 (실행 중인 프로세스 개수) +* 복제(실행 중인 프로세스 수) * 메모리 -* 시작하기 전 단계들 +* 시작 전 사전 단계 -## HTTPS +## HTTPS { #https } -만약 우리가 FastAPI 어플리케이션을 위한 **컨테이너 이미지**에만 집중한다면 (그리고 나중에 실행될 **컨테이너**에), HTTPS는 일반적으로 다른 도구에 의해 **외부적으로** 다루어질 것 입니다. +FastAPI 애플리케이션의 **컨테이너 이미지**(그리고 나중에 실행 중인 **컨테이너**)에만 집중한다면, HTTPS는 보통 다른 도구에 의해 **외부적으로** 처리됩니다. -**HTTPS**와 **인증서**의 **자동** 취득을 다루는 것은 다른 컨테이너가 될 수 있는데, 예를 들어 Traefik을 사용하는 것입니다. +예를 들어 Traefik을 사용하는 다른 컨테이너가 **HTTPS**와 **인증서**의 **자동** 획득을 처리할 수 있습니다. /// tip | 팁 -Traefik은 도커, 쿠버네티스, 그리고 다른 도구와 통합되어 있어 여러분의 컨테이너를 포함하는 HTTPS를 셋업하고 설정하는 것이 매우 쉽습니다. +Traefik은 Docker, Kubernetes 등과 통합되어 있어, 이를 사용해 컨테이너에 HTTPS를 설정하고 구성하기가 매우 쉽습니다. /// -대안적으로, HTTPS는 클라우드 제공자에 의해 서비스의 일환으로 다루어질 수도 있습니다 (이때도 어플리케이션은 여전히 컨테이너에서 실행될 것입니다). +또는 HTTPS를 클라우드 제공자가 서비스의 일부로 처리할 수도 있습니다(애플리케이션은 여전히 컨테이너에서 실행됩니다). -## 구동과 재시작 +## 시작 시 자동 실행과 재시작 { #running-on-startup-and-restarts } -여러분의 컨테이너를 **시작하고 실행하는** 데에 일반적으로 사용되는 도구는 따로 있습니다. +보통 컨테이너를 **시작하고 실행**하는 역할을 담당하는 다른 도구가 있습니다. -이는 **도커** 자체일 수도 있고, **도커 컴포즈**, **쿠버네티스**, **클라우드 서비스** 등이 될 수 있습니다. +직접 **Docker**일 수도 있고, **Docker Compose**, **Kubernetes**, **클라우드 서비스** 등일 수도 있습니다. -대부분 (또는 전체) 경우에, 컨테이너를 구동하거나 고장시에 재시작하도록 하는 간단한 옵션이 있습니다. 예를 들어, 도커에서는, 커맨드 라인 옵션 `--restart` 입니다. +대부분(또는 전부)의 경우, 시작 시 컨테이너를 실행하고 실패 시 재시작을 활성화하는 간단한 옵션이 있습니다. 예를 들어 Docker에서는 커맨드 라인 옵션 `--restart`입니다. -컨테이너를 사용하지 않고서는, 어플리케이션을 구동하고 재시작하는 것이 매우 번거롭고 어려울 수 있습니다. 하지만 **컨테이너를 사용한다면** 대부분의 경우에 이런 기능은 기본적으로 포함되어 있습니다. ✨ +컨테이너를 사용하지 않으면 애플리케이션을 시작 시 자동 실행하고 재시작까지 구성하는 것이 번거롭고 어렵습니다. 하지만 **컨테이너로 작업할 때**는 대부분의 경우 그 기능이 기본으로 포함되어 있습니다. ✨ -## 복제 - 프로세스 개수 +## 복제 - 프로세스 개수 { #replication-number-of-processes } -만약 여러분이 **쿠버네티스**와 머신 클러스터, 도커 스왐 모드, 노마드, 또는 다른 여러 머신 위에 분산 컨테이너를 관리하는 복잡한 시스템을 다루고 있다면, 여러분은 각 컨테이너에서 (워커와 함께 사용하는 Gunicorn 같은) **프로세스 매니저** 대신 **클러스터 레벨**에서 **복제를 다루**고 싶을 것입니다. +**Kubernetes**, Docker Swarm Mode, Nomad 등의 복잡한 시스템으로 여러 머신에 분산된 컨테이너를 관리하는 cluster를 사용한다면, 각 컨테이너에서(**워커를 사용하는 Uvicorn** 같은) **프로세스 매니저**를 쓰는 대신, **클러스터 레벨**에서 **복제를 처리**하고 싶을 가능성이 큽니다. -쿠버네티스와 같은 분산 컨테이너 관리 시스템 중 일부는 일반적으로 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서 **컨테이너 복제**를 다루는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서 말이죠. +Kubernetes 같은 분산 컨테이너 관리 시스템은 보통 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서도, **컨테이너 복제**를 처리하는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서요. -이런 경우에, 여러분은 [위에서 묘사된 것](#dockerfile)처럼 **처음부터 도커 이미지를** 빌드해서, 의존성을 설치하고, Uvicorn 워커를 관리하는 Gunicorn 대신 **단일 Uvicorn 프로세스**를 실행하고 싶을 것입니다. +그런 경우에는 [위에서 설명한 대로](#dockerfile) 의존성을 설치하고, 여러 Uvicorn 워커를 사용하는 대신 **단일 Uvicorn 프로세스**를 실행하는 **처음부터 만든 Docker 이미지**를 사용하는 것이 좋을 것입니다. -### 로드 밸런서 +### 로드 밸런서 { #load-balancer } -컨테이너로 작업할 때, 여러분은 일반적으로 **메인 포트의 상황을 감지하는** 요소를 가지고 있을 것입니다. 이는 **HTTPS**를 다루는 **TLS 종료 프록시**와 같은 다른 컨테이너일 수도 있고, 유사한 다른 도구일 수도 있습니다. +컨테이너를 사용할 때는 보통 **메인 포트에서 대기(listening)하는** 컴포넌트가 있습니다. **HTTPS**를 처리하기 위한 **TLS 종료 프록시** 역할을 하는 다른 컨테이너일 수도 있고, 유사한 도구일 수도 있습니다. -이 요소가 요청들의 **로드**를 읽어들이고 각 워커에게 (바라건대) **균형적으로** 분배한다면, 이 요소는 일반적으로 **로드 밸런서**라고 불립니다. +이 컴포넌트가 요청의 **부하(load)**를 받아 워커들에 (가능하면) **균형 있게** 분산한다면, 보통 **로드 밸런서**라고 부릅니다. /// tip | 팁 -HTTPS를 위해 사용된 **TLS 종료 프록시** 요소 또한 **로드 밸런서**가 될 수 있습니다. +HTTPS에 사용되는 동일한 **TLS 종료 프록시** 컴포넌트가 **로드 밸런서**이기도 한 경우가 많습니다. /// -또한 컨테이너로 작업할 때, 컨테이너를 시작하고 관리하기 위해 사용한 것과 동일한 시스템은 이미 해당 **로드 밸런서**로 부터 여러분의 앱에 해당하는 컨테이너로 **네트워크 통신**(예를 들어, HTTP 요청)을 전송하는 내부적인 도구를 가지고 있을 것입니다 (여기서도 로드 밸런서는 **TLS 종료 프록시**일 수 있습니다). +또한 컨테이너로 작업할 때, 이를 시작하고 관리하는 시스템은 이미 해당 **로드 밸런서**(또는 **TLS 종료 프록시**)에서 여러분의 앱이 있는 컨테이너로 **네트워크 통신**(예: HTTP 요청)을 전달하는 내부 도구를 가지고 있습니다. -### 하나의 로드 밸런서 - 다중 워커 컨테이너 +### 하나의 로드 밸런서 - 여러 워커 컨테이너 { #one-load-balancer-multiple-worker-containers } -**쿠버네티스**나 또는 다른 분산 컨테이너 관리 시스템으로 작업할 때, 시스템 내부의 네트워킹 메커니즘을 이용함으로써 메인 **포트**를 감지하고 있는 단일 **로드 밸런서**는 여러분의 앱에서 실행되고 있는 **여러개의 컨테이너**에 통신(요청들)을 전송할 수 있게 됩니다. +**Kubernetes** 같은 분산 컨테이너 관리 시스템에서는 내부 네트워킹 메커니즘을 통해, 메인 **포트**에서 대기하는 단일 **로드 밸런서**가 여러분의 앱을 실행하는 **여러 컨테이너**로 통신(요청)을 전달할 수 있습니다. -여러분의 앱에서 실행되고 있는 각각의 컨테이너는 일반적으로 **하나의 프로세스**만 가질 것입니다 (예를 들어, FastAPI 어플리케이션에서 실행되는 하나의 Uvicorn 프로세스처럼). 이 컨테이너들은 모두 같은 것을 실행하는 점에서 **동일한 컨테이너**이지만, 프로세스, 메모리 등은 공유하지 않습니다. 이 방식으로 여러분은 CPU의 **서로 다른 코어들** 또는 **서로 다른 머신들**을 **병렬화**하는 이점을 얻을 수 있습니다. +앱을 실행하는 각 컨테이너는 보통 **프로세스 하나만** 가집니다(예: FastAPI 애플리케이션을 실행하는 Uvicorn 프로세스). 모두 같은 것을 실행하는 **동일한 컨테이너**이지만, 각자 고유한 프로세스, 메모리 등을 가집니다. 이렇게 하면 CPU의 **서로 다른 코어** 또는 **서로 다른 머신**에서 **병렬화**의 이점을 얻을 수 있습니다. -또한 **로드 밸런서**가 있는 분산 컨테이너 시스템은 여러분의 앱에 있는 컨테이너 각각에 **차례대로 요청을 분산**시킬 것 입니다. 따라서 각 요청은 여러분의 앱에서 실행되는 여러개의 **복제된 컨테이너들** 중 하나에 의해 다루어질 것 입니다. +그리고 **로드 밸런서**가 있는 분산 컨테이너 시스템은 여러분의 앱을 실행하는 각 컨테이너에 **번갈아가며** 요청을 **분산**합니다. 따라서 각 요청은 여러분의 앱을 실행하는 여러 **복제된 컨테이너** 중 하나에서 처리될 수 있습니다. -그리고 일반적으로 **로드 밸런서**는 여러분의 클러스터에 있는 *다른* 앱으로 가는 요청들도 다룰 수 있으며 (예를 들어, 다른 도메인으로 가거나 다른 URL 경로 접두사를 가지는 경우), 이 통신들을 클러스터에 있는 *바로 그 다른* 어플리케이션으로 제대로 전송할 수 있습니다. +또한 보통 이 **로드 밸런서**는 클러스터 내 *다른* 앱으로 가는 요청(예: 다른 도메인, 또는 다른 URL 경로 접두사 아래로 가는 요청)도 처리할 수 있으며, 그 통신을 클러스터에서 실행 중인 *그 다른* 애플리케이션의 올바른 컨테이너로 전달할 수 있습니다. -### 단일 프로세스를 가지는 컨테이너 +### 컨테이너당 하나의 프로세스 { #one-process-per-container } -이 시나리오의 경우, 여러분은 이미 클러스터 레벨에서 복제를 다루고 있을 것이므로 **컨테이너 당 단일 (Uvicorn) 프로세스**를 가지고자 할 것입니다. +이 시나리오에서는 이미 클러스터 레벨에서 복제를 처리하고 있으므로, **컨테이너당 단일 (Uvicorn) 프로세스**를 두는 것이 좋을 가능성이 큽니다. -따라서, 여러분은 Gunicorn 이나 Uvicorn 워커, 또는 Uvicorn 워커를 사용하는 Uvicorn 매니저와 같은 프로세스 매니저를 가지고 싶어하지 **않을** 것입니다. 여러분은 컨테이너 당 **단일 Uvicorn 프로세스**를 가지고 싶어할 것입니다 (그러나 아마도 다중 컨테이너를 가질 것입니다). +따라서 이 경우 컨테이너에서 `--workers` 커맨드 라인 옵션 같은 방식으로 여러 워커를 두고 싶지는 **않을** 것입니다. 컨테이너당 **단일 Uvicorn 프로세스**만 두고(하지만 컨테이너는 여러 개일 수 있습니다) 싶을 것입니다. -이미 여러분이 클러스터 시스템을 관리하고 있으므로, (Uvicorn 워커를 관리하는 Gunicorn 이나 Uvicorn 처럼) 컨테이너 내에 다른 프로세스 매니저를 가지는 것은 **불필요한 복잡성**만 더하게 될 것입니다. +컨테이너 내부에 (여러 워커를 위한) 또 다른 프로세스 매니저를 두는 것은, 이미 클러스터 시스템에서 처리하고 있는 **불필요한 복잡성**만 추가할 가능성이 큽니다. -### 다중 프로세스를 가지는 컨테이너와 특수한 경우들 +### 여러 프로세스를 가진 컨테이너와 특수한 경우 { #containers-with-multiple-processes-and-special-cases } -당연한 말이지만, 여러분이 내부적으로 **Uvicorn 워커 프로세스들**를 시작하는 **Gunicorn 프로세스 매니저**를 가지는 단일 컨테이너를 원하는 **특수한 경우**도 있을 것입니다. +물론 컨테이너 하나에 여러 **Uvicorn 워커 프로세스**를 두고 싶을 수 있는 **특수한 경우**도 있습니다. -그런 경우에, 여러분들은 **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로 설정합니다. -여러분은 **단일 프로세스**를 가지는 **다중 컨테이너** 대신 **다중 프로세스**를 가지는 **단일 컨테이너**를 채택하는 **다른 이유**가 있을 수 있습니다. +이런 방식이 의미가 있을 수 있는 예시는 다음과 같습니다: -예를 들어 (여러분의 장치 설정에 따라) Prometheus 익스포터와 같이 같은 컨테이너에 들어오는 **각 요청에 대해** 접근권한을 가지는 도구를 사용할 수 있습니다. +#### 단순한 앱 { #a-simple-app } -이 경우에 여러분이 **여러개의 컨테이너들**을 가지고 있다면, Prometheus가 **메트릭을 읽어 들일 때**, 디폴트로 **매번 하나의 컨테이너**(특정 리퀘스트를 관리하는 바로 그 컨테이너)로 부터 읽어들일 것입니다. 이는 모든 복제된 컨테이너에 대해 **축적된 메트릭들**을 읽어들이는 것과 대비됩니다. +애플리케이션이 **충분히 단순**해서 클러스터가 아닌 **단일 서버**에서 실행할 수 있다면, 컨테이너에 프로세스 매니저를 두고 싶을 수 있습니다. -그렇다면 이 경우에는 **다중 프로세스**를 가지는 **하나의 컨테이너**를 두어서 같은 컨테이너에서 모든 내부 프로세스에 대한 Prometheus 메트릭을 수집하는 로컬 도구(예를 들어 Prometheus 익스포터 같은)를 두어서 이 메그릭들을 하나의 컨테이너에 내에서 공유하는 방법이 더 단순할 것입니다. +#### Docker Compose { #docker-compose } + +**Docker Compose**로 클러스터가 아닌 **단일 서버**에 배포하는 경우, 공유 네트워크와 **로드 밸런싱**을 유지하면서(Docker Compose로) 컨테이너 복제를 관리하는 쉬운 방법이 없을 수 있습니다. + +그렇다면 **프로세스 매니저**가 컨테이너 내부에서 **여러 워커 프로세스**를 시작하는 **단일 컨테이너**를 원할 수 있습니다. --- -요점은, 이 중의 **어느것도** 여러분들이 반드시 따라야하는 **확정된 사실**이 아니라는 것입니다. 여러분은 이 아이디어들을 **여러분의 고유한 이용 사례를 평가**하는데 사용하고, 여러분의 시스템에 가장 적합한 접근법이 어떤 것인지 결정하며, 다음의 개념들을 관리하는 방법을 확인할 수 있습니다: +핵심은, 이것들 중 **어느 것도** 무조건 따라야 하는 **절대적인 규칙**은 아니라는 것입니다. 이 아이디어들을 사용해 **여러분의 사용 사례를 평가**하고, 여러분의 시스템에 가장 적합한 접근 방식을 결정하면서 다음 개념을 어떻게 관리할지 확인할 수 있습니다: * 보안 - HTTPS -* 구동하기 +* 시작 시 자동 실행 * 재시작 -* 복제 (실행 중인 프로세스 개수) +* 복제(실행 중인 프로세스 수) * 메모리 -* 시작하기 전 단계들 +* 시작 전 사전 단계 -## 메모리 +## 메모리 { #memory } -만약 여러분이 **컨테이너 당 단일 프로세스**를 실행한다면, 여러분은 각 컨테이너(복제된 경우에는 여러개의 컨테이너들)에 대해 잘 정의되고, 안정적이며, 제한된 용량의 메모리 소비량을 가지고 있을 것입니다. +**컨테이너당 단일 프로세스**를 실행하면, 각 컨테이너(복제된 경우 여러 개)마다 소비하는 메모리 양이 대체로 잘 정의되고 안정적이며 제한된 값이 됩니다. -그러면 여러분의 컨테이너 관리 시스템(예를 들어 **쿠버네티스**) 설정에서 앞서 정의된 것과 같은 메모리 제한과 요구사항을 설정할 수 있습니다. 이런 방법으로 **가용 머신**이 필요로하는 메모리와 클러스터에 있는 가용 머신들을 염두에 두고 **컨테이너를 복제**할 수 있습니다. +그런 다음 컨테이너 관리 시스템(예: **Kubernetes**) 설정에서 동일하게 메모리 제한과 요구사항을 설정할 수 있습니다. 그러면 클러스터에서 사용 가능한 머신에 있는 메모리와 컨테이너가 필요로 하는 메모리 양을 고려해 **컨테이너를 복제**할 수 있습니다. -만약 여러분의 어플리케이션이 **단순**하다면, 이것은 **문제가 되지 않을** 것이고, 고정된 메모리 제한을 구체화할 필요도 없을 것입니다. 하지만 여러분의 어플리케이션이 (예를 들어 **머신 러닝** 모델같이) **많은 메모리를 소요한다면**, 어플리케이션이 얼마나 많은 양의 메모리를 사용하는지 확인하고 **각 머신에서** 사용하는 **컨테이너의 수**를 조정할 필요가 있습니다 (그리고 필요에 따라 여러분의 클러스터에 머신을 추가할 수 있습니다). +애플리케이션이 **단순**하다면 이는 아마도 **문제가 되지 않을** 것이고, 엄격한 메모리 제한을 지정할 필요가 없을 수도 있습니다. 하지만 **많은 메모리를 사용한다면**(예: **머신 러닝** 모델), 얼마나 많은 메모리를 소비하는지 확인하고, **각 머신**에서 실행되는 **컨테이너 수**를 조정해야 합니다(필요하다면 클러스터에 머신을 더 추가할 수도 있습니다). -만약 여러분이 **컨테이너 당 여러개의 프로세스**를 실행한다면 (예를 들어 공식 도커 이미지 처럼), 여러분은 시작된 프로세스 개수가 가용한 것 보다 **더 많은 메모리를 소비**하지 않는지 확인해야 합니다. +**컨테이너당 여러 프로세스**를 실행한다면, 시작되는 프로세스 수가 사용 가능한 것보다 **더 많은 메모리를 소비하지** 않는지 확인해야 합니다. -## 시작하기 전 단계들과 컨테이너 +## 시작 전 단계와 컨테이너 { #previous-steps-before-starting-and-containers } -만약 여러분이 컨테이너(예를 들어 도커, 쿠버네티스)를 사용한다면, 여러분이 접근할 수 있는 주요 방법은 크게 두가지가 있습니다. +컨테이너(예: Docker, Kubernetes)를 사용한다면, 사용할 수 있는 주요 접근 방식은 두 가지입니다. -### 다중 컨테이너 +### 여러 컨테이너 { #multiple-containers } -만약 여러분이 **여러개의 컨테이너**를 가지고 있다면, 아마도 각각의 컨테이너는 **하나의 프로세스**를 가지고 있을 것입니다(예를 들어, **쿠버네티스** 클러스터에서). 그러면 여러분은 복제된 워커 컨테이너를 실행하기 **이전에**, 하나의 컨테이너에 있는 **이전의 단계들을** 수행하는 단일 프로세스를 가지는 **별도의 컨테이너들**을 가지고 싶을 것입니다. +**여러 컨테이너**가 있고 각 컨테이너가 보통 **단일 프로세스**를 실행한다면(예: **Kubernetes** 클러스터), 복제된 워커 컨테이너를 실행하기 **전에**, 단일 컨테이너에서 단일 프로세스로 **시작 전 사전 단계**를 수행하는 **별도의 컨테이너**를 두고 싶을 가능성이 큽니다. /// info | 정보 -만약 여러분이 쿠버네티스를 사용하고 있다면, 아마도 이는 Init Container일 것입니다. +Kubernetes를 사용한다면, 이는 아마도 Init Container일 것입니다. /// -만약 여러분의 이용 사례에서 이전 단계들을 **병렬적으로 여러번** 수행하는데에 문제가 없다면 (예를 들어 데이터베이스 이전을 실행하지 않고 데이터베이스가 준비되었는지 확인만 하는 경우), 메인 프로세스를 시작하기 전에 이 단계들을 각 컨테이너에 넣을 수 있습니다. - -### 단일 컨테이너 - -만약 여러분의 셋업이 **다중 프로세스**(또는 하나의 프로세스)를 시작하는 **하나의 컨테이너**를 가지는 단순한 셋업이라면, 사전 단계들을 앱을 포함하는 프로세스를 시작하기 직전에 같은 컨테이너에서 실행할 수 있습니다. 공식 도커 이미지는 이를 내부적으로 지원합니다. +사용 사례에서 시작 전 사전 단계를 **여러 번 병렬로 실행**해도 문제가 없다면(예: 데이터베이스 마이그레이션을 실행하는 것이 아니라, 데이터베이스가 준비되었는지 확인만 하는 경우), 메인 프로세스를 시작하기 직전에 각 컨테이너에 그 단계를 넣을 수도 있습니다. -## Gunicorn과 함께하는 공식 도커 이미지 - Uvicorn +### 단일 컨테이너 { #single-container } -앞 챕터에서 자세하게 설명된 것 처럼, Uvicorn 워커와 같이 실행되는 Gunicorn을 포함하는 공식 도커 이미지가 있습니다: [서버 워커 - Uvicorn과 함께하는 Gunicorn](server-workers.md){.internal-link target=_blank}. +**단일 컨테이너**에서 여러 **워커 프로세스**(또는 단일 프로세스)를 시작하는 단순한 셋업이라면, 앱이 있는 프로세스를 시작하기 직전에 같은 컨테이너에서 시작 전 사전 단계를 실행할 수 있습니다. -이 이미지는 주로 위에서 설명된 상황에서 유용할 것입니다: [다중 프로세스를 가지는 컨테이너와 특수한 경우들](#containers-with-multiple-processes-and-special-cases). - -* tiangolo/uvicorn-gunicorn-fastapi. - -/// warning | 경고 +### 베이스 도커 이미지 { #base-docker-image } -여러분이 이 베이스 이미지 또는 다른 유사한 이미지를 필요로 하지 **않을** 높은 가능성이 있으며, [위에서 설명된 것처럼: FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi) 처음부터 이미지를 빌드하는 것이 더 나을 수 있습니다. +과거에는 공식 FastAPI Docker 이미지가 있었습니다: tiangolo/uvicorn-gunicorn-fastapi. 하지만 이제는 deprecated되었습니다. ⛔️ -/// +아마도 이 베이스 도커 이미지(또는 유사한 다른 이미지)는 **사용하지 않는** 것이 좋습니다. -이 이미지는 가능한 CPU 코어에 기반한 **몇개의 워커 프로세스**를 설정하는 **자동-튜닝** 메커니즘을 포함하고 있습니다. +**Kubernetes**(또는 다른 도구)를 사용하고, 클러스터 레벨에서 여러 **컨테이너**로 **복제**를 이미 설정해 둔 경우라면, 위에서 설명한 대로 **처음부터 이미지를 빌드하는 것**이 더 낫습니다: [FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi). -이 이미지는 **민감한 디폴트** 값을 가지고 있지만, 여러분들은 여전히 **환경 변수** 또는 설정 파일을 통해 설정값을 수정하고 업데이트 할 수 있습니다. +그리고 여러 워커가 필요하다면, `--workers` 커맨드 라인 옵션을 간단히 사용하면 됩니다. -또한 스크립트를 통해 **시작하기 전 사전 단계**를 실행하는 것을 지원합니다. +/// note Technical Details | 기술 세부사항 -/// tip | 팁 +이 Docker 이미지는 Uvicorn이 죽은 워커를 관리하고 재시작하는 기능을 지원하지 않던 시기에 만들어졌습니다. 그래서 Gunicorn과 Uvicorn을 함께 사용해야 했고, Gunicorn이 Uvicorn 워커 프로세스를 관리하고 재시작하도록 하기 위해 상당한 복잡성이 추가되었습니다. -모든 설정과 옵션을 보려면, 도커 이미지 페이지로 이동합니다: tiangolo/uvicorn-gunicorn-fastapi. +하지만 이제 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의 도커 이미지 - -만약 여러분들이 프로젝트 의존성을 관리하기 위해 Poetry를 사용한다면, 도커의 멀티-스테이지 빌딩을 사용할 수 있습니다: - -```{ .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를 설치합니다. +프로젝트를 설치하고 관리하기 위해 uv를 사용한다면, uv Docker guide를 따를 수 있습니다. -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 캐시**를 신경 쓰면 **빌드 시간을 최소화**해 생산성을 최대화할 수 있습니다(그리고 지루함도 피할 수 있습니다). 😎 diff --git a/docs/ko/docs/deployment/index.md b/docs/ko/docs/deployment/index.md index 87b05b68f1..e0d2375344 100644 --- a/docs/ko/docs/deployment/index.md +++ b/docs/ko/docs/deployment/index.md @@ -1,21 +1,23 @@ -# 배포하기 - 들어가면서 +# 배포 { #deployment } -**FastAPI**을 배포하는 것은 비교적 쉽습니다. +**FastAPI** 애플리케이션을 배포하는 것은 비교적 쉽습니다. -## 배포의 의미 +## 배포의 의미 { #what-does-deployment-mean } -**배포**란 애플리케이션을 **사용자가 사용**할 수 있도록 하는 데 필요한 단계를 수행하는 것을 의미합니다. +애플리케이션을 **배포**한다는 것은 **사용자가 사용**할 수 있도록 하는 데 필요한 단계를 수행하는 것을 의미합니다. -**웹 API**의 경우, 일반적으로 **사용자**가 중단이나 오류 없이 애플리케이션에 효율적으로 **접근**할 수 있도록 좋은 성능, 안정성 등을 제공하는 **서버 프로그램과** 함께 **원격 시스템**에 이를 설치하는 작업을 의미합니다. +**웹 API**의 경우, 일반적으로 **원격 머신**에 이를 설치하고, 좋은 성능, 안정성 등을 제공하는 **서버 프로그램**과 함께 구성하여 **사용자**가 중단이나 문제 없이 애플리케이션에 효율적으로 **접근**할 수 있게 하는 것을 포함합니다. -이는 지속적으로 코드를 변경하고, 지우고, 수정하고, 개발 서버를 중지했다가 다시 시작하는 등의 **개발** 단계와 대조됩니다. +이는 지속적으로 코드를 변경하고, 망가뜨리고 고치고, 개발 서버를 중지했다가 다시 시작하는 등의 **개발** 단계와 대조됩니다. -## 배포 전략 +## 배포 전략 { #deployment-strategies } -사용하는 도구나 특정 사례에 따라 여러 가지 방법이 있습니다. +구체적인 사용 사례와 사용하는 도구에 따라 여러 가지 방법이 있습니다. -배포도구들을 사용하여 직접 **서버에 배포**하거나, 배포작업의 일부를 수행하는 **클라우드 서비스** 또는 다른 방법을 사용할 수도 있습니다. +여러 도구를 조합해 직접 **서버를 배포**할 수도 있고, 작업의 일부를 대신해 주는 **클라우드 서비스**를 사용할 수도 있으며, 다른 가능한 선택지도 있습니다. -**FastAPI** 애플리케이션을 배포할 때 선택할 수 있는 몇 가지 주요 방법을 보여 드리겠습니다 (대부분 다른 유형의 웹 애플리케이션에도 적용됩니다). +예를 들어, FastAPI 뒤에 있는 저희 팀은 FastAPI로 작업하는 것과 같은 개발자 경험을 유지하면서, FastAPI 앱을 클라우드에 가능한 한 간소화된 방식으로 배포할 수 있도록 **FastAPI Cloud**를 만들었습니다. -다음 차례에 자세한 내용과 이를 위한 몇 가지 기술을 볼 수 있습니다. ✨ +**FastAPI** 애플리케이션을 배포할 때 아마 염두에 두어야 할 몇 가지 주요 개념을 보여드리겠습니다(대부분은 다른 유형의 웹 애플리케이션에도 적용됩니다). + +다음 섹션에서 염두에 둘 더 많은 세부사항과 이를 위한 몇 가지 기술을 볼 수 있습니다. ✨ diff --git a/docs/ko/docs/deployment/server-workers.md b/docs/ko/docs/deployment/server-workers.md index b40b25cd8f..e98cfd1142 100644 --- a/docs/ko/docs/deployment/server-workers.md +++ b/docs/ko/docs/deployment/server-workers.md @@ -1,130 +1,87 @@ -# 서버 워커 - 구니콘과 유비콘 +# 서버 워커 - 워커와 함께 사용하는 Uvicorn { #server-workers-uvicorn-with-workers } -전단계에서의 배포 개념들을 다시 확인해보겠습니다: +이전의 배포 개념들을 다시 확인해보겠습니다: * 보안 - HTTPS -* 서버 시작과 동시에 실행하기 +* 서버 시작 시 실행 * 재시작 -* **복제본 (실행 중인 프로세스의 숫자)** +* **복제(실행 중인 프로세스 수)** * 메모리 -* 시작하기 전의 여러 단계들 +* 시작하기 전의 이전 단계 -지금까지 문서의 모든 튜토리얼을 참고하여 **단일 프로세스**로 Uvicorn과 같은 **서버 프로그램**을 실행했을 것입니다. +지금까지 문서의 모든 튜토리얼을 참고하면서, `fastapi` 명령처럼 Uvicorn을 실행하는 **서버 프로그램**을 사용해 **단일 프로세스**로 실행해 왔을 가능성이 큽니다. -애플리케이션을 배포할 때 **다중 코어**를 활용하고 더 많은 요청을 처리할 수 있도록 **프로세스 복제본**이 필요합니다. +애플리케이션을 배포할 때는 **다중 코어**를 활용하고 더 많은 요청을 처리할 수 있도록 **프로세스 복제**를 하고 싶을 가능성이 큽니다. -전 과정이었던 [배포 개념들](concepts.md){.internal-link target=_blank}에서 본 것처럼 여러가지 방법이 존재합니다. +이전 장의 [배포 개념들](concepts.md){.internal-link target=_blank}에서 본 것처럼, 사용할 수 있는 전략이 여러 가지 있습니다. -지금부터 **구니콘**을 **유비콘 워커 프로세스**와 함께 사용하는 방법을 알려드리겠습니다. +여기서는 `fastapi` 명령을 사용하거나 `uvicorn` 명령을 직접 사용해서, **워커 프로세스**와 함께 **Uvicorn**을 사용하는 방법을 보여드리겠습니다. /// info | 정보 -만약 도커와 쿠버네티스 같은 컨테이너를 사용하고 있다면 다음 챕터 [FastAPI와 컨테이너 - 도커](docker.md){.internal-link target=_blank}에서 더 많은 정보를 얻을 수 있습니다. +Docker나 Kubernetes 같은 컨테이너를 사용하고 있다면, 다음 장인 [컨테이너에서의 FastAPI - 도커](docker.md){.internal-link target=_blank}에서 더 자세히 설명하겠습니다. -특히, 쿠버네티스에서 실행할 때는 구니콘을 사용하지 않고 대신 컨테이너당 하나의 유비콘 프로세스를 실행하는 것이 좋습니다. 이 장의 뒷부분에서 설명하겠습니다. +특히 **Kubernetes**에서 실행할 때는 워커를 사용하기보다는, 대신 **컨테이너당 단일 Uvicorn 프로세스 하나**를 실행하고 싶을 가능성이 크지만, 해당 내용은 그 장의 뒤에서 설명하겠습니다. /// -## 구니콘과 유비콘 워커 +## 여러 워커 { #multiple-workers } -**Gunicorn**은 **WSGI 표준**을 주로 사용하는 애플리케이션 서버입니다. 이것은 구니콘이 플라스크와 쟝고와 같은 애플리케이션을 제공할 수 있다는 것을 의미합니다. 구니콘 자체는 최신 **ASGI 표준**을 사용하기 때문에 FastAPI와 호환되지 않습니다. +`--workers` 커맨드라인 옵션으로 여러 워커를 시작할 수 있습니다: -하지만 구니콘은 **프로세스 관리자**역할을 하고 사용자에게 특정 **워커 프로세스 클래스**를 알려줍니다. 그런 다음 구니콘은 해당 클래스를 사용하여 하나 이상의 **워커 프로세스**를 시작합니다. +//// tab | `fastapi` -그리고 **유비콘**은 **구니콘과 호환되는 워커 클래스**가 있습니다. - -이 조합을 사용하여 구니콘은 **프로세스 관리자** 역할을 하며 **포트**와 **IP**를 관찰하고, **유비콘 클래스**를 실행하는 워커 프로세스로 통신 정보를 **전송**합니다. - -그리고 나서 구니콘과 호환되는 **유비콘 워커** 클래스는 구니콘이 보낸 데이터를 FastAPI에서 사용하기 위한 ASGI 표준으로 변환하는 일을 담당합니다. - -## 구니콘과 유비콘 설치하기 +`fastapi` 명령을 사용한다면:
```console -$ pip install "uvicorn[standard]" gunicorn - ----> 100% -``` - -
+$ fastapi run --workers 4 main.py -이 명령어는 유비콘 `standard` 추가 패키지(좋은 성능을 위한)와 구니콘을 설치할 것입니다. + FastAPI Starting production server 🚀 -## 구니콘을 유비콘 워커와 함께 실행하기 + Searching for package file structure from directories with + __init__.py files + Importing from /home/user/code/awesomeapp -설치 후 구니콘 실행하기: + module 🐍 main.py -
- -```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. -``` - -
+ code Importing the FastAPI app object from the module with the + following code: -각 옵션이 무엇을 의미하는지 살펴봅시다: + from main import app -* 이것은 유비콘과 똑같은 문법입니다. `main`은 파이썬 모듈 네임 "`main`"을 의미하므로 `main.py`파일을 뜻합니다. 그리고 `app`은 **FastAPI** 어플리케이션이 들어 있는 변수의 이름입니다. - * `main:app`이 파이썬의 `import` 문법과 흡사한 면이 있다는 걸 알 수 있습니다: + app Using import string: main:app - ```Python - from main import app - ``` + server Server started at http://0.0.0.0:8000 + server Documentation at http://0.0.0.0:8000/docs - * 곧, `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개의 워커**를 실행합니다. - - -또한 구니콘은 워커의 수를 유지하기 위해 **죽은 프로세스**를 관리하고 **재시작**하는 작업을 책임집니다. 이것은 이번 장 상단 목록의 **재시작** 개념을 부분적으로 도와주는 것입니다. - -그럼에도 불구하고 필요할 경우 외부에서 **구니콘을 재시작**하고, 혹은 **서버를 시작할 때 실행**할 수 있도록 하고 싶어할 것입니다. + INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to + quit) + INFO Started parent process [27365] + INFO Started server process [27368] + INFO Started server process [27369] + INFO Started server process [27370] + INFO Started server process [27367] + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Application startup complete. + INFO Application startup complete. + INFO Application startup complete. + INFO Application startup complete. +``` -## 유비콘과 워커 + -유비콘은 몇 개의 **워커 프로세스**와 함께 실행할 수 있는 선택지가 있습니다. +//// -그럼에도 불구하고, 유비콘은 워커 프로세스를 다루는 데에 있어서 구니콘보다 더 제한적입니다. 따라서 이 수준(파이썬 수준)의 프로세스 관리자를 사용하려면 구니콘을 프로세스 관리자로 사용하는 것이 좋습니다. +//// tab | `uvicorn` -보통 이렇게 실행할 수 있습니다: +`uvicorn` 명령을 직접 사용하는 편이 좋다면:
@@ -148,36 +105,35 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
-새로운 옵션인 `--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 } -또한 간단한 케이스에서 사용할 수 있는, **구니콘과 유비콘 워커**가 포함돼 있는 **공식 도커 이미지**와 함께 몇 가지 기본 구성을 보여드리겠습니다. +다음 장인 [컨테이너에서의 FastAPI - 도커](docker.md){.internal-link target=_blank}에서는 다른 **배포 개념들**을 처리하기 위해 사용할 수 있는 몇 가지 전략을 설명하겠습니다. -그리고 단일 유비콘 프로세스(구니콘 없이)를 실행할 수 있도록 **사용자 자신의 이미지를 처음부터 구축**하는 방법도 보여드리겠습니다. 이는 간단한 과정이며, **쿠버네티스**와 같은 분산 컨테이너 관리 시스템을 사용할 때 수행할 작업입니다. +단일 Uvicorn 프로세스를 실행하기 위해, **처음부터 여러분만의 이미지를 직접 빌드**하는 방법을 보여드리겠습니다. 이는 간단한 과정이며, **Kubernetes** 같은 분산 컨테이너 관리 시스템을 사용할 때 아마도 이렇게 하고 싶을 것입니다. -## 요약 +## 요약 { #recap } -당신은 **구니콘**(또는 유비콘)을 유비콘 워커와 함께 프로세스 관리자로 사용하여 **멀티-코어 CPU**를 활용하는 **멀티 프로세스를 병렬로 실행**할 수 있습니다. +`fastapi` 또는 `uvicorn` 명령에서 `--workers` CLI 옵션을 사용해 여러 워커 프로세스를 실행하면, **멀티 코어 CPU**를 활용해 **여러 프로세스를 병렬로 실행**할 수 있습니다. -다른 배포 개념을 직접 다루면서 **자신만의 배포 시스템**을 구성하는 경우 이러한 도구와 개념들을 활용할 수 있습니다. +다른 배포 개념들을 직접 처리하면서 **자체 배포 시스템**을 구축하는 경우, 이러한 도구와 아이디어를 활용할 수 있습니다. -다음 장에서 컨테이너(예: 도커 및 쿠버네티스)와 함께하는 **FastAPI**에 대해 배워보세요. 이러한 툴에는 다른 **배포 개념**들을 간단히 해결할 수 있는 방법이 있습니다. ✨ +다음 장에서 컨테이너(예: Docker 및 Kubernetes)와 함께 사용하는 **FastAPI**에 대해 알아보세요. 해당 도구들이 다른 **배포 개념들**도 간단히 해결하는 방법이 있다는 것을 확인할 수 있습니다. ✨ diff --git a/docs/ko/docs/deployment/versions.md b/docs/ko/docs/deployment/versions.md index 559a892ab9..173ba925cf 100644 --- a/docs/ko/docs/deployment/versions.md +++ b/docs/ko/docs/deployment/versions.md @@ -1,94 +1,93 @@ -# FastAPI 버전들에 대하여 +# FastAPI 버전들에 대하여 { #about-fastapi-versions } -**FastAPI** 는 이미 많은 응용 프로그램과 시스템들을 만드는데 사용되고 있습니다. 그리고 100%의 테스트 정확성을 가지고 있습니다. 하지만 이것은 아직까지도 빠르게 발전하고 있습니다. +**FastAPI**는 이미 많은 애플리케이션과 시스템에서 프로덕션으로 사용되고 있습니다. 그리고 테스트 커버리지는 100%로 유지됩니다. 하지만 개발은 여전히 빠르게 진행되고 있습니다. -새로운 특징들이 빈번하게 추가되고, 오류들이 지속적으로 수정되고 있습니다. 그리고 코드가 계속적으로 향상되고 있습니다. +새로운 기능이 자주 추가되고, 버그가 규칙적으로 수정되며, 코드는 계속해서 지속적으로 개선되고 있습니다. -이것이 아직도 최신 버전이 `0.x.x`인 이유입니다. 이것은 각각의 버전들이 잠재적으로 변할 수 있다는 것을 보여줍니다. 이는 유의적 버전 관습을 따릅니다. +그래서 현재 버전이 아직 `0.x.x`인 것입니다. 이는 각 버전이 잠재적으로 하위 호환성이 깨지는 변경을 포함할 수 있음을 반영합니다. 이는 Semantic Versioning 관례를 따릅니다. -지금 바로 **FastAPI**로 응용 프로그램을 만들 수 있습니다. 이때 (아마 지금까지 그래 왔던 것처럼), 사용하는 버전이 코드와 잘 맞는지 확인해야합니다. +지금 바로 **FastAPI**로 프로덕션 애플리케이션을 만들 수 있습니다(그리고 아마도 한동안 그렇게 해오셨을 것입니다). 다만 나머지 코드와 함께 올바르게 동작하는 버전을 사용하고 있는지 확인하기만 하면 됩니다. -## `fastapi` 버전을 표시 +## `fastapi` 버전을 고정하기 { #pin-your-fastapi-version } -가장 먼저 해야할 것은 응용 프로그램이 잘 작동하는 가장 최신의 구체적인 **FastAPI** 버전을 표시하는 것입니다. +가장 먼저 해야 할 일은 여러분의 애플리케이션에서 올바르게 동작하는 것으로 알고 있는 **FastAPI**의 최신 구체 버전에 맞춰 사용 중인 버전을 "고정(pin)"하는 것입니다. -예를 들어, 응용 프로그램에 `0.45.0` 버전을 사용했다고 가정합니다. +예를 들어, 앱에서 `0.112.0` 버전을 사용하고 있다고 가정해 보겠습니다. -만약에 `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 } -유의적 버전 관습을 따라서, `1.0.0` 이하의 모든 버전들은 잠재적으로 급변할 수 있습니다. +Semantic Versioning 관례에 따르면, `1.0.0` 미만의 어떤 버전이든 잠재적으로 하위 호환성이 깨지는 변경을 추가할 수 있습니다. -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 } -응용 프로그램을 검사해야합니다. +앱에 테스트를 추가해야 합니다. -(Starlette 덕분에), **FastAPI** 를 이용하여 굉장히 쉽게 할 수 있습니다. [Testing](../tutorial/testing.md){.internal-link target=_blank}문서를 확인해 보십시오: +**FastAPI**에서는 매우 쉽습니다(Starlette 덕분에). 문서를 확인해 보세요: [Testing](../tutorial/testing.md){.internal-link target=_blank} -검사를 해보고 난 후에, **FastAPI** 버전을 더 최신으로 업그레이드 할 수 있습니다. 그리고 코드들이 테스트에 정상적으로 작동하는지 확인을 해야합니다. +테스트를 갖춘 뒤에는 **FastAPI** 버전을 더 최신 버전으로 업그레이드하고, 테스트를 실행하여 모든 코드가 올바르게 동작하는지 확인하세요. -만약에 모든 것이 정상 작동하거나 필요한 부분을 변경하고, 모든 검사를 통과한다면, 새로운 버전의 `fastapi`를 표시할 수 있습니다. +모든 것이 동작하거나 필요한 변경을 한 뒤 모든 테스트가 통과한다면, `fastapi`를 그 새로운 최신 버전으로 고정할 수 있습니다. -## Starlette에 대해 +## Starlette에 대해 { #about-starlette } -`starlette`의 버전은 표시할 수 없습니다. +`starlette`의 버전은 고정하지 않는 것이 좋습니다. -서로다른 버전의 **FastAPI**가 구체적이고 새로운 버전의 Starlette을 사용할 것입니다. +서로 다른 **FastAPI** 버전은 Starlette의 특정한 더 새로운 버전을 사용하게 됩니다. -그러므로 **FastAPI**가 알맞은 Starlette 버전을 사용하도록 하십시오. +따라서 **FastAPI**가 올바른 Starlette 버전을 사용하도록 그냥 두면 됩니다. -## Pydantic에 대해 +## Pydantic에 대해 { #about-pydantic } -Pydantic은 **FastAPI** 를 위한 검사를 포함하고 있습니다. 따라서, 새로운 버전의 Pydantic(`1.0.0`이상)은 항상 FastAPI와 호환됩니다. +Pydantic은 자체 테스트에 **FastAPI**에 대한 테스트도 포함하고 있으므로, Pydantic의 새 버전(`1.0.0` 초과)은 항상 FastAPI와 호환됩니다. -작업을 하고 있는 `1.0.0` 이상의 모든 버전과 `2.0.0` 이하의 Pydantic 버전을 표시할 수 있습니다. +여러분에게 맞는 `1.0.0` 초과의 어떤 Pydantic 버전으로든 고정할 수 있습니다. -예를 들어 다음과 같습니다: +예를 들어: ```txt -pydantic>=1.2.0,<2.0.0 +pydantic>=2.7.0,<3.0.0 ``` diff --git a/docs/ko/docs/environment-variables.md b/docs/ko/docs/environment-variables.md index 1e6af3ceba..dc231acb64 100644 --- a/docs/ko/docs/environment-variables.md +++ b/docs/ko/docs/environment-variables.md @@ -1,4 +1,4 @@ -# 환경 변수 +# 환경 변수 { #environment-variables } /// tip | 팁 @@ -6,11 +6,11 @@ /// -환경 변수는 파이썬 코드의 **바깥**인, **운영 체제**에 존재하는 변수입니다. 파이썬 코드나 다른 프로그램에서 읽을 수 있습니다. +환경 변수(또는 "**env var**"라고도 합니다)는 파이썬 코드의 **바깥**인, **운영 체제**에 존재하는 변수이며, 파이썬 코드(또는 다른 프로그램에서도)에서 읽을 수 있습니다. -환경 변수는 애플리케이션 **설정**을 처리하거나, 파이썬의 **설치** 과정의 일부로 유용합니다. +환경 변수는 애플리케이션 **설정**을 처리하거나, 파이썬의 **설치** 과정의 일부로 유용할 수 있습니다. -## 환경 변수를 만들고 사용하기 +## 환경 변수를 만들고 사용하기 { #create-and-use-env-vars } 파이썬 없이도, **셸 (터미널)** 에서 환경 변수를 **생성** 하고 사용할 수 있습니다. @@ -50,9 +50,9 @@ Hello Wade Wilson //// -## 파이썬에서 환경 변수 읽기 +## 파이썬에서 env var 읽기 { #read-env-vars-in-python } -파이썬 **바깥**인 터미널에서(다른 도구로도 가능) 환경 변수를 생성도 할 수도 있고, 이를 **파이썬에서 읽을 수 있습니다.** +파이썬 **바깥**인 터미널에서(또는 다른 어떤 방법으로든) 환경 변수를 만들고, 그런 다음 **파이썬에서 읽을 수 있습니다**. 예를 들어 다음과 같은 `main.py` 파일이 있다고 합시다: @@ -67,7 +67,7 @@ print(f"Hello {name} from Python") `os.getenv()` 의 두 번째 인자는 반환할 기본값입니다. -여기서는 `"World"`를 넣었기에 기본값으로써 사용됩니다. 넣지 않으면 `None` 이 기본값으로 사용됩니다. +제공하지 않으면 기본값은 `None`이며, 여기서는 사용할 기본값으로 `"World"`를 제공합니다. /// @@ -129,7 +129,7 @@ Hello Wade Wilson from Python 환경변수는 코드 바깥에서 설정될 수 있지만, 코드에서 읽을 수 있고, 나머지 파일과 함께 저장(`git`에 커밋)할 필요가 없으므로, 구성이나 **설정** 에 사용하는 것이 일반적입니다. -**특정 프로그램 호출**에 대해서만 사용할 수 있는 환경 변수를 만들 수도 있습니다. 해당 프로그램에서만 사용할 수 있고, 해당 프로그램이 실행되는 동안만 사용할 수 있습니다. +또한 **특정 프로그램 호출**에 대해서만 사용할 수 있는 환경 변수를 만들 수도 있는데, 해당 프로그램에서만 사용할 수 있고, 해당 프로그램이 실행되는 동안만 사용할 수 있습니다. 그렇게 하려면 프로그램 바로 앞, 같은 줄에 환경 변수를 만들어야 합니다: @@ -157,17 +157,17 @@ Hello World from Python /// -## 타입과 검증 +## 타입과 검증 { #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에서는 세미콜론 `;`으로 구분된 디렉토리로 구성된 긴 문자열입니다. @@ -181,11 +181,11 @@ Hello World from Python 이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다: -- `/usr/local/bin` -- `/usr/bin` -- `/bin` -- `/usr/sbin` -- `/sbin` +* `/usr/local/bin` +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` //// @@ -197,9 +197,9 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3 이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다: -- `C:\Program Files\Python312\Scripts` -- `C:\Program Files\Python312` -- `C:\Windows\System32` +* `C:\Program Files\Python312\Scripts` +* `C:\Program Files\Python312` +* `C:\Windows\System32` //// @@ -209,7 +209,7 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3 찾으면 **사용합니다**. 그렇지 않으면 **다른 디렉토리**에서 계속 찾습니다. -### 파이썬 설치와 `PATH` 업데이트 +### 파이썬 설치와 `PATH` 업데이트 { #installing-python-and-updating-the-path } 파이썬을 설치할 때, 아마 `PATH` 환경 변수를 업데이트 할 것이냐고 물어봤을 겁니다. @@ -285,13 +285,13 @@ $ C:\opt\custompython\bin\python //// -이 정보는 [가상 환경](virtual-environments.md){.internal-link target=\_blank} 에 대해 알아볼 때 유용할 것입니다. +이 정보는 [가상 환경](virtual-environments.md){.internal-link target=_blank} 에 대해 알아볼 때 유용할 것입니다. -## 결론 +## 결론 { #conclusion } -이 문서를 읽고 **환경 변수**가 무엇이고 파이썬에서 어떻게 사용하는지 기본적으로 이해하셨을 겁니다. +이 문서를 통해 **환경 변수**가 무엇이고 파이썬에서 어떻게 사용하는지 기본적으로 이해하셨을 겁니다. -또한 환경 변수에 대한 위키피디아(한국어)에서 이에 대해 자세히 알아볼 수 있습니다. +또한 환경 변수에 대한 위키피디아에서 이에 대해 자세히 알아볼 수 있습니다. 많은 경우에서, 환경 변수가 어떻게 유용하고 적용 가능한지 바로 명확하게 알 수는 없습니다. 하지만 개발할 때 다양한 시나리오에서 계속 나타나므로 이에 대해 아는 것이 좋습니다. diff --git a/docs/ko/docs/how-to/conditional-openapi.md b/docs/ko/docs/how-to/conditional-openapi.md index 79c7f0dd2d..16e6833661 100644 --- a/docs/ko/docs/how-to/conditional-openapi.md +++ b/docs/ko/docs/how-to/conditional-openapi.md @@ -1,46 +1,41 @@ -# 조건부적인 OpenAPI +# 조건부 OpenAPI { #conditional-openapi } -필요한 경우, 설정 및 환경 변수를 사용하여 환경에 따라 조건부로 OpenAPI를 구성하고 완전히 비활성화할 수도 있습니다. +필요한 경우, 설정 및 환경 변수를 사용하여 환경에 따라 OpenAPI를 조건부로 구성하고 완전히 비활성화할 수도 있습니다. -## 보안, API 및 docs에 대해서 +## 보안, API 및 docs에 대해서 { #about-security-apis-and-docs } 프로덕션에서, 문서화된 사용자 인터페이스(UI)를 숨기는 것이 API를 보호하는 방법이 *되어서는 안 됩니다*. -이는 API에 추가적인 보안을 제공하지 않으며, *경로 작업*은 여전히 동일한 위치에서 사용 할 수 있습니다. +이는 API에 추가적인 보안을 제공하지 않으며, *경로 처리*는 여전히 동일한 위치에서 사용 할 수 있습니다. 코드에 보안 결함이 있다면, 그 결함은 여전히 존재할 것입니다. -문서를 숨기는 것은 API와 상호작용하는 방법을 이해하기 어렵게 만들며, 프로덕션에서 디버깅을 더 어렵게 만들 수 있습니다. 이는 단순히 '모호성에 의한 보안'의 한 형태로 간주될 수 있습니다. +문서를 숨기는 것은 API와 상호작용하는 방법을 이해하기 어렵게 만들며, 프로덕션에서 디버깅을 더 어렵게 만들 수 있습니다. 이는 단순히 Security through obscurity의 한 형태로 간주될 수 있습니다. 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 포함)를 비활성화할 수도 있습니다. 예를 들어:
diff --git a/docs/ko/docs/how-to/configure-swagger-ui.md b/docs/ko/docs/how-to/configure-swagger-ui.md index 5a57342cf2..174f976f67 100644 --- a/docs/ko/docs/how-to/configure-swagger-ui.md +++ b/docs/ko/docs/how-to/configure-swagger-ui.md @@ -1,4 +1,4 @@ -# Swagger UI 구성 +# Swagger UI 구성 { #configure-swagger-ui } 추가적인 Swagger UI 매개변수를 구성할 수 있습니다. @@ -8,7 +8,7 @@ FastAPI는 이 구성을 **JSON** 형식으로 변환하여 JavaScript와 호환되도록 합니다. 이는 Swagger UI에서 필요로 하는 형식입니다. -## 구문 강조 비활성화 +## 구문 강조 비활성화 { #disable-syntax-highlighting } 예를 들어, Swagger UI에서 구문 강조 기능을 비활성화할 수 있습니다. @@ -18,41 +18,41 @@ FastAPI는 이 구성을 **JSON** 형식으로 변환하여 JavaScript와 호환 그러나 `syntaxHighlight`를 `False`로 설정하여 구문 강조 기능을 비활성화할 수 있습니다: -{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} ...그럼 Swagger UI에서 더 이상 구문 강조 기능이 표시되지 않습니다: -## 테마 변경 +## 테마 변경 { #change-the-theme } 동일한 방식으로 `"syntaxHighlight.theme"` 키를 사용하여 구문 강조 테마를 설정할 수 있습니다 (중간에 점이 포함된 것을 참고하십시오). -{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} 이 설정은 구문 강조 색상 테마를 변경합니다: -## 기본 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 매개변수에 대한 공식 문서를 참조하십시오. +사용할 수 있는 다른 모든 구성 옵션을 확인하려면, Swagger UI 매개변수에 대한 공식 Swagger UI 매개변수 문서를 참조하십시오. -## JavaScript 전용 설정 +## JavaScript 전용 설정 { #javascript-only-settings } Swagger UI는 **JavaScript 전용** 객체(예: JavaScript 함수)로 다른 구성을 허용하기도 합니다. @@ -67,4 +67,4 @@ presets: [ 이들은 문자열이 아닌 **JavaScript** 객체이므로 Python 코드에서 직접 전달할 수 없습니다. -이와 같은 JavaScript 전용 구성을 사용해야 하는 경우, 위의 방법 중 하나를 사용하여 모든 Swagger UI 경로 작업을 재정의하고 필요한 JavaScript를 수동으로 작성할 수 있습니다. +이와 같은 JavaScript 전용 구성을 사용해야 하는 경우, 위의 방법 중 하나를 사용할 수 있습니다. Swagger UI *경로 처리*를 모두 재정의하고 필요한 JavaScript를 수동으로 작성하세요. diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index b6b4765dad..0c317f296d 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -1,11 +1,11 @@ -# FastAPI +# FastAPI { #fastapi }

- FastAPI + FastAPI

FastAPI 프레임워크, 고성능, 간편한 학습, 빠른 코드 작성, 준비된 프로덕션 @@ -27,7 +27,7 @@ --- -**문서**: https://fastapi.tiangolo.com +**문서**: https://fastapi.tiangolo.com **소스 코드**: https://github.com/fastapi/fastapi @@ -37,36 +37,41 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 주요 특징으로: -* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#_11). - +* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#performance). * **빠른 코드 작성**: 약 200%에서 300%까지 기능 개발 속도 증가. * * **적은 버그**: 사람(개발자)에 의한 에러 약 40% 감소. * * **직관적**: 훌륭한 편집기 지원. 모든 곳에서 자동완성. 적은 디버깅 시간. * **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간. * **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그. * **견고함**: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께. -* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: OpenAPI (이전에 Swagger로 알려졌던) 및 JSON 스키마. +* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: OpenAPI (이전에 Swagger로 알려졌던) 및 JSON Schema. * 내부 개발팀의 프로덕션 애플리케이션을 빌드한 테스트에 근거한 측정 -## 골드 스폰서 +## 스폰서 { #sponsors } -{% if sponsors %} +### 키스톤 스폰서 { #keystone-sponsor } + +{% for sponsor in sponsors.keystone -%} + +{% endfor -%} + +### 골드 및 실버 스폰서 { #gold-and-silver-sponsors } + {% for sponsor in sponsors.gold -%} {% endfor -%} {%- for sponsor in sponsors.silver -%} {% endfor %} -{% endif %} -다른 스폰서 +다른 스폰서 -## 의견들 +## 의견들 { #opinions } "_[...] 저는 요즘 **FastAPI**를 많이 사용하고 있습니다. [...] 사실 우리 팀의 **마이크로소프트 ML 서비스** 전부를 바꿀 계획입니다. 그중 일부는 핵심 **Windows**와 몇몇의 **Office** 제품들이 통합되고 있습니다._" @@ -94,7 +99,7 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 "_솔직히, 당신이 만든 것은 매우 견고하고 세련되어 보입니다. 여러 면에서 **Hug**가 이렇게 되었으면 합니다 - 그걸 만든 누군가를 보는 것은 많은 영감을 줍니다._" -

Timothy Crosley - Hug 제작자 (ref)
+
Timothy Crosley - Hug 제작자 (ref)
--- @@ -106,50 +111,54 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 --- -## **Typer**, FastAPI의 CLI +"_프로덕션 Python API를 만들고자 한다면, 저는 **FastAPI**를 강력히 추천합니다. **아름답게 설계**되었고, **사용이 간단**하며, **확장성이 매우 뛰어나**고, 우리의 API 우선 개발 전략에서 **핵심 구성 요소**가 되었으며 Virtual TAC Engineer 같은 많은 자동화와 서비스를 이끌고 있습니다._" + +
Deon Pillsbury - Cisco (ref)
+ +--- + +## FastAPI 미니 다큐멘터리 { #fastapi-mini-documentary } + +2025년 말에 공개된 FastAPI 미니 다큐멘터리가 있습니다. 온라인에서 시청할 수 있습니다: + +FastAPI Mini Documentary + +## **Typer**, CLI를 위한 FastAPI { #typer-the-fastapi-of-clis } 웹 API 대신 터미널에서 사용할 CLI 앱을 만들고 있다면, **Typer**를 확인해 보십시오. -**Typer**는 FastAPI의 동생입니다. 그리고 **FastAPI의 CLI**가 되기 위해 생겼습니다. ⌨️ 🚀 +**Typer**는 FastAPI의 동생입니다. 그리고 **CLI를 위한 FastAPI**가 되기 위해 생겼습니다. ⌨️ 🚀 -## 요구사항 +## 요구사항 { #requirements } FastAPI는 거인들의 어깨 위에 서 있습니다: * 웹 부분을 위한 Starlette. * 데이터 부분을 위한 Pydantic. -## 설치 - -
- -```console -$ pip install fastapi - ----> 100% -``` +## 설치 { #installation } -
- -프로덕션을 위해 Uvicorn 또는 Hypercorn과 같은 ASGI 서버도 필요할 겁니다. +가상 환경을 생성하고 활성화한 다음 FastAPI를 설치하세요:
```console -$ pip install "uvicorn[standard]" +$ pip install "fastapi[standard]" ---> 100% ```
-## 예제 +**Note**: 모든 터미널에서 동작하도록 `"fastapi[standard]"`를 따옴표로 감싸 넣었는지 확인하세요. + +## 예제 { #example } -### 만들기 +### 만들기 { #create-it } -* `main.py` 파일을 만드십시오: +다음 내용으로 `main.py` 파일을 만드십시오: ```Python from typing import Union @@ -172,9 +181,9 @@ def read_item(item_id: int, q: Union[str, None] = None):
또는 async def 사용하기... -여러분의 코드가 `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 @@ -194,22 +203,35 @@ async def read_item(item_id: int, q: Union[str, None] = None): **Note**: -잘 모르겠다면, 문서에서 `async`와 `await`에 관한 _"급하세요?"_ 섹션을 확인해 보십시오. +잘 모르겠다면, 문서에서 `async`와 `await`에 관한 _"급하세요?"_ 섹션을 확인해 보십시오.
-### 실행하기 +### 실행하기 { #run-it } -서버를 실행하십시오: +다음 명령으로 서버를 실행하십시오:
```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. ``` @@ -217,17 +239,17 @@ INFO: Application startup complete.
-uvicorn main:app --reload 명령에 관하여... +fastapi dev main.py 명령에 관하여... + +`fastapi dev` 명령은 `main.py` 파일을 읽고, 그 안의 **FastAPI** 앱을 감지한 다음, Uvicorn을 사용해 서버를 시작합니다. -명령 `uvicorn main:app`은 다음을 나타냅니다: +기본적으로 `fastapi dev`는 로컬 개발을 위해 auto-reload가 활성화된 상태로 시작됩니다. -* `main`: `main.py` 파일 (파이썬 "모듈"). -* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. -* `--reload`: 코드가 변경된 후 서버 재시작하기. 개발환경에서만 사용하십시오. +자세한 내용은 FastAPI CLI 문서에서 확인할 수 있습니다.
-### 확인하기 +### 확인하기 { #check-it } 브라우저로 http://127.0.0.1:8000/items/5?q=somequery를 열어보십시오. @@ -241,10 +263,10 @@ INFO: Application startup complete. * _경로_ `/` 및 `/items/{item_id}`에서 HTTP 요청 받기. * 두 _경로_ 모두 `GET` 연산(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 } 이제 http://127.0.0.1:8000/docs로 가보십시오. @@ -252,7 +274,7 @@ INFO: Application startup complete. ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### 대안 API 문서 +### 대안 API 문서 { #alternative-api-docs } 그리고 이제 http://127.0.0.1:8000/redoc로 가봅시다. @@ -260,13 +282,13 @@ INFO: Application startup complete. ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## 예제 심화 +## 예제 업그레이드 { #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 @@ -296,25 +318,25 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -서버가 자동으로 리로딩 할 수 있어야 합니다 (위에서 `uvicorn` 명령에 `--reload`을 추가 했기 때문입니다). +`fastapi dev` 서버는 자동으로 리로딩되어야 합니다. -### 대화형 API 문서 업그레이드 +### 대화형 API 문서 업그레이드 { #interactive-api-docs-upgrade } 이제 http://127.0.0.1:8000/docs로 이동합니다. -* 대화형 API 문서가 새 본문과 함께 자동으로 업데이트 합니다: +* 대화형 API 문서는 새 본문을 포함해 자동으로 업데이트됩니다: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* "Try it out" 버튼을 클릭하면, 매개변수를 채울 수 있게 해주고 직접 API와 상호작용 할 수 있습니다: +* "Try it out" 버튼을 클릭하면, 매개변수를 채우고 API와 직접 상호작용할 수 있습니다: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* 그러고 나서 "Execute" 버튼을 누르면, 사용자 인터페이스는 API와 통신하고 매개변수를 전송하며 그 결과를 가져와서 화면에 표시합니다: +* 그런 다음 "Execute" 버튼을 클릭하면, 사용자 인터페이스가 API와 통신하고 매개변수를 전송한 뒤 결과를 받아 화면에 표시합니다: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### 대안 API 문서 업그레이드 +### 대안 API 문서 업그레이드 { #alternative-api-docs-upgrade } 그리고 이제, http://127.0.0.1:8000/redoc로 이동합니다. @@ -322,7 +344,7 @@ def update_item(item_id: int, item: Item): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### 요약 +### 요약 { #recap } 요약하면, 여러분은 매개변수의 타입, 본문 등을 함수 매개변수로서 **한번에** 선언했습니다. @@ -351,8 +373,8 @@ item: Item * 타입 검사. * 데이터 검증: * 데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러. - * 중첩된 JSON 객체에 대한 유효성 검사. -* 입력 데이터 변환: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들: + * 깊이 중첩된 JSON 객체에 대한 유효성 검사. +* 입력 데이터 변환: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들: * JSON. * 경로 매개변수. * 쿼리 매개변수. @@ -360,7 +382,7 @@ item: Item * 헤더. * 폼(Forms). * 파일. -* 출력 데이터 변환: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로): +* 출력 데이터 변환: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로): * 파이썬 타입 변환 (`str`, `int`, `float`, `bool`, `list`, 등). * `datetime` 객체. * `UUID` 객체. @@ -377,13 +399,13 @@ item: Item * `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` 형인지 검사. - * 만약 주어진다면, `is_offer`를 선택 속성으로 갖고 `bool` 형인지 검사. + * `price`를 필수 속성으로 갖고 `float` 형이어야 하는지 검사. + * 만약 주어진다면, `is_offer`를 선택 속성으로 갖고 `bool` 형이어야 하는지 검사. * 이 모든 것은 깊이 중첩된 JSON 객체에도 적용됩니다. * JSON을 변환하거나 JSON으로 변환하는 것을 자동화. * 다음에서 사용할 수 있는 모든 것을 OpenAPI로 문서화: @@ -417,30 +439,88 @@ item: Item ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -더 많은 기능을 포함한 보다 완전한 예제의 경우, 튜토리얼 - 사용자 가이드를 보십시오. +더 많은 기능을 포함한 보다 완전한 예제의 경우, 튜토리얼 - 사용자 가이드를 보십시오. **스포일러 주의**: 튜토리얼 - 사용자 가이드는: * 서로 다른 장소에서 **매개변수** 선언: **헤더**, **쿠키**, **폼 필드** 그리고 **파일**. * `maximum_length` 또는 `regex`처럼 **유효성 제약**하는 방법. -* 강력하고 사용하기 쉬운 **의존성 주입** 시스템. +* 강력하고 사용하기 쉬운 **의존성 주입** 시스템. * **OAuth2** 지원을 포함한 **JWT tokens** 및 **HTTP Basic**을 갖는 보안과 인증. * (Pydantic 덕분에) **깊은 중첩 JSON 모델**을 선언하는데 더 진보한 (하지만 마찬가지로 쉬운) 기술. +* Strawberry 및 기타 라이브러리와의 **GraphQL** 통합. * (Starlette 덕분에) 많은 추가 기능: * **웹 소켓** - * **GraphQL** * HTTPX 및 `pytest`에 기반한 극히 쉬운 테스트 * **CORS** * **쿠키 세션** * ...기타 등등. -## 성능 +### 앱 배포하기(선택 사항) { #deploy-your-app-optional } + +선택적으로 FastAPI 앱을 FastAPI Cloud에 배포할 수 있습니다. 아직이라면 대기자 명단에 등록해 보세요. 🚀 + +이미 **FastAPI Cloud** 계정이 있다면(대기자 명단에서 초대해 드렸습니다 😉), 한 번의 명령으로 애플리케이션을 배포할 수 있습니다. -독립된 TechEmpower 벤치마크에서 Uvicorn에서 작동하는 FastAPI 어플리케이션이 사용 가능한 가장 빠른 프레임워크 중 하나로 Starlette와 Uvicorn(FastAPI에서 내부적으로 사용)에만 밑돌고 있습니다. (*) +배포하기 전에, 로그인되어 있는지 확인하세요: -자세한 내용은 벤치마크 섹션을 보십시오. +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` -## 선택가능한 의존성 +
+ +그런 다음 앱을 배포하세요: + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +이게 전부입니다! 이제 해당 URL에서 앱에 접근할 수 있습니다. ✨ + +#### FastAPI Cloud 소개 { #about-fastapi-cloud } + +**FastAPI Cloud**는 **FastAPI** 뒤에 있는 동일한 작성자와 팀이 만들었습니다. + +최소한의 노력으로 API를 **빌드**, **배포**, **접근**하는 과정을 간소화합니다. + +FastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데까지 확장해 줍니다. 🎉 + +FastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 스폰서이자 자금 제공자입니다. ✨ + +#### 다른 클라우드 제공자에 배포하기 { #deploy-to-other-cloud-providers } + +FastAPI는 오픈 소스이며 표준을 기반으로 합니다. 선택한 어떤 클라우드 제공자에도 FastAPI 앱을 배포할 수 있습니다. + +클라우드 제공자의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓 + +## 성능 { #performance } + +독립된 TechEmpower 벤치마크에서 Uvicorn에서 작동하는 FastAPI 애플리케이션이 사용 가능한 가장 빠른 Python 프레임워크 중 하나로 Starlette와 Uvicorn(FastAPI에서 내부적으로 사용)에만 밑돌고 있습니다. (*) + +자세한 내용은 벤치마크 섹션을 보십시오. + +## 의존성 { #dependencies } + +FastAPI는 Pydantic과 Starlette에 의존합니다. + +### `standard` 의존성 { #standard-dependencies } + +FastAPI를 `pip install "fastapi[standard]"`로 설치하면 `standard` 그룹의 선택적 의존성이 함께 설치됩니다. Pydantic이 사용하는: @@ -448,21 +528,38 @@ Pydantic이 사용하는: Starlette이 사용하는: -* HTTPX - `TestClient`를 사용하려면 필요. -* jinja2 - 기본 템플릿 설정을 사용하려면 필요. -* python-multipart - `request.form()`과 함께 "parsing"의 지원을 원하면 필요. -* itsdangerous - `SessionMiddleware` 지원을 위해 필요. -* pyyaml - Starlette의 `SchemaGenerator` 지원을 위해 필요 (FastAPI와 쓸때는 필요 없을 것입니다). -* graphene - `GraphQLApp` 지원을 위해 필요. +* httpx - `TestClient`를 사용하려면 필요. +* jinja2 - 기본 템플릿 설정을 사용하려면 필요. +* python-multipart - `request.form()`과 함께 form "parsing" 지원을 원하면 필요. -FastAPI / Starlette이 사용하는: +FastAPI가 사용하는: -* uvicorn - 애플리케이션을 로드하고 제공하는 서버. -* orjson - `ORJSONResponse`을 사용하려면 필요. -* ujson - `UJSONResponse`를 사용하려면 필요. +* uvicorn - 애플리케이션을 로드하고 제공하는 서버를 위한 것입니다. 여기에는 고성능 서빙에 필요한 일부 의존성(예: `uvloop`)이 포함된 `uvicorn[standard]`가 포함됩니다. +* `fastapi-cli[standard]` - `fastapi` 명령을 제공하기 위한 것입니다. + * 여기에는 FastAPI 애플리케이션을 FastAPI Cloud에 배포할 수 있게 해주는 `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 의존성: + +* pydantic-settings - 설정 관리를 위한 것입니다. +* pydantic-extra-types - Pydantic에서 사용할 추가 타입을 위한 것입니다. + +추가 선택적 FastAPI 의존성: + +* orjson - `ORJSONResponse`를 사용하려면 필요. +* ujson - `UJSONResponse`를 사용하려면 필요. -## 라이센스 +## 라이센스 { #license } 이 프로젝트는 MIT 라이센스 조약에 따라 라이센스가 부여됩니다. diff --git a/docs/ko/docs/learn/index.md b/docs/ko/docs/learn/index.md index 7ac3a99b64..0b4d14ff47 100644 --- a/docs/ko/docs/learn/index.md +++ b/docs/ko/docs/learn/index.md @@ -1,5 +1,5 @@ -# 배우기 +# 배우기 { #learn } -여기 **FastAPI**를 배우기 위한 입문 자료와 자습서가 있습니다. +여기 **FastAPI**를 배우기 위한 입문 섹션과 자습서가 있습니다. -여러분은 FastAPI를 배우기 위해 **책**, **강의**, **공식 자료** 그리고 추천받은 방법을 고려할 수 있습니다. 😎 +여러분은 이것을 FastAPI를 배우기 위한 **책**, **강의**, **공식**이자 권장되는 방법으로 생각할 수 있습니다. 😎 diff --git a/docs/ko/docs/project-generation.md b/docs/ko/docs/project-generation.md index dd11fca703..73ea67d3e5 100644 --- a/docs/ko/docs/project-generation.md +++ b/docs/ko/docs/project-generation.md @@ -1,4 +1,4 @@ -# Full Stack FastAPI 템플릿 +# Full Stack FastAPI 템플릿 { #full-stack-fastapi-template } 템플릿은 일반적으로 특정 설정과 함께 제공되지만, 유연하고 커스터마이징이 가능하게 디자인 되었습니다. 이 특성들은 여러분이 프로젝트의 요구사항에 맞춰 수정, 적용을 할 수 있게 해주고, 템플릿이 완벽한 시작점이 되게 해줍니다. 🏁 @@ -6,23 +6,23 @@ GitHub 저장소: Full Stack FastAPI 템플릿 -## 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 (지속적인 배포). diff --git a/docs/ko/docs/python-types.md b/docs/ko/docs/python-types.md index 18d4b341e4..dc264df805 100644 --- a/docs/ko/docs/python-types.md +++ b/docs/ko/docs/python-types.md @@ -1,313 +1,466 @@ -# 파이썬 타입 소개 +# 파이썬 타입 소개 { #python-types-intro } -파이썬은 선택적으로 "타입 힌트(type hints)"를 지원합니다. +파이썬은 선택적으로 "타입 힌트(type hints)"(“type annotations”라고도 함)를 지원합니다. -이러한 **타입 힌트**들은 변수의 타입을 선언할 수 있게 해주는 특수한 구문입니다. +이러한 **"타입 힌트"** 또는 애너테이션은 변수의 타입을 선언할 수 있게 해주는 특수한 구문입니다. -변수의 타입을 지정하면 에디터와 툴이 더 많은 도움을 줄 수 있게 됩니다. +변수의 타입을 선언하면 에디터와 도구가 더 나은 지원을 제공할 수 있습니다. -이 문서는 파이썬 타입 힌트에 대한 **빠른 자습서 / 내용환기** 수준의 문서입니다. 여기서는 **FastAPI**를 쓰기 위한 최소한의 내용만을 다룹니다. +이 문서는 파이썬 타입 힌트에 대한 **빠른 자습서 / 내용 환기**입니다. **FastAPI**와 함께 사용하기 위해 필요한 최소한만 다룹니다... 실제로는 아주 조금만 있으면 됩니다. -**FastAPI**는 타입 힌트에 기반을 두고 있으며, 이는 많은 장점과 이익이 있습니다. +**FastAPI**는 모두 이러한 타입 힌트에 기반을 두고 있으며, 이는 많은 장점과 이점을 제공합니다. -비록 **FastAPI**를 쓰지 않는다고 하더라도, 조금이라도 알아두면 도움이 될 것입니다. +하지만 **FastAPI**를 전혀 사용하지 않더라도, 타입 힌트를 조금만 배워도 도움이 됩니다. /// note | 참고 -파이썬에 능숙하셔서 타입 힌트에 대해 모두 아신다면, 다음 챕터로 건너뛰세요. +파이썬에 능숙하고 타입 힌트에 대해 이미 모두 알고 있다면, 다음 장으로 건너뛰세요. /// -## 동기 부여 +## 동기 부여 { #motivation } -간단한 예제부터 시작해봅시다: +간단한 예제로 시작해봅시다: -{* ../../docs_src/python_types/tutorial001.py *} +{* ../../docs_src/python_types/tutorial001_py39.py *} - -이 프로그램을 실행한 결과값: +이 프로그램을 호출하면 다음이 출력됩니다: ``` John Doe ``` -함수는 아래와 같이 실행됩니다: +이 함수는 다음을 수행합니다: * `first_name`과 `last_name`를 받습니다. -* `title()`로 각 첫 문자를 대문자로 변환시킵니다. -* 두 단어를 중간에 공백을 두고 연결합니다. - -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +* `title()`로 각각의 첫 글자를 대문자로 변환합니다. +* 가운데에 공백을 두고 연결합니다. +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} -### 코드 수정 +### 수정하기 { #edit-it } -이건 매우 간단한 프로그램입니다. +매우 간단한 프로그램입니다. -그런데 처음부터 작성한다고 생각을 해봅시다. +하지만 이제, 이것을 처음부터 작성한다고 상상해봅시다. -여러분은 매개변수를 준비했고, 함수를 정의하기 시작했을 겁니다. +어느 시점엔 함수를 정의하기 시작했고, 매개변수도 준비해두었을 겁니다... -이때 "첫 글자를 대문자로 바꾸는 함수"를 호출해야 합니다. +그런데 "첫 글자를 대문자로 변환하는 그 메서드"를 호출해야 합니다. -`upper`였나? 아니면 `uppercase`? `first_uppercase`? `capitalize`? +`upper`였나요? `uppercase`였나요? `first_uppercase`? `capitalize`? -그때 개발자들의 오랜 친구, 에디터 자동완성을 시도해봅니다. +그 다음, 개발자들의 오랜 친구인 에디터 자동완성을 시도합니다. -당신은 `first_name`를 입력한 뒤 점(`.`)을 입력하고 자동완성을 켜기 위해서 `Ctrl+Space`를 눌렀습니다. +함수의 첫 번째 매개변수인 `first_name`을 입력하고, 점(`.`)을 찍은 다음, 완성을 트리거하기 위해 `Ctrl+Space`를 누릅니다. -하지만 슬프게도 아무런 도움이 되지 않습니다: +하지만, 슬프게도 쓸만한 게 아무것도 없습니다: -### 타입 추가하기 +### 타입 추가하기 { #add-types } 이전 버전에서 한 줄만 수정해봅시다. -저희는 이 함수의 매개변수 부분: +함수의 매개변수인 정확히 이 부분을: ```Python first_name, last_name ``` -을 아래와 같이 바꿀 겁니다: +에서: ```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" ``` -이는 다른 것입니다. +다른 것입니다. -등호(`=`) 대신 콜론(`:`)을 쓰고 있습니다. +등호(`=`)가 아니라 콜론(`:`)을 사용합니다. -일반적으로 타입힌트를 추가한다고 해서 특별하게 어떤 일이 일어나지도 않습니다. +그리고 보통 타입 힌트를 추가해도, 타입 힌트 없이 일어나는 일과 비교해 특별히 달라지는 것은 없습니다. -그렇지만 이제, 다시 함수를 만드는 도중이라고 생각해봅시다. 다만 이번엔 타입 힌트가 있습니다. +하지만 이제, 타입 힌트를 포함해 그 함수를 다시 만드는 중이라고 상상해봅시다. -같은 상황에서 `Ctrl+Space`로 자동완성을 작동시키면, +같은 지점에서 `Ctrl+Space`로 자동완성을 트리거하면 다음이 보입니다: -아래와 같이 "그렇지!"하는 옵션이 나올때까지 스크롤을 내려서 볼 수 있습니다: +그러면 스크롤하며 옵션을 보다가, "기억나는" 것을 찾을 수 있습니다: -## 더 큰 동기부여 - -아래 함수를 보면, 이미 타입 힌트가 적용되어 있는 걸 볼 수 있습니다: +## 더 큰 동기부여 { #more-motivation } -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +이 함수를 확인해보세요. 이미 타입 힌트가 있습니다: +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} -편집기가 변수의 타입을 알고 있기 때문에, 자동완성 뿐 아니라 에러도 확인할 수 있습니다: +에디터가 변수의 타입을 알고 있기 때문에, 자동완성만 되는 게 아니라 오류 검사도 할 수 있습니다: -이제 고쳐야하는 걸 알기 때문에, `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 } -방금 함수의 매개변수로써 타입 힌트를 선언하는 주요 장소를 보았습니다. +방금 타입 힌트를 선언하는 주요 위치를 보았습니다. 함수 매개변수입니다. -이 위치는 여러분이 **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 등 포함)과 호환된다는 뜻입니다. -콜론(`:`) 문법을 이용하여 변수를 선언합니다. +**최신 버전의 Python**을 사용할 수 있다면, 최신 버전용 예제를 사용하세요. 예를 들어 "**Python 3.10+**"처럼, 가장 **좋고 가장 단순한 문법**을 갖게 됩니다. -타입으로는 `List`를 넣어줍니다. +#### List { #list } -이때 배열은 내부 타입을 포함하는 타입이기 때문에 대괄호 안에 넣어줍니다. +예를 들어, `str`의 `list`인 변수를 정의해봅시다. -{* ../../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`이다"라는 뜻입니다. -이렇게 함으로써, 에디터는 배열에 들어있는 아이템을 처리할때도 도움을 줄 수 있게 됩니다: +이렇게 하면, 에디터는 리스트의 아이템을 처리하는 동안에도 지원을 제공할 수 있습니다: -타입이 없으면 이건 거의 불가능이나 다름 없습니다. +타입이 없으면, 이는 거의 불가능합니다. + +변수 `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에는 가능한 타입들을 세로 막대(`|`)로 구분해 넣을 수 있는 **새 문법**도 있습니다. +//// 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`을 사용하는 대안으로, 타입 유니온을 선언하기 위해 세로 막대(`|`)를 사용할 수 있는데, 훨씬 더 좋고 단순합니다. -### 타입으로서의 클래스 +//// -변수의 타입으로 클래스를 선언할 수도 있습니다. +//// 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] *} + +그리고 다시, 에디터의 모든 지원을 받을 수 있습니다: -## Pydantic 모델 +이는 "`one_person`은 `Person` 클래스의 **인스턴스**"라는 뜻입니다. + +"`one_person`은 `Person`이라는 **클래스**다"라는 뜻이 아닙니다. -Pydantic은 데이터 검증(Validation)을 위한 파이썬 라이브러리입니다. +## Pydantic 모델 { #pydantic-models } -당신은 속성들을 포함한 클래스 형태로 "모양(shape)"을 선언할 수 있습니다. +Pydantic은 데이터 검증을 수행하는 파이썬 라이브러리입니다. -그리고 각 속성은 타입을 가지고 있습니다. +속성을 가진 클래스 형태로 데이터의 "모양(shape)"을 선언합니다. -이 클래스를 활용하여서 값을 가지고 있는 인스턴스를 만들게 되면, 필요한 경우에는 적당한 타입으로 변환까지 시키기도 하여 데이터가 포함된 객체를 반환합니다. +그리고 각 속성은 타입을 가집니다. -그리고 결과 객체에 대해서는 에디터의 도움을 받을 수 있게 됩니다. +그 다음 그 클래스의 인스턴스를 몇 가지 값으로 생성하면, 값들을 검증하고, (그런 경우라면) 적절한 타입으로 변환한 뒤, 모든 데이터를 가진 객체를 제공합니다. -Pydantic 공식 문서 예시: +그리고 그 결과 객체에 대해 에디터의 모든 지원을 받을 수 있습니다. -{* ../../docs_src/python_types/tutorial011.py *} +Pydantic 공식 문서의 예시: +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info | 정보 -Pydantic<에 대해 더 배우고 싶다면 공식 문서를 참고하세요. +Pydantic에 대해 더 알아보려면 문서를 확인하세요. /// -**FastAPI**는 모두 Pydantic을 기반으로 되어 있습니다. +**FastAPI**는 모두 Pydantic에 기반을 두고 있습니다. + +이 모든 것은 [자습서 - 사용자 안내서](tutorial/index.md){.internal-link target=_blank}에서 실제로 많이 보게 될 것입니다. + +/// tip | 팁 + +Pydantic은 기본값 없이 `Optional` 또는 `Union[Something, None]`을 사용할 때 특별한 동작이 있습니다. 이에 대해서는 Pydantic 문서의 Required Optional fields에서 더 읽을 수 있습니다. + +/// + +## 메타데이터 애너테이션이 있는 타입 힌트 { #type-hints-with-metadata-annotations } + +파이썬에는 `Annotated`를 사용해 이러한 타입 힌트에 **추가 메타데이터**를 넣을 수 있는 기능도 있습니다. + +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**는 여러 부분에서 타입 힌트의 장점을 취하고 있습니다. +**FastAPI**는 이러한 타입 힌트를 활용해 여러 가지를 합니다. -**FastAPI**에서 타입 힌트와 함께 매개변수를 선언하면 장점은: +**FastAPI**에서는 타입 힌트로 매개변수를 선언하면 다음을 얻습니다: * **에디터 도움**. * **타입 확인**. -...그리고 **FastAPI**는 같은 정의를 아래에도 적용합니다: +...그리고 **FastAPI**는 같은 선언을 다음에도 사용합니다: -* **요구사항 정의**: 요청 경로 매개변수, 쿼리 매개변수, 헤더, 바디, 의존성 등. -* **데이터 변환**: 요청에서 요구한 타입으로. -* **데이터 검증**: 각 요청마다: - * 데이터가 유효하지 않은 경우에는 **자동으로 에러**를 발생합니다. -* OpenAPI를 활용한 **API 문서화**: - * 자동으로 상호작용하는 유저 인터페이스에 쓰이게 됩니다. +* **요구사항 정의**: 요청 경로 매개변수, 쿼리 매개변수, 헤더, 바디, 의존성 등에서. +* **데이터 변환**: 요청에서 필요한 타입으로. +* **데이터 검증**: 각 요청에서: + * 데이터가 유효하지 않을 때 클라이언트에 반환되는 **자동 오류**를 생성합니다. +* OpenAPI를 사용해 API를 **문서화**: + * 자동 상호작용 문서 UI에서 사용됩니다. -위 내용이 다소 추상적일 수도 있지만, 걱정마세요. [자습서 - 사용자 안내서](tutorial/index.md){.internal-link target=_blank}에서 전부 확인 가능합니다. +이 모든 것이 다소 추상적으로 들릴 수도 있습니다. 걱정하지 마세요. [자습서 - 사용자 안내서](tutorial/index.md){.internal-link target=_blank}에서 실제로 확인하게 될 것입니다. -가장 중요한 건, 표준 파이썬 타입을 한 곳에서(클래스를 더하거나, 데코레이터 사용하는 대신) 사용함으로써 **FastAPI**가 당신을 위해 많은 일을 해준다는 사실이죠. +가장 중요한 점은 표준 파이썬 타입을 한 곳에서 사용함으로써(더 많은 클래스, 데코레이터 등을 추가하는 대신) **FastAPI**가 여러분을 위해 많은 일을 해준다는 사실입니다. /// info | 정보 -만약 모든 자습서를 다 보았음에도 타입에 대해서 더 보고자 방문한 경우에는 `mypy`에서 제공하는 "cheat sheet"이 좋은 자료가 될 겁니다. +자습서를 모두 끝내고 타입에 대해 더 알아보기 위해 다시 돌아왔다면, 좋은 자료로 `mypy`의 "cheat sheet"가 있습니다. /// diff --git a/docs/ko/docs/resources/index.md b/docs/ko/docs/resources/index.md index e804dd4d56..477b93a584 100644 --- a/docs/ko/docs/resources/index.md +++ b/docs/ko/docs/resources/index.md @@ -1,3 +1,3 @@ -# 리소스 +# 리소스 { #resources } -추가 리소스, 외부 링크, 기사 등. ✈️ +추가 리소스, 외부 링크 등. ✈️ diff --git a/docs/ko/docs/tutorial/background-tasks.md b/docs/ko/docs/tutorial/background-tasks.md index 9c4d57481f..9e868f2fa7 100644 --- a/docs/ko/docs/tutorial/background-tasks.md +++ b/docs/ko/docs/tutorial/background-tasks.md @@ -1,84 +1,86 @@ -# 백그라운드 작업 +# 백그라운드 작업 { #background-tasks } -FastAPI에서는 응답을 반환한 후에 실행할 백그라운드 작업을 정의할 수 있습니다. +FastAPI에서는 응답을 반환한 *후에* 실행할 백그라운드 작업을 정의할 수 있습니다. -백그라운드 작업은 클라이언트가 응답을 받기 위해 작업이 완료될 때까지 기다릴 필요가 없기 때문에 요청 후에 발생해야하는 작업에 매우 유용합니다. +백그라운드 작업은 요청 후에 발생해야 하지만, 클라이언트가 응답을 받기 전에 작업이 완료될 때까지 기다릴 필요가 없는 작업에 유용합니다. -이러한 작업에는 다음이 포함됩니다. +예를 들면 다음과 같습니다. -* 작업을 수행한 후 전송되는 이메일 알림 - * 이메일 서버에 연결하고 이메일을 전송하는 것은 (몇 초 정도) "느린" 경향이 있으므로, 응답은 즉시 반환하고 이메일 알림은 백그라운드에서 전송하는 게 가능합니다. +* 작업을 수행한 후 전송되는 이메일 알림: + * 이메일 서버에 연결하고 이메일을 전송하는 것은 (몇 초 정도) "느린" 경향이 있으므로, 응답은 즉시 반환하고 이메일 알림은 백그라운드에서 전송할 수 있습니다. * 데이터 처리: - * 예를 들어 처리에 오랜 시간이 걸리는 데이터를 받았을 때 "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 } -백그라운드 작업으로 실행할 함수를 정의합니다. +백그라운드 작업으로 실행할 함수를 생성합니다. -이것은 단순히 매개변수를 받을 수 있는 표준 함수일 뿐입니다. +이는 매개변수를 받을 수 있는 표준 함수일 뿐입니다. -**FastAPI**는 이것이 `async def` 함수이든, 일반 `def` 함수이든 내부적으로 이를 올바르게 처리합니다. +`async def` 함수일 수도, 일반 `def` 함수일 수도 있으며, **FastAPI**가 이를 올바르게 처리하는 방법을 알고 있습니다. -이 경우, 아래 작업은 파일에 쓰는 함수입니다. (이메일 보내기 시물레이션) +이 경우 작업 함수는 파일에 쓰기를 수행합니다(이메일 전송을 시뮬레이션). -그리고 이 작업은 `async`와 `await`를 사용하지 않으므로 일반 `def` 함수로 선언합니다. +그리고 쓰기 작업은 `async`와 `await`를 사용하지 않으므로, 일반 `def`로 함수를 정의합니다: -{* ../../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`를 의존성 주입 시스템과 함께 사용하면 _경로 작동 함수_, 종속성, 하위 종속성 등 여러 수준에서 BackgroundTasks 유형의 매개변수를 선언할 수 있습니다. +`BackgroundTasks`는 의존성 주입 시스템에서도 동작하며, *경로 처리 함수*, 의존성(dependable), 하위 의존성 등 여러 수준에서 `BackgroundTasks` 타입의 매개변수를 선언할 수 있습니다. -**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] *} -요청에 쿼리가 있는 경우 백그라운드 작업의 로그에 기록됩니다. -그리고 _경로 작동 함수_ 에서 생성된 또 다른 백그라운드 작업은 경로 매개 변수를 활용하여 사용하여 메시지를 작성합니다. +이 예제에서는 응답이 전송된 *후에* 메시지가 `log.txt` 파일에 작성됩니다. -## 기술적 세부사항 +요청에 쿼리가 있었다면, 백그라운드 작업으로 로그에 작성됩니다. + +그 다음 *경로 처리 함수*에서 생성된 또 다른 백그라운드 작업이 `email` 경로 매개변수를 사용해 메시지를 작성합니다. + +## 기술적 세부사항 { #technical-details } `BackgroundTasks` 클래스는 `starlette.background`에서 직접 가져옵니다. -`BackgroundTasks` 클래스는 FastAPI에서 직접 임포트하거나 포함하기 때문에 실수로 `BackgroundTask` (끝에 `s`가 없음)을 임포트하더라도 starlette.background에서 `BackgroundTask`를 가져오는 것을 방지할 수 있습니다. +FastAPI에 직접 임포트/포함되어 있으므로 `fastapi`에서 임포트할 수 있고, 실수로 `starlette.background`에서 대안인 `BackgroundTask`(끝에 `s`가 없음)를 임포트하는 것을 피할 수 있습니다. -(`BackgroundTask`가 아닌) `BackgroundTasks`를 사용하면, _경로 작동 함수_ 매개변수로 사용할 수 있게 되고 나머지는 **FastAPI**가 대신 처리하도록 할 수 있습니다. 이것은 `Request` 객체를 직접 사용하는 것과 같은 방식입니다. +`BackgroundTask`가 아닌 `BackgroundTasks`만 사용하면, 이를 *경로 처리 함수*의 매개변수로 사용할 수 있고 나머지는 **FastAPI**가 `Request` 객체를 직접 사용할 때처럼 대신 처리해 줍니다. -FastAPI에서 `BackgroundTask`를 단독으로 사용하는 것은 여전히 가능합니다. 하지만 객체를 코드에서 생성하고, 이 객체를 포함하는 Starlette `Response`를 반환해야 합니다. +FastAPI에서 `BackgroundTask`만 단독으로 사용하는 것도 가능하지만, 코드에서 객체를 생성하고 이를 포함하는 Starlette `Response`를 반환해야 합니다. -`Starlette의 공식 문서`에서 백그라운드 작업에 대한 자세한 내용을 확인할 수 있습니다. +더 자세한 내용은 Starlette의 Background Tasks 공식 문서에서 확인할 수 있습니다. -## 경고 +## 주의사항 { #caveat } -만약 무거운 백그라운드 작업을 수행해야하고 동일한 프로세스에서 실행할 필요가 없는 경우 (예: 메모리, 변수 등을 공유할 필요가 없음) `Celery`와 같은 큰 도구를 사용하면 도움이 될 수 있습니다. +무거운 백그라운드 계산을 수행해야 하고, 반드시 동일한 프로세스에서 실행할 필요가 없다면(예: 메모리, 변수 등을 공유할 필요가 없음) Celery 같은 더 큰 도구를 사용하는 것이 도움이 될 수 있습니다. -RabbitMQ 또는 Redis와 같은 메시지/작업 큐 시스템 보다 복잡한 구성이 필요한 경향이 있지만, 여러 작업 프로세스를 특히 여러 서버의 백그라운드에서 실행할 수 있습니다. +이들은 RabbitMQ나 Redis 같은 메시지/작업 큐 관리자 등 더 복잡한 설정을 필요로 하는 경향이 있지만, 여러 프로세스에서, 특히 여러 서버에서 백그라운드 작업을 실행할 수 있습니다. -그러나 동일한 FastAPI 앱에서 변수 및 개체에 접근해야햐는 작은 백그라운드 수행이 필요한 경우 (예 : 알림 이메일 보내기) 간단하게 `BackgroundTasks`를 사용해보세요. +하지만 동일한 **FastAPI** 앱의 변수와 객체에 접근해야 하거나(또는 이메일 알림 전송처럼) 작은 백그라운드 작업을 수행해야 한다면, `BackgroundTasks`를 간단히 사용하면 됩니다. -## 요약 +## 요약 { #recap } -백그라운드 작업을 추가하기 위해 _경로 작동 함수_ 에 매개변수로 `BackgroundTasks`를 가져오고 사용합니다. +*경로 처리 함수*와 의존성에서 매개변수로 `BackgroundTasks`를 임포트해 사용하여 백그라운드 작업을 추가합니다. diff --git a/docs/ko/docs/tutorial/body-fields.md b/docs/ko/docs/tutorial/body-fields.md index 4708e7099f..c98734ab37 100644 --- a/docs/ko/docs/tutorial/body-fields.md +++ b/docs/ko/docs/tutorial/body-fields.md @@ -1,8 +1,8 @@ -# 본문 - 필드 +# 본문 - 필드 { #body-fields } -`Query`, `Path`와 `Body`를 사용해 *경로 작동 함수* 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 `Field`를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다. +`Query`, `Path`와 `Body`를 사용해 *경로 처리 함수* 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 `Field`를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다. -## `Field` 임포트 +## `Field` 임포트 { #import-field } 먼저 이를 임포트해야 합니다: @@ -14,7 +14,7 @@ /// -## 모델 어트리뷰트 선언 +## 모델 어트리뷰트 선언 { #declare-model-attributes } 그 다음 모델 어트리뷰트와 함께 `Field`를 사용할 수 있습니다: @@ -22,7 +22,7 @@ `Field`는 `Query`, `Path`와 `Body`와 같은 방식으로 동작하며, 모두 같은 매개변수들 등을 가집니다. -/// note | 기술적 세부사항 +/// note | 기술 세부사항 실제로 `Query`, `Path`등, 여러분이 앞으로 볼 다른 것들은 공통 클래스인 `Param` 클래스의 서브클래스 객체를 만드는데, 그 자체로 Pydantic의 `FieldInfo` 클래스의 서브클래스입니다. @@ -36,11 +36,11 @@ /// tip | 팁 -주목할 점은 타입, 기본 값 및 `Field`로 이루어진 각 모델 어트리뷰트가 `Path`, `Query`와 `Body`대신 `Field`를 사용하는 *경로 작동 함수*의 매개변수와 같은 구조를 가진다는 점 입니다. +주목할 점은 타입, 기본 값 및 `Field`로 이루어진 각 모델 어트리뷰트가 `Path`, `Query`와 `Body`대신 `Field`를 사용하는 *경로 처리 함수*의 매개변수와 같은 구조를 가진다는 점 입니다. /// -## 별도 정보 추가 +## 별도 정보 추가 { #add-extra-information } `Field`, `Query`, `Body`, 그 외 안에 별도 정보를 선언할 수 있습니다. 이는 생성된 JSON 스키마에 포함됩니다. @@ -53,7 +53,7 @@ /// -## 요약 +## 요약 { #recap } 모델 어트리뷰트를 위한 추가 검증과 메타데이터 선언하기 위해 Pydantic의 `Field` 를 사용할 수 있습니다. diff --git a/docs/ko/docs/tutorial/body-multiple-params.md b/docs/ko/docs/tutorial/body-multiple-params.md index edf892dfab..701351e637 100644 --- a/docs/ko/docs/tutorial/body-multiple-params.md +++ b/docs/ko/docs/tutorial/body-multiple-params.md @@ -1,26 +1,24 @@ -# 본문 - 다중 매개변수 +# 본문 - 다중 매개변수 { #body-multiple-parameters } -지금부터 `Path`와 `Query`를 어떻게 사용하는지 확인하겠습니다. +이제 `Path`와 `Query`를 어떻게 사용하는지 확인했으니, 요청 본문 선언에 대한 더 고급 사용법을 살펴보겠습니다. -요청 본문 선언에 대한 심화 사용법을 알아보겠습니다. +## `Path`, `Query` 및 본문 매개변수 혼합 { #mix-path-query-and-body-parameters } -## `Path`, `Query` 및 본문 매개변수 혼합 +먼저, 물론 `Path`, `Query` 및 요청 본문 매개변수 선언을 자유롭게 혼합해서 사용할 수 있고, **FastAPI**는 어떤 동작을 할지 압니다. -당연하게 `Path`, `Query` 및 요청 본문 매개변수 선언을 자유롭게 혼합해서 사용할 수 있고, **FastAPI**는 어떤 동작을 할지 압니다. +또한 기본 값을 `None`으로 설정해 본문 매개변수를 선택사항으로 선언할 수 있습니다: -또한, 기본 값을 `None`으로 설정해 본문 매개변수를 선택사항으로 선언할 수 있습니다. - -{* ../../docs_src/body_multiple_params/tutorial001.py hl[19:21] *} +{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *} /// note | 참고 -이 경우에는 본문으로 부터 가져온 ` item`은 기본값이 `None`이기 때문에, 선택사항이라는 점을 유의해야 합니다. +이 경우에는 본문에서 가져올 `item`이 선택사항이라는 점을 유의하세요. 기본값이 `None`이기 때문입니다. /// -## 다중 본문 매개변수 +## 다중 본문 매개변수 { #multiple-body-parameters } -이전 예제에서 보듯이, *경로 작동*은 아래와 같이 `Item` 속성을 가진 JSON 본문을 예상합니다: +이전 예제에서, *경로 처리*는 아래처럼 `Item`의 속성을 가진 JSON 본문을 예상합니다: ```JSON { @@ -33,11 +31,12 @@ 하지만, 다중 본문 매개변수 역시 선언할 수 있습니다. 예. `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 모델입니다). -그래서, 본문의 매개변수 이름을 키(필드 명)로 사용할 수 있고, 다음과 같은 본문을 예측합니다: +그래서, 본문에서 매개변수 이름을 키(필드 이름)로 사용하고, 다음과 같은 본문을 예상합니다: ```JSON { @@ -56,29 +55,28 @@ /// 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`라는 다른 키를 두고 싶을 수 있습니다. -단일 값을 그대로 선언한다면, **FastAPI**는 쿼리 매개변수로 가정할 것입니다. +단일 값이므로 그대로 선언하면, **FastAPI**는 이를 쿼리 매개변수라고 가정할 것입니다. -하지만, **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 { @@ -96,58 +94,55 @@ FastAPI는 요청을 자동으로 변환해, 매개변수의 `item`과 `user`를 } ``` -다시 말해, 데이터 타입, 검증, 문서 등을 변환합니다. +다시 말해, 데이터 타입을 변환하고, 검증하고, 문서화하는 등의 작업을 수행합니다. -## 다중 본문 매개변수와 쿼리 +## 다중 본문 매개변수와 쿼리 { #multiple-body-params-and-query } -당연히, 필요할 때마다 추가적인 쿼리 매개변수를 선언할 수 있고, 이는 본문 매개변수에 추가됩니다. +물론, 필요할 때마다 어떤 본문 매개변수에 추가로 쿼리 매개변수도 선언할 수 있습니다. -기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `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", @@ -158,12 +153,23 @@ item: Item = Body(..., embed=True) } ``` -## 정리 +다음 대신에: + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 +} +``` + +## 정리 { #recap } -요청이 단 한개의 본문을 가지고 있더라도, *경로 작동 함수*로 다중 본문 매개변수를 추가할 수 있습니다. +요청은 본문을 하나만 가질 수 있지만, *경로 처리 함수*에 다중 본문 매개변수를 추가할 수 있습니다. -하지만, **FastAPI**는 이를 처리하고, 함수에 올바른 데이터를 제공하며, *경로 작동*으로 올바른 스키마를 검증하고 문서화 합니다. +하지만 **FastAPI**는 이를 처리하고, 함수에 올바른 데이터를 제공하며, *경로 처리*에서 올바른 스키마를 검증하고 문서화합니다. -또한, 단일 값을 본문의 일부로 받도록 선언할 수 있습니다. +또한 단일 값을 본문의 일부로 받도록 선언할 수 있습니다. -그리고 **FastAPI**는 단 한개의 매개변수가 선언 되더라도, 본문 내의 키로 삽입 시킬 수 있습니다. +그리고 단 하나의 매개변수만 선언되어 있더라도, **FastAPI**에 본문을 키 안에 삽입하도록 지시할 수 있습니다. diff --git a/docs/ko/docs/tutorial/body-nested-models.md b/docs/ko/docs/tutorial/body-nested-models.md index ebd7b3ba6a..4a8c1afc13 100644 --- a/docs/ko/docs/tutorial/body-nested-models.md +++ b/docs/ko/docs/tutorial/body-nested-models.md @@ -1,35 +1,26 @@ -# 본문 - 중첩 모델 +# 본문 - 중첩 모델 { #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] ``` 이 모든 것은 타입 선언을 위한 표준 파이썬 문법입니다. @@ -38,45 +29,45 @@ 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) 문자열이어야 할 것 같습니다. +그런데 생각해보니 태그는 반복되면 안 되고, 아마 고유한 문자열이어야 할 것입니다. -그리고 파이썬은 집합을 위한 특별한 데이터 타입 `set`이 있습니다. +그리고 파이썬에는 고유한 항목들의 집합을 위한 특별한 데이터 타입 `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 } -예를 들어, `Image` 모델을 선언할 수 있습니다: +예를 들어, `Image` 모델을 정의할 수 있습니다: -{* ../../docs_src/body_nested_models/tutorial004.py hl[9:11] *} +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *} -### 서브모듈을 타입으로 사용 +### 서브모델을 타입으로 사용 { #use-the-submodel-as-a-type } -그리고 어트리뷰트의 타입으로 사용할 수 있습니다: +그리고 이를 어트리뷰트의 타입으로 사용할 수 있습니다: -{* ../../docs_src/body_nested_models/tutorial004.py hl[20] *} +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *} 이는 **FastAPI**가 다음과 유사한 본문을 기대한다는 것을 의미합니다: @@ -94,32 +85,32 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다. } ``` -다시 한번, **FastAPI**를 사용하여 해당 선언을 함으로써 얻는 것은: +다시 한번, **FastAPI**로 그 선언만 해도 얻는 것은: * 중첩 모델도 편집기 지원(자동완성 등) * 데이터 변환 * 데이터 검증 * 자동 문서화 -## 특별한 타입과 검증 +## 특별한 타입과 검증 { #special-types-and-validation } -`str`, `int`, `float` 등과 같은 단일 타입과는 별개로, `str`을 상속하는 더 복잡한 단일 타입을 사용할 수 있습니다. +`str`, `int`, `float` 등과 같은 일반적인 단일 타입과는 별개로, `str`을 상속하는 더 복잡한 단일 타입을 사용할 수 있습니다. -모든 옵션을 보려면, Pydantic's exotic types 문서를 확인하세요. 다음 장에서 몇가지 예제를 볼 수 있습니다. +사용할 수 있는 모든 옵션을 보려면 Pydantic의 Type Overview를 확인하세요. 다음 장에서 몇 가지 예제를 볼 수 있습니다. -예를 들어 `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] *} -이 문자열이 유효한 URL인지 검사하고 JSON 스키마/OpenAPI로 문서화 됩니다. +이 문자열은 유효한 URL인지 검사되며, JSON Schema / OpenAPI에도 그에 맞게 문서화됩니다. -## 서브모델 리스트를 갖는 어트리뷰트 +## 서브모델 리스트를 갖는 어트리뷰트 { #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] *} -아래와 같은 JSON 본문으로 예상(변환, 검증, 문서화 등을)합니다: +아래와 같은 JSON 본문을 예상(변환, 검증, 문서화 등)합니다: ```JSON hl_lines="11" { @@ -147,84 +138,84 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다. /// info | 정보 -`images` 키가 어떻게 이미지 객체 리스트를 갖는지 주목하세요. +`images` 키가 이제 이미지 객체 리스트를 갖는지 주목하세요. /// -## 깊게 중첩된 모델 +## 깊게 중첩된 모델 { #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 모델에서와 마찬가지로 함수의 매개변수에서 타입을 선언할 수 있습니다: +예상되는 JSON 본문의 최상위 값이 JSON `array`(파이썬 `list`)라면, Pydantic 모델에서와 마찬가지로 함수의 매개변수에서 타입을 선언할 수 있습니다: ```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 } -그리고 어디서나 편집기 지원을 받을수 있습니다. +그리고 어디서나 편집기 지원을 받을 수 있습니다. 리스트 내부 항목의 경우에도: -Pydantic 모델 대신에 `dict`를 직접 사용하여 작업할 경우, 이러한 편집기 지원을 받을수 없습니다. +Pydantic 모델 대신 `dict`로 직접 작업한다면 이런 종류의 편집기 지원을 받을 수 없습니다. -하지만 수신한 딕셔너리가 자동으로 변환되고 출력도 자동으로 JSON으로 변환되므로 걱정할 필요는 없습니다. +하지만 그 부분에 대해서도 걱정할 필요는 없습니다. 들어오는 dict는 자동으로 변환되고, 출력도 자동으로 JSON으로 변환됩니다. -## 단독 `dict`의 본문 +## 임의의 `dict` 본문 { #bodies-of-arbitrary-dicts } -일부 타입의 키와 다른 타입의 값을 사용하여 `dict`로 본문을 선언할 수 있습니다. +또한 키는 어떤 타입이고 값은 다른 타입인 `dict`로 본문을 선언할 수 있습니다. -(Pydantic을 사용한 경우처럼) 유효한 필드/어트리뷰트 이름이 무엇인지 알 필요가 없습니다. +이렇게 하면 (Pydantic 모델을 사용하는 경우처럼) 유효한 필드/어트리뷰트 이름이 무엇인지 미리 알 필요가 없습니다. -아직 모르는 키를 받으려는 경우 유용합니다. +아직 모르는 키를 받으려는 경우에 유용합니다. --- -다른 유용한 경우는 다른 타입의 키를 가질 때입니다. 예. `int`. +또 다른 유용한 경우는 다른 타입(예: `int`)의 키를 갖고 싶을 때입니다. 여기서 그 경우를 볼 것입니다. -이 경우, `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이 이를 변환하고 검증합니다. -그러므로 `weights`로 받은 `dict`는 실제로 `int` 키와 `float` 값을 가집니다. +그리고 `weights`로 받는 `dict`는 실제로 `int` 키와 `float` 값을 갖게 됩니다. /// -## 요약 +## 요약 { #recap } -**FastAPI**를 사용하면 Pydantic 모델이 제공하는 최대 유연성을 확보하면서 코드를 간단하고 짧게, 그리고 우아하게 유지할 수 있습니다. +**FastAPI**를 사용하면 Pydantic 모델이 제공하는 최대 유연성을 확보하면서 코드를 간단하고 짧고 우아하게 유지할 수 있습니다. -물론 아래의 이점도 있습니다: +하지만 아래의 모든 이점도 있습니다: -* 편집기 지원 (자동완성이 어디서나!) -* 데이터 변환 (일명 파싱/직렬화) +* 편집기 지원(어디서나 자동완성!) +* 데이터 변환(일명 파싱/직렬화) * 데이터 검증 * 스키마 문서화 * 자동 문서 diff --git a/docs/ko/docs/tutorial/body.md b/docs/ko/docs/tutorial/body.md index b3914fa4b4..1e66c60c22 100644 --- a/docs/ko/docs/tutorial/body.md +++ b/docs/ko/docs/tutorial/body.md @@ -1,10 +1,10 @@ -# 요청 본문 +# 요청 본문 { #request-body } 클라이언트(브라우저라고 해봅시다)로부터 여러분의 API로 데이터를 보내야 할 때, **요청 본문**으로 보냅니다. **요청** 본문은 클라이언트에서 API로 보내지는 데이터입니다. **응답** 본문은 API가 클라이언트로 보내는 데이터입니다. -여러분의 API는 대부분의 경우 **응답** 본문을 보내야 합니다. 하지만 클라이언트는 **요청** 본문을 매 번 보낼 필요가 없습니다. +여러분의 API는 대부분의 경우 **응답** 본문을 보내야 합니다. 하지만 클라이언트는 항상 **요청 본문**을 보낼 필요는 없고, 때로는 (쿼리 매개변수와 함께) 어떤 경로만 요청하고 본문은 보내지 않을 수도 있습니다. **요청** 본문을 선언하기 위해서 모든 강력함과 이점을 갖춘 Pydantic 모델을 사용합니다. @@ -18,13 +18,13 @@ /// -## Pydantic의 `BaseModel` 임포트 +## Pydantic의 `BaseModel` 임포트 { #import-pydantics-basemodel } 먼저 `pydantic`에서 `BaseModel`를 임포트해야 합니다: {* ../../docs_src/body/tutorial001_py310.py hl[2] *} -## 여러분의 데이터 모델 만들기 +## 여러분의 데이터 모델 만들기 { #create-your-data-model } `BaseModel`를 상속받은 클래스로 여러분의 데이터 모델을 선언합니다. @@ -32,6 +32,7 @@ {* ../../docs_src/body/tutorial001_py310.py hl[5:9] *} + 쿼리 매개변수를 선언할 때와 같이, 모델 어트리뷰트가 기본 값을 가지고 있어도 이는 필수가 아닙니다. 그외에는 필수입니다. 그저 `None`을 사용하여 선택적으로 만들 수 있습니다. 예를 들면, 위의 이 모델은 JSON "`object`" (혹은 파이썬 `dict`)을 다음과 같이 선언합니다: @@ -39,7 +40,7 @@ ```JSON { "name": "Foo", - "description": "선택적인 설명란", + "description": "An optional description", "price": 45.2, "tax": 3.5 } @@ -54,15 +55,15 @@ } ``` -## 매개변수로서 선언하기 +## 매개변수로서 선언하기 { #declare-it-as-a-parameter } -여러분의 *경로 작동*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다. +여러분의 *경로 처리*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다. {* ../../docs_src/body/tutorial001_py310.py hl[16] *} ...그리고 만들어낸 모델인 `Item`으로 타입을 선언합니다. -## 결과 +## 결과 { #results } 위에서의 단순한 파이썬 타입 선언으로, **FastAPI**는 다음과 같이 동작합니다: @@ -72,20 +73,20 @@ * 만약 데이터가 유효하지 않다면, 정확히 어떤 것이 그리고 어디에서 데이터가 잘 못 되었는지 지시하는 친절하고 명료한 에러를 반환할 것입니다. * 매개변수 `item`에 포함된 수신 데이터를 제공합니다. * 함수 내에서 매개변수를 `Item` 타입으로 선언했기 때문에, 모든 어트리뷰트와 그에 대한 타입에 대한 편집기 지원(완성 등)을 또한 받을 수 있습니다. -* 여러분의 모델을 위한 JSON 스키마 정의를 생성합니다. 여러분의 프로젝트에 적합하다면 여러분이 사용하고 싶은 곳 어디에서나 사용할 수 있습니다. -* 이러한 스키마는, 생성된 OpenAPI 스키마 일부가 될 것이며, 자동 문서화 UI에 사용됩니다. +* 여러분의 모델을 위한 JSON Schema 정의를 생성합니다. 여러분의 프로젝트에 적합하다면 여러분이 사용하고 싶은 곳 어디에서나 사용할 수 있습니다. +* 이러한 스키마는, 생성된 OpenAPI 스키마 일부가 될 것이며, 자동 문서화 UIs에 사용됩니다. -## 자동 문서화 +## 자동 문서화 { #automatic-docs } 모델의 JSON 스키마는 생성된 OpenAPI 스키마에 포함되며 대화형 API 문서에 표시됩니다: -이를 필요로 하는 각각의 *경로 작동*내부의 API 문서에도 사용됩니다: +이를 필요로 하는 각각의 *경로 처리* 내부의 API 문서에도 사용됩니다: -## 편집기 지원 +## 편집기 지원 { #editor-support } 편집기에서, 함수 내에서 타입 힌트와 완성을 어디서나 (만약 Pydantic model 대신에 `dict`을 받을 경우 나타나지 않을 수 있습니다) 받을 수 있습니다: @@ -97,13 +98,13 @@ 단순한 우연이 아닙니다. 프레임워크 전체가 이러한 디자인을 중심으로 설계되었습니다. -그 어떤 실행 전에, 모든 편집기에서 작동할 수 있도록 보장하기 위해 설계 단계에서 혹독하게 테스트되었습니다. +그 어떤 구현 전에, 모든 편집기에서 작동할 수 있도록 보장하기 위해 설계 단계에서 혹독하게 테스트되었습니다. 이를 지원하기 위해 Pydantic 자체에서 몇몇 변경점이 있었습니다. 이전 스크린샷은 Visual Studio Code를 찍은 것입니다. -하지만 똑같은 편집기 지원을 PyCharm에서 받을 수 있거나, 대부분의 다른 편집기에서도 받을 수 있습니다: +하지만 똑같은 편집기 지원을 PyCharm와 대부분의 다른 파이썬 편집기에서도 받을 수 있습니다: @@ -113,21 +114,21 @@ 다음 사항을 포함해 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 } 경로 매개변수와 요청 본문을 동시에 선언할 수 있습니다. @@ -135,7 +136,8 @@ {* ../../docs_src/body/tutorial003_py310.py hl[15:16] *} -## 요청 본문 + 경로 + 쿼리 매개변수 + +## 요청 본문 + 경로 + 쿼리 매개변수 { #request-body-path-query-parameters } **본문**, **경로** 그리고 **쿼리** 매개변수 모두 동시에 선언할 수도 있습니다. @@ -153,10 +155,12 @@ 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} 문서를 확인하세요. diff --git a/docs/ko/docs/tutorial/cookie-param-models.md b/docs/ko/docs/tutorial/cookie-param-models.md index e7eef0b1de..00238d1b79 100644 --- a/docs/ko/docs/tutorial/cookie-param-models.md +++ b/docs/ko/docs/tutorial/cookie-param-models.md @@ -1,8 +1,8 @@ -# 쿠키 매개변수 모델 +# 쿠키 매개변수 모델 { #cookie-parameter-models } 관련있는 **쿠키**들의 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다. 🍪 -이를 통해 **여러 위치**에서 **모델을 재사용** 할 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😍 +이를 통해 **여러 위치**에서 **모델을 재사용** 할 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😎 /// note | 참고 @@ -16,7 +16,7 @@ /// -## Pydantic 모델을 사용한 쿠키 +## Pydantic 모델을 사용한 쿠키 { #cookies-with-a-pydantic-model } **Pydantic 모델**에 필요한 **쿠키** 매개변수를 선언한 다음, 해당 매개변수를 `Cookie`로 선언합니다: @@ -24,7 +24,7 @@ **FastAPI**는 요청에서 받은 **쿠키**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다. -## 문서 확인하기 +## 문서 확인하기 { #check-the-docs } 문서 UI `/docs`에서 정의한 쿠키를 볼 수 있습니다: @@ -36,27 +36,27 @@ 명심하세요, 내부적으로 **브라우저는 쿠키를 특별한 방식으로 처리**하기 때문에 **자바스크립트**가 쉽게 쿠키를 건드릴 수 **없습니다**. -`/docs`에서 **API 문서 UI**로 이동하면 *경로 작업*에 대한 쿠키의 **문서**를 볼 수 있습니다. +`/docs`에서 **API 문서 UI**로 이동하면 *경로 처리*에 대한 쿠키의 **문서**를 볼 수 있습니다. 하지만 아무리 **데이터를 입력**하고 "실행(Execute)"을 클릭해도, 문서 UI는 **자바스크립트**로 작동하기 때문에 쿠키는 전송되지 않고, 아무 값도 쓰지 않은 것처럼 **오류** 메시지를 보게 됩니다. /// -## 추가 쿠키 금지하기 +## 추가 쿠키 금지하기 { #forbid-extra-cookies } 일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 쿠키를 **제한**할 수 있습니다. -이제 API는 자신의 쿠키 동의를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪 +이제 API는 자신의 cookie consent를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪 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] *} 클라이언트가 **추가 쿠키**를 보내려고 시도하면, **오류** 응답을 받게 됩니다. -API가 거부하는데도 동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들. 🍪 +동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들, API가 거부하는데도. 🍪 -예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` 쿠키가 허용되지 않는다는 **오류** 응답을 받게 됩니다: +예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` 쿠키가 허용되지 않는다는 **오류** 응답을 받게 됩니다: ```json { @@ -71,6 +71,6 @@ Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forb } ``` -## 요약 +## 요약 { #summary } -**Pydantic 모델**을 사용하여 **FastAPI**에서 **쿠키**를 선언할 수 있습니다. 😍 +**Pydantic 모델**을 사용하여 **FastAPI**에서 **쿠키**를 선언할 수 있습니다. 😎 diff --git a/docs/ko/docs/tutorial/cookie-params.md b/docs/ko/docs/tutorial/cookie-params.md index fba756d498..0591a5e96b 100644 --- a/docs/ko/docs/tutorial/cookie-params.md +++ b/docs/ko/docs/tutorial/cookie-params.md @@ -1,14 +1,14 @@ -# 쿠키 매개변수 +# 쿠키 매개변수 { #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`처럼 동일한 구조를 사용하는 쿠키 매개변수를 선언합니다. @@ -20,7 +20,7 @@ `Cookie`는 `Path` 및 `Query`의 "자매"클래스입니다. 이 역시 동일한 공통 `Param` 클래스를 상속합니다. -`Query`, `Path`, `Cookie` 그리고 다른 것들은 `fastapi`에서 임포트 할 때, 실제로는 특별한 클래스를 반환하는 함수임을 기억하세요. +하지만 `fastapi`에서 `Query`, `Path`, `Cookie` 그리고 다른 것들을 임포트할 때, 실제로는 특별한 클래스를 반환하는 함수임을 기억하세요. /// @@ -30,6 +30,16 @@ /// -## 요약 +/// info | 정보 + +**브라우저는 쿠키를** 내부적으로 특별한 방식으로 처리하기 때문에, **JavaScript**가 쉽게 쿠키를 다루도록 허용하지 않는다는 점을 염두에 두세요. + +`/docs`의 **API docs UI**로 이동하면 *경로 처리*에 대한 쿠키 **문서**를 확인할 수 있습니다. + +하지만 **데이터를 채우고** "Execute"를 클릭하더라도, docs UI는 **JavaScript**로 동작하기 때문에 쿠키가 전송되지 않고, 아무 값도 입력하지 않은 것처럼 **오류** 메시지를 보게 될 것입니다. + +/// + +## 요약 { #recap } -`Cookie`는 `Query`, `Path`와 동일한 패턴을 사용하여 선언합니다. +`Query`와 `Path`에서 사용하는 것과 동일한 공통 패턴으로, `Cookie`를 사용해 쿠키를 선언합니다. diff --git a/docs/ko/docs/tutorial/cors.md b/docs/ko/docs/tutorial/cors.md index 1ef5a74803..0f3948a3dc 100644 --- a/docs/ko/docs/tutorial/cors.md +++ b/docs/ko/docs/tutorial/cors.md @@ -1,10 +1,10 @@ -# 교차 출처 리소스 공유 +# CORS (교차-출처 리소스 공유) { #cors-cross-origin-resource-sharing } -CORS 또는 "교차-출처 리소스 공유"란, 브라우저에서 동작하는 프론트엔드가 자바스크립트로 코드로 백엔드와 통신하고, 백엔드는 해당 프론트엔드와 다른 "출처"에 존재하는 상황을 의미합니다. +CORS 또는 "Cross-Origin Resource Sharing"란, 브라우저에서 실행되는 프론트엔드에 백엔드와 통신하는 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`)의 조합을 의미합니다. 따라서, 아래는 모두 상이한 출처입니다: @@ -12,74 +12,78 @@ * `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)" 목록을 가지고 있어야 합니다. -이 경우, 프론트엔드가 제대로 동작하기 위해 `http://localhost:8080`을 목록에 포함해야 합니다. +이 경우, `:8080`-프론트엔드가 올바르게 동작하려면 목록에 `http://localhost:8080`이 포함되어야 합니다. -## 와일드카드 +## 와일드카드 { #wildcards } -모든 출처를 허용하기 위해 목록을 `"*"` ("와일드카드")로 선언하는 것도 가능합니다. +또한 목록을 `"*"`("와일드카드")로 선언해 모두 허용된다고 말할 수도 있습니다. -하지만 이것은 특정한 유형의 통신만을 허용하며, 쿠키 및 액세스 토큰과 사용되는 인증 헤더(Authoriztion header) 등이 포함된 경우와 같이 자격 증명(credentials)이 포함된 통신은 허용되지 않습니다. +하지만 그러면 자격 증명(credentials)이 포함된 모든 것을 제외하고 특정 유형의 통신만 허용하게 됩니다. 예: 쿠키, Bearer Token에 사용되는 것과 같은 Authorization 헤더 등. -따라서 모든 작업을 의도한대로 실행하기 위해, 허용되는 출처를 명시적으로 지정하는 것이 좋습니다. +따라서 모든 것이 올바르게 동작하게 하려면, 허용된 출처를 명시적으로 지정하는 것이 더 좋습니다. -## `CORSMiddleware` 사용 +## `CORSMiddleware` 사용 { #use-corsmiddleware } -`CORSMiddleware` 을 사용하여 **FastAPI** 응용 프로그램의 교차 출처 리소스 공유 환경을 설정할 수 있습니다. +`CORSMiddleware`를 사용하여 **FastAPI** 애플리케이션에서 이를 설정할 수 있습니다. -* `CORSMiddleware` 임포트. -* 허용되는 출처(문자열 형식)의 리스트 생성. -* FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가. +* `CORSMiddleware`를 임포트합니다. +* 허용된 출처(문자열)의 리스트를 생성합니다. +* **FastAPI** 애플리케이션에 "미들웨어(middleware)"로 추가합니다. -백엔드에서 다음의 사항을 허용할지에 대해 설정할 수도 있습니다: +또한 백엔드가 다음을 허용할지 여부도 지정할 수 있습니다: -* 자격증명 (인증 헤더, 쿠키 등). -* 특정한 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` 헤더는 단순 CORS 요청에 대해 항상 허용됩니다. +* `allow_credentials` - 교차-출처 요청에 대해 쿠키를 지원해야 함을 나타냅니다. 기본값은 `False`입니다. -### CORS 사전 요청 + `allow_credentials`가 `True`로 설정된 경우 `allow_origins`, `allow_methods`, `allow_headers` 중 어느 것도 `['*']`로 설정할 수 없습니다. 모두 명시적으로 지정되어야 합니다. -`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` 응답을 반환합니다. -CORS에 대한 더 많은 정보를 알고싶다면, Mozilla CORS 문서를 참고하기 바랍니다. +### 단순한 요청 { #simple-requests } -/// note | 기술적 세부 사항 +`Origin` 헤더가 있는 모든 요청입니다. 이 경우 미들웨어는 요청을 정상적으로 통과시키지만, 응답에 적절한 CORS 헤더를 포함합니다. -`from starlette.middleware.cors import CORSMiddleware` 역시 사용할 수 있습니다. +## 더 많은 정보 { #more-info } -**FastAPI**는 개발자인 당신의 편의를 위해 `fastapi.middleware` 에서 몇가지의 미들웨어를 제공합니다. 하지만 대부분의 미들웨어가 Stralette으로부터 직접 제공됩니다. +CORS에 대한 더 많은 정보는 Mozilla CORS 문서를 참고하세요. + +/// note | 기술 세부사항 + +`from starlette.middleware.cors import CORSMiddleware`도 사용할 수 있습니다. + +**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.middleware`에 여러 미들웨어를 제공합니다. 하지만 사용 가능한 미들웨어 대부분은 Starlette에서 직접 제공됩니다. /// diff --git a/docs/ko/docs/tutorial/debugging.md b/docs/ko/docs/tutorial/debugging.md index e42f1ba880..ca20acff64 100644 --- a/docs/ko/docs/tutorial/debugging.md +++ b/docs/ko/docs/tutorial/debugging.md @@ -1,14 +1,14 @@ -# 디버깅 +# 디버깅 { #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__"`의 주요 목적은 다음과 같이 파일이 호출될 때 실행되는 일부 코드를 갖는 것입니다. @@ -26,7 +26,7 @@ $ python myapp.py from myapp import app ``` -#### 추가 세부사항 +#### 추가 세부사항 { #more-details } 파일 이름이 `myapp.py`라고 가정해 보겠습니다. @@ -62,7 +62,7 @@ from myapp import app # Some more code ``` -이 경우 `myapp.py` 내부의 자동 변수에는 값이 `"__main__"`인 변수 `__name__`이 없습니다. +이 경우 `myapp.py` 내부의 자동 변수 `__name__`에는 값이 `"__main__"`이 들어가지 않습니다. 따라서 다음 행 @@ -74,11 +74,11 @@ from myapp import app /// info | 정보 -자세한 내용은 공식 Python 문서를 확인하세요 +자세한 내용은 공식 Python 문서를 확인하세요. /// -## 디버거로 코드 실행 +## 디버거로 코드 실행 { #run-your-code-with-your-debugger } 코드에서 직접 Uvicorn 서버를 실행하고 있기 때문에 디버거에서 직접 Python 프로그램(FastAPI 애플리케이션)을 호출할 수 있습니다. @@ -101,7 +101,7 @@ from myapp import app Pycharm을 사용하는 경우 다음을 수행할 수 있습니다 -* "Run" 메뉴를 엽니다 +* "Run" 메뉴를 엽니다. * "Debug..." 옵션을 선택합니다. * 그러면 상황에 맞는 메뉴가 나타납니다. * 디버그할 파일을 선택합니다(이 경우 `main.py`). diff --git a/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md index 3e5cdcc8c8..68bba669ae 100644 --- a/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md @@ -1,30 +1,30 @@ -# 의존성으로서의 클래스 +# 의존성으로서의 클래스 { #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`를 받게 됩니다. -그리고 우리는 에디터들이 `딕셔너리` 객체의 키나 밸류의 자료형을 알 수 없기 때문에 자동 완성과 같은 기능을 제공해 줄 수 없다는 것을 알고 있습니다. +그리고 에디터는 `dict`의 키와 값 타입을 알 수 없기 때문에 `dict`에 대해서는 (완성 기능 같은) 많은 지원을 제공할 수 없다는 것을 알고 있습니다. -더 나은 방법이 있을 것 같습니다... +더 나은 방법이 있습니다... -## 의존성으로 사용 가능한 것 +## 의존성이 되기 위한 조건 { #what-makes-a-dependency } -지금까지 함수로 선언된 의존성을 봐왔습니다. +지금까지는 함수로 선언된 의존성을 봤습니다. -아마도 더 일반적이기는 하겠지만 의존성을 선언하는 유일한 방법은 아닙니다. +하지만 그것만이 의존성을 선언하는 유일한 방법은 아닙니다(아마도 더 일반적이긴 하겠지만요). -핵심 요소는 의존성이 "호출 가능"해야 한다는 것입니다 +핵심 요소는 의존성이 "호출 가능(callable)"해야 한다는 것입니다. -파이썬에서의 "**호출 가능**"은 파이썬이 함수처럼 "호출"할 수 있는 모든 것입니다. +파이썬에서 "**호출 가능(callable)**"이란 파이썬이 함수처럼 "호출"할 수 있는 모든 것입니다. -따라서, 만약 당신이 `something`(함수가 아닐 수도 있음) 객체를 가지고 있고, +따라서 `something`(함수가 _아닐_ 수도 있습니다)이라는 객체가 있고, 다음처럼 "호출"(실행)할 수 있다면: ```Python something() @@ -36,11 +36,11 @@ something() something(some_argument, some_keyword_argument="foo") ``` -상기와 같은 방식으로 "호출(실행)" 할 수 있다면 "호출 가능"이 됩니다. +그것은 "호출 가능(callable)"입니다. -## 의존성으로서의 클래스 +## 의존성으로서의 클래스 { #classes-as-dependencies_1 } -파이썬 클래스의 인스턴스를 생성하기 위해 사용하는 것과 동일한 문법을 사용한다는 걸 알 수 있습니다. +파이썬 클래스의 인스턴스를 만들 때도 같은 문법을 사용한다는 것을 알 수 있을 겁니다. 예를 들어: @@ -53,125 +53,236 @@ class Cat: 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] *} - +하지만 타입을 선언하는 것을 권장합니다. 그러면 에디터가 매개변수 `commons`에 무엇이 전달되는지 알 수 있고, 코드 완성, 타입 체크 등에서 도움을 받을 수 있습니다: -## 코드 단축 + -그러나 여기 `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 | 팁 -만약 이것이 도움이 되기보다 더 헷갈리게 만든다면, 잊어버리십시오. 이것이 반드시 필요한 것은 아닙니다. +도움이 되기보다 더 헷갈린다면, 무시하세요. 이건 *필수*가 아닙니다. -이것은 단지 손쉬운 방법일 뿐입니다. 왜냐하면 **FastAPI**는 코드 반복을 최소화할 수 있는 방법을 고민하기 때문입니다. +그저 단축 방법일 뿐입니다. **FastAPI**는 코드 반복을 최소화하도록 도와주는 것을 중요하게 생각하기 때문입니다. /// diff --git a/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md index 4a3854cefa..39c78c0786 100644 --- a/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md +++ b/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -1,4 +1,4 @@ -# 경로 작동 데코레이터에서의 의존성 +# 경로 작동 데코레이터에서의 의존성 { #dependencies-in-path-operation-decorators } 몇몇 경우에는, *경로 작동 함수* 안에서 의존성의 반환 값이 필요하지 않습니다. @@ -8,7 +8,7 @@ 그런 경우에, `Depends`를 사용하여 *경로 작동 함수*의 매개변수로 선언하는 것보다 *경로 작동 데코레이터*에 `dependencies`의 `list`를 추가할 수 있습니다. -## *경로 작동 데코레이터*에 `dependencies` 추가하기 +## *경로 작동 데코레이터*에 `dependencies` 추가하기 { #add-dependencies-to-the-path-operation-decorator } *경로 작동 데코레이터*는 `dependencies`라는 선택적인 인자를 받습니다. @@ -22,7 +22,7 @@ 일부 편집기에서는 사용되지 않는 함수 매개변수를 검사하고 오류로 표시합니다. -*경로 작동 데코레이터*에서 `dependencies`를 사용하면 편집기/도구 오류를 피하며 실행되도록 할 수 있습니다. +*경로 작동 데코레이터*에서 이러한 `dependencies`를 사용하면 편집기/도구 오류를 피하면서도 실행되도록 할 수 있습니다. 또한 코드에서 사용되지 않는 매개변수를 보고 불필요하다고 생각할 수 있는 새로운 개발자의 혼란을 방지하는데 도움이 될 수 있습니다. @@ -36,23 +36,23 @@ /// -## 의존성 오류와 값 반환하기 +## 의존성 오류와 값 반환하기 { #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 } 값을 반환하거나, 그러지 않을 수 있으며 값은 사용되지 않습니다. @@ -60,10 +60,10 @@ {* ../../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` 애플리케이션 전체에 의존성을 추가하는 법을 볼 것입니다. diff --git a/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md index ff174937de..9bf6c0693a 100644 --- a/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md @@ -1,6 +1,6 @@ -# yield를 사용하는 의존성 +# `yield`를 사용하는 의존성 { #dependencies-with-yield } -FastAPI는 작업 완료 후 추가 단계를 수행하는 의존성을 지원합니다. +FastAPI는 작업 완료 후 추가 단계를 수행하는 의존성을 지원합니다. 이를 구현하려면 `return` 대신 `yield`를 사용하고, 추가로 실행할 단계 (코드)를 그 뒤에 작성하세요. @@ -23,21 +23,21 @@ FastAPI는 하여 추가할 수 있습니다. +사용자 정의 독점 헤더는 `X-` 접두사를 사용하여 추가할 수 있다는 점을 기억하세요. -그러나 만약 클라이언트의 브라우저에서 볼 수 있는 사용자 정의 헤더를 가지고 있다면, 그것들을 CORS 설정([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank})에 Starlette CORS 문서에 명시된 `expose_headers` 매개변수를 이용하여 헤더들을 추가하여야합니다. +하지만 브라우저에서 클라이언트가 볼 수 있게 하려는 사용자 정의 헤더가 있다면, Starlette의 CORS 문서에 문서화된 `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()` 대신 `time.perf_counter()`를 사용합니다. 🤓 /// -### `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 } -미들웨어에 대한 더 많은 정보는 [숙련된 사용자 안내서: 향상된 미들웨어](../advanced/middleware.md){.internal-link target=\_blank}에서 확인할 수 있습니다. +다른 미들웨어에 대한 더 많은 정보는 나중에 [숙련된 사용자 안내서: 향상된 미들웨어](../advanced/middleware.md){.internal-link target=_blank}에서 확인할 수 있습니다. -다음 부분에서 미들웨어와 함께 CORS를 어떻게 다루는지에 대해 확인할 것입니다. +다음 섹션에서 미들웨어로 CORS를 처리하는 방법을 보게 될 것입니다. diff --git a/docs/ko/docs/tutorial/path-operation-configuration.md b/docs/ko/docs/tutorial/path-operation-configuration.md index 81914182af..b8a87667a0 100644 --- a/docs/ko/docs/tutorial/path-operation-configuration.md +++ b/docs/ko/docs/tutorial/path-operation-configuration.md @@ -1,97 +1,107 @@ -# 경로 작동 설정 +# 경로 처리 설정 { #path-operation-configuration } -*경로 작동 데코레이터*를 설정하기 위해서 전달할수 있는 몇 가지 매개변수가 있습니다. +*경로 처리 데코레이터*를 설정하기 위해 전달할 수 있는 몇 가지 매개변수가 있습니다. /// warning | 경고 -아래 매개변수들은 *경로 작동 함수*가 아닌 *경로 작동 데코레이터*에 직접 전달된다는 사실을 기억하십시오. +아래 매개변수들은 *경로 처리 함수*가 아닌 *경로 처리 데코레이터*에 직접 전달된다는 사실을 기억하세요. /// -## 응답 상태 코드 +## 응답 상태 코드 { #response-status-code } -*경로 작동*의 응답에 사용될 (HTTP) `status_code`를 정의할수 있습니다. +*경로 처리*의 응답에 사용될 (HTTP) `status_code`를 정의할 수 있습니다. -`404`와 같은 `int`형 코드를 직접 전달할수 있습니다. +`404`와 같은 `int`형 코드를 직접 전달할 수 있습니다. -하지만 각 코드의 의미를 모른다면, `status`에 있는 단축 상수들을 사용할수 있습니다: +하지만 각 숫자 코드가 무엇을 의미하는지 기억하지 못한다면, `status`에 있는 단축 상수들을 사용할 수 있습니다: -{* ../../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의 스키마에 추가되며, 자동 문서 인터페이스에서 사용됩니다: -## 요약과 기술 +### 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 } -설명은 보통 길어지고 여러 줄에 걸쳐있기 때문에, *경로 작동* 기술을 함수 독스트링 에 선언할 수 있습니다, 이를 **FastAPI**가 독스트링으로부터 읽습니다. +설명은 보통 길어지고 여러 줄에 걸쳐있기 때문에, *경로 처리* 설명을 함수 docstring에 선언할 수 있으며, **FastAPI**는 그곳에서 이를 읽습니다. -마크다운 문법으로 독스트링을 작성할 수 있습니다, 작성된 마크다운 형식의 독스트링은 (마크다운의 들여쓰기를 고려하여) 올바르게 화면에 출력됩니다. +독스트링에는 Markdown을 작성할 수 있으며, (독스트링의 들여쓰기를 고려하여) 올바르게 해석되고 표시됩니다. -{* ../../docs_src/path_operation_configuration/tutorial004.py hl[19:27] *} +{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *} 이는 대화형 문서에서 사용됩니다: -## 응답 기술 +## 응답 설명 { #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`은 구체적으로 응답을 지칭하며, `description`은 일반적인 *경로 작동*을 지칭합니다. +`response_description`은 구체적으로 응답을 지칭하며, `description`은 일반적인 *경로 처리*를 지칭합니다. /// /// check | 확인 -OpenAPI는 각 *경로 작동*이 응답에 관한 설명을 요구할 것을 명시합니다. +OpenAPI는 각 *경로 처리*가 응답에 관한 설명을 요구할 것을 명시합니다. -따라서, 응답에 관한 설명이 없을경우, **FastAPI**가 자동으로 "성공 응답" 중 하나를 생성합니다. +따라서, 응답에 관한 설명을 제공하지 않으면, **FastAPI**가 "Successful response" 중 하나를 자동으로 생성합니다. /// -## 단일 *경로 작동* 지원중단 +## *경로 처리* 지원중단하기 { #deprecate-a-path-operation } -단일 *경로 작동*을 없애지 않고 지원중단을 해야한다면, `deprecated` 매개변수를 전달하면 됩니다. +*경로 처리*를 제거하지 않고 deprecated로 표시해야 한다면, `deprecated` 매개변수를 전달하면 됩니다: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} -대화형 문서에 지원중단이라고 표시됩니다. +대화형 문서에서 지원중단으로 명확하게 표시됩니다: -지원중단된 경우와 지원중단 되지 않은 경우에 대한 *경로 작동*이 어떻게 보이는 지 확인하십시오. +지원중단된 *경로 처리*와 지원중단되지 않은 *경로 처리*가 어떻게 보이는지 확인해 보세요: -## 정리 +## 정리 { #recap } -*경로 작동 데코레이터*에 매개변수(들)를 전달함으로 *경로 작동*을 설정하고 메타데이터를 추가할수 있습니다. +*경로 처리 데코레이터*에 매개변수(들)를 전달하여 *경로 처리*를 설정하고 메타데이터를 쉽게 추가할 수 있습니다. diff --git a/docs/ko/docs/tutorial/path-params-numeric-validations.md b/docs/ko/docs/tutorial/path-params-numeric-validations.md index f21c9290ed..f2c52d4aac 100644 --- a/docs/ko/docs/tutorial/path-params-numeric-validations.md +++ b/docs/ko/docs/tutorial/path-params-numeric-validations.md @@ -1,116 +1,153 @@ -# 경로 매개변수와 숫자 검증 +# 경로 매개변수와 숫자 검증 { #path-parameters-and-numeric-validations } `Query`를 사용하여 쿼리 매개변수에 더 많은 검증과 메타데이터를 선언하는 방법과 동일하게 `Path`를 사용하여 경로 매개변수에 검증과 메타데이터를 같은 타입으로 선언할 수 있습니다. -## 경로 임포트 +## `Path` 임포트 { #import-path } -먼저 `fastapi`에서 `Path`를 임포트합니다: +먼저 `fastapi`에서 `Path`를 임포트하고, `Annotated`도 임포트합니다: -{* ../../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 | 참고 -경로 매개변수는 경로의 일부여야 하므로 언제나 필수적입니다. +경로 매개변수는 경로의 일부여야 하므로 언제나 필수입니다. `None`으로 선언하거나 기본값을 지정하더라도 아무 영향이 없으며, 항상 필수입니다. -즉, `...`로 선언해서 필수임을 나타내는게 좋습니다. +/// -그럼에도 `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] *} +함수의 첫 번째 매개변수로 `*`를 전달하세요. -## 필요한 경우 매개변수 정렬하기, 트릭 +파이썬은 `*`으로 아무것도 하지 않지만, 뒤따르는 모든 매개변수는 키워드 인자(키-값 쌍)로 호출되어야 함을 알게 됩니다. 이는 kwargs로도 알려져 있습니다. 기본값이 없더라도 마찬가지입니다. -`Query`나 아무런 기본값으로도 `q` 경로 매개변수를 선언하고 싶지 않지만 `Path`를 사용하여 경로 매개변수를 `item_id` 다른 순서로 선언하고 싶다면, 파이썬은 이를 위한 작고 특별한 문법이 있습니다. +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} -`*`를 함수의 첫 번째 매개변수로 전달하세요. +### `Annotated`를 쓰면 더 좋습니다 { #better-with-annotated } -파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 kwargs로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다. +`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` 값에도 동작합니다. -여기에서 ge뿐만 아니라 gt를 선언 할 수있는 것이 중요해집니다. 예를 들어 필요한 경우, 값이 `1`보다 작더라도 반드시 `0`보다 커야합니다. +여기에서 gt를, ge뿐만 아니라 선언할 수 있다는 점이 중요해집니다. 예를 들어 값이 `1`보다 작더라도, 반드시 `0`보다 커야 한다고 요구할 수 있습니다. 즉, `0.5`는 유효한 값입니다. 그러나 `0.0` 또는 `0`은 그렇지 않습니다. lt 역시 마찬가지입니다. -{* ../../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`라는 이름을 가진 클래스의 인스턴스를 반환합니다. -편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해 (클래스를 직접 사용하는 대신) 이러한 함수들이 있습니다. +이 함수들이 있는 이유는(클래스를 직접 사용하는 대신) 편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해서입니다. 이렇게 하면 오류를 무시하기 위한 사용자 설정을 추가하지 않고도 일반 편집기와 코딩 도구를 사용할 수 있습니다. diff --git a/docs/ko/docs/tutorial/path-params.md b/docs/ko/docs/tutorial/path-params.md index b72787e0b2..ea5170eccb 100644 --- a/docs/ko/docs/tutorial/path-params.md +++ b/docs/ko/docs/tutorial/path-params.md @@ -1,8 +1,8 @@ -# 경로 매개변수 +# 경로 매개변수 { #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` 인자로 전달됩니다. @@ -12,11 +12,11 @@ {"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`로 선언되었습니다. @@ -26,7 +26,7 @@ /// -## 데이터 변환 +## 데이터 변환 { #data-conversion } 이 예제를 실행하고 http://127.0.0.1:8000/items/3을 열면, 다음 응답을 볼 수 있습니다: @@ -42,40 +42,41 @@ /// -## 데이터 검증 +## 데이터 검증 { #data-validation } -하지만 브라우저에서 http://127.0.0.1:8000/items/foo로 이동하면, HTTP 오류가 잘 뜨는 것을 확인할 수 있습니다: +하지만 브라우저에서 http://127.0.0.1:8000/items/foo로 이동하면, 다음과 같은 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`을 전달하는 경우에도 동일한 오류가 나타납니다: http://127.0.0.1:8000/items/4.2 +`int` 대신 `float`을 제공하면(예: http://127.0.0.1:8000/items/4.2) 동일한 오류가 나타납니다. /// check | 확인 즉, 파이썬 타입 선언을 하면 **FastAPI**는 데이터 검증을 합니다. -오류에는 정확히 어느 지점에서 검증을 통과하지 못했는지 명시됩니다. +또한 오류에는 검증을 통과하지 못한 지점이 정확히 명시됩니다. 이는 API와 상호 작용하는 코드를 개발하고 디버깅하는 데 매우 유용합니다. /// -## 문서화 +## 문서화 { #documentation } 그리고 브라우저에서 http://127.0.0.1:8000/docs를 열면, 다음과 같이 자동 대화식 API 문서를 볼 수 있습니다: @@ -83,23 +84,23 @@ /// check | 확인 -그저 파이썬 타입 선언을 하기만 하면 **FastAPI**는 자동 대화형 API 문서(Swagger UI)를 제공합니다. +다시 한 번, 동일한 파이썬 타입 선언만으로 **FastAPI**는 자동 대화형 문서(Swagger UI 통합)를 제공합니다. -경로 매개변수가 정수형으로 명시된 것을 확인할 수 있습니다. +경로 매개변수가 정수형으로 선언된 것을 확인할 수 있습니다. /// -## 표준 기반의 이점, 대체 문서 +## 표준 기반의 이점, 대체 문서 { #standards-based-benefits-alternative-documentation } -그리고 생성된 스키마는 OpenAPI 표준에서 나온 것이기 때문에 호환되는 도구가 많이 있습니다. +그리고 생성된 스키마는 OpenAPI 표준에서 나온 것이기 때문에 호환되는 도구가 많이 있습니다. -이 덕분에 **FastAPI**는 http://127.0.0.1:8000/redoc로 접속할 수 있는 (ReDoc을 사용하는) 대체 API 문서를 제공합니다: +이 덕분에 **FastAPI** 자체에서 http://127.0.0.1:8000/redoc로 접속할 수 있는 (ReDoc을 사용하는) 대체 API 문서를 제공합니다: 이와 마찬가지로 다양한 언어에 대한 코드 생성 도구를 포함하여 여러 호환되는 도구가 있습니다. -## Pydantic +## Pydantic { #pydantic } 모든 데이터 검증은 Pydantic에 의해 내부적으로 수행되므로 이로 인한 이점을 모두 얻을 수 있습니다. 여러분은 관리를 잘 받고 있음을 느낄 수 있습니다. @@ -107,73 +108,73 @@ 이 중 몇 가지는 자습서의 다음 장에 설명되어 있습니다. -## 순서 문제 +## 순서 문제 { #order-matters } -*경로 작동*을 만들때 고정 경로를 갖고 있는 상황들을 맞닥뜨릴 수 있습니다. +*경로 처리*를 만들 때 고정 경로를 갖고 있는 상황들을 맞닥뜨릴 수 있습니다. `/users/me`처럼, 현재 사용자의 데이터를 가져온다고 합시다. 사용자 ID를 이용해 특정 사용자의 정보를 가져오는 경로 `/users/{user_id}`도 있습니다. -*경로 작동*은 순차적으로 실행되기 때문에 `/users/{user_id}` 이전에 `/users/me`를 먼저 선언해야 합니다: +*경로 처리*는 순차적으로 평가되기 때문에 `/users/{user_id}` 이전에 `/users/me`에 대한 경로가 먼저 선언되었는지 확인해야 합니다: -{* ../../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"` 값이 들어왔다고 "생각하게" 됩니다. -## 사전정의 값 +마찬가지로, 경로 처리를 재정의할 수는 없습니다: -만약 *경로 매개변수*를 받는 *경로 작동*이 있지만, *경로 매개변수*로 가능한 값들을 미리 정의하고 싶다면 파이썬 표준 `Enum`을 사용할 수 있습니다. +{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *} -### `Enum` 클래스 생성 +경로가 먼저 매칭되기 때문에 첫 번째 것이 항상 사용됩니다. -`Enum`을 임포트하고 `str`과 `Enum`을 상속하는 서브 클래스를 만듭니다. +## 사전정의 값 { #predefined-values } -`str`을 상속함으로써 API 문서는 값이 `string` 형이어야 하는 것을 알게 되고 이는 문서에 제대로 표시됩니다. +만약 *경로 매개변수*를 받는 *경로 처리*가 있지만, 가능한 유효한 *경로 매개변수* 값들을 미리 정의하고 싶다면 파이썬 표준 `Enum`을 사용할 수 있습니다. -가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다: +### `Enum` 클래스 생성 { #create-an-enum-class } -{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *} +`Enum`을 임포트하고 `str`과 `Enum`을 상속하는 서브 클래스를 만듭니다. -/// info | 정보 +`str`을 상속함으로써 API 문서는 값이 `string` 형이어야 하는 것을 알게 되고 이는 문서에 제대로 표시됩니다. -열거형(또는 enums)은 파이썬 버전 3.4 이후로 사용 가능합니다. +가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다: -/// +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip | 팁 -혹시 궁금하다면, "AlexNet", "ResNet", 그리고 "LeNet"은 그저 기계 학습 모델들의 이름입니다. +혹시 궁금하다면, "AlexNet", "ResNet", 그리고 "LeNet"은 그저 머신 러닝 모델들의 이름입니다. /// -### *경로 매개변수* 선언 +### *경로 매개변수* 선언 { #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 } *경로 매개변수*에 사용할 수 있는 값은 미리 정의되어 있으므로 대화형 문서에서 잘 표시됩니다: -### 파이썬 *열거형*으로 작업하기 +### 파이썬 *열거형*으로 작업하기 { #working-with-python-enumerations } *경로 매개변수*의 값은 *열거형 멤버*가 됩니다. -#### *열거형 멤버* 비교 +#### *열거형 멤버* 비교 { #compare-enumeration-members } -열거형 `ModelName`의 *열거형 멤버*를 비교할 수 있습니다: +생성한 열거형 `ModelName`의 *열거형 멤버*와 비교할 수 있습니다: -{* ../../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 | 팁 @@ -181,15 +182,15 @@ /// -#### *열거형 멤버* 반환 +#### *열거형 멤버* 반환 { #return-enumeration-members } -*경로 작동*에서 *열거형 멤버*를 반환할 수 있습니다. 이는 중첩 JSON 본문(예: `dict`)내의 값으로도 가능합니다. +*경로 처리*에서 *enum 멤버*를 반환할 수 있습니다. 이는 JSON 본문(예: `dict`) 내에 중첩된 형태로도 가능합니다. 클라이언트에 반환하기 전에 해당 값(이 경우 문자열)으로 변환됩니다: -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} -클라이언트는 아래의 JSON 응답을 얻습니다: +클라이언트는 아래와 같은 JSON 응답을 얻게 됩니다: ```JSON { @@ -198,53 +199,53 @@ } ``` -## 경로를 포함하는 경로 매개변수 +## 경로를 포함하는 경로 매개변수 { #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**에서는 이가 가능합니다. -문서에 매개변수에 경로가 포함되어야 한다는 정보가 명시되지는 않지만 여전히 작동합니다. +또한 문서가 여전히 동작하긴 하지만, 매개변수에 경로가 포함되어야 한다는 내용을 추가로 문서화하지는 않습니다. -### 경로 변환기 +### 경로 변환기 { #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**를 이용하면 짧고 직관적인 표준 파이썬 타입 선언을 사용하여 다음을 얻을 수 있습니다: * 편집기 지원: 오류 검사, 자동완성 등 -* 데이터 "파싱" +* 데이터 "parsing" * 데이터 검증 * API 주석(Annotation)과 자동 문서 -단 한번의 선언만으로 위 사항들을 모두 선언할 수 있습니다. +그리고 한 번만 선언하면 됩니다. 이는 대체 프레임워크와 비교했을 때 (엄청나게 빠른 성능 외에도) **FastAPI**의 주요한 장점일 것입니다. diff --git a/docs/ko/docs/tutorial/query-param-models.md b/docs/ko/docs/tutorial/query-param-models.md index 2ca65a3319..d354c56c3d 100644 --- a/docs/ko/docs/tutorial/query-param-models.md +++ b/docs/ko/docs/tutorial/query-param-models.md @@ -1,48 +1,48 @@ -# 쿼리 매개변수 모델 +# 쿼리 매개변수 모델 { #query-parameter-models } -연관된 쿼리 **매개변수** 그룹이 있다면 **Pydantic 모델** 을 사용해 선언할 수 있습니다. +연관된 **쿼리 매개변수** 그룹이 있다면 이를 선언하기 위해 **Pydantic 모델**을 생성할 수 있습니다. 이렇게 하면 **여러 곳**에서 **모델을 재사용**할 수 있을 뿐만 아니라, 매개변수에 대한 검증 및 메타데이터도 한 번에 선언할 수 있습니다. 😎 /// note | 참고 -이 기능은 FastAPI 버전 `0.115.0`부터 제공됩니다. 🤓 +이 기능은 FastAPI 버전 `0.115.0`부터 지원됩니다. 🤓 /// -## 쿼리 매개변수와 Pydantic 모델 +## Pydantic 모델과 쿼리 매개변수 { #query-parameters-with-a-pydantic-model } -필요한 **쿼리 매개변수**를 **Pydantic 모델** 안에 선언한 다음, 모델을 `Query`로 선언합니다. +필요한 **쿼리 매개변수**를 **Pydantic 모델** 안에 선언한 다음, 매개변수를 `Query`로 선언합니다: {* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *} -**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델로 제공합니다. +**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델을 제공합니다. -## 문서 확인하기 +## 문서 확인하기 { #check-the-docs } -`/docs` 경로의 API 문서에서 매개변수를 확인할 수 있습니다. +`/docs`의 문서 UI에서 쿼리 매개변수를 확인할 수 있습니다:
-## 추가 쿼리 매개변수 금지 +## 추가 쿼리 매개변수 금지 { #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 { @@ -57,12 +57,12 @@ https://example.com/items/?limit=10&tool=plumbus } ``` -## 요약 +## 요약 { #summary } -**FastAPI** 에서 **쿼리 매개변수** 를 선언할 때 **Pydantic 모델** 을 사용할 수 있습니다. 😎 +**FastAPI**에서 **쿼리 매개변수**를 선언할 때 **Pydantic 모델**을 사용할 수 있습니다. 😎 /// tip | 팁 -스포일러 경고: Pydantic 모델을 쿠키와 헤더에도 적용할 수 있습니다. 이에 대해서는 이후 튜토리얼에서 다룰 예정입니다. 🤫 +스포일러 경고: Pydantic 모델을 쿠키와 헤더에도 사용할 수 있지만, 이에 대해서는 이후 튜토리얼에서 읽게 될 것입니다. 🤫 /// diff --git a/docs/ko/docs/tutorial/query-params-str-validations.md b/docs/ko/docs/tutorial/query-params-str-validations.md index f2ca453ac5..68824932ee 100644 --- a/docs/ko/docs/tutorial/query-params-str-validations.md +++ b/docs/ko/docs/tutorial/query-params-str-validations.md @@ -1,118 +1,226 @@ -# 쿼리 매개변수와 문자열 검증 +# 쿼리 매개변수와 문자열 검증 { #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`가 선택적이지만 값이 주어질 때마다 **값이 50 글자를 초과하지 않게** 강제하려 합니다. +`q`가 선택적이지만 값이 주어질 때마다 **길이가 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` 지원을 추가했고(그리고 이를 권장하기 시작했습니다). -기본값 `None`을 `Query(None)`으로 바꿔야 하므로, `Query`의 첫 번째 매개변수는 기본값을 정의하는 것과 같은 목적으로 사용됩니다. +이전 버전을 사용하면 `Annotated`를 사용하려고 할 때 오류가 발생합니다. -그러므로: +`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 버전(0.95.0 이전)에서는 `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` 매개변수를 사용할 수 없다는 점을 기억하세요. -매개변수와 일치해야 하는 정규표현식을 정의할 수 있습니다: +대신 함수 매개변수의 실제 기본값을 사용하세요. 그렇지 않으면 일관성이 깨집니다. + +예를 들어, 다음은 허용되지 않습니다: + +```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**도 오류를 냅니다. -하지만 언제든지 가서 배울수 있고, **FastAPI**에서 직접 사용할 수 있다는 사실을 알고 있어야 합니다. +`Annotated`를 사용하지 않고 **(이전) 기본값 스타일**을 사용하면, FastAPI 없이 **다른 곳에서** 함수를 호출할 때도 제대로 동작하도록 함수에 인자를 전달해야 한다는 것을 **기억**해야 합니다. 그렇지 않으면 값이 기대와 다르게 됩니다(예: `str` 대신 `QueryInfo` 같은 것). 그리고 편집기도 경고하지 않고 Python도 그 함수를 실행할 때는 불평하지 않으며, 오직 내부 동작에서 오류가 발생할 때만 문제가 드러납니다. -## 기본값 +`Annotated`는 하나 이상의 메타데이터 어노테이션을 가질 수 있기 때문에, 이제 Typer 같은 다른 도구에서도 같은 함수를 사용할 수 있습니다. 🚀 -기본값으로 사용하는 첫 번째 인자로 `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 } + +매개변수와 일치해야 하는 정규 표현식 `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`를 필수로 만들 수 있습니다: @@ -123,42 +231,42 @@ q: str 아래 대신: ```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 } -이전에 `...`를 본적이 없다면: 특별한 단일값으로, 파이썬의 일부이며 "Ellipsis"라 부릅니다. +매개변수가 `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에 대한 응답은 다음과 같습니다: @@ -173,7 +281,7 @@ http://localhost:8000/items/?q=foo&q=bar /// tip | 팁 -위의 예와 같이 `list` 자료형으로 쿼리 매개변수를 선언하려면 `Query`를 명시적으로 사용해야 합니다. 그렇지 않으면 요청 본문으로 해석됩니다. +위의 예와 같이 `list` 타입으로 쿼리 매개변수를 선언하려면 `Query`를 명시적으로 사용해야 합니다. 그렇지 않으면 요청 본문으로 해석됩니다. /// @@ -181,19 +289,19 @@ http://localhost:8000/items/?q=foo&q=bar -### 쿼리 매개변수 리스트 / 기본값을 사용하는 다중값 +### 쿼리 매개변수 리스트 / 기본값이 있는 다중값 { #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 { @@ -204,21 +312,21 @@ http://localhost:8000/items/ } ``` -#### `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 } 매개변수에 대한 정보를 추가할 수 있습니다. @@ -226,7 +334,7 @@ http://localhost:8000/items/ /// note | 참고 -도구에 따라 OpenAPI 지원 수준이 다를 수 있음을 명심하기 바랍니다. +도구에 따라 OpenAPI 지원 수준이 다를 수 있음을 명심하세요. 일부는 아직 선언된 추가 정보를 모두 표시하지 않을 수 있지만, 대부분의 경우 누락된 기능은 이미 개발 계획이 있습니다. @@ -234,13 +342,13 @@ http://localhost:8000/items/ `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`이길 원한다고 가정해 봅시다. @@ -250,31 +358,99 @@ http://localhost:8000/items/ 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 } -이제는 더이상 이 매개변수를 마음에 들어하지 않는다고 가정해 봅시다. +이제는 더 이상 이 매개변수를 마음에 들어하지 않는다고 가정해 봅시다. -이 매개변수를 사용하는 클라이언트가 있기 때문에 한동안은 남겨둬야 하지만, 사용되지 않는다(deprecated)고 확실하게 문서에서 보여주고 싶습니다. +이 매개변수를 사용하는 클라이언트가 있기 때문에 한동안은 남겨둬야 하지만, 문서에서 deprecated로 명확하게 보여주고 싶습니다. 그렇다면 `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] *} 문서가 아래와 같이 보일겁니다: -## 요약 +## 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` 안에서 Pydantic의 `AfterValidator`를 사용하면 이를 구현할 수 있습니다. + +/// tip | 팁 + +Pydantic에는 `BeforeValidator`와 같은 다른 것들도 있습니다. 🤓 + +/// + +예를 들어, 이 커스텀 validator는 ISBN 도서 번호의 경우 아이템 ID가 `isbn-`으로 시작하고, IMDB 영화 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()`를 사용하면 각 딕셔너리 항목의 키와 값을 담은 튜플로 구성된 iterable object를 얻습니다. + +이 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 } 매개변수에 검증과 메타데이터를 추가 선언할 수 있습니다. @@ -285,12 +461,14 @@ http://127.0.0.1:8000/items/?item-query=foobaritems * `description` * `deprecated` -특정 문자열 검증: +문자열에 특화된 검증: * `min_length` * `max_length` -* `regex` +* `pattern` + +`AfterValidator`를 사용하는 커스텀 검증. 예제에서 `str` 값의 검증을 어떻게 추가하는지 살펴보았습니다. -숫자와 같은 다른 자료형에 대한 검증을 어떻게 선언하는지 확인하려면 다음 장을 확인하기 바랍니다. +숫자와 같은 다른 타입에 대한 검증을 어떻게 선언하는지 확인하려면 다음 장을 확인하기 바랍니다. diff --git a/docs/ko/docs/tutorial/query-params.md b/docs/ko/docs/tutorial/query-params.md index d5b9837c4e..5124f73bf5 100644 --- a/docs/ko/docs/tutorial/query-params.md +++ b/docs/ko/docs/tutorial/query-params.md @@ -1,8 +1,8 @@ -# 쿼리 매개변수 +# 쿼리 매개변수 { #query-parameters } 경로 매개변수의 일부가 아닌 다른 함수 매개변수를 선언하면 "쿼리" 매개변수로 자동 해석합니다. -{* ../../docs_src/query_params/tutorial001.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} 쿼리는 URL에서 `?` 후에 나오고 `&`으로 구분되는 키-값 쌍의 집합입니다. @@ -24,11 +24,11 @@ URL의 일부이므로 "자연스럽게" 문자열입니다. 경로 매개변수에 적용된 동일한 프로세스가 쿼리 매개변수에도 적용됩니다: * (당연히) 편집기 지원 -* 데이터 "파싱" +* 데이터 "파싱" * 데이터 검증 * 자동 문서화 -## 기본값 +## 기본값 { #defaults } 쿼리 매개변수는 경로에서 고정된 부분이 아니기 때문에 선택적일 수 있고 기본값을 가질 수 있습니다. @@ -57,33 +57,25 @@ http://127.0.0.1:8000/items/?skip=20 * `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] *} 이 경우, 아래로 이동하면: @@ -115,10 +107,10 @@ http://127.0.0.1:8000/items/foo?short=on http://127.0.0.1:8000/items/foo?short=yes ``` -또는 다른 어떤 변형(대문자, 첫글자만 대문자 등)이더라도 함수는 매개변수 `bool`형을 가진 `short`의 값이 `True`임을 압니다. 그렇지 않은 경우 `False`입니다. +또는 다른 어떤 변형(대문자, 첫글자만 대문자 등)이더라도 함수는 `bool` 값이 `True`인 매개변수 `short`를 보게 됩니다. 그렇지 않은 경우 `False`입니다. -## 여러 경로/쿼리 매개변수 +## 여러 경로/쿼리 매개변수 { #multiple-path-and-query-parameters } 여러 경로 매개변수와 쿼리 매개변수를 동시에 선언할 수 있으며 **FastAPI**는 어느 것이 무엇인지 알고 있습니다. @@ -126,9 +118,9 @@ http://127.0.0.1:8000/items/foo?short=yes 매개변수들은 이름으로 감지됩니다: -{* ../../docs_src/query_params/tutorial004.py hl[8,10] *} +{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *} -## 필수 쿼리 매개변수 +## 필수 쿼리 매개변수 { #required-query-parameters } 경로가 아닌 매개변수에 대한 기본값을 선언할 때(지금은 쿼리 매개변수만 보았습니다), 해당 매개변수는 필수적(Required)이지 않았습니다. @@ -136,7 +128,7 @@ http://127.0.0.1:8000/items/foo?short=yes 그러나 쿼리 매개변수를 필수로 만들려면 단순히 기본값을 선언하지 않으면 됩니다: -{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} 여기 쿼리 매개변수 `needy`는 `str`형인 필수 쿼리 매개변수입니다. @@ -150,16 +142,17 @@ http://127.0.0.1:8000/items/foo-item ```JSON { - "detail": [ - { - "loc": [ - "query", - "needy" - ], - "msg": "field required", - "type": "value_error.missing" - } - ] + "detail": [ + { + "type": "missing", + "loc": [ + "query", + "needy" + ], + "msg": "Field required", + "input": null + } + ] } ``` @@ -180,7 +173,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy 그리고 물론, 일부 매개변수는 필수로, 다른 일부는 기본값을, 또 다른 일부는 선택적으로 선언할 수 있습니다: -{* ../../docs_src/query_params/tutorial006.py hl[10] *} +{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *} 위 예시에서는 3가지 쿼리 매개변수가 있습니다: @@ -188,8 +181,8 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy * `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`을 사용할 수 있습니다. /// diff --git a/docs/ko/docs/tutorial/request-files.md b/docs/ko/docs/tutorial/request-files.md index 9162b353cd..cc00009211 100644 --- a/docs/ko/docs/tutorial/request-files.md +++ b/docs/ko/docs/tutorial/request-files.md @@ -1,4 +1,4 @@ -# 파일 요청 +# 파일 요청 { #request-files } `File`을 사용하여 클라이언트가 업로드할 파일들을 정의할 수 있습니다. @@ -6,23 +6,27 @@ 업로드된 파일을 전달받기 위해 먼저 `python-multipart`를 설치해야합니다. -예시) `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 | 정보 @@ -40,20 +44,21 @@ File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본 파일들은 "폼 데이터"의 형태로 업로드 됩니다. -*경로 작동 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다. +*경로 처리 함수*의 매개변수를 `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()`을 사용할 필요가 없습니다. * "스풀 파일"을 사용합니다. * 최대 크기 제한까지만 메모리에 저장되며, 이를 초과하는 경우 디스크에 저장됩니다. * 따라서 이미지, 동영상, 큰 이진코드와 같은 대용량 파일들을 많은 메모리를 소모하지 않고 처리하기에 적합합니다. @@ -61,13 +66,13 @@ File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본 * file-like `async` 인터페이스를 갖고 있습니다. * file-like object를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 파이썬 `SpooledTemporaryFile` 객체를 반환합니다. -### `UploadFile` +### `UploadFile` { #uploadfile } `UploadFile` 은 다음과 같은 어트리뷰트가 있습니다: * `filename` : 문자열(`str`)로 된 업로드된 파일의 파일명입니다 (예: `myimage.jpg`). * `content_type` : 문자열(`str`)로 된 파일 형식(MIME type / media type)입니다 (예: `image/jpeg`). -* `file` : `SpooledTemporaryFile` (파일류 객체)입니다. 이것은 "파일류" 객체를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일입니다. +* `file` : `SpooledTemporaryFile` (a file-like object)입니다. 이것은 "file-like" 객체를 필요로하는 다른 함수나 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일 객체입니다. `UploadFile` 에는 다음의 `async` 메소드들이 있습니다. 이들은 내부적인 `SpooledTemporaryFile` 을 사용하여 해당하는 파일 메소드를 호출합니다. @@ -80,77 +85,79 @@ File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본 상기 모든 메소드들이 `async` 메소드이기 때문에 “await”을 사용하여야 합니다. -예를들어, `async` *경로 작동 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다: +예를들어, `async` *경로 처리 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다: ```Python contents = await myfile.read() ``` -만약 일반적인 `def` *경로 작동 함수*의 내부라면, 다음과 같이 `UploadFile.file` 에 직접 접근할 수 있습니다: +만약 일반적인 `def` *경로 처리 함수*의 내부라면, 다음과 같이 `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의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다. **FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다. -/// note | 기술적 세부사항 +/// note | 기술 세부사항 폼의 데이터는 파일이 포함되지 않은 경우 일반적으로 "미디어 유형" `application/x-www-form-urlencoded` 을 사용해 인코딩 됩니다. 하지만 파일이 포함된 경우, `multipart/form-data`로 인코딩됩니다. `File`을 사용하였다면, **FastAPI**는 본문의 적합한 부분에서 파일을 가져와야 한다는 것을 인지합니다. -인코딩과 폼 필드에 대해 더 알고싶다면, POST에 관한MDN웹 문서 를 참고하기 바랍니다,. +인코딩과 폼 필드에 대해 더 알고싶다면, MDN web docs for POST를 참고하기 바랍니다. /// /// warning | 경고 -다수의 `File` 과 `Form` 매개변수를 한 *경로 작동*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다. +다수의 `File` 과 `Form` 매개변수를 한 *경로 처리*에 선언하는 것이 가능하지만, 요청의 본문이 `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가 하나의 폼 필드로 다수의 파일을 업로드하는 것을 지원하지 않습니다. 더 많은 정보를 원하면, #4276과 #3641을 참고하세요. +여러 파일을 동시에 업로드 할 수 있습니다. -그럼에도, **FastAPI**는 표준 Open API를 사용해 이미 호환이 가능합니다. +그들은 "폼 데이터"를 사용하여 전송된 동일한 "폼 필드"에 연결됩니다. -따라서 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` 역시 사용할 수 있습니다. @@ -158,6 +165,12 @@ HTML의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 /// -## 요약 +### 추가 메타데이터를 포함한 다중 파일 업로드 { #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`을 사용하여 폼 데이터로 전송되는 요청에서 업로드할 파일을 선언하세요. diff --git a/docs/ko/docs/tutorial/request-form-models.md b/docs/ko/docs/tutorial/request-form-models.md index 3316a93d52..b37186dfb8 100644 --- a/docs/ko/docs/tutorial/request-form-models.md +++ b/docs/ko/docs/tutorial/request-form-models.md @@ -1,12 +1,12 @@ -# 폼 모델 +# 폼 모델 { #form-models } FastAPI에서 **Pydantic 모델**을 이용하여 **폼 필드**를 선언할 수 있습니다. /// info | 정보 -폼(Form)을 사용하려면, 먼저 `python-multipart`를 설치하세요. +폼을 사용하려면, 먼저 `python-multipart`를 설치하세요. -[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, 아래와 같이 설치할 수 있습니다: +[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, 예를 들어 아래와 같이 설치하세요: ```console $ pip install python-multipart @@ -20,7 +20,7 @@ $ pip install python-multipart /// -## Pydantic 모델을 사용한 폼 +## 폼을 위한 Pydantic 모델 { #pydantic-models-for-forms } **폼 필드**로 받고 싶은 필드를 **Pydantic 모델**로 선언한 다음, 매개변수를 `Form`으로 선언하면 됩니다: @@ -28,7 +28,7 @@ $ pip install python-multipart **FastAPI**는 요청에서 받은 **폼 데이터**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다. -## 문서 확인하기 +## 문서 확인하기 { #check-the-docs } 문서 UI `/docs`에서 확인할 수 있습니다: @@ -36,9 +36,9 @@ $ pip install python-multipart
-## 추가 폼 필드 금지하기 +## 추가 폼 필드 금지하기 { #forbid-extra-form-fields } -일부 특별한 사용 사례(흔하지는 않겠지만)에서는 Pydantic 모델에서 정의한 폼 필드를 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다. +일부 특별한 사용 사례(아마도 흔하지는 않겠지만)에서는 Pydantic 모델에서 선언된 폼 필드로만 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다. /// note | 참고 @@ -46,7 +46,7 @@ $ pip install python-multipart /// -Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다: +Pydantic의 모델 구성을 사용하여 `extra` 필드를 `forbid`할 수 있습니다: {* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *} @@ -73,6 +73,6 @@ Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forb } ``` -## 요약 +## 요약 { #summary } Pydantic 모델을 사용하여 FastAPI에서 폼 필드를 선언할 수 있습니다. 😎 diff --git a/docs/ko/docs/tutorial/request-forms-and-files.md b/docs/ko/docs/tutorial/request-forms-and-files.md index dc1bda21a8..a5309b5c07 100644 --- a/docs/ko/docs/tutorial/request-forms-and-files.md +++ b/docs/ko/docs/tutorial/request-forms-and-files.md @@ -1,37 +1,41 @@ -# 폼 및 파일 요청 +# 폼 및 파일 요청 { #request-forms-and-files } -`File` 과 `Form` 을 사용하여 파일과 폼을 함께 정의할 수 있습니다. +`File` 과 `Form` 을 사용하여 파일과 폼 필드를 동시에 정의할 수 있습니다. /// info | 정보 -파일과 폼 데이터를 함께, 또는 각각 업로드하기 위해 먼저 `python-multipart`를 설치해야합니다. +업로드된 파일 및/또는 폼 데이터를 받으려면 먼저 `python-multipart`를 설치해야 합니다. -예 ) `pip install python-multipart`. +[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 다음 설치해야 합니다. 예: + +```console +$ pip install python-multipart +``` /// -## `File` 및 `Form` 업로드 +## `File` 및 `Form` 임포트 { #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 | 경고 -다수의 `File`과 `Form` 매개변수를 한 *경로 작동*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json`가 아닌 `multipart/form-data`로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다. +다수의 `File`과 `Form` 매개변수를 한 *경로 처리*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json`가 아닌 `multipart/form-data`로 인코딩되기 때문에 JSON으로 받기를 기대하는 `Body` 필드를 함께 선언할 수는 없습니다. -이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다. +이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜의 일부입니다. /// -## 요약 +## 요약 { #recap } 하나의 요청으로 데이터와 파일들을 받아야 할 경우 `File`과 `Form`을 함께 사용하기 바랍니다. diff --git a/docs/ko/docs/tutorial/request-forms.md b/docs/ko/docs/tutorial/request-forms.md index 5ca17b0d68..584cbba35c 100644 --- a/docs/ko/docs/tutorial/request-forms.md +++ b/docs/ko/docs/tutorial/request-forms.md @@ -1,4 +1,4 @@ -# 폼 데이터 +# 폼 데이터 { #form-data } JSON 대신 폼 필드를 받아야 하는 경우 `Form`을 사용할 수 있습니다. @@ -14,13 +14,13 @@ $ pip install python-multipart /// -## `Form` 임포트하기 +## `Form` 임포트하기 { #import-form } `fastapi`에서 `Form`을 임포트합니다: {* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *} -## `Form` 매개변수 정의하기 +## `Form` 매개변수 정의하기 { #define-form-parameters } `Body` 또는 `Query`와 동일한 방식으로 폼 매개변수를 만듭니다: @@ -28,7 +28,7 @@ $ pip install python-multipart 예를 들어, OAuth2 사양을 사용할 수 있는 방법 중 하나("패스워드 플로우"라고 함)로 `username`과 `password`를 폼 필드로 보내야 합니다. -사양에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다. +spec에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다. `Form`을 사용하면 유효성 검사, 예제, 별칭(예: `username` 대신 `user-name`) 등을 포함하여 `Body`(및 `Query`, `Path`, `Cookie`)와 동일한 구성을 선언할 수 있습니다. @@ -44,7 +44,7 @@ $ pip install python-multipart /// -## "폼 필드"에 대해 +## "폼 필드"에 대해 { #about-form-fields } HTML 폼(`
`)이 데이터를 서버로 보내는 방식은 일반적으로 해당 데이터에 대해 "특수" 인코딩을 사용하며, 이는 JSON과 다릅니다. @@ -56,19 +56,18 @@ HTML 폼(`
`)이 데이터를 서버로 보내는 방식은 일반 그러나 폼에 파일이 포함된 경우, `multipart/form-data`로 인코딩합니다. 다음 장에서 파일 처리에 대해 읽을 겁니다. - -이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, POST에 대한 MDN 웹 문서를 참조하세요. +이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, POST에 대한 MDN 웹 문서를 참조하세요. /// /// warning | 경고 -*경로 작업*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다. +*경로 처리*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다. 이는 **FastAPI**의 제한 사항이 아니며 HTTP 프로토콜의 일부입니다. /// -## 요약 +## 요약 { #recap } 폼 데이터 입력 매개변수를 선언하려면 `Form`을 사용하세요. diff --git a/docs/ko/docs/tutorial/response-model.md b/docs/ko/docs/tutorial/response-model.md index a71d649f90..6246ed9ad1 100644 --- a/docs/ko/docs/tutorial/response-model.md +++ b/docs/ko/docs/tutorial/response-model.md @@ -1,81 +1,173 @@ -# 응답 모델 +# 응답 모델 - 반환 타입 { #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`은 "데코레이터" 메소드(`get`, `post`, 등)의 매개변수입니다. 모든 매개변수들과 본문(body)처럼 *경로 작동 함수*가 아닙니다. +`response_model`은 "데코레이터" 메서드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수와 body처럼, *경로 처리 함수*의 매개변수가 아닙니다. /// -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`을 사용하려면 먼저 `email-validator`를 설치하세요. + +[가상 환경](../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 } -여기서 *경로 작동 함수*가 비밀번호를 포함하는 동일한 입력 사용자를 반환할지라도: +이전 예제에서 계속해 봅시다. 함수에 **하나의 타입으로 어노테이션**을 하고 싶지만, 함수에서 실제로는 **더 많은 데이터**를 포함하는 것을 반환할 수 있길 원했습니다. -{* ../../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를 가지고 있음을 확인할 수 있습니다: @@ -83,29 +175,73 @@ FastAPI는 이 `response_model`를 사용하여: -## 응답 모델 인코딩 매개변수 +## 기타 반환 타입 어노테이션 { #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 타입이 아닌 타입이 하나 이상 포함된 여러 타입 간의 union이 있는 경우에도 동일합니다. 예를 들어, 아래는 실패합니다 💥: + +{* ../../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 } -*경로 작동 데코레이터* 매개변수를 `response_model_exclude_unset=True`로 설정 할 수 있습니다: +*경로 처리 데코레이터* 매개변수 `response_model_exclude_unset=True`로 설정할 수 있습니다: -{* ../../docs_src/response_model/tutorial004.py hl[24] *} +{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *} -이러한 기본값은 응답에 포함되지 않고 실제로 설정된 값만 포함됩니다. +그러면 이러한 기본값은 응답에 포함되지 않고, 실제로 설정된 값만 포함됩니다. -따라서 해당 *경로 작동*에 ID가 `foo`인 항목(items)을 요청으로 보내면 (기본값을 제외한) 응답은 다음과 같습니다: +따라서 ID가 `foo`인 항목에 대해 해당 *경로 처리*로 요청을 보내면, (기본값을 제외한) 응답은 다음과 같습니다: ```JSON { @@ -116,24 +252,18 @@ FastAPI는 이 `response_model`를 사용하여: /// info | 정보 -FastAPI는 이를 위해 Pydantic 모델의 `.dict()`의 `exclude_unset` 매개변수를 사용합니다. - -/// - -/// info | 정보 - -아래 또한 사용할 수 있습니다: +다음도 사용할 수 있습니다: * `response_model_exclude_defaults=True` * `response_model_exclude_none=True` -Pydantic 문서에서 `exclude_defaults` 및 `exclude_none`에 대해 설명한 대로 사용할 수 있습니다. +`exclude_defaults` 및 `exclude_none`에 대해 Pydantic 문서에 설명된 대로 사용할 수 있습니다. /// -#### 기본값이 있는 필드를 갖는 값의 데이터 +#### 기본값이 있는 필드에 값이 있는 데이터 { #data-with-values-for-fields-with-defaults } -하지만 모델의 필드가 기본값이 있어도 ID가 `bar`인 항목(items)처럼 데이터가 값을 갖는다면: +하지만 ID가 `bar`인 항목처럼, 기본값이 있는 모델의 필드에 값이 있다면: ```Python hl_lines="3 5" { @@ -144,12 +274,11 @@ FastAPI는 이를 위해 Pydantic 모델의 `.dict()`의 `http.HTTPStatus` 와 같은 `IntEnum` 을 입력받을 수도 있습니다. /// `status_code` 매개변수는: * 응답에서 해당 상태 코드를 반환합니다. -* 상태 코드를 OpenAPI 스키마(및 사용자 인터페이스)에 문서화 합니다. +* 상태 코드를 OpenAPI 스키마(따라서, 사용자 인터페이스에도)에 문서화합니다: - + /// note | 참고 -어떤 응답 코드들은 해당 응답에 본문이 없다는 것을 의미하기도 합니다 (다음 항목 참고). +일부 응답 코드(다음 섹션 참고)는 응답에 본문이 없다는 것을 나타냅니다. -이에 따라 FastAPI는 응답 본문이 없음을 명시하는 OpenAPI를 생성합니다. +FastAPI는 이를 알고 있으며, 응답 본문이 없다고 명시하는 OpenAPI 문서를 생성합니다. /// -## HTTP 상태 코드에 대하여 +## HTTP 상태 코드에 대하여 { #about-http-status-codes } /// note | 참고 -만약 HTTP 상태 코드에 대하여 이미 알고있다면, 다음 항목으로 넘어가십시오. +만약 HTTP 상태 코드가 무엇인지 이미 알고 있다면, 다음 섹션으로 넘어가세요. /// -HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다. +HTTP에서는 응답의 일부로 3자리 숫자 상태 코드를 보냅니다. -이 상태 코드들은 각자를 식별할 수 있도록 지정된 이름이 있으나, 중요한 것은 숫자 코드입니다. +이 상태 코드들은 이를 식별할 수 있도록 이름이 연결되어 있지만, 중요한 부분은 숫자입니다. 요약하자면: -* `1xx` 상태 코드는 "정보"용입니다. 이들은 직접적으로는 잘 사용되지는 않습니다. 이 상태 코드를 갖는 응답들은 본문을 가질 수 없습니다. -* **`2xx`** 상태 코드는 "성공적인" 응답을 위해 사용됩니다. 가장 많이 사용되는 유형입니다. - * `200` 은 디폴트 상태 코드로, 모든 것이 "성공적임"을 의미합니다. - * 다른 예로는 `201` "생성됨"이 있습니다. 일반적으로 데이터베이스에 새로운 레코드를 생성한 후 사용합니다. - * 단, `204` "내용 없음"은 특별한 경우입니다. 이것은 클라이언트에게 반환할 내용이 없는 경우 사용합니다. 따라서 응답은 본문을 가질 수 없습니다. -* **`3xx`** 상태 코드는 "리다이렉션"용입니다. 본문을 가질 수 없는 `304` "수정되지 않음"을 제외하고, 이 상태 코드를 갖는 응답에는 본문이 있을 수도, 없을 수도 있습니다. -* **`4xx`** 상태 코드는 "클라이언트 오류" 응답을 위해 사용됩니다. 이것은 아마 가장 많이 사용하게 될 두번째 유형입니다. - * 일례로 `404` 는 "찾을 수 없음" 응답을 위해 사용합니다. - * 일반적인 클라이언트 오류의 경우 `400` 을 사용할 수 있습니다. -* `5xx` 상태 코드는 서버 오류에 사용됩니다. 이것들을 직접 사용할 일은 거의 없습니다. 응용 프로그램 코드나 서버의 일부에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다. +* `100 - 199` 는 "정보"용입니다. 직접 사용할 일은 거의 없습니다. 이 상태 코드를 갖는 응답은 본문을 가질 수 없습니다. +* **`200 - 299`** 는 "성공적인" 응답을 위한 것입니다. 가장 많이 사용하게 될 유형입니다. + * `200` 은 기본 상태 코드로, 모든 것이 "OK"임을 의미합니다. + * 다른 예로는 `201` "생성됨"이 있습니다. 일반적으로 데이터베이스에 새 레코드를 생성한 후 사용합니다. + * 특별한 경우로 `204` "내용 없음"이 있습니다. 이 응답은 클라이언트에게 반환할 내용이 없을 때 사용되며, 따라서 응답은 본문을 가지면 안 됩니다. +* **`300 - 399`** 는 "리다이렉션"용입니다. 이 상태 코드를 갖는 응답은 본문이 있을 수도 없을 수도 있으며, 본문이 없어야 하는 `304` "수정되지 않음"을 제외합니다. +* **`400 - 499`** 는 "클라이언트 오류" 응답을 위한 것입니다. 아마 두 번째로 가장 많이 사용하게 될 유형입니다. + * 예를 들어 `404` 는 "찾을 수 없음" 응답을 위해 사용합니다. + * 클라이언트의 일반적인 오류에는 `400` 을 그냥 사용할 수 있습니다. +* `500 - 599` 는 서버 오류에 사용됩니다. 직접 사용할 일은 거의 없습니다. 애플리케이션 코드의 일부나 서버에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다. /// tip | 팁 -각각의 상태 코드와 이들이 의미하는 내용에 대해 더 알고싶다면 MDN HTTP 상태 코드에 관한 문서 를 확인하십시오. +각 상태 코드와 어떤 코드가 어떤 용도인지 더 알고 싶다면 MDN의 HTTP 상태 코드에 관한 문서를 확인하세요. /// -## 이름을 기억하는 쉬운 방법 +## 이름을 기억하는 쉬운 방법 { #shortcut-to-remember-the-names } -상기 예시 참고: +이전 예시를 다시 확인해보겠습니다: -{* ../../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 상태 코드와 동일한 번호를 갖고있지만, 이를 사용하면 편집기의 자동완성 기능을 사용할 수 있습니다: +이것들은 단지 편의를 위한 것으로, 동일한 숫자를 갖고 있지만, 이를 통해 편집기의 자동완성 기능으로 찾을 수 있습니다: - + -/// note | 기술적 세부사항 +/// note | 기술 세부사항 `from starlette import status` 역시 사용할 수 있습니다. @@ -96,6 +96,6 @@ HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다 /// -## 기본값 변경 +## 기본값 변경 { #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}에서, 여기서 선언하는 기본값과 다른 상태 코드를 반환하는 방법을 확인할 수 있습니다. diff --git a/docs/ko/docs/tutorial/schema-extra-example.md b/docs/ko/docs/tutorial/schema-extra-example.md index 77e94db720..b2b54836ac 100644 --- a/docs/ko/docs/tutorial/schema-extra-example.md +++ b/docs/ko/docs/tutorial/schema-extra-example.md @@ -1,43 +1,21 @@ -# 요청 예제 데이터 선언 +# 요청 예제 데이터 선언 { #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에서 Pydantic 공식 문서: Model Config에 나와 있는 것처럼 `dict`를 받는 `model_config` 어트리뷰트를 사용할 것입니다. +Pydantic 문서: Configuration에 설명된 것처럼 `dict`를 받는 `model_config` 어트리뷰트를 사용할 수 있습니다. `"json_schema_extra"`를 생성된 JSON 스키마에서 보여주고 싶은 별도의 데이터와 `examples`를 포함하는 `dict`으로 설정할 수 있습니다. -//// - -//// tab | Pydantic v1 - -Pydantic v1에서 Pydantic 공식 문서: Schema customization에서 설명하는 것처럼, 내부 클래스인 `Config`와 `schema_extra`를 사용할 것입니다. - -`schema_extra`를 생성된 JSON 스키마에서 보여주고 싶은 별도의 데이터와 `examples`를 포함하는 `dict`으로 설정할 수 있습니다. - -//// - /// tip | 팁 JSON 스키마를 확장하고 여러분의 별도의 자체 데이터를 추가하기 위해 같은 기술을 사용할 수 있습니다. @@ -52,19 +30,19 @@ 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()` @@ -74,45 +52,45 @@ Pydantic 모델과 같이 `Field()`를 사용할 때 추가적인 `examples`를 * `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`에서 다음과 같이 보일 것입니다: -### 다중 `examples`를 포함한 `Body` +### 다중 `examples`를 포함한 `Body` { #body-with-multiple-examples } 물론 여러 `examples`를 넘길 수 있습니다: {* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *} -이와 같이 하면 이 예제는 그 본문 데이터를 위한 내부 **JSON 스키마**의 일부가 될 것입니다. +이와 같이 하면 예제들은 그 본문 데이터의 내부 **JSON 스키마**의 일부가 될 것입니다. 그럼에도 불구하고, 지금 이 문서를 작성하는 시간에, 문서 UI를 보여주는 역할을 맡은 Swagger UI는 **JSON 스키마** 속 데이터를 위한 여러 예제의 표현을 지원하지 않습니다. 하지만 해결 방안을 밑에서 읽어보세요. -### OpenAPI-특화 `examples` +### OpenAPI-특화 `examples` { #openapi-specific-examples } -**JSON 스키마**가 `examples`를 지원하기 전 부터, OpenAPI는 `examples`이라 불리는 다른 필드를 지원해 왔습니다. +**JSON 스키마**가 `examples`를 지원하기 전부터 OpenAPI는 `examples`이라 불리는 다른 필드를 지원해 왔습니다. -이 **OpenAPI-특화** `examples`는 OpenAPI 명세서의 다른 구역으로 들어갑니다. 각 JSON 스키마 내부가 아니라 **각 *경로 작동* 세부 정보**에 포함됩니다. +이 **OpenAPI-특화** `examples`는 OpenAPI 명세서의 다른 구역으로 들어갑니다. 각 JSON 스키마 내부가 아니라 **각 *경로 처리* 세부 정보**에 포함됩니다. 그리고 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()` @@ -122,26 +100,26 @@ Pydantic 모델과 같이 `Field()`를 사용할 때 추가적인 `examples`를 * `Form()` * `File()` -`dict`의 키가 또 다른 `dict`인 각 예제와 값을 구별합니다. +`dict`의 키는 각 예제를 식별하고, 각 값은 또 다른 `dict`입니다. -각각의 특정 `examples` 속 `dict` 예제는 다음을 포함할 수 있습니다: +`examples` 안의 각 특정 예제 `dict`에는 다음이 포함될 수 있습니다: * `summary`: 예제에 대한 짧은 설명문. * `description`: 마크다운 텍스트를 포함할 수 있는 긴 설명문. * `value`: 실제로 보여지는 예시, 예를 들면 `dict`. -* `externalValue`: `value`의 대안이며 예제를 가르키는 URL. 비록 `value`처럼 많은 도구를 지원하지 못할 수 있습니다. +* `externalValue`: `value`의 대안이며 예제를 가리키는 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`는 다음과 같이 보일 것입니다: -## 기술적 세부 사항 +## 기술적 세부 사항 { #technical-details } /// tip | 팁 @@ -167,12 +145,12 @@ JSON 스키마는 `examples`를 가지고 있지 않았고, 따라서 OpenAPI는 OpenAPI는 또한 `example`과 `examples` 필드를 명세서의 다른 부분에 추가했습니다: -* `(명세서에 있는) Parameter Object`는 FastAPI의 다음 기능에서 쓰였습니다: +* `Parameter Object` (명세서에 있는)는 FastAPI의 다음 기능에서 쓰였습니다: * `Path()` * `Query()` * `Header()` * `Cookie()` -* (명세서에 있는)`Media Type Object`속 `content`에 있는 `Request Body Object`는 FastAPI의 다음 기능에서 쓰였습니다: +* `Request Body Object`, `Media Type Object` (명세서에 있는)의 `content` 필드에 있는는 FastAPI의 다음 기능에서 쓰였습니다: * `Body()` * `File()` * `Form()` @@ -183,15 +161,15 @@ OpenAPI는 또한 `example`과 `examples` 필드를 명세서의 다른 부분 /// -### JSON 스키마의 `examples` 필드 +### JSON 스키마의 `examples` 필드 { #json-schemas-examples-field } -하지만, 후에 JSON 스키마는 `examples`필드를 명세서의 새 버전에 추가했습니다. +하지만, 후에 JSON 스키마는 `examples` 필드를 명세서의 새 버전에 추가했습니다. 그리고 새로운 OpenAPI 3.1.0은 이 새로운 `examples` 필드가 포함된 최신 버전 (JSON 스키마 2020-12)을 기반으로 했습니다. -이제 새로운 `examples` 필드는 이전의 단일 (그리고 커스텀) `example` 필드보다 우선되며, `example`은 사용하지 않는 것이 좋습니다. +그리고 이제 이 새로운 `examples` 필드는 이제 지원 중단된, 예전의 단일 (그리고 커스텀) `example` 필드보다 우선됩니다. -JSON 스키마의 새로운 `examples` 필드는 예제 속 **단순한 `list`**이며, (위에서 상술한 것처럼) OpenAPI의 다른 곳에 존재하는 dict으로 된 추가적인 메타데이터가 아닙니다. +JSON 스키마의 새로운 `examples` 필드는 예제의 **단순한 `list`**일 뿐이며, (위에서 상술한 것처럼) OpenAPI의 다른 곳에 존재하는 추가 메타데이터가 있는 dict가 아닙니다. /// info | 정보 @@ -201,24 +179,24 @@ JSON 스키마의 새로운 `examples` 필드는 예제 속 **단순한 `list`** /// -### 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 부분 밖에서). -하지만 지금은 FastAPI 0.99.0 및 이후 버전에서는 JSON 스키마 2020-12를 사용하는 OpenAPI 3.1.0과 Swagger UI 5.0.0 및 이후 버전을 사용하며, 모든 것이 더 일관성을 띄고 예시는 JSON 스키마에 포함됩니다. +하지만 이제 FastAPI 0.99.0 및 이후 버전에서는 JSON 스키마 2020-12를 사용하는 OpenAPI 3.1.0과 Swagger UI 5.0.0 및 이후 버전을 사용하기 때문에, 모든 것이 더 일관성을 띄고 예제도 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 기준), 사용자는 문서에 여러 예제를 표시할 방법이 없었습니다. -이를 해결하기 위해, FastAPI `0.103.0`은 새로운 매개변수인 `openapi_examples`를 포함하는 예전 **OpenAPI-특화** `examples` 필드를 선언하기 위한 **지원을 추가**했습니다. 🤓 +이를 해결하기 위해, FastAPI `0.103.0`은 새로운 매개변수인 `openapi_examples`로 동일한 예전 **OpenAPI-특화** `examples` 필드를 선언하는 **지원**을 추가했습니다. 🤓 -### 요약 +### 요약 { #summary } -저는 역사를 그다지 좋아하는 편이 아니라고 말하고는 했지만... "기술 역사" 강의를 가르치는 지금의 저를 보세요. +저는 역사를 그다지 좋아하는 편이 아니라고 말하고는 했지만... "기술 역사" 강의를 하는 지금의 저를 보세요. 😅 -요약하자면 **FastAPI 0.99.0 혹은 그 이상의 버전**으로 업그레이드하는 것은 많은 것들이 더 **쉽고, 일관적이며 직관적이게** 되며, 여러분은 이 모든 역사적 세부 사항을 알 필요가 없습니다. 😎 +요약하자면 **FastAPI 0.99.0 혹은 그 이상의 버전**으로 업그레이드하면, 많은 것들이 훨씬 더 **단순하고, 일관적이며 직관적**이 되며, 여러분은 이 모든 역사적 세부 사항을 알 필요가 없습니다. 😎 diff --git a/docs/ko/docs/tutorial/security/get-current-user.md b/docs/ko/docs/tutorial/security/get-current-user.md index 98ef3885e4..f21a22b7a0 100644 --- a/docs/ko/docs/tutorial/security/get-current-user.md +++ b/docs/ko/docs/tutorial/security/get-current-user.md @@ -1,105 +1,105 @@ -# 현재 사용자 가져오기 +# 현재 사용자 가져오기 { #get-current-user } -이전 장에서 (의존성 주입 시스템을 기반으로 한)보안 시스템은 *경로 작동 함수*에서 `str`로 `token`을 제공했습니다: +이전 장에서 (의존성 주입 시스템을 기반으로 한) 보안 시스템은 *경로 처리 함수*에 `str`로 `token`을 제공했습니다: -{* ../../docs_src/security/tutorial001.py hl[10] *} +{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} -그러나 아직도 유용하지 않습니다. +하지만 이는 여전히 그다지 유용하지 않습니다. -현재 사용자를 제공하도록 합시다. +현재 사용자를 제공하도록 해봅시다. -## 유저 모델 생성하기 +## 사용자 모델 생성하기 { #create-a-user-model } -먼저 Pydantic 유저 모델을 만들어 보겠습니다. +먼저 Pydantic 사용자 모델을 만들어 봅시다. -Pydantic을 사용하여 본문을 선언하는 것과 같은 방식으로 다른 곳에서 사용할 수 있습니다. +Pydantic을 사용해 본문을 선언하는 것과 같은 방식으로, 다른 곳에서도 어디서든 사용할 수 있습니다: -{* ../../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`를 만들어 봅시다. -의존성이 하위 의존성을 가질 수 있다는 것을 기억하십니까? +의존성이 하위 의존성을 가질 수 있다는 것을 기억하시나요? -`get_current_user`는 이전에 생성한 것과 동일한 `oauth2_scheme`과 종속성을 갖게 됩니다. +`get_current_user`는 이전에 생성한 것과 동일한 `oauth2_scheme`에 대한 의존성을 갖게 됩니다. -이전에 *경로 작동*에서 직접 수행했던 것과 동일하게 새 종속성 `get_current_user`는 하위 종속성 `oauth2_scheme`에서 `str`로 `token`을 수신합니다. +이전에 *경로 처리*에서 직접 수행했던 것과 동일하게, 새 의존성 `get_current_user`는 하위 의존성 `oauth2_scheme`로부터 `str`로 `token`을 받게 됩니다: -{* ../../docs_src/security/tutorial002.py hl[25] *} +{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *} -## 유저 가져오기 +## 사용자 가져오기 { #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] *} -## 현재 유저 주입하기 +## 현재 사용자 주입하기 { #inject-the-current-user } -이제 *경로 작동*에서 `get_current_user`와 동일한 `Depends`를 사용할 수 있습니다. +이제 *경로 처리*에서 `get_current_user`와 함께 같은 `Depends`를 사용할 수 있습니다: -{* ../../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 | 팁 -요청 본문도 Pydantic 모델로 선언된다는 것을 기억할 것입니다. +요청 본문도 Pydantic 모델로 선언된다는 것을 기억하실지도 모릅니다. -여기서 **FastAPI**는 `Depends`를 사용하고 있기 때문에 혼동되지 않습니다. +여기서 **FastAPI**는 `Depends`를 사용하고 있기 때문에 혼동하지 않습니다. /// /// check | 확인 -이 의존성 시스템이 설계된 방식은 모두 `User` 모델을 반환하는 다양한 의존성(다른 "의존적인")을 가질 수 있도록 합니다. +이 의존성 시스템이 설계된 방식은 모두 `User` 모델을 반환하는 서로 다른 의존성(서로 다른 "dependables")을 가질 수 있도록 합니다. -해당 타입의 데이터를 반환할 수 있는 의존성이 하나만 있는 것으로 제한되지 않습니다. +해당 타입의 데이터를 반환할 수 있는 의존성이 하나만 있어야 하는 것으로 제한되지 않습니다. /// -## 다른 모델 +## 다른 모델 { #other-models } -이제 *경로 작동 함수*에서 현재 사용자를 직접 가져올 수 있으며 `Depends`를 사용하여 **의존성 주입** 수준에서 보안 메커니즘을 처리할 수 있습니다. +이제 *경로 처리 함수*에서 현재 사용자를 직접 가져올 수 있으며, `Depends`를 사용해 **의존성 주입** 수준에서 보안 메커니즘을 처리할 수 있습니다. -그리고 보안 요구 사항에 대한 모든 모델 또는 데이터를 사용할 수 있습니다(이 경우 Pydantic 모델 `User`). +그리고 보안 요구 사항을 위해 어떤 모델이나 데이터든 사용할 수 있습니다(이 경우 Pydantic 모델 `User`). -그러나 일부 특정 데이터 모델, 클래스 또는 타입을 사용하도록 제한되지 않습니다. +하지만 특정 데이터 모델, 클래스 또는 타입만 사용해야 하는 것은 아닙니다. -모델에 `id`와 `email`이 있고 `username`이 없길 원하십니까? 맞습니다. 이들은 동일한 도구를 사용할 수 있습니다. +모델에 `id`와 `email`이 있고 `username`은 없게 하고 싶으신가요? 물론입니다. 같은 도구를 사용할 수 있습니다. -`str`만 갖고 싶습니까? 아니면 그냥 `dict`를 갖고 싶습니까? 아니면 데이터베이스 클래스 모델 인스턴스를 직접 갖고 싶습니까? 그들은 모두 같은 방식으로 작동합니다. +`str`만 갖고 싶으신가요? 아니면 `dict`만요? 또는 데이터베이스 클래스 모델 인스턴스를 직접 쓰고 싶으신가요? 모두 같은 방식으로 동작합니다. -실제로 애플리케이션에 로그인하는 사용자가 없지만 액세스 토큰만 있는 로봇, 봇 또는 기타 시스템이 있습니까? 다시 말하지만 모두 동일하게 작동합니다. +애플리케이션에 로그인하는 사용자는 없고, 액세스 토큰만 가진 로봇, 봇 또는 다른 시스템만 있나요? 이것도 마찬가지로 모두 동일하게 동작합니다. -애플리케이션에 필요한 모든 종류의 모델, 모든 종류의 클래스, 모든 종류의 데이터베이스를 사용하십시오. **FastAPI**는 의존성 주입 시스템을 다루었습니다. +애플리케이션에 필요한 어떤 종류의 모델, 어떤 종류의 클래스, 어떤 종류의 데이터베이스든 사용하세요. **FastAPI**는 의존성 주입 시스템으로 이를 지원합니다. -## 코드 사이즈 +## 코드 크기 { #code-size } -이 예는 장황해 보일 수 있습니다. 동일한 파일에서 보안, 데이터 모델, 유틸리티 기능 및 *경로 작동*을 혼합하고 있음을 염두에 두십시오. +이 예시는 장황해 보일 수 있습니다. 동일한 파일에서 보안, 데이터 모델, 유틸리티 함수 및 *경로 처리*를 섞어서 사용하고 있다는 점을 기억하세요. -그러나 이게 키포인트입니다. +하지만 여기 핵심이 있습니다. -보안과 종속성 주입 항목을 한 번만 작성하면 됩니다. +보안과 의존성 주입 관련 코드는 한 번만 작성합니다. -그리고 원하는 만큼 복잡하게 만들 수 있습니다. 그래도 유연성과 함께 한 곳에 한 번에 작성할 수 있습니다. +그리고 원하는 만큼 복잡하게 만들 수 있습니다. 그럼에도 여전히 한 번만, 한 곳에만 작성하면 됩니다. 유연성을 모두 유지하면서요. -그러나 동일한 보안 시스템을 사용하여 수천 개의 엔드포인트(*경로 작동*)를 가질 수 있습니다. +하지만 같은 보안 시스템을 사용해 수천 개의 엔드포인트(*경로 처리*)를 가질 수 있습니다. -그리고 그들 모두(또는 원하는 부분)는 이러한 의존성 또는 생성한 다른 의존성을 재사용하는 이점을 얻을 수 있습니다. +그리고 그들 모두(또는 원하는 일부)는 이러한 의존성 또는 여러분이 생성한 다른 의존성을 재사용하는 이점을 얻을 수 있습니다. -그리고 이 수천 개의 *경로 작동*은 모두 3줄 정도로 줄일 수 있습니다. +그리고 이 수천 개의 *경로 처리*는 3줄 정도로도 만들 수 있습니다: -{* ../../docs_src/security/tutorial002.py hl[30:32] *} +{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *} -## 요약 +## 요약 { #recap } -이제 *경로 작동 함수*에서 현재 사용자를 직접 가져올 수 있습니다. +이제 *경로 처리 함수*에서 현재 사용자를 직접 가져올 수 있습니다. -우리는 이미 이들 사이에 있습니다. +우리는 이미 절반은 왔습니다. -사용자/클라이언트가 실제로 `username`과 `password`를 보내려면 *경로 작동*을 추가하기만 하면 됩니다. +사용자/클라이언트가 실제로 `username`과 `password`를 보내도록 하는 *경로 처리*만 추가하면 됩니다. -다음 장을 확인해 봅시다. +다음에 이어집니다. diff --git a/docs/ko/docs/tutorial/security/oauth2-jwt.md b/docs/ko/docs/tutorial/security/oauth2-jwt.md index 8d27856e84..907795ca4b 100644 --- a/docs/ko/docs/tutorial/security/oauth2-jwt.md +++ b/docs/ko/docs/tutorial/security/oauth2-jwt.md @@ -1,36 +1,36 @@ -# 패스워드 해싱을 이용한 OAuth2, JWT 토큰을 사용하는 Bearer 인증 +# 패스워드(해싱 포함)를 사용하는 OAuth2, JWT 토큰을 사용하는 Bearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens } -모든 보안 흐름을 구성했으므로, 이제 JWT 토큰과 패스워드 해싱을 사용해 애플리케이션을 안전하게 만들 것입니다. +모든 보안 흐름을 구성했으므로, 이제 JWT 토큰과 안전한 패스워드 해싱을 사용해 애플리케이션을 실제로 안전하게 만들겠습니다. -이 코드는 실제로 애플리케이션에서 패스워드를 해싱하여 DB에 저장하는 등의 작업에 활용할 수 있습니다. +이 코드는 실제로 애플리케이션에서 사용할 수 있으며, 패스워드 해시를 데이터베이스에 저장하는 등의 작업에 활용할 수 있습니다. -이전 장에 이어서 시작해 봅시다. +이전 장에서 멈춘 지점부터 시작해 내용을 확장해 나가겠습니다. -## JWT +## JWT 알아보기 { #about-jwt } -JWT 는 "JSON Web Tokens" 을 의미합니다. +JWT는 "JSON Web Tokens"를 의미합니다. -JSON 객체를 공백이 없는 긴 문자열로 인코딩하는 표준이며, 다음과 같은 형태입니다: +JSON 객체를 공백이 없는 길고 밀집된 문자열로 부호화하는 표준입니다. 다음과 같은 형태입니다: ``` eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ``` -JWT는 암호화되지 않아 누구든지 토큰에서 정보를 복원할 수 있습니다. +암호화된 것이 아니므로, 누구나 내용에서 정보를 복원할 수 있습니다. -하지만 JWT는 서명되어 있습니다. 그래서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한게 맞는지 검증할 수 있습니다. +하지만 서명되어 있습니다. 따라서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한 것이 맞는지 검증할 수 있습니다. -만료 기간이 일주일인 토큰을 발행했다고 가정해 봅시다. 다음 날 사용자가 토큰을 가져왔을 때, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다. +예를 들어 만료 기간이 1주일인 토큰을 생성할 수 있습니다. 그리고 사용자가 다음 날 토큰을 가지고 돌아오면, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다. -일주일 뒤에는 토큰이 만료될 것이고, 사용자는 인가되지 않아 새 토큰을 받기 위해 다시 로그인해야 할 것입니다. 만약 사용자(또는 제3자)가 토큰을 수정하거나 만료일을 변경하면, 서명이 일치하지 않기 때문에 알아챌 수 있을 것입니다. +1주일 뒤에는 토큰이 만료되고 사용자는 인가되지 않으므로 새 토큰을 받기 위해 다시 로그인해야 합니다. 그리고 사용자(또는 제3자)가 만료 시간을 바꾸기 위해 토큰을 수정하려고 하면, 서명이 일치하지 않기 때문에 이를 알아챌 수 있습니다. -만약 JWT 토큰을 다뤄보고, 작동 방식도 알아보고 싶다면 https://jwt.io 을 확인하십시오. +JWT 토큰을 직접 다뤄보고 동작 방식을 확인해보고 싶다면 https://jwt.io를 확인하십시오. -## `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`를 설치하십시오:
@@ -42,77 +42,77 @@ $ pip install pyjwt
-/// info | 참고 +/// info -RSA나 ECDSA 같은 전자 서명 알고리즘을 사용하려면, `pyjwt[crypto]`라는 암호화 라이브러리 의존성을 설치해야 합니다. +RSA나 ECDSA 같은 전자 서명 알고리즘을 사용할 계획이라면, cryptography 라이브러리 의존성인 `pyjwt[crypto]`를 설치해야 합니다. -더 자세한 내용은 PyJWT 설치 에서 확인할 수 있습니다. +자세한 내용은 PyJWT Installation docs에서 확인할 수 있습니다. /// -## 패스워드 해싱 +## 패스워드 해싱 { #password-hashing } -"해싱(Hashing)"은 어떤 내용(여기서는 패스워드)을 해석할 수 없는 일련의 바이트 집합(단순 문자열)으로 변환하는 것을 의미합니다. +"해싱(Hashing)"은 어떤 내용(여기서는 패스워드)을 알아볼 수 없는 바이트 시퀀스(그냥 문자열)로 변환하는 것을 의미합니다. -동일한 내용(똑같은 패스워드)을 해싱하면 동일한 문자열을 얻습니다. +정확히 같은 내용(정확히 같은 패스워드)을 넣으면 정확히 같은 알아볼 수 없는 문자열이 나옵니다. -하지만 그 문자열을 다시 패스워드로 되돌릴 수는 없습니다. +하지만 그 알아볼 수 없는 문자열에서 다시 패스워드로 되돌릴 수는 없습니다. -### 패스워드를 해싱하는 이유 +### 패스워드 해싱을 사용하는 이유 { #why-use-password-hashing } -데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시 값만 얻을 수 있습니다. +데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시만 얻게 됩니다. -따라서 침입자는 훔친 사용자 패스워드를 다른 시스템에서 활용할 수 없습니다. (대다수 사용자가 여러 시스템에서 동일한 패스워드를 사용하기 때문에 평문 패스워드가 유출되면 위험합니다.) +따라서 침입자는 그 패스워드를 다른 시스템에서 사용해 보려고 시도할 수 없습니다(많은 사용자가 어디서나 같은 패스워드를 사용하므로, 이는 위험합니다). -## `passlib` 설치 +## `pwdlib` 설치 { #install-pwdlib } -PassLib는 패스워드 해시를 다루는 훌륭한 파이썬 패키지입니다. +pwdlib는 패스워드 해시를 다루기 위한 훌륭한 Python 패키지입니다. -많은 안전한 해시 알고리즘과 도구들을 지원합니다. +많은 안전한 해싱 알고리즘과 이를 다루기 위한 유틸리티를 지원합니다. -추천하는 알고리즘은 "Bcrypt"입니다. +추천 알고리즘은 "Argon2"입니다. -[가상환경](../../virtual-environments.md){.internal-link target=_blank} 을 만들고 활성화한 다음 PassLib와 Bcrypt를 설치하십시오: +[가상환경](../../virtual-environments.md){.internal-link target=_blank}을 만들고 활성화한 다음 Argon2와 함께 pwdlib를 설치하십시오:
```console -$ pip install "passlib[bcrypt]" +$ pip install "pwdlib[argon2]" ---> 100% ```
-/// 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 "컨텍스트(context)"를 생성합니다. 이것은 패스워드를 해싱하고 검증하는데 사용합니다. +권장 설정으로 PasswordHash 인스턴스를 생성합니다. 이는 패스워드를 해싱하고 검증하는 데 사용됩니다. -/// tip | 팁 +/// tip -PassLib 컨텍스트는 다양한 해싱 알고리즘을 사용할 수 있는 기능을 제공하며, 더 이상 사용이 권장되지 않는 오래된 해싱 알고리즘을 검증하는 기능도 포함되어 있습니다. +pwdlib는 bcrypt 해싱 알고리즘도 지원하지만 레거시 알고리즘은 포함하지 않습니다. 오래된 해시로 작업해야 한다면 passlib 라이브러리를 사용하는 것을 권장합니다. -예를 들어, 다른 시스템(Django 같은)에서 생성한 패스워드를 읽고 검증할 수 있으며, 새로운 패스워드를 Bcrypt 같은 다른 알고리즘으로 해싱할 수도 있습니다. +예를 들어, 다른 시스템(Django 같은)에서 생성한 패스워드를 읽고 검증하되, 새 패스워드는 Argon2나 Bcrypt 같은 다른 알고리즘으로 해싱하도록 할 수 있습니다. -그리고 동시에 그런 모든 알고리즘과 호환성을 유지합니다. +그리고 동시에 그 모든 것과 호환되게 만들 수 있습니다. /// 사용자로부터 받은 패스워드를 해싱하는 유틸리티 함수를 생성합니다. -그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티 함수도 생성합니다. +그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티도 생성합니다. 그리고 사용자를 인증하고 반환하는 또 다른 함수도 생성합니다. @@ -120,17 +120,17 @@ PassLib 컨텍스트는 다양한 해싱 알고리즘을 사용할 수 있는 /// 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 토큰을 서명하는 데 사용할 임의의 비밀 키를 생성합니다. -안전한 임의의 비밀키를 생성하려면 다음 명령어를 사용하십시오: +안전한 임의의 비밀 키를 생성하려면 다음 명령을 사용하십시오:
@@ -142,67 +142,67 @@ $ openssl rand -hex 32
-그리고 생성한 비밀키를 복사해 변수 `SECRET_KEY`에 대입합니다. (이 예제의 변수 값을 그대로 사용하지 마십시오.) +그리고 출력 결과를 변수 `SECRET_KEY`에 복사합니다(예제의 값을 사용하지 마십시오). -JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM` 을 생성하고 `"HS256"` 으로 설정합니다. +JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM`을 생성하고 `"HS256"`으로 설정합니다. -토큰 만료 기간을 위한 변수를 생성합니다. +토큰 만료를 위한 변수를 생성합니다. -응답을 위한 토큰 엔드포인트에 사용될 Pydantic 모델을 정의합니다. +응답을 위해 토큰 엔드포인트에서 사용될 Pydantic 모델을 정의합니다. 새 액세스 토큰을 생성하기 위한 유틸리티 함수를 생성합니다. {* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *} -## 의존성 수정 +## 의존성 업데이트 { #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 } -토큰의 만료 시각을 설정하기 위해 `timedelta` 를 생성합니다. +토큰의 만료 시간으로 `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` 키가 있습니다. -사용 여부는 선택사항이지만, 사용자의 식별 정보를 저장할 수 있으므로 여기서는 이를 사용합니다. +선택적으로 사용할 수 있지만, 여기에 사용자 식별 정보를 넣게 되므로 여기서는 이를 사용합니다. -JWT는 사용자를 식별하고 사용자가 API를 직접 사용할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수도 있습니다. +JWT는 사용자를 식별하고 사용자가 API에서 직접 작업을 수행할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수 있습니다. -예를 들어 "자동차"나 "블로그 게시물"을 식별하는 데 사용할 수 있습니다. +예를 들어 "자동차"나 "블로그 게시물"을 식별할 수 있습니다. -그리고 "자동차를 운전하다"나 "블로그 게시물을 수정하다"처럼 해당 엔터티에 대한 권한을 추가할 수 있습니다. +그런 다음 해당 엔터티에 대한 권한(자동차의 경우 "drive", 블로그의 경우 "edit" 등)을 추가할 수 있습니다. -그 후 이 JWT 토큰을 사용자(또는 봇)에게 제공하면, 그들은 계정을 따로 만들 필요 없이 API가 생성한 JWT 토큰만으로 작업(자동차 운전 또는 블로그 게시물 편집)을 수행할 수 있습니다. +그리고 그 JWT 토큰을 사용자(또는 봇)에게 제공하면, 계정이 없어도 API가 생성한 JWT 토큰만으로 그 동작들(자동차 운전, 블로그 편집)을 수행할 수 있습니다. -이러한 개념을 활용하면 JWT는 훨씬 더 복잡한 시나리오에도 사용할 수 있습니다. +이러한 아이디어를 활용하면 JWT는 훨씬 더 정교한 시나리오에도 사용될 수 있습니다. -이 경우 여러 엔터티가 동일한 ID를 가질 수 있습니다. 예를 들어 foo라는 ID를 가진 사용자, 자동차, 블로그 게시물이 있을 수 있습니다. +그런 경우 여러 엔터티가 동일한 ID(예: `foo`)를 가질 수도 있습니다(사용자 `foo`, 자동차 `foo`, 블로그 게시물 `foo`). -그래서 ID 충돌을 방지하기 위해, 사용자의 JWT 토큰을 생성할 때 접두사로 `sub` 키를 추가할 수 있습니다. 예를 들어 `username:` 을 붙이는 방식입니다. 이 예제에서는 `sub` 값이 `username:johndoe`이 될 수 있습니다. +따라서 ID 충돌을 방지하기 위해, 사용자에 대한 JWT 토큰을 생성할 때 `sub` 키의 값에 접두사를 붙일 수 있습니다. 예를 들어 `username:` 같은 것입니다. 그러면 이 예제에서 `sub` 값은 `username:johndoe`가 될 수 있습니다. -가장 중요한 점은 `sub` 키는 전체 애플리케이션에서 고유한 식별자가 되어야 하며 문자열이어야 한다는 점입니다. +기억해야 할 중요한 점은 `sub` 키가 전체 애플리케이션에서 고유한 식별자여야 하고, 문자열이어야 한다는 것입니다. -## 확인해봅시다 +## 확인하기 { #check-it } 서버를 실행하고 문서로 이동하십시오: http://127.0.0.1:8000/docs. -다음과 같은 사용자 인터페이스를 볼 수 있습니다: +다음과 같은 사용자 인터페이스가 보일 것입니다: -이전과 같은 방법으로 애플리케이션에 인증하십시오. +이전과 같은 방법으로 애플리케이션을 인가하십시오. 다음 인증 정보를 사용하십시오: @@ -211,13 +211,13 @@ Password: `secret` /// check -코드 어디에도 평문 패스워드 "`secret`" 이 없다는 점에 유의하십시오. 해시된 버전만 있습니다. +코드 어디에도 평문 패스워드 "`secret`"은 없고, 해시된 버전만 있다는 점에 유의하십시오. /// -`/users/me/` 를 호출하면 다음과 같은 응답을 얻을 수 있습니다: +엔드포인트 `/users/me/`를 호출하면 다음과 같은 응답을 받게 됩니다: ```JSON { @@ -230,44 +230,44 @@ Password: `secret` -개발자 도구를 열어보면 전송된 데이터에 토큰만 포함된 것을 확인할 수 있습니다. 패스워드는 사용자를 인증하고 액세스 토큰을 받기 위한 첫 번째 요청에만 전송되며, 이후에는 전송되지 않습니다: +개발자 도구를 열어보면 전송된 데이터에는 토큰만 포함되어 있고, 패스워드는 사용자를 인증하고 해당 액세스 토큰을 얻기 위한 첫 번째 요청에서만 전송되며 이후에는 전송되지 않는 것을 확인할 수 있습니다: /// note -`Bearer `로 시작하는 `Authorization` 헤더에 주목하십시오. +`Bearer `로 시작하는 값을 가진 `Authorization` 헤더에 주목하십시오. /// -## `scopes` 의 고급 사용법 +## `scopes`의 고급 사용법 { #advanced-usage-with-scopes } -OAuth2는 "스코프(scopes)" 라는 개념을 갖고 있습니다. +OAuth2에는 "scopes"라는 개념이 있습니다. -이를 사용하여 JWT 토큰에 특정 권한 집합을 추가할 수 있습니다. +이를 사용해 JWT 토큰에 특정 권한 집합을 추가할 수 있습니다. -그 후 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에있는 API와 통신하도록 할 수 있습니다. +그런 다음 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에서 API와 상호작용하도록 할 수 있습니다. -**FastAPI** 에서의 사용 방법과 통합 방식은 **심화 사용자 안내서** 에서 자세히 배울 수 있습니다. +어떻게 사용하는지, 그리고 **FastAPI**에 어떻게 통합되는지는 이후 **심화 사용자 안내서**에서 배울 수 있습니다. -## 요약 +## 요약 { #recap } -지금까지 살펴본 내용을 바탕으로, OAuth2와 JWT 같은 표준을 사용하여 안전한 **FastAPI** 애플리케이션을 만들 수 있습니다. +지금까지 살펴본 내용을 바탕으로, OAuth2와 JWT 같은 표준을 사용해 안전한 **FastAPI** 애플리케이션을 설정할 수 있습니다. -거의 모든 프레임워크에서 보안 처리는 상당히 복잡한 주제입니다. +거의 모든 프레임워크에서 보안 처리는 꽤 빠르게 복잡한 주제가 됩니다. -이를 단순화하는 많은 패키지는 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 여러 제약이 있습니다. 그리고 지나치게 단순화하는 일부 패키지들은 심각한 보안 결함을 가질 수도 있습니다. +이를 크게 단순화하는 많은 패키지들은 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 많은 타협을 해야 합니다. 그리고 지나치게 단순화하는 일부 패키지들은 실제로 내부에 보안 결함이 있기도 합니다. --- -**FastAPI** 는 어떤 데이터베이스, 데이터 모델, 도구도 강요하지 않습니다. +**FastAPI**는 어떤 데이터베이스, 데이터 모델, 도구에도 타협하지 않습니다. -프로젝트에 가장 적합한 것을 선택할 수 있는 유연성을 제공합니다. +프로젝트에 가장 잘 맞는 것들을 선택할 수 있는 모든 유연성을 제공합니다. -그리고 `passlib` 와 `PyJWT` 처럼 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다. **FastAPI** 는 외부 패키지 통합을 위해 복잡한 메커니즘이 필요하지 않기 때문입니다. +그리고 **FastAPI**는 외부 패키지를 통합하기 위해 복잡한 메커니즘을 요구하지 않기 때문에 `pwdlib`와 `PyJWT` 같은 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다. -그러나 유연성, 견고성, 보안성을 해치지 않으면서 과정을 단순화할 수 있는 도구들을 제공합니다. +하지만 유연성, 견고성, 보안성을 해치지 않으면서 과정을 가능한 한 단순화할 수 있도록 도구들을 제공합니다. -그리고 OAuth2와 같은 표준 프로토콜을 비교적 간단한 방법으로 구현하고 사용할 수 있습니다. +또한 OAuth2 같은 안전한 표준 프로토콜을 비교적 간단한 방식으로 사용하고 구현할 수 있습니다. -더 세분화된 권한 체계를 위해 OAuth2의 "스코프"를 사용하는 방법은 **심화 사용자 안내서**에서 더 자세히 배울 수 있습니다. OAuth2의 스코프는 제3자 애플리케이션이 사용자를 대신해 그들의 API와 상호작용하도록 권한을 부여하기 위해, Facebook, Google, GitHub, Microsoft, X (Twitter) 등의 많은 대형 인증 제공업체들이 사용하는 메커니즘입니다. +더 세분화된 권한 시스템을 위해 OAuth2 "scopes"를 사용하는 방법은, 같은 표준을 따르는 방식으로 **심화 사용자 안내서**에서 더 자세히 배울 수 있습니다. 스코프를 사용하는 OAuth2는 Facebook, Google, GitHub, Microsoft, X (Twitter) 등 많은 대형 인증 제공업체들이 제3자 애플리케이션이 사용자 대신 그들의 API와 상호작용할 수 있도록 인가하는 데 사용하는 메커니즘입니다. diff --git a/docs/ko/docs/tutorial/security/simple-oauth2.md b/docs/ko/docs/tutorial/security/simple-oauth2.md index f10c4f588d..189dd89f2a 100644 --- a/docs/ko/docs/tutorial/security/simple-oauth2.md +++ b/docs/ko/docs/tutorial/security/simple-oauth2.md @@ -1,8 +1,8 @@ -# 패스워드와 Bearer를 이용한 간단한 OAuth2 +# 패스워드와 Bearer를 이용한 간단한 OAuth2 { #simple-oauth2-with-password-and-bearer } 이제 이전 장에서 빌드하고 누락된 부분을 추가하여 완전한 보안 흐름을 갖도록 하겠습니다. -## `username`와 `password` 얻기 +## `username`와 `password` 얻기 { #get-the-username-and-password } **FastAPI** 보안 유틸리티를 사용하여 `username` 및 `password`를 가져올 것입니다. @@ -14,11 +14,11 @@ OAuth2는 (우리가 사용하고 있는) "패스워드 플로우"을 사용할 그리고 데이터베이스 모델은 원하는 다른 이름을 사용할 수 있습니다. -그러나 로그인 *경로 작동*의 경우 사양과 호환되도록 이러한 이름을 사용해야 합니다(예를 들어 통합 API 문서 시스템을 사용할 수 있어야 합니다). +그러나 로그인 *경로 처리*의 경우 사양과 호환되도록 이러한 이름을 사용해야 합니다(예를 들어 통합 API 문서 시스템을 사용할 수 있어야 합니다). 사양에는 또한 `username`과 `password`가 폼 데이터로 전송되어야 한다고 명시되어 있습니다(따라서 여기에는 JSON이 없습니다). -### `scope` +### `scope` { #scope } 사양에는 클라이언트가 다른 폼 필드 "`scope`"를 보낼 수 있다고 나와 있습니다. @@ -44,15 +44,15 @@ OAuth2의 경우 문자열일 뿐입니다. /// -## `username`과 `password`를 가져오는 코드 +## `username`과 `password`를 가져오는 코드 { #code-to-get-the-username-and-password } 이제 **FastAPI**에서 제공하는 유틸리티를 사용하여 이를 처리해 보겠습니다. -### `OAuth2PasswordRequestForm` +### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform } -먼저 `OAuth2PasswordRequestForm`을 가져와 `/token`에 대한 *경로 작동*에서 `Depends`의 의존성으로 사용합니다. +먼저 `OAuth2PasswordRequestForm`을 가져와 `/token`에 대한 *경로 처리*에서 `Depends`의 의존성으로 사용합니다. -{* ../../docs_src/security/tutorial003.py hl[4,76] *} +{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *} `OAuth2PasswordRequestForm`은 다음을 사용하여 폼 본문을 선언하는 클래스 의존성입니다: @@ -84,7 +84,7 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` /// -### 폼 데이터 사용하기 +### 폼 데이터 사용하기 { #use-the-form-data } /// tip | 팁 @@ -100,9 +100,9 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` 오류의 경우 `HTTPException` 예외를 사용합니다: -{* ../../docs_src/security/tutorial003.py hl[3,77:79] *} +{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *} -### 패스워드 확인하기 +### 패스워드 확인하기 { #check-the-password } 이 시점에서 데이터베이스의 사용자 데이터 형식을 확인했지만 암호를 확인하지 않았습니다. @@ -112,7 +112,7 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` 두 패스워드가 일치하지 않으면 동일한 오류가 반환됩니다. -#### 패스워드 해싱 +#### 패스워드 해싱 { #password-hashing } "해싱"은 일부 콘텐츠(이 경우 패스워드)를 횡설수설하는 것처럼 보이는 일련의 바이트(문자열)로 변환하는 것을 의미합니다. @@ -120,21 +120,15 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` 그러나 횡설수설에서 암호로 다시 변환할 수는 없습니다. -##### 패스워드 해싱을 사용해야 하는 이유 +##### 패스워드 해싱을 사용해야 하는 이유 { #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)`는 다음을 의미한다: @@ -152,11 +146,11 @@ UserInDB( /// 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 객체여야 합니다. @@ -174,7 +168,7 @@ UserInDB( /// -{* ../../docs_src/security/tutorial003.py hl[85] *} +{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *} /// tip | 팁 @@ -188,19 +182,19 @@ UserInDB( /// -## 의존성 업데이트하기 +## 의존성 업데이트하기 { #update-the-dependencies } 이제 의존성을 업데이트를 할 겁니다. 이 사용자가 활성화되어 있는 *경우에만* `current_user`를 가져올 겁니다. -따라서 `get_current_user`를 의존성으로 사용하는 추가 종속성 `get_current_active_user`를 만듭니다. +따라서 `get_current_user`를 의존성으로 사용하는 추가 의존성 `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 | 정보 @@ -220,11 +214,11 @@ UserInDB( /// -## 확인하기 +## 확인하기 { #see-it-in-action } 대화형 문서 열기: http://127.0.0.1:8000/docs. -### 인증하기 +### 인증하기 { #authenticate } "Authorize" 버튼을 눌러봅시다. @@ -240,7 +234,7 @@ UserInDB( -### 자신의 유저 데이터 가져오기 +### 자신의 유저 데이터 가져오기 { #get-your-own-user-data } 이제 `/users/me` 경로에 `GET` 작업을 진행합시다. @@ -266,7 +260,7 @@ UserInDB( } ``` -### 비활성된 유저 +### 비활성된 유저 { #inactive-user } 이제 비활성된 사용자로 시도하고, 인증해봅시다: @@ -284,7 +278,7 @@ UserInDB( } ``` -## 요약 +## 요약 { #recap } 이제 API에 대한 `username` 및 `password`를 기반으로 완전한 보안 시스템을 구현할 수 있는 도구가 있습니다. diff --git a/docs/ko/docs/tutorial/sql-databases.md b/docs/ko/docs/tutorial/sql-databases.md index 58c7017d6a..3d64cf627a 100644 --- a/docs/ko/docs/tutorial/sql-databases.md +++ b/docs/ko/docs/tutorial/sql-databases.md @@ -1,18 +1,18 @@ -# SQL (관계형) 데이터베이스 +# SQL (관계형) 데이터베이스 { #sql-relational-databases } -**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다. +**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 하지만 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다. 여기서는 SQLModel을 사용하는 예제를 살펴보겠습니다. -**SQLModel**은 SQLAlchemy와 Pydantic을 기반으로 구축되었습니다.SQLModel은 **SQL 데이터베이스**를 사용하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**의 제작자가 설계한 도구입니다. +**SQLModel**은 SQLAlchemy와 Pydantic을 기반으로 구축되었습니다. **SQL 데이터베이스**를 사용해야 하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**와 같은 제작자가 만든 도구입니다. /// tip | 팁 -다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 "ORM"이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎 +다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 "ORMs"이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎 /// -SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(SQLModel에서도 동일하게 지원됩니다). 예를 들면: +SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(이것들은 SQLModel에서도 지원됩니다). 예를 들면: * PostgreSQL * MySQL @@ -20,19 +20,19 @@ SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하 * Oracle * Microsoft SQL Server 등. -이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 파이썬에서 기본적으로 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다. +이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 Python에서 통합 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다. -나중에 실제 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다. +나중에 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다. /// tip | 팁 -**FastAPI**와 **PostgreSQL**를 포함하여 프론트엔드와 다양한 도구를 제공하는 공식 프로젝트 생성기가 있습니다: https://github.com/fastapi/full-stack-fastapi-template +프론트엔드와 더 많은 도구를 포함하여 **FastAPI**와 **PostgreSQL**을 포함한 공식 프로젝트 생성기가 있습니다: https://github.com/fastapi/full-stack-fastapi-template /// -이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 복잡한 기능에 대해 배우고 싶다면, SQLModel 문서를 참고하세요. +이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 고급 기능에 대해 배우고 싶다면, SQLModel 문서를 참고하세요. -## `SQLModel` 설치하기 +## `SQLModel` 설치하기 { #install-sqlmodel } 먼저, [가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `sqlmodel`을 설치하세요: @@ -45,13 +45,13 @@ $ pip install sqlmodel -## 단일 모델로 애플리케이션 생성하기 +## 단일 모델로 애플리케이션 생성하기 { #create-the-app-with-a-single-model } 우선 단일 **SQLModel** 모델을 사용하여 애플리케이션의 가장 간단한 첫 번째 버전을 생성해보겠습니다. -이후 **다중 모델**을 추가하여 보안과 유연성을 강화할 것입니다. 🤓 +이후 아래에서 **여러 모델**로 보안과 유연성을 강화하며 개선하겠습니다. 🤓 -### 모델 생성하기 +### 모델 생성하기 { #create-models } `SQLModel`을 가져오고 데이터베이스 모델을 생성합니다: @@ -61,45 +61,45 @@ $ pip install 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`*로 정의합니다. 자세한 내용은 기본 키에 대한 SQLModel 문서를 참고하세요. -* `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 } 애플리케이션 시작 시 데이터베이스 테이블을 생성합니다. @@ -115,9 +115,9 @@ SQLModel은 Alembic을 감싸는 마이그레이션 유틸리티를 제공할 /// -### Hero 생성하기 +### Hero 생성하기 { #create-a-hero } -각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 **타입 어노테이**션에서 동일하게 사용할 수 있습니다. +각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 동일한 **타입 어노테이션**에서 사용할 수 있습니다. 예를 들어, 파라미터를 `Hero` 타입으로 선언하면 **JSON 본문**에서 값을 읽어옵니다. @@ -125,31 +125,29 @@ SQLModel은 Alembic을 감싸는 마이그레이션 유틸리티를 제공할 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} - +여기서는 `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 } -애플리케이션을 실행하려면 다음 명령을 사용합니다: +애플리케이션을 실행할 수 있습니다:
@@ -161,33 +159,33 @@ $ fastapi dev main.py
-그런 다음 `/docs` UI로 이동하면, **FastAPI**가 해당 **model들**을 사용하여 API **문서를 생성**하는 것으르 확인할 수 있습니다. 또한 이 모델들은 데이터를 직렬화하고 검증하는 데에도 사용됩니다. +그런 다음 `/docs` UI로 이동하면, **FastAPI**가 이 **모델**들을 사용해 API를 **문서화**하고, 데이터를 **직렬화**하고 **검증**하는 데에도 사용하는 것을 확인할 수 있습니다.
-## 여러 모델로 애플리케이션 업데이트 +## 여러 모델로 애플리케이션 업데이트 { #update-the-app-with-multiple-models } -이제 애플리케이션을 약간 **리팩토링**하여 **보안**과 **유연성**을 개선해 보겠습니다. +이제 이 애플리케이션을 약간 **리팩터링**하여 **보안**과 **유연성**을 개선해 보겠습니다. -이전 애플리케이션의 UI를 보면, 지금까지는 클라이언트가 생성할 `Hero`의 `id`를 직접 지정할 수 있다는 것을 알 수 있습니다. 😱 +이전 애플리케이션을 확인해 보면, 지금까지는 UI에서 클라이언트가 생성할 `Hero`의 `id`를 결정할 수 있게 되어 있는 것을 볼 수 있습니다. 😱 -이는 허용되어선 안 됩니다. 클라이언트가 이미 데이터베이스에 저장된 `id`를 덮어쓸 위험이 있기 때문입니다. `id`는 **백엔드** 또는 **데이터베이스**가 결정해야 하며, **클라이언트**가 결정해서는 안 됩니다. +이렇게 해서는 안 됩니다. 클라이언트가 DB에 이미 할당되어 있는 `id`를 덮어쓸 수 있기 때문입니다. `id`를 결정하는 것은 **백엔드** 또는 **데이터베이스**가 해야 하며, **클라이언트**가 해서는 안 됩니다. -또한 hero의 `secret_name`을 생성하긴 했지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅 +또한 hero에 대한 `secret_name`을 생성하지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅 -이러한 문제를 해결하기 위해 몇 가지 **추가 모델**을 추가할 것입니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨ +이러한 문제는 몇 가지 **추가 모델**을 추가해 해결하겠습니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨ -### 여러 모델 생성하기 +### 여러 모델 생성하기 { #create-multiple-models } **SQLModel**에서 `table=True`가 설정된 모델 클래스는 **테이블 모델**입니다. -`table=True`가 없는 모델 클래스는 **데이터 모델**로, 이는 실제로 몇 가지 추가 기능이 포함된 Pydantic 모델에 불과합니다. 🤓 +그리고 `table=True`가 없는 모델 클래스는 **데이터 모델**인데, 이것들은 실제로는 (몇 가지 작은 추가 기능이 있는) Pydantic 모델일 뿐입니다. 🤓 SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중복 선언하지 않아도** 됩니다. -#### `HeroBase` - 기본 클래스 +#### `HeroBase` - 기본 클래스 { #herobase-the-base-class } 모든 모델에서 **공유되는 필드**를 가진 `HeroBase` 모델을 시작해 봅시다: @@ -196,14 +194,14 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 {* ../../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` @@ -212,11 +210,11 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} -#### `HeroPublic` - 공개 *데이터 모델* +#### `HeroPublic` - 공개 *데이터 모델* { #heropublic-the-public-data-model } 다음으로 `HeroPublic` 모델을 생성합니다. 이 모델은 API 클라이언트에 **반환**되는 모델입니다. -`HeroPublic`은 `HeroBase`와 동일한 필드를 가지며, `secret_name`은 포함하지 않습니다. +`HeroPublic`은 `HeroBase`와 동일한 필드를 가지므로, `secret_name`은 포함하지 않습니다. 마침내 우리의 heroes의 정체가 보호됩니다! 🥷 @@ -224,9 +222,9 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 /// tip | 팁 -반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API와 통신하는 개발자가 훨씬 더 간단한 코드를 작성할 수 있습니다. +반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API 클라이언트는 이런 확신을 바탕으로 훨씬 더 간단한 코드를 작성할 수 있습니다. -또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 훨씬 수월하게 작업할 수 있습니다. 😎 +또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 API를 사용하면서 훨씬 더 좋은 경험을 할 수 있습니다. 😎 /// @@ -235,23 +233,22 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 * `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에서 반환하지는 않습니다. -비밀번호 값을 저장하기 전에 **해싱**하여 저장하고, **평문으로 저장하지 마십시오**. +또한 비밀번호 값을 저장하기 전에 **해싱**하여 저장하고, **평문으로 저장하지 마십시오**. /// @@ -263,15 +260,15 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 {* ../../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`의 필드는 다음과 같습니다: @@ -281,61 +278,61 @@ SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중 {* ../../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 | 팁 -이제 **반환 타입 주석** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다. +이제 **반환 타입 어노테이션** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다. -만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 반환값이 `HeroPublic`이 아니라 `Hero`라고 경고했을 것입니다. 이는 적절한 경고입니다. +만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 `HeroPublic` 대신 `Hero`를 반환한다고 (당연히) 불평할 것입니다. -`response_model`에 선언함으로써 **FastAPI**가 이를 처리하도록 하고, 타입 어노테이션과 에디터 및 다른 도구의 도움에는 영향을 미치지 않도록 설정합니다. +`response_model`에 선언함으로써 **FastAPI**가 처리하도록 하고, 타입 어노테이션과 에디터 및 다른 도구의 도움에는 영향을 미치지 않도록 합니다. /// -### `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`를 사용합니다. 이것이 주요 핵심입니다. 🪄 -그런 다음, `hero_db.sqlmodel_update(hero_data)`를 사용하여 `hero_data`의 데이터를 `hero_db`에 업데이트합니다. +그런 다음, `hero_db.sqlmodel_update(hero_data)`를 사용하여 `hero_data`의 데이터로 `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 **삭제**는 이전과 거의 동일합니다. -이번에는 모든 것을 리팩토링하고 싶은 욕구를 만족시키지 못할 것 같습니다. 😅 +이번에는 모든 것을 리팩터링하고 싶은 욕구를 만족시키지 못하겠습니다. 😅 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} -### 애플리케이션 다시 실행하기 +### 애플리케이션 다시 실행하기 { #run-the-app-again } -다음 명령을 사용해 애플리케이션을 다시 실행할 수 있습니다: +애플리케이션을 다시 실행할 수 있습니다:
@@ -347,14 +344,14 @@ $ fastapi dev main.py
-`/docs` API UI로 이동하면 업데이트된 것을 확인할 수 있습니다. 클라이언트가 영웅을 생성할 때 `id`를 제공할 필요가 없게 되는 등의 변화도 보입니다. +`/docs` API UI로 이동하면 이제 업데이트되어 있고, hero를 생성할 때 클라이언트가 `id`를 보낼 것이라고 기대하지 않는 것 등을 확인할 수 있습니다.
-## 요약 +## 요약 { #recap } **SQLModel**을 사용하여 SQL 데이터베이스와 상호작용하고, *데이터 모델* 및 *테이블 모델*로 코드를 간소화할 수 있습니다. -더 많은 내용을 배우고 싶다면, **SQLModel** 문서를 참고하세요. SQLModel을 **FastAPI**와 함께 사용하는 것에 대한 더 긴 미니 튜토리얼도 제공합니다. 🚀 +더 많은 내용을 배우려면 **SQLModel** 문서를 참고하세요. **FastAPI**와 함께 SQLModel을 사용하는 더 긴 미니 튜토리얼도 있습니다. 🚀 diff --git a/docs/ko/docs/tutorial/static-files.md b/docs/ko/docs/tutorial/static-files.md index 4f3e3ab286..aa4c571793 100644 --- a/docs/ko/docs/tutorial/static-files.md +++ b/docs/ko/docs/tutorial/static-files.md @@ -1,41 +1,40 @@ -# 정적 파일 +# 정적 파일 { #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 } -"마운팅"은 특정 경로에 완전히 "독립적인" 애플리케이션을 추가하는 것을 의미하는데, 그 후 모든 하위 경로에 대해서도 적용됩니다. +"마운팅"은 특정 경로에 완전한 "독립적인" 애플리케이션을 추가하고, 그 애플리케이션이 모든 하위 경로를 처리하도록 하는 것을 의미합니다. -마운트된 응용 프로그램은 완전히 독립적이기 때문에 `APIRouter`를 사용하는 것과는 다릅니다. OpenAPI 및 응용 프로그램의 문서는 마운트된 응용 프로그램 등에서 어떤 것도 포함하지 않습니다. +마운트된 애플리케이션은 완전히 독립적이므로 `APIRouter`를 사용하는 것과는 다릅니다. 메인 애플리케이션의 OpenAPI 및 문서에는 마운트된 애플리케이션의 내용 등이 포함되지 않습니다. -자세한 내용은 **숙련된 사용자 안내서**에서 확인할 수 있습니다. +자세한 내용은 [고급 사용자 가이드](../advanced/index.md){.internal-link target=_blank}에서 확인할 수 있습니다. -## 세부사항 +## 세부사항 { #details } -첫 번째 `"/static"`은 이 "하위 응용 프로그램"이 "마운트"될 하위 경로를 가리킵니다. 따라서 `"/static"`으로 시작하는 모든 경로는 `"/static"`으로 처리됩니다. +첫 번째 `"/static"`은 이 "하위 애플리케이션"이 "마운트"될 하위 경로를 가리킵니다. 따라서 `"/static"`으로 시작하는 모든 경로는 이 애플리케이션이 처리합니다. -`'directory="static"`은 정적 파일이 들어 있는 디렉토리의 이름을 나타냅니다. +`directory="static"`은 정적 파일이 들어 있는 디렉터리의 이름을 나타냅니다. `name="static"`은 **FastAPI**에서 내부적으로 사용할 수 있는 이름을 제공합니다. -이 모든 매개변수는 "`static`"과 다를 수 있으며, 사용자 응용 프로그램의 요구 사항 및 구체적인 세부 정보에 따라 매개변수를 조정할 수 있습니다. +이 모든 매개변수는 "`static`"과 다를 수 있으며, 여러분의 애플리케이션 요구 사항 및 구체적인 세부 정보에 맞게 조정하세요. +## 추가 정보 { #more-info } -## 추가 정보 - -자세한 내용과 선택 사항을 보려면 Starlette의 정적 파일에 관한 문서를 확인하십시오. +자세한 내용과 옵션은 Starlette의 정적 파일 문서를 확인하세요. diff --git a/docs/ko/docs/tutorial/testing.md b/docs/ko/docs/tutorial/testing.md index 915ff6d22d..db7fb17ead 100644 --- a/docs/ko/docs/tutorial/testing.md +++ b/docs/ko/docs/tutorial/testing.md @@ -1,18 +1,18 @@ -# 테스팅 +# 테스팅 { #testing } -Starlette 덕분에 **FastAPI** 를 테스트하는 일은 쉽고 즐거운 일이 되었습니다. +Starlette 덕분에 **FastAPI** 애플리케이션을 테스트하는 일은 쉽고 즐거운 일이 되었습니다. -Starlette는 HTTPX를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다. +Starlette는 HTTPX를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다. -이를 사용하면 FastAPI에서 pytest를 직접 사용할 수 있습니다. +이를 사용하면 **FastAPI**에서 pytest를 직접 사용할 수 있습니다. -## `TestClient` 사용하기 +## `TestClient` 사용하기 { #using-testclient } /// info | 정보 -`TestClient` 사용하려면, 우선 `httpx` 를 설치해야 합니다. +`TestClient` 사용하려면, 우선 `httpx`를 설치해야 합니다. -[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시: +[virtual environment](../virtual-environments.md){.internal-link target=_blank}를 만들고, 활성화 시킨 뒤에 설치하세요. 예시: ```console $ pip install httpx @@ -20,52 +20,51 @@ $ pip install httpx /// -`TestClient` 를 임포트하세요. +`TestClient`를 임포트하세요. -**FastAPI** 어플리케이션을 전달하여 `TestClient` 를 만드세요. +**FastAPI** 애플리케이션을 전달하여 `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}에 묘사된 파일 구조를 가지고 있는 것으로 가정해봅시다. ``` . @@ -76,11 +75,12 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 `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" . @@ -90,18 +90,18 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 │   └── test_main.py ``` -파일들이 동일한 패키지에 위치해 있으므로, 상대 참조를 사용하여 `main` 에서 `app` 객체를 임포트 해올 수 있습니다. +파일들이 동일한 패키지에 위치해 있으므로, 상대 임포트를 사용하여 `main` 모듈(`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 } 이전과 같은 파일 구조를 계속 사용해 보겠습니다. @@ -113,100 +113,50 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 │   └── test_main.py ``` -이제 **FastAPI** 앱이 있는 `main.py` 파일에 몇 가지 다른 **경로 작업** 이 추가된 경우를 생각해봅시다. +이제 **FastAPI** 앱이 있는 `main.py` 파일에 몇 가지 다른 **경로 처리**가 추가된 경우를 생각해봅시다. 단일 오류를 반환할 수 있는 `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` 를 이용해서) HTTPX documentation 를 확인하세요. +백엔드로 데이터를 어떻게 보내는지 정보를 더 얻으려면 (`httpx` 혹은 `TestClient`를 이용해서) HTTPX documentation를 확인하세요. /// 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 } -테스트 코드를 작성하고, `pytest` 를 설치해야합니다. +그 후에는 `pytest`를 설치하기만 하면 됩니다. -[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시: +[virtual environment](../virtual-environments.md){.internal-link target=_blank}를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
@@ -218,7 +168,7 @@ $ pip install pytest
-`pytest` 파일과 테스트를 자동으로 감지하고 실행한 다음, 결과를 보고할 것입니다. +`pytest`는 파일과 테스트를 자동으로 감지하고 실행한 다음, 결과를 보고할 것입니다. 테스트를 다음 명령어로 실행하세요. diff --git a/docs/ko/docs/virtual-environments.md b/docs/ko/docs/virtual-environments.md index 0d10c3200d..b639f8a3e4 100644 --- a/docs/ko/docs/virtual-environments.md +++ b/docs/ko/docs/virtual-environments.md @@ -1,16 +1,16 @@ -# 가상 환경 +# 가상 환경 { #virtual-environments } -Python 프로젝트를 작업할 때는 **가상 환경** (또는 이와 유사한 도구)을 사용하는 것이 좋습니다. 각 프로젝트 마다 설치하는 패키지를 분리하여 관리할 수 있습니다. +Python 프로젝트를 작업할 때는 **가상 환경**(또는 이와 유사한 메커니즘)을 사용해 각 프로젝트마다 설치하는 패키지를 분리하는 것이 좋습니다. -/// info | 정보 +/// info -이미 가상 환경에 대해 잘 알고 있다면, 이 섹션은 건너 뛰어도 괜찮습니다. 🤓 +이미 가상 환경에 대해 알고 있고, 어떻게 생성하고 사용하는지도 알고 있다면, 이 섹션은 건너뛰어도 괜찮습니다. 🤓 /// -/// tip | 팁 +/// tip -**가상 환경(Virtual Environment)** 은 **환경 변수(Environment Variable)** 와 다릅니다. +**가상 환경**은 **환경 변수**와 다릅니다. **환경 변수**는 시스템에 존재하며, 프로그램이 사용할 수 있는 변수입니다. @@ -18,50 +18,52 @@ Python 프로젝트를 작업할 때는 **가상 환경** (또는 이와 유사 /// -/// info | 정보 +/// info -이 페이지에서는 **가상 환경**의 사용 방법과 작동 방식을 설명합니다. +이 페이지에서는 **가상 환경**을 사용하는 방법과 작동 방식을 알려드립니다. -만약 **모든 것을 관리해주는 도구** (Python 설치까지 포함)를 사용하고 싶다면 uv를 사용해보세요. +Python 설치까지 포함해 **모든 것을 관리해주는 도구**를 도입할 준비가 되었다면 uv를 사용해 보세요. /// -## 프로젝트 생성 +## 프로젝트 생성 { #create-a-project } 먼저, 프로젝트를 위한 디렉터리를 하나 생성합니다. -보통 사용자 홈 디렉터리 안에 `code`라는 디렉터리를 만들고, 그 안에 프로젝트마다 하나씩 디렉터리를 만들어 관리합니다. +제가 보통 하는 방법은 사용자 홈/유저 디렉터리 안에 `code`라는 디렉터리를 만드는 것입니다. + +그리고 그 안에 프로젝트마다 디렉터리를 하나씩 만듭니다.
```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 ```
-## 가상 환경 생성 +## 가상 환경 생성 { #create-a-virtual-environment } -Python 프로젝트를 **처음 시작할 때**, 가상 환경을 **프로젝트 내부**에 생성합니다. +Python 프로젝트를 **처음 시작할 때**, **프로젝트 내부**에 가상 환경을 생성하세요. -/// tip | 팁 +/// tip -이 작업은 **프로젝트를 처음 설정할 때 한번만** 해주면 됩니다. 이후 작업할 때 반복할 필요는 없습니다. +이 작업은 **프로젝트당 한 번만** 하면 되며, 작업할 때마다 할 필요는 없습니다. /// //// tab | `venv` -Python 표준 라이브러리에 포함된 venv 모듈을 사용해 가상 환경을 생성할 수 있습니다. +가상 환경을 만들려면 Python에 포함된 `venv` 모듈을 사용할 수 있습니다.
@@ -71,12 +73,12 @@ $ python -m venv .venv
-/// details | 명령어 상세 설명 +/// details | 명령어 의미 -* `python`: `python` 프로그램을 실행합니다. -* `-m`: 특정 모듈을 스크립트처럼 실행합니다. 대상 모듈을 바로 뒤에 지정합니다. -* `venv`: Python 표준 라이브러리에 포함된 `venv` 모듈을 실행합니다. -* `.venv`: 가상 환경을 `.venv` 디렉터리에 생성합니다. +* `python`: `python`이라는 프로그램을 사용합니다 +* `-m`: 모듈을 스크립트로 호출합니다. 다음에 어떤 모듈인지 지정합니다 +* `venv`: 보통 Python에 기본으로 설치되어 있는 `venv` 모듈을 사용합니다 +* `.venv`: 새 디렉터리인 `.venv`에 가상 환경을 생성합니다 /// @@ -84,7 +86,7 @@ $ python -m venv .venv //// tab | `uv` -`uv`가 설치되어 있다면, uv를 통해 가상 환경을 생성할 수 있습니다. +`uv`가 설치되어 있다면, 이를 사용해 가상 환경을 생성할 수 있습니다.
@@ -94,31 +96,31 @@ $ uv venv
-/// tip | 팁 +/// tip -`uv`는 기본적으로 `.venv` 디렉터리에 가상 환경을 생성합니다. +기본적으로 `uv`는 `.venv`라는 디렉터리에 가상 환경을 생성합니다. -별도로 디렉터리 이름을 추가 인자로 넘겨 주면 경로를 지정 할 수 있습니다. +하지만 디렉터리 이름을 추가 인자로 전달해 이를 커스터마이즈할 수 있습니다. /// //// -해당 명령어는 `.venv` 디렉터리에 새로운 가상 환경을 생성합니다. +해당 명령어는 `.venv`라는 디렉터리에 새로운 가상 환경을 생성합니다. /// details | `.venv` 또는 다른 이름 -가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv` 디렉터리 이름을 사용합니다. +가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv`라는 이름을 사용합니다. /// -## 가상 환경 활성화 +## 가상 환경 활성화 { #activate-the-virtual-environment } -이후 실행하는 Python 명령어와 패키지 설치가 가상 환경을 따르도록, 가상 환경을 활성화하세요. +이후 실행하는 Python 명령어와 설치하는 패키지가 새 가상 환경을 사용하도록, 새 가상 환경을 활성화하세요. -/// tip | 팁 +/// tip -**터미널을 새로 열고** 프로젝트 작업을 시작할 때는, **항상 이 작업을** 해주세요. +프로젝트 작업을 위해 **새 터미널 세션**을 시작할 때마다 **매번** 이 작업을 하세요. /// @@ -148,7 +150,7 @@ $ .venv\Scripts\Activate.ps1 //// tab | Windows Bash -Windows에서 Bash(예: Git Bash)를 사용하는 경우: +또는 Windows에서 Bash(예: Git Bash)를 사용하는 경우:
@@ -160,21 +162,21 @@ $ source .venv/Scripts/activate //// -/// tip | 팁 +/// tip -가상 환경에 새로운 패키지를 설치할 때마다, 해당 환경을 다시 활성화하세요. +해당 환경에 **새 패키지**를 설치할 때마다, 환경을 다시 **활성화**하세요. -이렇게 하면 해당 패키지로 설치된 **터미널(CLI) 프로그램**을 사용할 때, 전역에 설치된 다른 버전이 아니라, 가상 환경 안에 설치된 정확한 버전을 사용합니다. +이렇게 하면 해당 패키지가 설치한 **터미널(CLI) 프로그램**을 사용할 때, 전역으로 설치되어 있을 수도 있는(아마 필요한 버전과는 다른 버전인) 다른 프로그램이 아니라 가상 환경에 있는 것을 사용하게 됩니다. /// -## 가상 환경이 활성화 여부 확인 +## 가상 환경 활성화 여부 확인 { #check-the-virtual-environment-is-active } -가상 환경이 활성화되었는지 확인합니다. (이전 명령어가 제대로 작동했는지 확인합니다). +가상 환경이 활성화되어 있는지(이전 명령어가 작동했는지) 확인합니다. -/// tip | 팁 +/// tip -이 단계는 **선택 사항**이지만, 모든 것이 예상대로 작동하고 있는지, 그리고 의도한 가상 환경이 활성화 되었는 지 **확인**하는 좋은 방법입니다. +이 단계는 **선택 사항**이지만, 모든 것이 예상대로 작동하고 있는지, 그리고 의도한 가상 환경을 사용하고 있는지 **확인**하는 좋은 방법입니다. /// @@ -190,7 +192,7 @@ $ which python
-`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv/bin/python` 경로로 표시된다면 성공입니다. 🎉 +프로젝트 내부(이 경우 `awesome-project`)의 `.venv/bin/python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉 //// @@ -206,29 +208,29 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python -`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv\bin\python` 경로로 표시된다면 성공입니다. 🎉 +프로젝트 내부(이 경우 `awesome-project`)의 `.venv\Scripts\python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉 //// -## pip 업그레이드 +## `pip` 업그레이드 { #upgrade-pip } -/// tip | 팁 +/// tip -`uv`를 사용한다면, `pip` 대신 `uv`로 패키지를 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎 +`uv`를 사용한다면, `pip` 대신 `uv`로 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎 /// -`pip`을 사용하여 패키지를 설치하는 경우 (Python 표준 라이브러리에 포함되어 있습니다), **최신 버전으로 업그레이드**하는 것이 좋습니다. +`pip`로 패키지를 설치한다면(Python에 기본으로 포함되어 있습니다) 최신 버전으로 **업그레이드**하는 것이 좋습니다. -패키지 설치 중 발생하는 다양하고 특이한 에러들은 `pip` 업그레이드로 쉽게 해결되는 경우가 많습니다. +패키지 설치 중 발생하는 다양한 특이한 오류는 먼저 `pip`를 업그레이드하는 것만으로 해결되는 경우가 많습니다. -/// tip | 팁 +/// tip -이 작업은 보통 가상 환경을 생성한 **직후 한 번만** 하면 됩니다. +보통 이 작업은 가상 환경을 만든 직후 **한 번만** 하면 됩니다. /// -가상 환경이 활성화된 상태인지 확인한 후(앞서 설명한 명령어 사용), 아래 명령어를 실행하세요: +가상 환경이 활성화된 상태인지 확인한 다음(위의 명령어 사용) 아래를 실행하세요:
@@ -240,19 +242,39 @@ $ python -m pip install --upgrade pip
-## `.gitignore` 추가하기 +/// tip + +때로는 pip를 업그레이드하려고 할 때 **`No module named pip`** 오류가 발생할 수 있습니다. + +이 경우 아래 명령어로 pip를 설치하고 업그레이드하세요: + +
+ +```console +$ python -m ensurepip --upgrade -**Git**을 사용하고 있다면 (사용하는 것이 좋습니다), `.gitignore` 파일을 추가해서 `.venv` 디렉터리 전체를 Git에서 제외하세요. +---> 100% +``` -/// tip | 팁 +
-`uv`를 사용해 가상 환경을 생성했다면, 이미 이 작업이 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎 +이 명령어는 pip가 아직 설치되어 있지 않다면 설치하며, 설치된 pip 버전이 `ensurepip`에서 제공 가능한 버전만큼 최신임을 보장합니다. /// -/// tip | 팁 +## `.gitignore` 추가하기 { #add-gitignore } -이 작업도 마찬가지로, 가상 환경을 생성한 **직후 한 번만** 하면 됩니다. +**Git**을 사용하고 있다면(사용하는 것이 좋습니다), `.venv`의 모든 내용을 Git에서 제외하도록 `.gitignore` 파일을 추가하세요. + +/// tip + +`uv`로 가상 환경을 만들었다면, 이미 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎 + +/// + +/// tip + +가상 환경을 만든 직후 **한 번만** 하면 됩니다. /// @@ -264,16 +286,15 @@ $ echo "*" > .venv/.gitignore -/// details | 명령어 상세 설명 - -* `echo "*"`: 터미널에 `*` 텍스트를 "출력"합니다 (다음 설명에서 조금 바뀝니다) -* `>`: 왼쪽 명령어의 출력 내용을 터미널에 출력하지 않고, 오른쪽에 지정된 파일로 **기록(write)** 하라는 의미입니다. -* `.gitignore`: 출력된 텍스트가 기록될 파일 이름입니다. +/// details | 명령어 의미 -그리고 Git에서 `*`는 "모든 것"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시하게 됩니다. +* `echo "*"`: 터미널에 `*` 텍스트를 "출력"합니다(다음 부분이 이를 약간 변경합니다) +* `>`: `>` 왼쪽 명령어가 터미널에 출력한 내용을 터미널에 출력하지 않고, `>` 오른쪽에 있는 파일에 기록하라는 의미입니다 +* `.gitignore`: 텍스트가 기록될 파일 이름입니다 -이 명령어는 다음과 같은 내용을 가진 `.gitignore` 파일을 생성합니다: +그리고 Git에서 `*`는 "모든 것"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시합니다. +이 명령어는 다음 내용을 가진 `.gitignore` 파일을 생성합니다: ```gitignore * @@ -281,25 +302,25 @@ $ echo "*" > .venv/.gitignore /// -## 패키지 설치 +## 패키지 설치 { #install-packages } -가상 환경을 활성화한 후, 그 안에 필요한 패키지들을 설치할 수 있습니다. +환경을 활성화한 뒤, 그 안에 패키지를 설치할 수 있습니다. -/// tip | 팁 +/// tip -프로젝트에서 필요한 패키지를 설치하거나 업그레이드할 때는 이 작업을 **한 번만** 하면 됩니다. +프로젝트에 필요한 패키지를 설치하거나 업그레이드할 때는 **한 번**만 하면 됩니다. -만약 특정 패키지의 버전을 업그레이드하거나, 새로운 패키지를 추가할 필요가 생기면 **다시 이 작업을 반복**하면 됩니다. +버전을 업그레이드하거나 새 패키지를 추가해야 한다면 **다시 이 작업을** 하게 됩니다. /// -### 패키지 직접 설치 +### 패키지 직접 설치 { #install-packages-directly } -급하게 작업하거나, 프로젝트에 필요한 패키지 목록을 따로 파일로 관리하고 싶지 않은 경우, 패키지를 직접 설치할 수도 있습니다. +급하게 작업 중이고 프로젝트의 패키지 요구사항을 선언하는 파일을 사용하고 싶지 않다면, 패키지를 직접 설치할 수 있습니다. -/// tip | 팁 +/// tip -패키지 이름과 버전 정보를 파일에 정리해두는 것(예: `requirements.txt` 또는 `pyproject.toml`)은 (매우) 좋은 생각입니다. +프로그램에 필요한 패키지와 버전을 파일(예: `requirements.txt` 또는 `pyproject.toml`)에 적어두는 것은 (매우) 좋은 생각입니다. /// @@ -319,7 +340,7 @@ $ pip install "fastapi[standard]" //// tab | `uv` -`uv`를 사용하는 경우: +`uv`가 있다면:
@@ -332,9 +353,9 @@ $ uv pip install "fastapi[standard]" //// -### `requirements.txt`에서 설치 +### `requirements.txt`에서 설치 { #install-from-requirements-txt } -`requirements.txt` 파일이 있다면, 그 안에 명시된 패키지들을 한 번에 설치할 수 있습니다. +`requirements.txt`가 있다면, 이제 이를 사용해 그 안의 패키지를 설치할 수 있습니다. //// tab | `pip` @@ -351,7 +372,7 @@ $ pip install -r requirements.txt //// tab | `uv` -`uv`를 사용하는 경우: +`uv`가 있다면:
@@ -366,7 +387,7 @@ $ uv pip install -r requirements.txt /// details | `requirements.txt` -다음은 몇 가지 패키지를 포함한 `requirements.txt`의 예시입니다: +일부 패키지가 있는 `requirements.txt`는 다음과 같이 생겼을 수 있습니다: ```requirements.txt fastapi[standard]==0.113.0 @@ -375,9 +396,9 @@ pydantic==2.8.0 /// -## 프로그램 실행 +## 프로그램 실행 { #run-your-program } -가상 환경을 활성화한 후에는 프로그램을 실행할 수 있습니다. 이때 해당 가상 환경에 설치된 Python과 패키지들이 사용됩니다. +가상 환경을 활성화한 뒤에는 프로그램을 실행할 수 있으며, 설치한 패키지가 들어있는 가상 환경 내부의 Python을 사용하게 됩니다.
@@ -389,25 +410,24 @@ Hello World
-## 에디터 설정 +## 에디터 설정 { #configure-your-editor } -에디터를 사용할 경우, 앞서 만든 가상 환경을 사용하도록 설정하는 것이 좋습니다. (대부분의 에디터는 자동으로 감지하기도 합니다.) -이렇게 하면 자동 완성 기능이나 코드 내 오류 표시 기능을 제대로 사용할 수 있습니다. +아마 에디터를 사용할 텐데, 자동 완성과 인라인 오류 표시를 받을 수 있도록 생성한 가상 환경을 사용하도록 설정하세요(대부분 자동 감지합니다). -예시: +예를 들면: * VS Code * PyCharm -/// tip | 팁 +/// tip -이 설정은 보통 가상 환경을 **처음 만들었을 때 한 번만** 해주면 됩니다. +보통 이 설정은 가상 환경을 만들 때 **한 번만** 하면 됩니다. /// -## 가상 환경 비활성화 +## 가상 환경 비활성화 { #deactivate-the-virtual-environment } -프로젝트 작업이 끝났다면, 가상 환경을 **비활성화**할 수 있습니다. +프로젝트 작업을 마쳤다면 가상 환경을 **비활성화**할 수 있습니다.
@@ -417,54 +437,55 @@ $ deactivate
-이렇게 하면 이후에 `python` 명령어를 실행했을 때, 가상 환경의 Python이나 그 안에 설치된 패키지들을 사용하지 않게 됩니다. +이렇게 하면 `python`을 실행할 때, 해당 가상 환경과 그 안에 설치된 패키지에서 실행하려고 하지 않습니다. -## 이제 작업할 준비가 되었습니다 +## 작업할 준비 완료 { #ready-to-work } -이제 프로젝트 작업을 시작할 준비가 완료되었습니다. +이제 프로젝트 작업을 시작할 준비가 되었습니다. -/// tip | 팁 -위 내용을 더 깊이 이해하고 싶으신가요? +/// tip -그렇다면 계속 읽어 주세요. 👇🤓 +위의 내용이 무엇인지 더 이해하고 싶으신가요? + +계속 읽어보세요. 👇🤓 /// -## 가상 환경을 왜 사용하는가 +## 가상 환경을 왜 사용하나요 { #why-virtual-environments } -FastAPI를 사용하려면 먼저 Python을 설치해야 합니다. +FastAPI로 작업하려면 Python을 설치해야 합니다. -그 후에는 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] ``` -그런데 나중에 `아즈카반의 죄수(prisoner-of-azkaban)`이라는 또 다른 프로젝트를 만들게 되었고, 이 프로젝트도 역시 `harry` 패키지를 사용합니다. 그런데 이 프로젝트는 `harry`의 `v3` 버전이 필요합니다. +그다음, 나중에 `prisoner-of-azkaban`이라는 또 다른 프로젝트를 만들고, 이 프로젝트도 `harry`에 의존하지만, 이 프로젝트는 **`harry` 버전 `3`**이 필요합니다. ```mermaid flowchart LR azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3] ``` -하지만 이제 문제가 생깁니다. 로컬 가상 환경 대신에 전역 환경에 패키지를 설치하게 되면, 어떤 버전의 `harry`를 설치할지를 선택해야 하기 때문입니다. +하지만 이제 문제가 생깁니다. 로컬 **가상 환경**이 아니라 전역(전역 환경)에 패키지를 설치한다면, 어떤 버전의 `harry`를 설치할지 선택해야 합니다. -예를 들어, `마법사의 돌(philosophers-stone)`을 실행하고 싶다면 먼저 `harry` `v1` 버전을 다음과 같이 설치 해야 합니다: +`philosophers-stone`을 실행하고 싶다면, 먼저 `harry` 버전 `1`을 다음과 같이 설치해야 합니다:
@@ -474,7 +495,7 @@ $ pip install "harry==1"
-그러면 결국 전역 Python 환경에는 `harry` `v1`버전이 설치된 상태가 됩니다. +그리고 전역 Python 환경에 `harry` 버전 `1`이 설치된 상태가 됩니다. ```mermaid flowchart LR @@ -486,7 +507,7 @@ flowchart LR end ``` -하지만 이제 `아즈카반의 죄수(prisoner-of-azkaban)`을 실행하고 싶다면, `harry` `v1`버전을 제거하고 `harry` `v3`버전을 설치해야 합니다. (또는 단순히 `v3`버전을 설치하는 것만으로도 기존의 `v1`버전이 자동으로 제거됩니다.) +하지만 `prisoner-of-azkaban`을 실행하려면 `harry` 버전 `1`을 제거하고 `harry` 버전 `3`을 설치해야 합니다(또는 버전 `3`을 설치하기만 해도 버전 `1`이 자동으로 제거됩니다).
@@ -496,9 +517,9 @@ $ pip install "harry==3"
-그렇게 하면 이제 전역 Python 환경에는 `harry` `v3`버전이 설치된 상태가 됩니다. +그러면 전역 Python 환경에 `harry` 버전 `3`이 설치된 상태가 됩니다. -그리고 다시 `마법사의 돌(philosophers-stone)`을 실행하려고 하면, **작동하지** 않을 수 있습니다. 왜냐하면 이 프로그램은 `harry` `v1`버전을 필요로 하기 때문입니다. +그리고 `philosophers-stone`을 다시 실행하려고 하면, `harry` 버전 `1`이 필요하기 때문에 **작동하지 않을** 가능성이 있습니다. ```mermaid flowchart LR @@ -515,50 +536,49 @@ flowchart LR end ``` -/// tip | 팁 +/// tip -Python 패키지들은 **새 버전**에서 **호환성 문제(breaking changes)**가 발생하지 않도록 최대한 노력하는 것이 일반적입니다. 하지만 그래도 안전하게 작업하려면, 테스트를 실행해보면서 새 버전을 의도적으로 설치하는 것이 좋습니다. +Python 패키지에서는 **새 버전**에서 **호환성을 깨뜨리는 변경(breaking changes)**을 **피하려고** 최선을 다하는 것이 매우 일반적이지만, 안전을 위해 더 최신 버전은 의도적으로 설치하고, 테스트를 실행해 모든 것이 올바르게 작동하는지 확인할 수 있을 때 설치하는 것이 좋습니다. /// -이제, 이런 일이 여러분의 **모든 프로젝트**가 사용하는 **수많은 패키지들**에서 동시에 발생한다고 상상해보세요. 이는 매우 관리하기 어려우며, 결국 **서로 호환되지 않는 버전**의 패키지로 프로젝트를 실행하게 될 가능성이 높고, 그로 인해 어떤 문제가 왜 발생하는지 알 수 없게 될 수 있습니다. +이제 이런 일이 여러분의 **모든 프로젝트가 의존하는** **많은** 다른 **패키지**에서도 일어난다고 상상해 보세요. 이는 관리하기가 매우 어렵습니다. 그리고 결국 일부 프로젝트는 패키지의 **호환되지 않는 버전**으로 실행하게 될 가능성이 높으며, 왜 무언가가 작동하지 않는지 알지 못하게 될 수 있습니다. -또한 사용하는 운영체제(Linux, Windows, macOS 등)에 따라 Python이 **미리 설치되어 있을 수도** 있습니다. 이런 경우에는 운영체제의 동작에 필요한 특정 버전의 패키지들이 함께 설치되어 있을 수 있습니다. 이 상태에서 전역 Python 환경에 임의의 패키지를 설치하면, 운영체제에 포함된 프로그램 일부가 **깨질 위험**도 있습니다. +또한 운영체제(Linux, Windows, macOS 등)에 따라 Python이 이미 설치되어 있을 수도 있습니다. 그런 경우에는 시스템에 **필요한 특정 버전**의 패키지가 일부 미리 설치되어 있을 가능성이 큽니다. 전역 Python 환경에 패키지를 설치하면, 운영체제에 포함된 프로그램 일부가 **깨질** 수 있습니다. -## 패키지들은 어디에 설치되는가 +## 패키지는 어디에 설치되나요 { #where-are-packages-installed } -Python을 설치하면, 컴퓨터에 여러 디렉터리와 파일들이 생성됩니다. +Python을 설치하면 컴퓨터에 몇몇 파일이 들어 있는 디렉터리가 생성됩니다. -이 중 일부 디렉터리는 사용자가 설치한 패키지들을 보관하는 역할을 합니다. +이 디렉터리 중 일부는 설치한 모든 패키지를 담는 역할을 합니다. -예를 들어, 아래 명령어를 실행하면: +다음을 실행하면:
```console -// 지금 실행하지 않아도 됩니다, 그냥 예제일 뿐이에요 🤓 +// Don't run this now, it's just an example 🤓 $ pip install "fastapi[standard]" ---> 100% ```
-해당 명령어는 FastAPI 코드를 포함한 압축 파일을 다운로드합니다. 이 파일은 보통 PyPI에서 받아옵니다. - -또한 FastAPI가 의존하는 다른 패키지들도 함께 **다운로드**됩니다. +FastAPI 코드를 담은 압축 파일을 다운로드합니다. 보통 PyPI에서 받습니다. -그리고 그 모든 파일들을 **압축 해제**한 뒤, 컴퓨터의 특정 디렉터리에 저장합니다. +또한 FastAPI가 의존하는 다른 패키지들의 파일도 **다운로드**합니다. -기본적으로 이 파일들은 Python이 설치된 디렉터리 안, 즉 **전역 환경**에 내의 디렉터리에 저장됩니다. +그 다음 모든 파일을 **압축 해제**하고 컴퓨터의 한 디렉터리에 넣습니다. -## 가상 환경이란 +기본적으로, 다운로드하고 압축 해제한 파일들은 Python 설치와 함께 제공되는 디렉터리, 즉 **전역 환경**에 저장됩니다. -전역 환경에 모든 패키지를 설치하면서 발생하는 문제에 대한 해결책은, 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다. +## 가상 환경이란 무엇인가요 { #what-are-virtual-environments } -가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 그 안에 해당 프로젝트를 위한 패키지들을 설치할 수 있습니다. +전역 환경에 모든 패키지를 두는 문제에 대한 해결책은 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다. -이렇게 하면 각 프로젝트는 자체적인 가상 환경(`.venv` 디렉터리)을 가지게 되며, 그 안에 해당 프로젝트 전용 패키지들을 보유하게 됩니다. +가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 프로젝트의 패키지를 설치할 수 있습니다. +이렇게 하면 각 프로젝트는 자체 가상 환경(`.venv` 디렉터리)과 자체 패키지를 갖게 됩니다. ```mermaid flowchart TB @@ -577,9 +597,9 @@ flowchart TB stone-project ~~~ azkaban-project ``` -## 가상 환경 활성화 의미 +## 가상 환경을 활성화한다는 것은 무엇을 의미하나요 { #what-does-activating-a-virtual-environment-mean } -가상 환경을 활성화한다는 것은, 예를 들어 다음과 같은 명령어를 실행하는 것을 의미합니다: +가상 환경을 활성화한다는 것은, 예를 들어 다음과 같은 명령어로: //// tab | Linux, macOS @@ -607,7 +627,7 @@ $ .venv\Scripts\Activate.ps1 //// tab | Windows Bash -Windows에서 Bash(예: Git Bash)를 사용하는 경우: +또는 Windows에서 Bash(예: Git Bash)를 사용하는 경우:
@@ -619,19 +639,19 @@ $ source .venv/Scripts/activate //// -이 명령어는 이후에 실행될 명령어에서 사용될 [환경 변수](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} 섹션을 참고하세요. /// -가상 환경을 활성화하면, 가상 환경의 경로인 `.venv/bin` (Linux와 macOS) 또는 `.venv\Scripts`(Windows)를 `PATH` 환경 변수에 추가됩니다. +가상 환경을 활성화하면 가상 환경의 경로인 `.venv/bin`(Linux와 macOS) 또는 `.venv\Scripts`(Windows)를 `PATH` 환경 변수에 추가합니다. -예를 들어, 가상 환경을 활성화하기 전의 `PATH` 변수는 다음과 같았다고 가정해봅시다: +가령 환경을 활성화하기 전에는 `PATH` 변수가 다음과 같았다고 해보겠습니다: //// tab | Linux, macOS @@ -639,7 +659,7 @@ $ source .venv/Scripts/activate /usr/bin:/bin:/usr/sbin:/sbin ``` -시스템은 다음 경로들에서 프로그램을 찾게 됩니다: +이는 시스템이 다음 위치에서 프로그램을 찾는다는 뜻입니다: * `/usr/bin` * `/bin` @@ -654,13 +674,13 @@ $ source .venv/Scripts/activate C:\Windows\System32 ``` -시스템은 다음 경로들에서 프로그램을 찾게 됩니다: +이는 시스템이 다음 위치에서 프로그램을 찾는다는 뜻입니다: * `C:\Windows\System32` //// -가상 환경을 활성화한 후에는, `PATH` 변수는 다음과 같은 형태가 됩니다: +가상 환경을 활성화한 뒤에는 `PATH` 변수가 다음과 같이 보일 수 있습니다: //// tab | Linux, macOS @@ -668,21 +688,21 @@ C:\Windows\System32 /home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin ``` -시스템은 가장 먼저 다음 경로에서 프로그램을 찾기 시작합니다: +이는 시스템이 이제 다음 위치에서 프로그램을 가장 먼저 찾기 시작한다는 뜻입니다: ```plaintext /home/user/code/awesome-project/.venv/bin ``` -그 후에 다른 디렉터리들을 탐색합니다. +그리고 나서 다른 디렉터리들을 탐색합니다. -따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에 있는 Python 프로그램을 찾게 됩니다: +따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에서 Python 프로그램을 찾고: ```plaintext /home/user/code/awesome-project/.venv/bin/python ``` -그리고 해당 Python을 사용하게 됩니다. +그것을 사용하게 됩니다. //// @@ -692,31 +712,31 @@ C:\Windows\System32 C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 ``` -시스템은 가장 먼저 다음 경로에서 프로그램을 찾기 시작합니다: +이는 시스템이 이제 다음 위치에서 프로그램을 가장 먼저 찾기 시작한다는 뜻입니다: ```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 @@ -746,34 +766,33 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python //// -즉, 현재 사용되는 `python` 프로그램은 **가상 환경 내부에 있는 것**입니다. +이는 사용될 `python` 프로그램이 **가상 환경 내부에 있는 것**이라는 뜻입니다. -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`에서 작업하고 싶습니다. -그래서 그 프로젝트 디렉터리로 이동합니다: +해당 프로젝트로 이동합니다:
@@ -783,7 +802,7 @@ $ cd ~/code/prisoner-of-azkaban
-만약 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화하지 않았다면, 터미널에서 `python`을 실행할 때 여전히 `마법사의 돌(philosophers-stone)` 가상 환경의 Python을 사용하게 됩니다. +`philosophers-stone`의 가상 환경을 비활성화하지 않으면, 터미널에서 `python`을 실행할 때 `philosophers-stone`의 Python을 사용하려고 할 것입니다.
@@ -792,7 +811,7 @@ $ cd ~/code/prisoner-of-azkaban $ python main.py -// sirius를 임포트하는 데 실패했습니다. 설치되어 있지 않아요 😱 +// Error importing sirius, it's not installed 😱 Traceback (most recent call last): File "main.py", line 1, in import sirius @@ -800,47 +819,46 @@ Traceback (most recent call last):
-하지만 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화한 다음, `아즈카반의 죄수(prisoner-of-azkaban)` 프로젝트의 가상 환경을 활성화하면, 이제 `python` 명령어는 `아즈카반의 죄수(prisoner-of-azkaban)` 가상 환경의 Python을 사용하게 됩니다. +하지만 가상 환경을 비활성화하고 `prisoner-of-askaban`에 대한 새 가상 환경을 활성화하면, `python`을 실행할 때 `prisoner-of-azkaban`의 가상 환경에 있는 Python을 사용하게 됩니다.
```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 🐺 ```
-## 대안들 +## 대안들 { #alternatives } -이 문서는 여러분이 Python 프로젝트를 시작하고, **그 내부에서** 어떻게 돌아가는지 알려주는 간단한 가이드입니다. +이 문서는 시작을 돕고, 내부에서 모든 것이 어떻게 작동하는지 알려주는 간단한 가이드입니다. -가상 환경, 패키지 의존성(Requirements), 프로젝트를 관리하는 방법에는 이 외에도 다양한 **대안**들이 존재합니다. +가상 환경, 패키지 의존성(requirements), 프로젝트를 관리하는 방법에는 많은 **대안**이 있습니다. -만약 준비가 되었다면, **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 통합적으로 **관리**할 수 있는 도구를 써보는 것도 좋습니다. 그럴 때 추천하는 도구가 바로 uv입니다. +준비가 되었고 **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 **관리**하는 도구를 사용하고 싶다면 uv를 사용해 보시길 권합니다. -`uv`는 다양한 기능을 지원합니다: +`uv`는 많은 일을 할 수 있습니다. 예를 들어: -* 다양한 버전의 **Python 설치** -* 각 프로젝트 별 **가상 환경 관리** -* **패키지 설치** -* 프로젝트의 **의존성과 버전** 관리 -* 설치된 패키지들과 그 버전을 **정확히 고정(lock)**해서,개발 환경과 운영 환경이 완전히 동일하게 작동할 수 있도록 보장 -* 이 외에도 다양한 기능을 지원 +* 여러 버전을 포함해 **Python을 설치** +* 프로젝트의 **가상 환경** 관리 +* **패키지** 설치 +* 프로젝트의 패키지 **의존성과 버전** 관리 +* 의존성을 포함해 설치할 패키지와 버전의 **정확한** 세트를 보장하여, 개발 중인 컴퓨터와 동일하게 프로덕션에서 실행할 수 있도록 합니다. 이를 **locking**이라고 합니다 +* 그 외에도 많은 기능이 있습니다 -## 결론 +## 결론 { #conclusion } -여기까지 모두 읽고 이해했다면, 이제 많은 개발자들보다 가상 환경을 **훨씬 더 깊이 있게 이해**하게 되셨습니다. 🤓 +여기까지 모두 읽고 이해했다면, 이제 많은 개발자들보다 가상 환경에 대해 **훨씬 더 많이** 알게 된 것입니다. 🤓 -이런 세부적인 내용을 알고 있으면, 언젠가 복잡해 보이는 문제를 디버깅할 때 분명히 큰 도움이 될 것입니다. 이제는 **이 모든 것들이 내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎 +이 세부 사항을 알고 있으면, 나중에 복잡해 보이는 무언가를 디버깅할 때 아마도 도움이 될 것입니다. **내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎 diff --git a/scripts/docs.py b/scripts/docs.py index a9abce56b5..c350ee8319 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -23,6 +23,7 @@ SUPPORTED_LANGS = { "en", "de", "es", + "ko", "pt", "ru", "uk",