diff --git a/README.md b/README.md index a12e740f7..62eeda03b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 6db9c509a..1c83579e2 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -29,6 +29,9 @@ gold: - url: https://liblab.com?utm_source=fastapi title: liblab - Generate SDKs from FastAPI img: https://fastapi.tiangolo.com/img/sponsors/liblab.png + - url: https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi + title: Deploy & scale any full-stack web app on Render. Focus on building apps, not infra. + img: https://fastapi.tiangolo.com/img/sponsors/render.svg silver: - url: https://github.com/deepset-ai/haystack/ title: Build powerful search from composable, open source building blocks diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index d45028aaa..7470b0238 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -31,3 +31,4 @@ logins: - zuplo-oss - Kong - speakeasy-api + - jess-render diff --git a/docs/en/docs/advanced/security/oauth2-scopes.md b/docs/en/docs/advanced/security/oauth2-scopes.md index 3db284d02..5ba0b1c14 100644 --- a/docs/en/docs/advanced/security/oauth2-scopes.md +++ b/docs/en/docs/advanced/security/oauth2-scopes.md @@ -62,71 +62,7 @@ For OAuth2 they are just strings. First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes: -//// tab | Python 3.10+ - -```Python hl_lines="5 9 13 47 65 106 108-116 122-125 129-135 140 156" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="2 5 9 13 48 66 107 109-117 123-126 130-136 141 157" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4 8 12 46 64 105 107-115 121-124 128-134 139 155" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:125,129:135,140,156] *} Now let's review those changes step by step. @@ -136,71 +72,7 @@ The first change is that now we are declaring the OAuth2 security scheme with tw The `scopes` parameter receives a `dict` with each scope as a key and the description as the value: -//// tab | Python 3.10+ - -```Python hl_lines="63-66" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="63-66" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="64-67" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="62-65" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="63-66" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="63-66" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *} Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize. @@ -226,71 +98,7 @@ But in your application, for security, you should make sure you only add the sco /// -//// tab | Python 3.10+ - -```Python hl_lines="156" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="156" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="157" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="155" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="156" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="156" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[156] *} ## Declare scopes in *path operations* and dependencies @@ -316,71 +124,7 @@ We are doing it here to demonstrate how **FastAPI** handles scopes declared at d /// -//// tab | Python 3.10+ - -```Python hl_lines="5 140 171" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="5 140 171" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="5 141 172" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="4 139 168" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5 140 169" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="5 140 169" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,140,171] *} /// info | "Technical Details" @@ -406,71 +150,7 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly). -//// tab | Python 3.10+ - -```Python hl_lines="9 106" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="9 106" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="9 107" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="8 105" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="9 106" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="9 106" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *} ## Use the `scopes` @@ -484,71 +164,7 @@ We create an `HTTPException` that we can reuse (`raise`) later at several points In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in the `WWW-Authenticate` header (this is part of the spec). -//// tab | Python 3.10+ - -```Python hl_lines="106 108-116" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="106 108-116" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="107 109-117" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="105 107-115" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="106 108-116" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="106 108-116" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *} ## Verify the `username` and data shape @@ -564,71 +180,7 @@ Instead of, for example, a `dict`, or something else, as it could break the appl We also verify that we have a user with that username, and if not, we raise that same exception we created before. -//// tab | Python 3.10+ - -```Python hl_lines="47 117-128" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="47 117-128" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="48 118-129" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="46 116-127" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="47 117-128" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="47 117-128" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:128] *} ## Verify the `scopes` @@ -636,71 +188,7 @@ We now verify that all the scopes required, by this dependency and all the depen For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`. -//// tab | Python 3.10+ - -```Python hl_lines="129-135" -{!> ../../docs_src/security/tutorial005_an_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python hl_lines="129-135" -{!> ../../docs_src/security/tutorial005_an_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="130-136" -{!> ../../docs_src/security/tutorial005_an.py!} -``` - -//// - -//// tab | Python 3.10+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="128-134" -{!> ../../docs_src/security/tutorial005_py310.py!} -``` - -//// - -//// tab | Python 3.9+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="129-135" -{!> ../../docs_src/security/tutorial005_py39.py!} -``` - -//// - -//// tab | Python 3.8+ non-Annotated - -/// tip - -Prefer to use the `Annotated` version if possible. - -/// - -```Python hl_lines="129-135" -{!> ../../docs_src/security/tutorial005.py!} -``` - -//// +{* ../../docs_src/security/tutorial005_an_py310.py hl[129:135] *} ## Dependency tree and scopes diff --git a/docs/en/docs/deployment/cloud.md b/docs/en/docs/deployment/cloud.md index 41ada859d..471808851 100644 --- a/docs/en/docs/deployment/cloud.md +++ b/docs/en/docs/deployment/cloud.md @@ -15,3 +15,4 @@ You might want to try their services and follow their guides: * Platform.sh * Porter * Coherence +* Render diff --git a/docs/en/docs/img/sponsors/render-banner.svg b/docs/en/docs/img/sponsors/render-banner.svg new file mode 100644 index 000000000..b8b1ed2e9 --- /dev/null +++ b/docs/en/docs/img/sponsors/render-banner.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/render.svg b/docs/en/docs/img/sponsors/render.svg new file mode 100644 index 000000000..4a830482d --- /dev/null +++ b/docs/en/docs/img/sponsors/render.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e7bea3c76..85aa085ad 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Docs +* 📝 Update includes in `docs/en/docs/advanced/security/oauth2-scopes.md`. PR [#12572](https://github.com/fastapi/fastapi/pull/12572) by [@krishnamadhavan](https://github.com/krishnamadhavan). * 📝 Update includes for `docs/en/docs/how-to/conditional-openapi.md`. PR [#12624](https://github.com/fastapi/fastapi/pull/12624) by [@rabinlamadong](https://github.com/rabinlamadong). * 📝 Update includes in `docs/en/docs/tutorial/dependencies/index.md`. PR [#12615](https://github.com/fastapi/fastapi/pull/12615) by [@bharara](https://github.com/bharara). * 📝 Update includes in `docs/en/docs/tutorial/response-status-code.md`. PR [#12620](https://github.com/fastapi/fastapi/pull/12620) by [@kantandane](https://github.com/kantandane). @@ -26,11 +27,22 @@ hide: ### Translations +* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/websockets.md`. PR [#12703](https://github.com/fastapi/fastapi/pull/12703) by [@devfernandoa](https://github.com/devfernandoa). +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/simple-oauth2.md`. PR [#12520](https://github.com/fastapi/fastapi/pull/12520) by [@LidiaDomingos](https://github.com/LidiaDomingos). +* 🌐 Add Korean translation for `docs/ko/docs/advanced/response-directly.md`. PR [#12674](https://github.com/fastapi/fastapi/pull/12674) by [@9zimin9](https://github.com/9zimin9). +* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/middleware.md`. PR [#12704](https://github.com/fastapi/fastapi/pull/12704) by [@devluisrodrigues](https://github.com/devluisrodrigues). +* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/openapi-callbacks.md`. PR [#12705](https://github.com/fastapi/fastapi/pull/12705) by [@devfernandoa](https://github.com/devfernandoa). +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/request-files.md`. PR [#12706](https://github.com/fastapi/fastapi/pull/12706) by [@devluisrodrigues](https://github.com/devluisrodrigues). +* 🌐 Add Portuguese Translation for `docs/pt/docs/advanced/custom-response.md`. PR [#12631](https://github.com/fastapi/fastapi/pull/12631) by [@Joao-Pedro-P-Holanda](https://github.com/Joao-Pedro-P-Holanda). +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/metadata.md`. PR [#12538](https://github.com/fastapi/fastapi/pull/12538) by [@LinkolnR](https://github.com/LinkolnR). +* 🌐 Add Korean translation for `docs/ko/docs/tutorial/metadata.md`. PR [#12541](https://github.com/fastapi/fastapi/pull/12541) by [@kwang1215](https://github.com/kwang1215). +* 🌐 Add Korean Translation for `docs/ko/docs/advanced/response-cookies.md`. PR [#12546](https://github.com/fastapi/fastapi/pull/12546) by [@kim-sangah](https://github.com/kim-sangah). * 🌐 Add Korean translation for `docs/ko/docs/fastapi-cli.md`. PR [#12515](https://github.com/fastapi/fastapi/pull/12515) by [@dhdld](https://github.com/dhdld). * 🌐 Add Korean Translation for `docs/ko/docs/advanced/response-change-status-code.md`. PR [#12547](https://github.com/fastapi/fastapi/pull/12547) by [@9zimin9](https://github.com/9zimin9). ### Internal +* 🔧 Update sponsors: add Render. PR [#12733](https://github.com/fastapi/fastapi/pull/12733) by [@tiangolo](https://github.com/tiangolo). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#12707](https://github.com/fastapi/fastapi/pull/12707) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). ## 0.115.4 diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 462907e7c..70a05831f 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -82,6 +82,12 @@ +
+ + + + +
{% endblock %} diff --git a/docs/ko/docs/advanced/response-cookies.md b/docs/ko/docs/advanced/response-cookies.md new file mode 100644 index 000000000..3f87b320a --- /dev/null +++ b/docs/ko/docs/advanced/response-cookies.md @@ -0,0 +1,53 @@ +# 응답 쿠키 + +## `Response` 매개변수 사용하기 + +*경로 작동 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다. + +그런 다음 해당 *임시* 응답 객체에서 쿠키를 설정할 수 있습니다. + +```Python hl_lines="1 8-9" +{!../../docs_src/response_cookies/tutorial002.py!} +``` + +그런 다음 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다. + +그리고 `response_model`을 선언했다면 반환한 객체를 거르고 변환하는 데 여전히 사용됩니다. + +**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, 반환된 값이 포함된 최종 응답에 이를 넣습니다. 이 값은 `response_model`로 걸러지게 됩니다. + +또한 의존관계에서 `Response` 매개변수를 선언하고, 해당 의존성에서 쿠키(및 헤더)를 설정할 수도 있습니다. + +## `Response`를 직접 반환하기 + +코드에서 `Response`를 직접 반환할 때도 쿠키를 생성할 수 있습니다. + +이를 위해 [Response를 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성할 수 있습니다. + +그런 다음 쿠키를 설정하고 반환하면 됩니다: +```Python hl_lines="1 18" +{!../../docs_src/response_directly/tutorial002.py!} +``` +/// tip + +`Response` 매개변수를 사용하지 않고 응답을 직접 반환하는 경우, FastAPI는 이를 직접 반환한다는 점에 유의하세요. + +따라서 데이터가 올바른 유형인지 확인해야 합니다. 예: `JSONResponse`를 반환하는 경우, JSON과 호환되는지 확인하세요. + +또한 `response_model`로 걸러져야 할 데이터가 전달되지 않도록 확인하세요. + +/// + +### 추가 정보 + +/// note | "기술적 세부사항" + +`from starlette.responses import Response` 또는 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다. + +**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 그러나 대부분의 응답은 Starlette에서 직접 제공됩니다. + +또한 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용되므로, **FastAPI**는 이를 `fastapi.Response`로도 제공합니다. + +/// + +사용 가능한 모든 매개변수와 옵션은 Starlette 문서에서 확인할 수 있습니다. diff --git a/docs/ko/docs/advanced/response-directly.md b/docs/ko/docs/advanced/response-directly.md new file mode 100644 index 000000000..20389ff2a --- /dev/null +++ b/docs/ko/docs/advanced/response-directly.md @@ -0,0 +1,67 @@ +# 응답을 직접 반환하기 + +**FastAPI**에서 *경로 작업(path operation)*을 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다. + +기본적으로 **FastAPI**는 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}에 설명된 `jsonable_encoder`를 사용해 해당 반환 값을 자동으로 `JSON`으로 변환합니다. + +그런 다음, JSON 호환 데이터(예: `dict`)를 `JSONResponse`에 넣어 사용자의 응답을 전송하는 방식으로 처리됩니다. + +그러나 *경로 작업*에서 `JSONResponse`를 직접 반환할 수도 있습니다. + +예를 들어, 사용자 정의 헤더나 쿠키를 반환해야 하는 경우에 유용할 수 있습니다. + +## `Response` 반환하기 + +사실, `Response` 또는 그 하위 클래스를 반환할 수 있습니다. + +/// tip + +`JSONResponse` 자체도 `Response`의 하위 클래스입니다. + +/// + +그리고 `Response`를 반환하면 **FastAPI**가 이를 그대로 전달합니다. + +Pydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른 형식으로 변환하지 않습니다. + +이로 인해 많은 유연성을 얻을 수 있습니다. 어떤 데이터 유형이든 반환할 수 있고, 데이터 선언이나 유효성 검사를 재정의할 수 있습니다. + +## `Response`에서 `jsonable_encoder` 사용하기 + +**FastAPI**는 반환하는 `Response`에 아무런 변환을 하지 않으므로, 그 내용이 준비되어 있어야 합니다. + +예를 들어, Pydantic 모델을 `dict`로 변환해 `JSONResponse`에 넣지 않으면 JSON 호환 유형으로 변환된 데이터 유형(예: `datetime`, `UUID` 등)이 사용되지 않습니다. + +이러한 경우, 데이터를 응답에 전달하기 전에 `jsonable_encoder`를 사용하여 변환할 수 있습니다: + +```Python hl_lines="6-7 21-22" +{!../../docs_src/response_directly/tutorial001.py!} +``` + +/// note | "기술적 세부 사항" + +`from starlette.responses import JSONResponse`를 사용할 수도 있습니다. + +**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 제공합니다. 그러나 대부분의 가능한 응답은 Starlette에서 직접 제공합니다. + +/// + +## 사용자 정의 `Response` 반환하기 +위 예제는 필요한 모든 부분을 보여주지만, 아직 유용하지는 않습니다. 사실 데이터를 직접 반환하면 **FastAPI**가 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등 모든 작업을 자동으로 처리합니다. + +이제, 사용자 정의 응답을 반환하는 방법을 알아보겠습니다. + +예를 들어 XML 응답을 반환하고 싶다고 가정해보겠습니다. + +XML 내용을 문자열에 넣고, 이를 `Response`에 넣어 반환할 수 있습니다: + +```Python hl_lines="1 18" +{!../../docs_src/response_directly/tutorial002.py!} +``` + +## 참고 사항 +`Response`를 직접 반환할 때, 그 데이터는 자동으로 유효성 검사되거나, 변환(직렬화)되거나, 문서화되지 않습니다. + +그러나 [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}에서 설명된 대로 문서화할 수 있습니다. + +이후 단락에서 자동 데이터 변환, 문서화 등을 사용하면서 사용자 정의 `Response`를 선언하는 방법을 확인할 수 있습니다. diff --git a/docs/ko/docs/tutorial/metadata.md b/docs/ko/docs/tutorial/metadata.md new file mode 100644 index 000000000..87531152c --- /dev/null +++ b/docs/ko/docs/tutorial/metadata.md @@ -0,0 +1,131 @@ + +# 메타데이터 및 문서화 URL + +**FastAPI** 응용 프로그램에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다. + +## API에 대한 메타데이터 + +OpenAPI 명세 및 자동화된 API 문서 UI에 사용되는 다음 필드를 설정할 수 있습니다: + +| 매개변수 | 타입 | 설명 | +|----------|------|-------| +| `title` | `str` | API의 제목입니다. | +| `summary` | `str` | API에 대한 짧은 요약입니다. OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능 | +| `description` | `str` | API에 대한 짧은 설명입니다. 마크다운을 사용할 수 있습니다. | +| `version` | `string` | API의 버전입니다. OpenAPI의 버전이 아닌, 여러분의 애플리케이션의 버전을 나타냅니다. 예: `2.5.0` | +| `terms_of_service` | `str` | API 이용 약관의 URL입니다. 제공하는 경우 URL 형식이어야 합니다. | +| `contact` | `dict` | 노출된 API에 대한 연락처 정보입니다. 여러 필드를 포함할 수 있습니다.
contact 필드
매개변수타입설명
namestr연락처 인물/조직의 식별명입니다.
urlstr연락처 정보가 담긴 URL입니다. URL 형식이어야 합니다.
emailstr연락처 인물/조직의 이메일 주소입니다. 이메일 주소 형식이어야 합니다.
| +| `license_info` | `dict` | 노출된 API의 라이선스 정보입니다. 여러 필드를 포함할 수 있습니다.
license_info 필드
매개변수타입설명
namestr필수 (license_info가 설정된 경우). API에 사용된 라이선스 이름입니다.
identifierstrAPI에 대한 SPDX 라이선스 표현입니다. identifier 필드는 url 필드와 상호 배타적입니다. OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능
urlstrAPI에 사용된 라이선스의 URL입니다. URL 형식이어야 합니다.
| + +다음과 같이 설정할 수 있습니다: + +```Python hl_lines="3-16 19-32" +{!../../docs_src/metadata/tutorial001.py!} +``` + +/// tip + +`description` 필드에 마크다운을 사용할 수 있으며, 출력에서 렌더링됩니다. + +/// + +이 구성을 사용하면 문서 자동화(로 생성된) API 문서는 다음과 같이 보입니다: + + + +## 라이선스 식별자 + +OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `identifier`를 URL 대신 설정할 수 있습니다. + +예: + +```Python hl_lines="31" +{!../../docs_src/metadata/tutorial001_1.py!} +``` + +## 태그에 대한 메타데이터 + +`openapi_tags` 매개변수를 사용하여 경로 작동을 그룹화하는 데 사용되는 태그에 추가 메타데이터를 추가할 수 있습니다. + +리스트는 각 태그에 대해 하나의 딕셔너리를 포함해야 합니다. + +각 딕셔너리에는 다음이 포함될 수 있습니다: + +* `name` (**필수**): `tags` 매개변수에서 *경로 작동*과 `APIRouter`에 사용된 태그 이름과 동일한 `str`입니다. +* `description`: 태그에 대한 간단한 설명을 담은 `str`입니다. 마크다운을 사용할 수 있으며 문서 UI에 표시됩니다. +* `externalDocs`: 외부 문서를 설명하는 `dict`이며: + * `description`: 외부 문서에 대한 간단한 설명을 담은 `str`입니다. + * `url` (**필수**): 외부 문서의 URL을 담은 `str`입니다. + +### 태그에 대한 메타데이터 생성 + +`users` 및 `items`에 대한 태그 예시와 함께 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달해 보겠습니다: + +```Python hl_lines="3-16 18" +{!../../docs_src/metadata/tutorial004.py!} +``` + +설명 안에 마크다운을 사용할 수 있습니다. 예를 들어 "login"은 굵게(**login**) 표시되고, "fancy"는 기울임꼴(_fancy_)로 표시됩니다. + +/// tip + +사용 중인 모든 태그에 메타데이터를 추가할 필요는 없습니다. + +/// + +### 태그 사용 + +`tags` 매개변수를 *경로 작동* 및 `APIRouter`와 함께 사용하여 태그에 할당할 수 있습니다: + +```Python hl_lines="21 26" +{!../../docs_src/metadata/tutorial004.py!} +``` + +/// info + +태그에 대한 자세한 내용은 [경로 작동 구성](path-operation-configuration.md#tags){.internal-link target=_blank}에서 읽어보세요. + +/// + +### 문서 확인 + +이제 문서를 확인하면 모든 추가 메타데이터가 표시됩니다: + + + +### 태그 순서 + +각 태그 메타데이터 딕셔너리의 순서는 문서 UI에 표시되는 순서를 정의합니다. + +예를 들어, 알파벳 순서상 `users`는 `items` 뒤에 오지만, 우리는 `users` 메타데이터를 리스트의 첫 번째 딕셔너리로 추가했기 때문에 먼저 표시됩니다. + +## OpenAPI URL + +OpenAPI 구조는 기본적으로 `/openapi.json`에서 제공됩니다. + +`openapi_url` 매개변수를 통해 이를 설정할 수 있습니다. + +예를 들어, 이를 `/api/v1/openapi.json`에 제공하도록 설정하려면: + +```Python hl_lines="3" +{!../../docs_src/metadata/tutorial002.py!} +``` + +OpenAPI 구조를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다. + +## 문서화 URL + +포함된 두 가지 문서화 사용자 인터페이스를 설정할 수 있습니다: + +* **Swagger UI**: `/docs`에서 제공됩니다. + * `docs_url` 매개변수로 URL을 설정할 수 있습니다. + * `docs_url=None`으로 설정하여 비활성화할 수 있습니다. +* **ReDoc**: `/redoc`에서 제공됩니다. + * `redoc_url` 매개변수로 URL을 설정할 수 있습니다. + * `redoc_url=None`으로 설정하여 비활성화할 수 있습니다. + +예를 들어, Swagger UI를 `/documentation`에서 제공하고 ReDoc을 비활성화하려면: + +```Python hl_lines="3" +{!../../docs_src/metadata/tutorial003.py!} +``` diff --git a/docs/pt/docs/advanced/custom-response.md b/docs/pt/docs/advanced/custom-response.md new file mode 100644 index 000000000..5f673d7ce --- /dev/null +++ b/docs/pt/docs/advanced/custom-response.md @@ -0,0 +1,344 @@ +# Resposta Personalizada - HTML, Stream, File e outras + +Por padrão, o **FastAPI** irá retornar respostas utilizando `JSONResponse`. + +Mas você pode sobrescrever esse comportamento utilizando `Response` diretamente, como visto em [Retornando uma Resposta Diretamente](response-directly.md){.internal-link target=_blank}. + +Mas se você retornar uma `Response` diretamente (ou qualquer subclasse, como `JSONResponse`), os dados não serão convertidos automaticamente (mesmo que você declare um `response_model`), e a documentação não será gerada automaticamente (por exemplo, incluindo o "media type", no cabeçalho HTTP `Content-Type` como parte do esquema OpenAPI gerado). + +Mas você também pode declarar a `Response` que você deseja utilizar (e.g. qualquer subclasse de `Response`), em um *decorador de operação de rota* utilizando o parâmetro `response_class`. + +Os conteúdos que você retorna em sua *função de operador de rota* serão colocados dentro dessa `Response`. + +E se a `Response` tiver um media type JSON (`application/json`), como é o caso com `JSONResponse` e `UJSONResponse`, os dados que você retornar serão automaticamente convertidos (e filtrados) com qualquer `response_model` do Pydantic que for declarado em sua *função de operador de rota*. + +/// note | Nota + +Se você utilizar uma classe de Resposta sem media type, o FastAPI esperará que sua resposta não tenha conteúdo, então ele não irá documentar o formato da resposta na documentação OpenAPI gerada. + +/// + +## Utilizando `ORJSONResponse` + +Por exemplo, se você precisa bastante de performance, você pode instalar e utilizar o `orjson` e definir a resposta para ser uma `ORJSONResponse`. + +Importe a classe, ou subclasse, de `Response` que você deseja utilizar e declare ela no *decorador de operação de rota*. + +Para respostas grandes, retornar uma `Response` diretamente é muito mais rápido que retornar um dicionário. + +Isso ocorre por que, por padrão, o FastAPI irá verificar cada item dentro do dicionário e garantir que ele seja serializável para JSON, utilizando o mesmo[Codificador Compatível com JSON](../tutorial/encoder.md){.internal-link target=_blank} explicado no tutorial. Isso permite que você retorne **objetos abstratos**, como modelos do banco de dados, por exemplo. + +Mas se você tem certeza que o conteúdo que você está retornando é **serializável com JSON**, você pode passá-lo diretamente para a classe de resposta e evitar o trabalho extra que o FastAPI teria ao passar o conteúdo pelo `jsonable_encoder` antes de passar para a classe de resposta. + +```Python hl_lines="2 7" +{!../../docs_src/custom_response/tutorial001b.py!} +``` + +/// info | Informação + +O parâmetro `response_class` também será usado para definir o "media type" da resposta. + +Neste caso, o cabeçalho HTTP `Content-Type` irá ser definido como `application/json`. + +E será documentado como tal no OpenAPI. + +/// + +/// tip | Dica + +A `ORJSONResponse` está disponível apenas no FastAPI, e não no Starlette. + +/// + +## Resposta HTML + +Para retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLResponse`. + +* Importe `HTMLResponse` +* Passe `HTMLResponse` como o parâmetro de `response_class` do seu *decorador de operação de rota*. + +```Python hl_lines="2 7" +{!../../docs_src/custom_response/tutorial002.py!} +``` + +/// info | Informação + +O parâmetro `response_class` também será usado para definir o "media type" da resposta. + +Neste caso, o cabeçalho HTTP `Content-Type` será definido como `text/html`. + +E será documentado como tal no OpenAPI. + +/// + +### Retornando uma `Response` + +Como visto em [Retornando uma Resposta Diretamente](response-directly.md){.internal-link target=_blank}, você também pode sobrescrever a resposta diretamente na sua *operação de rota*, ao retornar ela. + +O mesmo exemplo de antes, retornando uma `HTMLResponse`, poderia parecer com: + +```Python hl_lines="2 7 19" +{!../../docs_src/custom_response/tutorial003.py!} +``` + +/// warning | Aviso + +Uma `Response` retornada diretamente em sua *função de operação de rota* não será documentada no OpenAPI (por exemplo, o `Content-Type` não será documentado) e não será visível na documentação interativa automática. + +/// + +/// info | Informação + +Obviamente, o cabeçalho `Content-Type`, o código de status, etc, virão do objeto `Response` que você retornou. + +/// + +### Documentar no OpenAPI e sobrescrever `Response` + +Se você deseja sobrescrever a resposta dentro de uma função, mas ao mesmo tempo documentar o "media type" no OpenAPI, você pode utilizar o parâmetro `response_class` E retornar um objeto `Response`. + +A `response_class` será usada apenas para documentar o OpenAPI da *operação de rota*, mas sua `Response` será usada como foi definida. + +##### Retornando uma `HTMLResponse` diretamente + +Por exemplo, poderia ser algo como: + +```Python hl_lines="7 21 23" +{!../../docs_src/custom_response/tutorial004.py!} +``` + +Neste exemplo, a função `generate_html_response()` já cria e retorna uma `Response` em vez de retornar o HTML em uma `str`. + +Ao retornar o resultado chamando `generate_html_response()`, você já está retornando uma `Response` que irá sobrescrever o comportamento padrão do **FastAPI**. + +Mas se você passasse uma `HTMLResponse` em `response_class` também, o **FastAPI** saberia como documentar isso no OpenAPI e na documentação interativa como um HTML com `text/html`: + + + +## Respostas disponíveis + +Aqui estão algumas dos tipos de resposta disponíveis. + +Lembre-se que você pode utilizar `Response` para retornar qualquer outra coisa, ou até mesmo criar uma subclasse personalizada. + +/// note | Detalhes Técnicos + +Você também pode utilizar `from starlette.responses import HTMLResponse`. + +O **FastAPI** provê a mesma `starlette.responses` como `fastapi.responses` apenas como uma facilidade para você, desenvolvedor. Mas a maioria das respostas disponíveis vêm diretamente do Starlette. + +/// + +### `Response` + +A classe principal de respostas, todas as outras respostas herdam dela. + +Você pode retorná-la diretamente. + +Ela aceita os seguintes parâmetros: + +* `content` - Uma sequência de caracteres (`str`) ou `bytes`. +* `status_code` - Um código de status HTTP do tipo `int`. +* `headers` - Um dicionário `dict` de strings. +* `media_type` - Uma `str` informando o media type. E.g. `"text/html"`. + +O FastAPI (Starlette, na verdade) irá incluir o cabeçalho Content-Length automaticamente. Ele também irá incluir o cabeçalho Content-Type, baseado no `media_type` e acrescentando uma codificação para tipos textuais. + +```Python hl_lines="1 18" +{!../../docs_src/response_directly/tutorial002.py!} +``` + +### `HTMLResponse` + +Usa algum texto ou sequência de bytes e retorna uma resposta HTML. Como você leu acima. + +### `PlainTextResponse` + +Usa algum texto ou sequência de bytes para retornar uma resposta de texto não formatado. + +```Python hl_lines="2 7 9" +{!../../docs_src/custom_response/tutorial005.py!} +``` + +### `JSONResponse` + +Pega alguns dados e retorna uma resposta com codificação `application/json`. + +É a resposta padrão utilizada no **FastAPI**, como você leu acima. + +### `ORJSONResponse` + +Uma alternativa mais rápida de resposta JSON utilizando o `orjson`, como você leu acima. + +/// info | Informação + +Essa resposta requer a instalação do pacote `orjson`, com o comando `pip install orjson`, por exemplo. + +/// + +### `UJSONResponse` + +Uma alternativa de resposta JSON utilizando a biblioteca `ujson`. + +/// info | Informação + +Essa resposta requer a instalação do pacote `ujson`, com o comando `pip install ujson`, por exemplo. + +/// + +/// warning | Aviso + +`ujson` é menos cauteloso que a implementação nativa do Python na forma que os casos especiais são tratados + +/// + +```Python hl_lines="2 7" +{!../../docs_src/custom_response/tutorial001.py!} +``` + +/// tip | Dica + +É possível que `ORJSONResponse` seja uma alternativa mais rápida. + +/// + +### `RedirectResponse` + +Retorna um redirecionamento HTTP. Utiliza o código de status 307 (Redirecionamento Temporário) por padrão. + +Você pode retornar uma `RedirectResponse` diretamente: + +```Python hl_lines="2 9" +{!../../docs_src/custom_response/tutorial006.py!} +``` + +--- + +Ou você pode utilizá-la no parâmetro `response_class`: + +```Python hl_lines="2 7 9" +{!../../docs_src/custom_response/tutorial006b.py!} +``` + +Se você fizer isso, então você pode retornar a URL diretamente da sua *função de operação de rota* + +Neste caso, o `status_code` utilizada será o padrão de `RedirectResponse`, que é `307`. + +--- + +Você também pode utilizar o parâmetro `status_code` combinado com o parâmetro `response_class`: + +```Python hl_lines="2 7 9" +{!../../docs_src/custom_response/tutorial006c.py!} +``` + +### `StreamingResponse` + +Recebe uma gerador assíncrono ou um gerador/iterador comum e retorna o corpo da requisição continuamente (stream). + +```Python hl_lines="2 14" +{!../../docs_src/custom_response/tutorial007.py!} +``` + +#### Utilizando `StreamingResponse` com objetos semelhantes a arquivos + +Se você tiver um objeto semelhante a um arquivo (e.g. o objeto retornado por `open()`), você pode criar uma função geradora para iterar sobre esse objeto. + +Dessa forma, você não precisa ler todo o arquivo na memória primeiro, e você pode passar essa função geradora para `StreamingResponse` e retorná-la. + +Isso inclui muitas bibliotecas que interagem com armazenamento em nuvem, processamento de vídeos, entre outras. + +```{ .python .annotate hl_lines="2 10-12 14" } +{!../../docs_src/custom_response/tutorial008.py!} +``` + +1. Essa é a função geradora. É definida como "função geradora" porque contém declarações `yield` nela. +2. Ao utilizar o bloco `with`, nós garantimos que o objeto semelhante a um arquivo é fechado após a função geradora ser finalizada. Isto é, após a resposta terminar de ser enivada. +3. Essa declaração `yield from` informa a função para iterar sobre essa coisa nomeada de `file_like`. E então, para cada parte iterada, fornece essa parte como se viesse dessa função geradora (`iterfile`). + + Então, é uma função geradora que transfere o trabalho de "geração" para alguma outra coisa interna. + + Fazendo dessa forma, podemos colocá-la em um bloco `with`, e assim garantir que o objeto semelhante a um arquivo é fechado quando a função termina. + +/// tip | Dica + +Perceba que aqui estamos utilizando o `open()` da biblioteca padrão que não suporta `async` e `await`, e declaramos a operação de rota com o `def` básico. + +/// + +### `FileResponse` + +Envia um arquivo de forma assíncrona e contínua (stream). +* +Recebe um conjunto de argumentos do construtor diferente dos outros tipos de resposta: + +* `path` - O caminho do arquivo que será transmitido +* `headers` - quaisquer cabeçalhos que serão incluídos, como um dicionário. +* `media_type` - Uma string com o media type. Se não for definida, o media type é inferido a partir do nome ou caminho do arquivo. +* `filename` - Se for definido, é incluído no cabeçalho `Content-Disposition`. + +Respostas de Arquivos incluem o tamanho do arquivo, data da última modificação e ETags apropriados, nos cabeçalhos `Content-Length`, `Last-Modified` e `ETag`, respectivamente. + +```Python hl_lines="2 10" +{!../../docs_src/custom_response/tutorial009.py!} +``` + +Você também pode usar o parâmetro `response_class`: + +```Python hl_lines="2 8 10" +{!../../docs_src/custom_response/tutorial009b.py!} +``` + +Nesse caso, você pode retornar o caminho do arquivo diretamente da sua *função de operação de rota*. + +## Classe de resposta personalizada + +Você pode criar sua própria classe de resposta, herdando de `Response` e usando essa nova classe. + +Por exemplo, vamos supor que você queira utilizar o `orjson`, mas com algumas configurações personalizadas que não estão incluídas na classe `ORJSONResponse`. + +Vamos supor também que você queira retornar um JSON indentado e formatado, então você quer utilizar a opção `orjson.OPT_INDENT_2` do orjson. + +Você poderia criar uma classe `CustomORJSONResponse`. A principal coisa a ser feita é sobrecarregar o método render da classe Response, `Response.render(content)`, que retorna o conteúdo em bytes, para retornar o conteúdo que você deseja: + +```Python hl_lines="9-14 17" +{!../../docs_src/custom_response/tutorial009c.py!} +``` + +Agora em vez de retornar: + +```json +{"message": "Hello World"} +``` + +...essa resposta retornará: + +```json +{ + "message": "Hello World" +} +``` + +Obviamente, você provavelmente vai encontrar maneiras muito melhores de se aproveitar disso do que a formatação de JSON. 😉 + +## Classe de resposta padrão + +Quando você criar uma instância da classe **FastAPI** ou um `APIRouter` você pode especificar qual classe de resposta utilizar por padrão. + +O padrão que define isso é o `default_response_class`. + +No exemplo abaixo, o **FastAPI** irá utilizar `ORJSONResponse` por padrão, em todas as *operações de rota*, em vez de `JSONResponse`. + +```Python hl_lines="2 4" +{!../../docs_src/custom_response/tutorial010.py!} +``` + +/// tip | Dica + +Você ainda pode substituir `response_class` em *operações de rota* como antes. + +/// + +## Documentação adicional + +Você também pode declarar o media type e muitos outros detalhes no OpenAPI utilizando `responses`: [Retornos Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/pt/docs/advanced/middleware.md b/docs/pt/docs/advanced/middleware.md new file mode 100644 index 000000000..8167f7d27 --- /dev/null +++ b/docs/pt/docs/advanced/middleware.md @@ -0,0 +1,96 @@ +# Middleware Avançado + +No tutorial principal você leu como adicionar [Middleware Personalizado](../tutorial/middleware.md){.internal-link target=_blank} à sua aplicação. + +E então você também leu como lidar com [CORS com o `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}. + +Nesta seção, veremos como usar outros middlewares. + +## Adicionando middlewares ASGI + +Como o **FastAPI** é baseado no Starlette e implementa a especificação ASGI, você pode usar qualquer middleware ASGI. + +O middleware não precisa ser feito para o FastAPI ou Starlette para funcionar, desde que siga a especificação ASGI. + +No geral, os middlewares ASGI são classes que esperam receber um aplicativo ASGI como o primeiro argumento. + +Então, na documentação de middlewares ASGI de terceiros, eles provavelmente dirão para você fazer algo como: + +```Python +from unicorn import UnicornMiddleware + +app = SomeASGIApp() + +new_app = UnicornMiddleware(app, some_config="rainbow") +``` + +Mas, o FastAPI (na verdade, o Starlette) fornece uma maneira mais simples de fazer isso que garante que os middlewares internos lidem com erros do servidor e que os manipuladores de exceções personalizados funcionem corretamente. + +Para isso, você usa `app.add_middleware()` (como no exemplo para CORS). + +```Python +from fastapi import FastAPI +from unicorn import UnicornMiddleware + +app = FastAPI() + +app.add_middleware(UnicornMiddleware, some_config="rainbow") +``` + +`app.add_middleware()` recebe uma classe de middleware como o primeiro argumento e quaisquer argumentos adicionais a serem passados para o middleware. + +## Middlewares Integrados + +**FastAPI** inclui vários middlewares para casos de uso comuns, veremos a seguir como usá-los. + +/// note | Detalhes Técnicos + +Para o próximo exemplo, você também poderia usar `from starlette.middleware.something import SomethingMiddleware`. + +**FastAPI** fornece vários middlewares em `fastapi.middleware` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria dos middlewares disponíveis vem diretamente do Starlette. + +/// + +## `HTTPSRedirectMiddleware` + +Garante que todas as requisições devem ser `https` ou `wss`. + +Qualquer requisição para `http` ou `ws` será redirecionada para o esquema seguro. + +{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *} + +## `TrustedHostMiddleware` + +Garante que todas as requisições recebidas tenham um cabeçalho `Host` corretamente configurado, a fim de proteger contra ataques de cabeçalho de host HTTP. + +{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *} + +Os seguintes argumentos são suportados: + +* `allowed_hosts` - Uma lista de nomes de domínio que são permitidos como nomes de host. Domínios com coringa, como `*.example.com`, são suportados para corresponder a subdomínios. Para permitir qualquer nome de host, use `allowed_hosts=["*"]` ou omita o middleware. + +Se uma requisição recebida não for validada corretamente, uma resposta `400` será enviada. + +## `GZipMiddleware` + +Gerencia respostas GZip para qualquer requisição que inclua `"gzip"` no cabeçalho `Accept-Encoding`. + +O middleware lidará com respostas padrão e de streaming. + +{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *} + +Os seguintes argumentos são suportados: + +* `minimum_size` - Não comprima respostas menores que este tamanho mínimo em bytes. O padrão é `500`. +* `compresslevel` - Usado durante a compressão GZip. É um inteiro variando de 1 a 9. O padrão é `9`. Um valor menor resulta em uma compressão mais rápida, mas em arquivos maiores, enquanto um valor maior resulta em uma compressão mais lenta, mas em arquivos menores. + +## Outros middlewares + +Há muitos outros middlewares ASGI. + +Por exemplo: + +* Uvicorn's `ProxyHeadersMiddleware` +* MessagePack + +Para checar outros middlewares disponíveis, confira Documentação de Middlewares do Starlette e a Lista Incrível do ASGI. diff --git a/docs/pt/docs/advanced/openapi-callbacks.md b/docs/pt/docs/advanced/openapi-callbacks.md new file mode 100644 index 000000000..c66ababa0 --- /dev/null +++ b/docs/pt/docs/advanced/openapi-callbacks.md @@ -0,0 +1,194 @@ +# Callbacks na OpenAPI + +Você poderia criar uma API com uma *operação de rota* que poderia acionar uma solicitação a uma *API externa* criada por outra pessoa (provavelmente o mesmo desenvolvedor que estaria *usando* sua API). + +O processo que acontece quando seu aplicativo de API chama a *API externa* é chamado de "callback". Porque o software que o desenvolvedor externo escreveu envia uma solicitação para sua API e então sua API *chama de volta*, enviando uma solicitação para uma *API externa* (que provavelmente foi criada pelo mesmo desenvolvedor). + +Nesse caso, você poderia querer documentar como essa API externa *deveria* ser. Que *operação de rota* ela deveria ter, que corpo ela deveria esperar, que resposta ela deveria retornar, etc. + +## Um aplicativo com callbacks + +Vamos ver tudo isso com um exemplo. + +Imagine que você tem um aplicativo que permite criar faturas. + +Essas faturas terão um `id`, `title` (opcional), `customer` e `total`. + +O usuário da sua API (um desenvolvedor externo) criará uma fatura em sua API com uma solicitação POST. + +Então sua API irá (vamos imaginar): + +* Enviar uma solicitação de pagamento para o desenvolvedor externo. +* Coletar o dinheiro. +* Enviar a notificação de volta para o usuário da API (o desenvolvedor externo). +* Isso será feito enviando uma solicitação POST (de *sua API*) para alguma *API externa* fornecida por esse desenvolvedor externo (este é o "callback"). + +## O aplicativo **FastAPI** normal + +Vamos primeiro ver como o aplicativo da API normal se pareceria antes de adicionar o callback. + +Ele terá uma *operação de rota* que receberá um corpo `Invoice`, e um parâmetro de consulta `callback_url` que conterá a URL para o callback. + +Essa parte é bastante normal, a maior parte do código provavelmente já é familiar para você: + +```Python hl_lines="9-13 36-53" +{!../../docs_src/openapi_callbacks/tutorial001.py!} +``` + +/// tip | Dica + +O parâmetro de consulta `callback_url` usa um tipo Pydantic Url. + +/// + +A única coisa nova é o argumento `callbacks=invoices_callback_router.routes` no decorador da *operação de rota*. Veremos o que é isso a seguir. + +## Documentando o callback + +O código real do callback dependerá muito do seu próprio aplicativo de API. + +E provavelmente variará muito de um aplicativo para o outro. + +Poderia ser apenas uma ou duas linhas de código, como: + +```Python +callback_url = "https://example.com/api/v1/invoices/events/" +httpx.post(callback_url, json={"description": "Invoice paid", "paid": True}) +``` + +Mas possivelmente a parte mais importante do callback é garantir que o usuário da sua API (o desenvolvedor externo) implemente a *API externa* corretamente, de acordo com os dados que *sua API* vai enviar no corpo da solicitação do callback, etc. + +Então, o que faremos a seguir é adicionar o código para documentar como essa *API externa* deve ser para receber o callback de *sua API*. + +A documentação aparecerá na interface do Swagger em `/docs` em sua API, e permitirá que os desenvolvedores externos saibam como construir a *API externa*. + +Esse exemplo não implementa o callback em si (que poderia ser apenas uma linha de código), apenas a parte da documentação. + +/// tip | Dica + +O callback real é apenas uma solicitação HTTP. + +Quando implementando o callback por você mesmo, você pode usar algo como HTTPX ou Requisições. + +/// + +## Escrevendo o código de documentação do callback + +Esse código não será executado em seu aplicativo, nós só precisamos dele para *documentar* como essa *API externa* deveria ser. + +Mas, você já sabe como criar facilmente documentação automática para uma API com o **FastAPI**. + +Então vamos usar esse mesmo conhecimento para documentar como a *API externa* deveria ser... criando as *operações de rota* que a *API externa* deveria implementar (as que sua API irá chamar). + +/// tip | Dica + +Quando escrever o código para documentar um callback, pode ser útil imaginar que você é aquele *desenvolvedor externo*. E que você está atualmente implementando a *API externa*, não *sua API*. + +Adotar temporariamente esse ponto de vista (do *desenvolvedor externo*) pode ajudar a sentir que é mais óbvio onde colocar os parâmetros, o modelo Pydantic para o corpo, para a resposta, etc. para essa *API externa*. + +/// + +### Criar um `APIRouter` para o callback + +Primeiramente crie um novo `APIRouter` que conterá um ou mais callbacks. + +```Python hl_lines="3 25" +{!../../docs_src/openapi_callbacks/tutorial001.py!} +``` + +### Crie a *operação de rota* do callback + +Para criar a *operação de rota* do callback, use o mesmo `APIRouter` que você criou acima. + +Ele deve parecer exatamente como uma *operação de rota* normal do FastAPI: + +* Ele provavelmente deveria ter uma declaração do corpo que deveria receber, por exemplo. `body: InvoiceEvent`. +* E também deveria ter uma declaração de um código de status de resposta, por exemplo. `response_model=InvoiceEventReceived`. + +```Python hl_lines="16-18 21-22 28-32" +{!../../docs_src/openapi_callbacks/tutorial001.py!} +``` + +Há 2 diferenças principais de uma *operação de rota* normal: + +* Ela não necessita ter nenhum código real, porque seu aplicativo nunca chamará esse código. Ele é usado apenas para documentar a *API externa*. Então, a função poderia ter apenas `pass`. +* A *rota* pode conter uma expressão OpenAPI 3 (veja mais abaixo) onde pode usar variáveis com parâmetros e partes da solicitação original enviada para *sua API*. + +### A expressão do caminho do callback + +A *rota* do callback pode ter uma expressão OpenAPI 3 que pode conter partes da solicitação original enviada para *sua API*. + +Nesse caso, é a `str`: + +```Python +"{$callback_url}/invoices/{$request.body.id}" +``` + +Então, se o usuário da sua API (o desenvolvedor externo) enviar uma solicitação para *sua API* para: + +``` +https://yourapi.com/invoices/?callback_url=https://www.external.org/events +``` + +com um corpo JSON de: + +```JSON +{ + "id": "2expen51ve", + "customer": "Mr. Richie Rich", + "total": "9999" +} +``` + +então *sua API* processará a fatura e, em algum momento posterior, enviará uma solicitação de callback para o `callback_url` (a *API externa*): + +``` +https://www.external.org/events/invoices/2expen51ve +``` + +com um corpo JSON contendo algo como: + +```JSON +{ + "description": "Payment celebration", + "paid": true +} +``` + +e esperaria uma resposta daquela *API externa* com um corpo JSON como: + +```JSON +{ + "ok": true +} +``` + +/// tip | Dica + +Perceba como a URL de callback usada contém a URL recebida como um parâmetro de consulta em `callback_url` (`https://www.external.org/events`) e também o `id` da fatura de dentro do corpo JSON (`2expen51ve`). + +/// + +### Adicionar o roteador de callback + +Nesse ponto você tem a(s) *operação de rota de callback* necessária(s) (a(s) que o *desenvolvedor externo* deveria implementar na *API externa*) no roteador de callback que você criou acima. + +Agora use o parâmetro `callbacks` no decorador da *operação de rota de sua API* para passar o atributo `.routes` (que é na verdade apenas uma `list` de rotas/*operações de rota*) do roteador de callback que você criou acima: + +```Python hl_lines="35" +{!../../docs_src/openapi_callbacks/tutorial001.py!} +``` + +/// tip | Dica + +Perceba que você não está passando o roteador em si (`invoices_callback_router`) para `callback=`, mas o atributo `.routes`, como em `invoices_callback_router.routes`. + +/// + +### Verifique a documentação + +Agora você pode iniciar seu aplicativo e ir para http://127.0.0.1:8000/docs. + +Você verá sua documentação incluindo uma seção "Callbacks" para sua *operação de rota* que mostra como a *API externa* deveria ser: + + diff --git a/docs/pt/docs/advanced/websockets.md b/docs/pt/docs/advanced/websockets.md new file mode 100644 index 000000000..694f2bb5d --- /dev/null +++ b/docs/pt/docs/advanced/websockets.md @@ -0,0 +1,188 @@ +# WebSockets + +Você pode usar WebSockets com **FastAPI**. + +## Instalando `WebSockets` + +Garanta que você criou um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, o ativou e instalou o `websockets`: + +
+ +```console +$ pip install websockets + +---> 100% +``` + +
+ +## Cliente WebSockets + +### Em produção + +Em seu sistema de produção, você provavelmente tem um frontend criado com um framework moderno como React, Vue.js ou Angular. + +E para comunicar usando WebSockets com seu backend, você provavelmente usaria as utilidades do seu frontend. + +Ou você pode ter um aplicativo móvel nativo que se comunica diretamente com seu backend WebSocket, em código nativo. + +Ou você pode ter qualquer outra forma de comunicar com o endpoint WebSocket. + +--- + +Mas para este exemplo, usaremos um documento HTML muito simples com algum JavaScript, tudo dentro de uma string longa. + +Esse, é claro, não é o ideal e você não o usaria para produção. + +Na produção, você teria uma das opções acima. + +Mas é a maneira mais simples de focar no lado do servidor de WebSockets e ter um exemplo funcional: + +```Python hl_lines="2 6-38 41-43" +{!../../docs_src/websockets/tutorial001.py!} +``` + +## Criando um `websocket` + +Em sua aplicação **FastAPI**, crie um `websocket`: + +{*../../docs_src/websockets/tutorial001.py hl[46:47]*} + +/// note | Detalhes Técnicos + +Você também poderia usar `from starlette.websockets import WebSocket`. + +A **FastAPI** fornece o mesmo `WebSocket` diretamente apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente do Starlette. + +/// + +## Aguardar por mensagens e enviar mensagens + +Em sua rota WebSocket você pode esperar (`await`) por mensagens e enviar mensagens. + +{*../../docs_src/websockets/tutorial001.py hl[48:52]*} + +Você pode receber e enviar dados binários, de texto e JSON. + +## Tente você mesmo + +Se seu arquivo for nomeado `main.py`, execute sua aplicação com: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Abra seu navegador em: http://127.0.0.1:8000. + +Você verá uma página simples como: + + + +Você pode digitar mensagens na caixa de entrada e enviá-las: + + + +E sua aplicação **FastAPI** com WebSockets responderá de volta: + + + +Você pode enviar (e receber) muitas mensagens: + + + +E todas elas usarão a mesma conexão WebSocket. + +## Usando `Depends` e outros + +Nos endpoints WebSocket você pode importar do `fastapi` e usar: + +* `Depends` +* `Security` +* `Cookie` +* `Header` +* `Path` +* `Query` + +Eles funcionam da mesma forma que para outros endpoints FastAPI/*operações de rota*: + +{*../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82]*} + +/// info | Informação + +Como isso é um WebSocket, não faz muito sentido levantar uma `HTTPException`, em vez disso levantamos uma `WebSocketException`. + +Você pode usar um código de fechamento dos códigos válidos definidos na especificação. + +/// + +### Tente os WebSockets com dependências + +Se seu arquivo for nomeado `main.py`, execute sua aplicação com: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Abrar seu browser em: http://127.0.0.1:8000. + +Lá você pode definir: + +* O "Item ID", usado na rota. +* O "Token" usado como um parâmetro de consulta. + +/// tip | Dica + +Perceba que a consulta `token` será manipulada por uma dependência. + +/// + +Com isso você pode conectar o WebSocket e então enviar e receber mensagens: + + + +## Lidando com desconexões e múltiplos clientes + +Quando uma conexão WebSocket é fechada, o `await websocket.receive_text()` levantará uma exceção `WebSocketDisconnect`, que você pode então capturar e lidar como neste exemplo. + +{*../../docs_src/websockets/tutorial003_py39.py hl[79:81]*} + +Para testar: + +* Abrar o aplicativo com várias abas do navegador. +* Escreva mensagens a partir delas. +* Então feche uma das abas. + +Isso levantará a exceção `WebSocketDisconnect`, e todos os outros clientes receberão uma mensagem como: + +``` +Client #1596980209979 left the chat +``` + +/// tip | Dica + +O app acima é um exemplo mínimo e simples para demonstrar como lidar e transmitir mensagens para várias conexões WebSocket. + +Mas tenha em mente que, como tudo é manipulado na memória, em uma única lista, ele só funcionará enquanto o processo estiver em execução e só funcionará com um único processo. + +Se você precisa de algo fácil de integrar com o FastAPI, mas que seja mais robusto, suportado por Redis, PostgreSQL ou outros, verifique o encode/broadcaster. + +/// + +## Mais informações + +Para aprender mais sobre as opções, verifique a documentação do Starlette para: + +* A classe `WebSocket`. +* Manipulação de WebSockets baseada em classes. diff --git a/docs/pt/docs/tutorial/metadata.md b/docs/pt/docs/tutorial/metadata.md new file mode 100644 index 000000000..5db2882b9 --- /dev/null +++ b/docs/pt/docs/tutorial/metadata.md @@ -0,0 +1,132 @@ +# Metadados e Urls de Documentos + +Você pode personalizar várias configurações de metadados na sua aplicação **FastAPI**. + +## Metadados para API + +Você pode definir os seguintes campos que são usados na especificação OpenAPI e nas interfaces automáticas de documentação da API: + +| Parâmetro | Tipo | Descrição | +|------------|------|-------------| +| `title` | `str` | O título da API. | +| `summary` | `str` | Um breve resumo da API. Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0. | +| `description` | `str` | Uma breve descrição da API. Pode usar Markdown. | +| `version` | `string` | A versão da API. Esta é a versão da sua aplicação, não do OpenAPI. Por exemplo, `2.5.0`. | +| `terms_of_service` | `str` | Uma URL para os Termos de Serviço da API. Se fornecido, deve ser uma URL. | +| `contact` | `dict` | As informações de contato da API exposta. Pode conter vários campos.
Campos de contact
ParâmetroTipoDescrição
namestrO nome identificador da pessoa/organização de contato.
urlstrA URL que aponta para as informações de contato. DEVE estar no formato de uma URL.
emailstrO endereço de e-mail da pessoa/organização de contato. DEVE estar no formato de um endereço de e-mail.
| +| `license_info` | `dict` | As informações de licença para a API exposta. Ela pode conter vários campos.
Campos de license_info
ParâmetroTipoDescrição
namestrOBRIGATÓRIO (se um license_info for definido). O nome da licença usada para a API.
identifierstrUma expressão de licença SPDX para a API. O campo identifier é mutuamente exclusivo do campo url. Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.
urlstrUma URL para a licença usada para a API. DEVE estar no formato de uma URL.
| + +Você pode defini-los da seguinte maneira: + +```Python hl_lines="3-16 19-32" +{!../../docs_src/metadata/tutorial001.py!} +``` + +/// tip | Dica + +Você pode escrever Markdown no campo `description` e ele será renderizado na saída. + +/// + +Com essa configuração, a documentação automática da API se pareceria com: + + + +## Identificador de Licença + +Desde o OpenAPI 3.1.0 e FastAPI 0.99.0, você também pode definir o license_info com um identifier em vez de uma url. + +Por exemplo: + +```Python hl_lines="31" +{!../../docs_src/metadata/tutorial001_1.py!} +``` + +## Metadados para tags + +Você também pode adicionar metadados adicionais para as diferentes tags usadas para agrupar suas operações de rota com o parâmetro `openapi_tags`. + +Ele recebe uma lista contendo um dicionário para cada tag. + +Cada dicionário pode conter: + +* `name` (**obrigatório**): uma `str` com o mesmo nome da tag que você usa no parâmetro `tags` nas suas *operações de rota* e `APIRouter`s. +* `description`: uma `str` com uma breve descrição da tag. Pode conter Markdown e será exibido na interface de documentação. +* `externalDocs`: um `dict` descrevendo a documentação externa com: + * `description`: uma `str` com uma breve descrição da documentação externa. + * `url` (**obrigatório**): uma `str` com a URL da documentação externa. + +### Criar Metadados para tags + +Vamos tentar isso em um exemplo com tags para `users` e `items`. + +Crie metadados para suas tags e passe-os para o parâmetro `openapi_tags`: + +```Python hl_lines="3-16 18" +{!../../docs_src/metadata/tutorial004.py!} +``` + +Observe que você pode usar Markdown dentro das descrições. Por exemplo, "login" será exibido em negrito (**login**) e "fancy" será exibido em itálico (_fancy_). + +/// tip | Dica + +Você não precisa adicionar metadados para todas as tags que você usa. + +/// + +### Use suas tags + +Use o parâmetro `tags` com suas *operações de rota* (e `APIRouter`s) para atribuí-los a diferentes tags: + +```Python hl_lines="21 26" +{!../../docs_src/metadata/tutorial004.py!} +``` + +/// info | Informação + +Leia mais sobre tags em [Configuração de Operação de Caminho](path-operation-configuration.md#tags){.internal-link target=_blank}. + +/// + +### Cheque os documentos + +Agora, se você verificar a documentação, ela exibirá todos os metadados adicionais: + + + +### Ordem das tags + +A ordem de cada dicionário de metadados de tag também define a ordem exibida na interface de documentação. + +Por exemplo, embora `users` apareça após `items` em ordem alfabética, ele é exibido antes deles, porque adicionamos seus metadados como o primeiro dicionário na lista. + +## URL da OpenAPI + +Por padrão, o esquema OpenAPI é servido em `/openapi.json`. + +Mas você pode configurá-lo com o parâmetro `openapi_url`. + +Por exemplo, para defini-lo para ser servido em `/api/v1/openapi.json`: + +```Python hl_lines="3" +{!../../docs_src/metadata/tutorial002.py!} +``` + +Se você quiser desativar completamente o esquema OpenAPI, pode definir `openapi_url=None`, o que também desativará as interfaces de documentação que o utilizam. + +## URLs da Documentação + +Você pode configurar as duas interfaces de documentação incluídas: + +* **Swagger UI**: acessível em `/docs`. + * Você pode definir sua URL com o parâmetro `docs_url`. + * Você pode desativá-la definindo `docs_url=None`. +* **ReDoc**: acessível em `/redoc`. + * Você pode definir sua URL com o parâmetro `redoc_url`. + * Você pode desativá-la definindo `redoc_url=None`. + +Por exemplo, para definir o Swagger UI para ser servido em `/documentation` e desativar o ReDoc: + +```Python hl_lines="3" +{!../../docs_src/metadata/tutorial003.py!} +``` diff --git a/docs/pt/docs/tutorial/request-files.md b/docs/pt/docs/tutorial/request-files.md new file mode 100644 index 000000000..d230f1feb --- /dev/null +++ b/docs/pt/docs/tutorial/request-files.md @@ -0,0 +1,176 @@ +# Arquivos de Requisição + +Você pode definir arquivos para serem enviados pelo cliente usando `File`. + +/// info | Informação + +Para receber arquivos enviados, primeiro instale o `python-multipart`. + +Garanta que você criou um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, o ativou e então o instalou, por exemplo: + +```console +$ pip install python-multipart +``` + +Isso é necessário, visto que os arquivos enviados são enviados como "dados de formulário". + +/// + +## Importe `File` + +Importe `File` e `UploadFile` de `fastapi`: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *} + +## Definir Parâmetros `File` + +Crie parâmetros de arquivo da mesma forma que você faria para `Body` ou `Form`: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *} + +/// info | Informação + +`File` é uma classe que herda diretamente de `Form`. + +Mas lembre-se que quando você importa `Query`, `Path`, `File` e outros de `fastapi`, eles são, na verdade, funções que retornam classes especiais. + +/// + +/// tip | Dica + +Para declarar corpos de arquivos, você precisa usar `File`, caso contrário, os parâmetros seriam interpretados como parâmetros de consulta ou parâmetros de corpo (JSON). + +/// + +Os arquivos serão enviados como "dados de formulário". + +Se você declarar o tipo do parâmetro da função da sua *operação de rota* como `bytes`, o **FastAPI** lerá o arquivo para você e você receberá o conteúdo como `bytes`. + +Mantenha em mente que isso significa que todo o conteúdo será armazenado na memória. Isso funcionará bem para arquivos pequenos. + +Mas há muitos casos em que você pode se beneficiar do uso de `UploadFile`. + +## Parâmetros de Arquivo com `UploadFile` + +Defina um parâmetro de arquivo com um tipo de `UploadFile`: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *} + +Utilizar `UploadFile` tem várias vantagens sobre `bytes`: + +* Você não precisa utilizar o `File()` no valor padrão do parâmetro. +* Ele utiliza um arquivo "spooled": + * Um arquivo armazenado na memória até um limite máximo de tamanho, e após passar esse limite, ele será armazenado no disco. +* Isso significa que funcionará bem para arquivos grandes como imagens, vídeos, binários grandes, etc., sem consumir toda a memória. +* Você pode receber metadados do arquivo enviado. +* Ele tem uma file-like interface `assíncrona`. +* Ele expõe um objeto python `SpooledTemporaryFile` que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo("file-like"). + +### `UploadFile` + +`UploadFile` tem os seguintes atributos: + +* `filename`: Uma `str` com o nome do arquivo original que foi enviado (por exemplo, `myimage.jpg`). +* `content_type`: Uma `str` com o tipo de conteúdo (tipo MIME / tipo de mídia) (por exemplo, `image/jpeg`). +* `file`: Um `SpooledTemporaryFile` (um file-like objeto). Este é o objeto de arquivo Python que você pode passar diretamente para outras funções ou bibliotecas que esperam um objeto semelhante a um arquivo("file-like"). + +`UploadFile` tem os seguintes métodos `assíncronos`. Todos eles chamam os métodos de arquivo correspondentes por baixo dos panos (usando o `SpooledTemporaryFile` interno). + +* `write(data)`: Escreve `data` (`str` ou `bytes`) no arquivo. +* `read(size)`: Lê `size` (`int`) bytes/caracteres do arquivo. +* `seek(offset)`: Vai para o byte na posição `offset` (`int`) no arquivo. + * Por exemplo, `await myfile.seek(0)` irá para o início do arquivo. + * Isso é especialmente útil se você executar `await myfile.read()` uma vez e precisar ler o conteúdo novamente. +* `close()`: Fecha o arquivo. + +Como todos esses métodos são métodos `assíncronos`, você precisa "aguardar" por eles. + +Por exemplo, dentro de uma função de *operação de rota* `assíncrona`, você pode obter o conteúdo com: + +```Python +contents = await myfile.read() +``` + +Se você estiver dentro de uma função de *operação de rota* normal `def`, você pode acessar o `UploadFile.file` diretamente, por exemplo: + +```Python +contents = myfile.file.read() +``` + +/// note | Detalhes Técnicos do `async` + +Quando você usa os métodos `async`, o **FastAPI** executa os métodos de arquivo em um threadpool e aguarda por eles. + +/// + +/// note | "Detalhes Técnicos do Starlette" + +O `UploadFile` do ***FastAPI** herda diretamente do `UploadFile` do **Starlette** , mas adiciona algumas partes necessárias para torná-lo compatível com o **Pydantic** e as outras partes do FastAPI. + +/// + +## O que é "Form Data" + +O jeito que os formulários HTML (`
`) enviam os dados para o servidor normalmente usa uma codificação "especial" para esses dados, a qual é diferente do JSON. + +**FastAPI** se certificará de ler esses dados do lugar certo, ao invés de JSON. + +/// note | "Detalhes Técnicos" + +Dados de formulários normalmente são codificados usando o "media type" (tipo de mídia) `application/x-www-form-urlencoded` quando não incluem arquivos. + +Mas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Se você usar `File`, o **FastAPI** saberá que tem que pegar os arquivos da parte correta do corpo da requisição. + +Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a MDN web docs para POST. + +/// + +/// warning | Aviso + +Você pode declarar múltiplos parâmetros `File` e `Form` em uma *operação de rota*, mas você não pode declarar campos `Body` que você espera receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`. + +Isso não é uma limitação do **FastAPI**, é parte do protocolo HTTP. + +/// + +## Upload de Arquivo Opcional + +Você pode tornar um arquivo opcional usando anotações de tipo padrão e definindo um valor padrão de `None`: + +{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *} + +## `UploadFile` com Metadados Adicionais + +Você também pode usar `File()` com `UploadFile`, por exemplo, para definir metadados adicionais: + +{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *} + +## Uploads de Múltiplos Arquivos + +É possível realizar o upload de vários arquivos ao mesmo tempo. + +Eles serão associados ao mesmo "campo de formulário" enviado usando "dados de formulário". + +Para usar isso, declare uma lista de `bytes` ou `UploadFile`: + +{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *} + +Você receberá, tal como declarado, uma `list` de `bytes` ou `UploadFile`. + +/// note | "Detalhes Técnicos" + +Você pode também pode usar `from starlette.responses import HTMLResponse`. + +**FastAPI** providencia o mesmo `starlette.responses` que `fastapi.responses` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria das respostas disponíveis vem diretamente do Starlette. + +/// + +### Uploads de Múltiplos Arquivos com Metadados Adicionais + +Da mesma forma de antes, você pode usar `File()` para definir parâmetros adicionais, mesmo para `UploadFile`: + +{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *} + +## Recapitulando + +Utilize `File`, `bytes` e `UploadFile` para declarar arquivos a serem enviados na requisição, enviados como dados de formulário. diff --git a/docs/pt/docs/tutorial/security/simple-oauth2.md b/docs/pt/docs/tutorial/security/simple-oauth2.md new file mode 100644 index 000000000..4e55f8c25 --- /dev/null +++ b/docs/pt/docs/tutorial/security/simple-oauth2.md @@ -0,0 +1,539 @@ +# Simples OAuth2 com senha e Bearer + +Agora vamos construir a partir do capítulo anterior e adicionar as partes que faltam para ter um fluxo de segurança completo. + +## Pegue o `username` (nome de usuário) e `password` (senha) + +É utilizado o utils de segurança da **FastAPI** para obter o `username` e a `password`. + +OAuth2 especifica que ao usar o "password flow" (fluxo de senha), que estamos usando, o cliente/usuário deve enviar os campos `username` e `password` como dados do formulário. + +E a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam. + +Mas não se preocupe, você pode mostrá-lo como quiser aos usuários finais no frontend. + +E seus modelos de banco de dados podem usar qualquer outro nome que você desejar. + +Mas para a *operação de rota* de login, precisamos usar esses nomes para serem compatíveis com a especificação (e poder, por exemplo, usar o sistema integrado de documentação da API). + +A especificação também afirma que o `username` e a `password` devem ser enviados como dados de formulário (portanto, não há JSON aqui). + +### `scope` + +A especificação também diz que o cliente pode enviar outro campo de formulário "`scope`" (Escopo). + +O nome do campo do formulário é `scope` (no singular), mas na verdade é uma longa string com "escopos" separados por espaços. + +Cada “scope” é apenas uma string (sem espaços). + +Normalmente são usados para declarar permissões de segurança específicas, por exemplo: + +* `users:read` ou `users:write` são exemplos comuns. +* `instagram_basic` é usado pelo Facebook e Instagram. +* `https://www.googleapis.com/auth/drive` é usado pelo Google. + +/// info | Informação + +No OAuth2, um "scope" é apenas uma string que declara uma permissão específica necessária. + +Não importa se tem outros caracteres como `:` ou se é uma URL. + +Esses detalhes são específicos da implementação. + +Para OAuth2 são apenas strings. + +/// + +## Código para conseguir o `username` e a `password` + +Agora vamos usar os utilitários fornecidos pelo **FastAPI** para lidar com isso. + +### `OAuth2PasswordRequestForm` + +Primeiro, importe `OAuth2PasswordRequestForm` e use-o como uma dependência com `Depends` na *operação de rota* para `/token`: + +//// tab | Python 3.10+ + +```Python hl_lines="4 78" +{!> ../../docs_src/security/tutorial003_an_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="4 78" +{!> ../../docs_src/security/tutorial003_an_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="4 79" +{!> ../../docs_src/security/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.10+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="2 74" +{!> ../../docs_src/security/tutorial003_py310.py!} +``` + +//// + +//// tab | Python 3.8+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="4 76" +{!> ../../docs_src/security/tutorial003.py!} +``` + +//// + +`OAuth2PasswordRequestForm` é uma dependência de classe que declara um corpo de formulário com: + +* O `username`. +* A `password`. +* Um campo `scope` opcional como uma string grande, composta de strings separadas por espaços. +* Um `grant_type` (tipo de concessão) opcional. + +/// tip | Dica + +A especificação OAuth2 na verdade *requer* um campo `grant_type` com um valor fixo de `password`, mas `OAuth2PasswordRequestForm` não o impõe. + +Se você precisar aplicá-lo, use `OAuth2PasswordRequestFormStrict` em vez de `OAuth2PasswordRequestForm`. + +/// + +* Um `client_id` opcional (não precisamos dele em nosso exemplo). +* Um `client_secret` opcional (não precisamos dele em nosso exemplo). + +/// info | Informação + +O `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como é `OAuth2PasswordBearer`. + +`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI. + +Mas `OAuth2PasswordRequestForm` é apenas uma dependência de classe que você mesmo poderia ter escrito ou poderia ter declarado os parâmetros do `Form` (formulário) diretamente. + +Mas como é um caso de uso comum, ele é fornecido diretamente pelo **FastAPI**, apenas para facilitar. + +/// + +### Use os dados do formulário + +/// tip | Dica + +A instância da classe de dependência `OAuth2PasswordRequestForm` não terá um atributo `scope` com a string longa separada por espaços, em vez disso, terá um atributo `scopes` com a lista real de strings para cada escopo enviado. + +Não estamos usando `scopes` neste exemplo, mas a funcionalidade está disponível se você precisar. + +/// + +Agora, obtenha os dados do usuário do banco de dados (falso), usando o `username` do campo do formulário. + +Se não existir tal usuário, retornaremos um erro dizendo "Incorrect username or password" (Nome de usuário ou senha incorretos). + +Para o erro, usamos a exceção `HTTPException`: + +//// tab | Python 3.10+ + +```Python hl_lines="3 79-81" +{!> ../../docs_src/security/tutorial003_an_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="3 79-81" +{!> ../../docs_src/security/tutorial003_an_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="3 80-82" +{!> ../../docs_src/security/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.10+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="1 75-77" +{!> ../../docs_src/security/tutorial003_py310.py!} +``` + +//// + +//// tab | Python 3.8+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="3 77-79" +{!> ../../docs_src/security/tutorial003.py!} +``` + +//// + +### Confira a password (senha) + +Neste ponto temos os dados do usuário do nosso banco de dados, mas não verificamos a senha. + +Vamos colocar esses dados primeiro no modelo `UserInDB` do Pydantic. + +Você nunca deve salvar senhas em texto simples, portanto, usaremos o sistema de hashing de senhas (falsas). + +Se as senhas não corresponderem, retornaremos o mesmo erro. + +#### Hashing de senha + +"Hashing" significa: converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece algo sem sentido. + +Sempre que você passa exatamente o mesmo conteúdo (exatamente a mesma senha), você obtém exatamente a mesma sequência aleatória de caracteres. + +Mas você não pode converter a sequência aleatória de caracteres de volta para a senha. + +##### Porque usar hashing de senha + +Se o seu banco de dados for roubado, o ladrão não terá as senhas em texto simples dos seus usuários, apenas os hashes. + +Assim, o ladrão não poderá tentar usar essas mesmas senhas em outro sistema (como muitos usuários usam a mesma senha em todos os lugares, isso seria perigoso). + +//// tab | Python 3.10+ + +```Python hl_lines="82-85" +{!> ../../docs_src/security/tutorial003_an_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="82-85" +{!> ../../docs_src/security/tutorial003_an_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="83-86" +{!> ../../docs_src/security/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.10+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="78-81" +{!> ../../docs_src/security/tutorial003_py310.py!} +``` + +//// + +//// tab | Python 3.8+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="80-83" +{!> ../../docs_src/security/tutorial003.py!} +``` + +//// + +#### Sobre `**user_dict` + +`UserInDB(**user_dict)` significa: + +*Passe as keys (chaves) e values (valores) de `user_dict` diretamente como argumentos de valor-chave, equivalente a:* + +```Python +UserInDB( + username = user_dict["username"], + email = user_dict["email"], + full_name = user_dict["full_name"], + disabled = user_dict["disabled"], + hashed_password = user_dict["hashed_password"], +) +``` + +/// info | Informação + +Para uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user_indict){.internal-link target=_blank}. + +/// + +## Retorne o token + +A resposta do endpoint `token` deve ser um objeto JSON. + +Deve ter um `token_type`. No nosso caso, como estamos usando tokens "Bearer", o tipo de token deve ser "`bearer`". + +E deve ter um `access_token`, com uma string contendo nosso token de acesso. + +Para este exemplo simples, seremos completamente inseguros e retornaremos o mesmo `username` do token. + +/// tip | Dica + +No próximo capítulo, você verá uma implementação realmente segura, com hash de senha e tokens JWT. + +Mas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisamos. + +/// + +//// tab | Python 3.10+ + +```Python hl_lines="87" +{!> ../../docs_src/security/tutorial003_an_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="87" +{!> ../../docs_src/security/tutorial003_an_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="88" +{!> ../../docs_src/security/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.10+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="83" +{!> ../../docs_src/security/tutorial003_py310.py!} +``` + +//// + +//// tab | Python 3.8+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="85" +{!> ../../docs_src/security/tutorial003.py!} +``` + +//// + +/// tip | Dica + +Pela especificação, você deve retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo. + +Isso é algo que você mesmo deve fazer em seu código e certifique-se de usar essas chaves JSON. + +É quase a única coisa que você deve se lembrar de fazer corretamente, para estar em conformidade com as especificações. + +De resto, **FastAPI** cuida disso para você. + +/// + +## Atualize as dependências + +Agora vamos atualizar nossas dependências. + +Queremos obter o `user_user` *somente* se este usuário estiver ativo. + +Portanto, criamos uma dependência adicional `get_current_active_user` que por sua vez usa `get_current_user` como dependência. + +Ambas as dependências retornarão apenas um erro HTTP se o usuário não existir ou se estiver inativo. + +Portanto, em nosso endpoint, só obteremos um usuário se o usuário existir, tiver sido autenticado corretamente e estiver ativo: + +//// tab | Python 3.10+ + +```Python hl_lines="58-66 69-74 94" +{!> ../../docs_src/security/tutorial003_an_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="58-66 69-74 94" +{!> ../../docs_src/security/tutorial003_an_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="59-67 70-75 95" +{!> ../../docs_src/security/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.10+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="56-64 67-70 88" +{!> ../../docs_src/security/tutorial003_py310.py!} +``` + +//// + +//// tab | Python 3.8+ non-Annotated + +/// tip | Dica + +Prefira usar a versão `Annotated`, se possível. + +/// + +```Python hl_lines="58-66 69-72 90" +{!> ../../docs_src/security/tutorial003.py!} +``` + +//// + +/// info | Informação + +O cabeçalho adicional `WWW-Authenticate` com valor `Bearer` que estamos retornando aqui também faz parte da especificação. + +Qualquer código de status HTTP (erro) 401 "UNAUTHORIZED" também deve retornar um cabeçalho `WWW-Authenticate`. + +No caso de tokens ao portador (nosso caso), o valor desse cabeçalho deve ser `Bearer`. + +Na verdade, você pode pular esse cabeçalho extra e ainda funcionaria. + +Mas é fornecido aqui para estar em conformidade com as especificações. + +Além disso, pode haver ferramentas que esperam e usam isso (agora ou no futuro) e que podem ser úteis para você ou seus usuários, agora ou no futuro. + +Esse é o benefício dos padrões... + +/// + +## Veja em ação + +Abra o docs interativo: http://127.0.0.1:8000/docs. + +### Autenticação + +Clique no botão "Authorize". + +Use as credenciais: + +User: `johndoe` + +Password: `secret` + + + +Após autenticar no sistema, você verá assim: + + + +### Obtenha seus próprios dados de usuário + +Agora use a operação `GET` com o caminho `/users/me`. + +Você obterá os dados do seu usuário, como: + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false, + "hashed_password": "fakehashedsecret" +} +``` + + + +Se você clicar no ícone de cadeado, sair e tentar a mesma operação novamente, receberá um erro HTTP 401 de: + +```JSON +{ + "detail": "Not authenticated" +} +``` + +### Usuário inativo + +Agora tente com um usuário inativo, autentique-se com: + +User: `alice` + +Password: `secret2` + +E tente usar a operação `GET` com o caminho `/users/me`. + +Você receberá um erro "Usuário inativo", como: + +```JSON +{ + "detail": "Inactive user" +} +``` + +## Recaptulando + +Agora você tem as ferramentas para implementar um sistema de segurança completo baseado em `username` e `password` para sua API. + +Usando essas ferramentas, você pode tornar o sistema de segurança compatível com qualquer banco de dados e com qualquer usuário ou modelo de dados. + +O único detalhe que falta é que ainda não é realmente "seguro". + +No próximo capítulo você verá como usar uma biblioteca de hashing de senha segura e tokens JWT.