mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'master' into docs/edit-timer-in-middleware
This commit is contained in:
commit
ead4f8c6a4
|
|
@ -10,6 +10,7 @@ permissions:
|
|||
deployments: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
|
||||
jobs:
|
||||
deploy-docs:
|
||||
|
|
@ -20,6 +21,25 @@ jobs:
|
|||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: actions/cache@v4
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-github-actions-${{ env.pythonLocation }}-${{ hashFiles('requirements-github-actions.txt') }}-v01
|
||||
- name: Install GitHub Actions dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-github-actions.txt
|
||||
- name: Deploy Docs Status Pending
|
||||
run: python ./scripts/deploy_docs_status.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
|
||||
- name: Clean site
|
||||
run: |
|
||||
rm -rf ./site
|
||||
|
|
@ -43,22 +63,11 @@ jobs:
|
|||
directory: './site'
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' && 'main' ) || ( github.event.workflow_run.head_sha ) }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: actions/cache@v4
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-github-actions-${{ env.pythonLocation }}-${{ hashFiles('requirements-github-actions.txt') }}-v01
|
||||
- name: Install GitHub Actions dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-github-actions.txt
|
||||
- name: Comment Deploy
|
||||
if: steps.deploy.outputs.url != ''
|
||||
run: python ./scripts/comment_docs_deploy_url_in_pr.py
|
||||
run: python ./scripts/deploy_docs_status.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DEPLOY_URL: ${{ steps.deploy.outputs.url }}
|
||||
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ hide:
|
|||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/using-request-directly.md`. PR [#11956](https://github.com/fastapi/fastapi/pull/11956) by [@ceb10n](https://github.com/ceb10n).
|
||||
* 🌐 Add French translation for `docs/fr/docs/tutorial/body-multiple-params.md`. PR [#11796](https://github.com/fastapi/fastapi/pull/11796) by [@pe-brian](https://github.com/pe-brian).
|
||||
* 🌐 Update Chinese translation for `docs/zh/docs/tutorial/query-params.md`. PR [#11557](https://github.com/fastapi/fastapi/pull/11557) by [@caomingpei](https://github.com/caomingpei).
|
||||
* 🌐 Update typo in Chinese translation for `docs/zh/docs/advanced/testing-dependencies.md`. PR [#11944](https://github.com/fastapi/fastapi/pull/11944) by [@bestony](https://github.com/bestony).
|
||||
|
|
@ -18,6 +19,8 @@ hide:
|
|||
|
||||
### Internal
|
||||
|
||||
* 🔒️ Update permissions for deploy-docs action. PR [#11964](https://github.com/fastapi/fastapi/pull/11964) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷🏻 Add deploy docs status and preview links to PRs. PR [#11961](https://github.com/fastapi/fastapi/pull/11961) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update docs setup with latest configs and plugins. PR [#11953](https://github.com/fastapi/fastapi/pull/11953) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔇 Ignore warning from attrs in Trio. PR [#11949](https://github.com/fastapi/fastapi/pull/11949) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
# Utilizando o Request diretamente
|
||||
|
||||
Até agora você declarou as partes da requisição que você precisa utilizando os seus tipos.
|
||||
|
||||
Obtendo dados de:
|
||||
|
||||
* Os parâmetros das rotas.
|
||||
* Cabeçalhos (*Headers*).
|
||||
* Cookies.
|
||||
* etc.
|
||||
|
||||
E ao fazer isso, o **FastAPI** está validando as informações, convertendo-as e gerando documentação para a sua API automaticamente.
|
||||
|
||||
Porém há situações em que você possa precisar acessar o objeto `Request` diretamente.
|
||||
|
||||
## Detalhes sobre o objeto `Request`
|
||||
|
||||
Como o **FastAPI** é na verdade o **Starlette** por baixo, com camadas de diversas funcionalidades por cima, você pode utilizar o objeto <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request`</a> do Starlette diretamente quando precisar.
|
||||
|
||||
Isso significaria também que se você obtiver informações do objeto `Request` diretamente (ler o corpo da requisição por exemplo), as informações não serão validadas, convertidas ou documentadas (com o OpenAPI, para a interface de usuário automática da API) pelo FastAPI.
|
||||
|
||||
Embora qualquer outro parâmetro declarado normalmente (o corpo da requisição com um modelo Pydantic, por exemplo) ainda seria validado, convertido, anotado, etc.
|
||||
|
||||
Mas há situações específicas onde é útil utilizar o objeto `Request`.
|
||||
|
||||
## Utilize o objeto `Request` diretamente
|
||||
|
||||
Vamos imaginar que você deseja obter o endereço de IP/host do cliente dentro da sua *função de operação de rota*.
|
||||
|
||||
Para isso você precisa acessar a requisição diretamente.
|
||||
|
||||
```Python hl_lines="1 7-8"
|
||||
{!../../../docs_src/using_request_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
Ao declarar o parâmetro com o tipo sendo um `Request` em sua *função de operação de rota*, o **FastAPI** saberá como passar o `Request` neste parâmetro.
|
||||
|
||||
/// tip | "Dica"
|
||||
|
||||
Note que neste caso, nós estamos declarando o parâmetro da rota ao lado do parâmetro da requisição.
|
||||
|
||||
Assim, o parâmetro da rota será extraído, validado, convertido para o tipo especificado e anotado com OpenAPI.
|
||||
|
||||
Do mesmo jeito, você pode declarar qualquer outro parâmetro normalmente, e além disso, obter o `Request` também.
|
||||
|
||||
///
|
||||
|
||||
## Documentação do `Request`
|
||||
|
||||
Você pode ler mais sobre os detalhes do objeto <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request` no site da documentação oficial do Starlette.</a>.
|
||||
|
||||
/// note | "Detalhes Técnicos"
|
||||
|
||||
Você também pode utilizar `from starlette.requests import Request`.
|
||||
|
||||
O **FastAPI** fornece isso diretamente apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente do Starlette.
|
||||
|
||||
///
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import logging
|
||||
import sys
|
||||
|
||||
from github import Github
|
||||
from pydantic import SecretStr
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
github_repository: str
|
||||
github_token: SecretStr
|
||||
deploy_url: str
|
||||
commit_sha: str
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.model_dump_json()}")
|
||||
g = Github(settings.github_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
use_pr = next(
|
||||
(pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None
|
||||
)
|
||||
if not use_pr:
|
||||
logging.error(f"No PR found for hash: {settings.commit_sha}")
|
||||
sys.exit(0)
|
||||
use_pr.as_issue().create_comment(
|
||||
f"📝 Docs preview for commit {settings.commit_sha} at: {settings.deploy_url}"
|
||||
)
|
||||
logging.info("Finished")
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import logging
|
||||
import re
|
||||
|
||||
from github import Github
|
||||
from pydantic import SecretStr
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
github_repository: str
|
||||
github_token: SecretStr
|
||||
deploy_url: str | None = None
|
||||
commit_sha: str
|
||||
run_id: int
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
|
||||
logging.info(f"Using config: {settings.model_dump_json()}")
|
||||
g = Github(settings.github_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
use_pr = next(
|
||||
(pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None
|
||||
)
|
||||
if not use_pr:
|
||||
logging.error(f"No PR found for hash: {settings.commit_sha}")
|
||||
return
|
||||
commits = list(use_pr.get_commits())
|
||||
current_commit = [c for c in commits if c.sha == settings.commit_sha][0]
|
||||
run_url = f"https://github.com/{settings.github_repository}/actions/runs/{settings.run_id}"
|
||||
if not settings.deploy_url:
|
||||
current_commit.create_status(
|
||||
state="pending",
|
||||
description="Deploy Docs",
|
||||
context="deploy-docs",
|
||||
target_url=run_url,
|
||||
)
|
||||
logging.info("No deploy URL available yet")
|
||||
return
|
||||
current_commit.create_status(
|
||||
state="success",
|
||||
description="Deploy Docs",
|
||||
context="deploy-docs",
|
||||
target_url=run_url,
|
||||
)
|
||||
|
||||
files = list(use_pr.get_files())
|
||||
docs_files = [f for f in files if f.filename.startswith("docs/")]
|
||||
|
||||
lang_links: dict[str, list[str]] = {}
|
||||
for f in docs_files:
|
||||
match = re.match(r"docs/([^/]+)/docs/(.*)", f.filename)
|
||||
assert match
|
||||
lang = match.group(1)
|
||||
path = match.group(2)
|
||||
if path.endswith("index.md"):
|
||||
path = path.replace("index.md", "")
|
||||
else:
|
||||
path = path.replace(".md", "/")
|
||||
if lang == "en":
|
||||
link = f"{settings.deploy_url}{path}"
|
||||
else:
|
||||
link = f"{settings.deploy_url}{lang}/{path}"
|
||||
lang_links.setdefault(lang, []).append(link)
|
||||
|
||||
links: list[str] = []
|
||||
en_links = lang_links.get("en", [])
|
||||
en_links.sort()
|
||||
links.extend(en_links)
|
||||
|
||||
langs = list(lang_links.keys())
|
||||
langs.sort()
|
||||
for lang in langs:
|
||||
if lang == "en":
|
||||
continue
|
||||
current_lang_links = lang_links[lang]
|
||||
current_lang_links.sort()
|
||||
links.extend(current_lang_links)
|
||||
|
||||
message = (
|
||||
f"📝 Docs preview for commit {settings.commit_sha} at: {settings.deploy_url}"
|
||||
)
|
||||
|
||||
if links:
|
||||
message += "\n\n### Modified Pages\n\n"
|
||||
message += "\n".join([f"* {link}" for link in links])
|
||||
|
||||
print(message)
|
||||
use_pr.as_issue().create_comment(message)
|
||||
|
||||
logging.info("Finished")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue