mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'master' of https://github.com/harol97/fastapi into fix/conider-alias-in-form
This commit is contained in:
commit
0c8b8a1d1e
|
|
@ -55,9 +55,7 @@ The key features are:
|
|||
<a href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge" target="_blank" title="Auth, user management and more for your B2B product"><img src="https://fastapi.tiangolo.com/img/sponsors/propelauth.png"></a>
|
||||
<a href="https://www.withcoherence.com/?utm_medium=advertising&utm_source=fastapi&utm_campaign=banner%20january%2024" target="_blank" title="Coherence"><img src="https://fastapi.tiangolo.com/img/sponsors/coherence.png"></a>
|
||||
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython-v2.jpg"></a>
|
||||
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
|
||||
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
|
||||
<a href="https://careers.powens.com/" target="_blank" title="Powens is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/powens.png"></a>
|
||||
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
|
||||
<a href="https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
|
||||
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# Öyrən
|
||||
|
||||
Burada **FastAPI** öyrənmək üçün giriş bölmələri və dərsliklər yer alır.
|
||||
|
||||
Siz bunu kitab, kurs, FastAPI öyrənmək üçün rəsmi və tövsiyə olunan üsul hesab edə bilərsiniz. 😎
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Externe Links und Artikel
|
||||
|
||||
**FastAPI** hat eine großartige Community, die ständig wächst.
|
||||
|
||||
Es gibt viele Beiträge, Artikel, Tools und Projekte zum Thema **FastAPI**.
|
||||
|
||||
Hier ist eine unvollständige Liste einiger davon.
|
||||
|
||||
!!! tip "Tipp"
|
||||
Wenn Sie einen Artikel, ein Projekt, ein Tool oder irgendetwas im Zusammenhang mit **FastAPI** haben, was hier noch nicht aufgeführt ist, erstellen Sie einen <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request und fügen Sie es hinzu</a>.
|
||||
|
||||
!!! note "Hinweis Deutsche Übersetzung"
|
||||
Die folgenden Überschriften und Links werden aus einer <a href="https://github.com/tiangolo/fastapi/blob/master/docs/en/data/external_links.yml" class="external-link" target="_blank">anderen Datei</a> gelesen und sind daher nicht ins Deutsche übersetzt.
|
||||
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
## {{ section_name }}
|
||||
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
## Projekte
|
||||
|
||||
Die neuesten GitHub-Projekte zum Thema `fastapi`:
|
||||
|
||||
<div class="github-topic-projects">
|
||||
</div>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# FastAPI und Freunde Newsletter
|
||||
|
||||
<iframe data-w-type="embedded" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://xr4n4.mjt.lu/wgt/xr4n4/hj5/form?c=40a44fa4" width="100%" style="height: 0;"></iframe>
|
||||
|
||||
<script type="text/javascript" src="https://app.mailjet.com/pas-nc-embedded-v1.js"></script>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Hintergrundtasks – `BackgroundTasks`
|
||||
|
||||
Sie können einen Parameter in einer *Pfadoperation-Funktion* oder einer Abhängigkeitsfunktion mit dem Typ `BackgroundTasks` deklarieren und diesen danach verwenden, um die Ausführung von Hintergrundtasks nach dem Senden der Response zu definieren.
|
||||
|
||||
Sie können `BackgroundTasks` direkt von `fastapi` importieren:
|
||||
|
||||
```python
|
||||
from fastapi import BackgroundTasks
|
||||
```
|
||||
|
||||
::: fastapi.BackgroundTasks
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Encoder – `jsonable_encoder`
|
||||
|
||||
::: fastapi.encoders.jsonable_encoder
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# `FastAPI`-Klasse
|
||||
|
||||
Hier sind die Referenzinformationen für die Klasse `FastAPI` mit all ihren Parametern, Attributen und Methoden.
|
||||
|
||||
Sie können die `FastAPI`-Klasse direkt von `fastapi` importieren:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
```
|
||||
|
||||
::: fastapi.FastAPI
|
||||
options:
|
||||
members:
|
||||
- openapi_version
|
||||
- webhooks
|
||||
- state
|
||||
- dependency_overrides
|
||||
- openapi
|
||||
- websocket
|
||||
- include_router
|
||||
- get
|
||||
- put
|
||||
- post
|
||||
- delete
|
||||
- options
|
||||
- head
|
||||
- patch
|
||||
- trace
|
||||
- on_event
|
||||
- middleware
|
||||
- exception_handler
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# `Request`-Klasse
|
||||
|
||||
Sie können einen Parameter in einer *Pfadoperation-Funktion* oder einer Abhängigkeit als vom Typ `Request` deklarieren und dann direkt auf das Requestobjekt zugreifen, ohne jegliche Validierung, usw.
|
||||
|
||||
Sie können es direkt von `fastapi` importieren:
|
||||
|
||||
```python
|
||||
from fastapi import Request
|
||||
```
|
||||
|
||||
!!! tip "Tipp"
|
||||
Wenn Sie Abhängigkeiten definieren möchten, die sowohl mit HTTP als auch mit WebSockets kompatibel sein sollen, können Sie einen Parameter definieren, der eine `HTTPConnection` anstelle eines `Request` oder eines `WebSocket` akzeptiert.
|
||||
|
||||
::: fastapi.Request
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
# Benutzerdefinierte Responseklassen – File, HTML, Redirect, Streaming, usw.
|
||||
|
||||
Es gibt mehrere benutzerdefinierte Responseklassen, von denen Sie eine Instanz erstellen und diese direkt von Ihren *Pfadoperationen* zurückgeben können.
|
||||
|
||||
Lesen Sie mehr darüber in der [FastAPI-Dokumentation zu benutzerdefinierten Responses – HTML, Stream, Datei, andere](../advanced/custom-response.md).
|
||||
|
||||
Sie können diese direkt von `fastapi.responses` importieren:
|
||||
|
||||
```python
|
||||
from fastapi.responses import (
|
||||
FileResponse,
|
||||
HTMLResponse,
|
||||
JSONResponse,
|
||||
ORJSONResponse,
|
||||
PlainTextResponse,
|
||||
RedirectResponse,
|
||||
Response,
|
||||
StreamingResponse,
|
||||
UJSONResponse,
|
||||
)
|
||||
```
|
||||
|
||||
## FastAPI-Responses
|
||||
|
||||
Es gibt einige benutzerdefinierte FastAPI-Responseklassen, welche Sie verwenden können, um die JSON-Performanz zu optimieren.
|
||||
|
||||
::: fastapi.responses.UJSONResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.ORJSONResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
## Starlette-Responses
|
||||
|
||||
::: fastapi.responses.FileResponse
|
||||
options:
|
||||
members:
|
||||
- chunk_size
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.HTMLResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.JSONResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.PlainTextResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.RedirectResponse
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.Response
|
||||
options:
|
||||
members:
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
||||
::: fastapi.responses.StreamingResponse
|
||||
options:
|
||||
members:
|
||||
- body_iterator
|
||||
- charset
|
||||
- status_code
|
||||
- media_type
|
||||
- body
|
||||
- background
|
||||
- raw_headers
|
||||
- render
|
||||
- init_headers
|
||||
- headers
|
||||
- set_cookie
|
||||
- delete_cookie
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Templating – `Jinja2Templates`
|
||||
|
||||
Sie können die `Jinja2Templates`-Klasse verwenden, um Jinja-Templates zu rendern.
|
||||
|
||||
Lesen Sie mehr darüber in der [FastAPI-Dokumentation zu Templates](../advanced/templates.md).
|
||||
|
||||
Sie können die Klasse direkt von `fastapi.templating` importieren:
|
||||
|
||||
```python
|
||||
from fastapi.templating import Jinja2Templates
|
||||
```
|
||||
|
||||
::: fastapi.templating.Jinja2Templates
|
||||
|
|
@ -27,15 +27,9 @@ silver:
|
|||
- url: https://training.talkpython.fm/fastapi-courses
|
||||
title: FastAPI video courses on demand from people you trust
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/talkpython-v2.jpg
|
||||
- url: https://testdriven.io/courses/tdd-fastapi/
|
||||
title: Learn to build high-quality web apps with best practices
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
- url: https://github.com/deepset-ai/haystack/
|
||||
title: Build powerful search from composable, open source building blocks
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg
|
||||
- url: https://careers.powens.com/
|
||||
title: Powens is hiring!
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/powens.png
|
||||
- url: https://databento.com/
|
||||
title: Pay as you go for market data
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/databento.svg
|
||||
|
|
@ -52,6 +46,6 @@ bronze:
|
|||
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
|
||||
title: Biosecurity risk assessments made easy.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png
|
||||
- url: https://bit.ly/3JJ7y5C
|
||||
title: Build cross-modal and multimodal applications on the cloud
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg
|
||||
- url: https://testdriven.io/courses/tdd-fastapi/
|
||||
title: Learn to build high-quality web apps with best practices
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
|
|
|
|||
|
|
@ -7,6 +7,43 @@ hide:
|
|||
|
||||
## Latest Changes
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Azerbaijani translation for `docs/az/learn/index.md`. PR [#11192](https://github.com/tiangolo/fastapi/pull/11192) by [@vusallyv](https://github.com/vusallyv).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors, remove Jina, remove Powens, move TestDriven.io. PR [#11213](https://github.com/tiangolo/fastapi/pull/11213) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.110.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* 🐛 Fix unhandled growing memory for internal server errors, refactor dependencies with `yield` and `except` to require raising again as in regular Python. PR [#11191](https://github.com/tiangolo/fastapi/pull/11191) by [@tiangolo](https://github.com/tiangolo).
|
||||
* This is a breaking change (and only slightly) if you used dependencies with `yield`, used `except` in those dependencies, and didn't raise again.
|
||||
* This was reported internally by [@rushilsrivastava](https://github.com/rushilsrivastava) as a memory leak when the server had unhandled exceptions that would produce internal server errors, the memory allocated before that point would not be released.
|
||||
* Read the new docs: [Dependencies with `yield` and `except`](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except).
|
||||
|
||||
In short, if you had dependencies that looked like:
|
||||
|
||||
```Python
|
||||
def my_dep():
|
||||
try:
|
||||
yield
|
||||
except SomeException:
|
||||
pass
|
||||
```
|
||||
|
||||
Now you need to make sure you raise again after `except`, just as you would in regular Python:
|
||||
|
||||
```Python
|
||||
def my_dep():
|
||||
try:
|
||||
yield
|
||||
except SomeException:
|
||||
raise
|
||||
```
|
||||
|
||||
### Docs
|
||||
|
||||
* ✏️ Fix minor typos in `docs/ko/docs/`. PR [#11126](https://github.com/tiangolo/fastapi/pull/11126) by [@KaniKim](https://github.com/KaniKim).
|
||||
|
|
@ -14,6 +51,16 @@ hide:
|
|||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/background.md`. PR [#10820](https://github.com/tiangolo/fastapi/pull/10820) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/templating.md`. PR [#10842](https://github.com/tiangolo/fastapi/pull/10842) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add German translation for `docs/de/docs/external-links.md`. PR [#10852](https://github.com/tiangolo/fastapi/pull/10852) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Update Turkish translation for `docs/tr/docs/tutorial/query-params.md`. PR [#11162](https://github.com/tiangolo/fastapi/pull/11162) by [@hasansezertasan](https://github.com/hasansezertasan).
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/encoders.md`. PR [#10840](https://github.com/tiangolo/fastapi/pull/10840) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/responses.md`. PR [#10825](https://github.com/tiangolo/fastapi/pull/10825) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/request.md`. PR [#10821](https://github.com/tiangolo/fastapi/pull/10821) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add Turkish translation for `docs/tr/docs/tutorial/query-params.md`. PR [#11078](https://github.com/tiangolo/fastapi/pull/11078) by [@emrhnsyts](https://github.com/emrhnsyts).
|
||||
* 🌐 Add German translation for `docs/de/docs/reference/fastapi.md`. PR [#10813](https://github.com/tiangolo/fastapi/pull/10813) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add German translation for `docs/de/docs/newsletter.md`. PR [#10853](https://github.com/tiangolo/fastapi/pull/10853) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* 🌐 Add Traditional Chinese translation for `docs/zh-hant/docs/learn/index.md`. PR [#11142](https://github.com/tiangolo/fastapi/pull/11142) by [@hsuanchi](https://github.com/hsuanchi).
|
||||
* 🌐 Add Korean translation for `/docs/ko/docs/tutorial/dependencies/global-dependencies.md`. PR [#11123](https://github.com/tiangolo/fastapi/pull/11123) by [@riroan](https://github.com/riroan).
|
||||
* 🌐 Add Korean translation for `/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#11124](https://github.com/tiangolo/fastapi/pull/11124) by [@riroan](https://github.com/riroan).
|
||||
|
|
@ -281,7 +328,7 @@ Read more in the [advisory: Content-Type Header ReDoS](https://github.com/tiango
|
|||
|
||||
### Upgrades
|
||||
|
||||
* ⬆️ Upgrade Starlette to `>=0.29.0,<0.33.0`, update docs and usage of templates with new Starlette arguments. PR [#10846](https://github.com/tiangolo/fastapi/pull/10846) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade Starlette to `>=0.29.0,<0.33.0`, update docs and usage of templates with new Starlette arguments. Remove pin of AnyIO `>=3.7.1,<4.0.0`, add support for AnyIO 4.x.x. PR [#10846](https://github.com/tiangolo/fastapi/pull/10846) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.107.0
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,63 @@ The same way, you could raise an `HTTPException` or similar in the exit code, af
|
|||
|
||||
An alternative you could use to catch exceptions (and possibly also raise another `HTTPException`) is to create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
## Dependencies with `yield` and `except`
|
||||
|
||||
If you catch an exception using `except` in a dependency with `yield` and you don't raise it again (or raise a new exception), FastAPI won't be able to notice there was an exception, the same way that would happen with regular Python:
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
```Python hl_lines="15-16"
|
||||
{!> ../../../docs_src/dependencies/tutorial008c_an_py39.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="14-15"
|
||||
{!> ../../../docs_src/dependencies/tutorial008c_an.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+ non-Annotated"
|
||||
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="13-14"
|
||||
{!> ../../../docs_src/dependencies/tutorial008c.py!}
|
||||
```
|
||||
|
||||
In this case, the client will see an *HTTP 500 Internal Server Error* response as it should, given that we are not raising an `HTTPException` or similar, but the server will **not have any logs** or any other indication of what was the error. 😱
|
||||
|
||||
### Always `raise` in Dependencies with `yield` and `except`
|
||||
|
||||
If you catch an exception in a dependency with `yield`, unless you are raising another `HTTPException` or similar, you should re-raise the original exception.
|
||||
|
||||
You can re-raise the same exception using `raise`:
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
```Python hl_lines="17"
|
||||
{!> ../../../docs_src/dependencies/tutorial008d_an_py39.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!> ../../../docs_src/dependencies/tutorial008d_an.py!}
|
||||
```
|
||||
|
||||
|
||||
=== "Python 3.8+ non-Annotated"
|
||||
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="15"
|
||||
{!> ../../../docs_src/dependencies/tutorial008d.py!}
|
||||
```
|
||||
|
||||
Now the client will get the same *HTTP 500 Internal Server Error* response, but the server will have our custom `InternalError` in the logs. 😎
|
||||
|
||||
## Execution of dependencies with `yield`
|
||||
|
||||
The sequence of execution is more or less like this diagram. Time flows from top to bottom. And each column is one of the parts interacting or executing code.
|
||||
|
|
@ -187,7 +244,6 @@ participant tasks as Background tasks
|
|||
operation -->> dep: Raise Exception (e.g. HTTPException)
|
||||
opt handle
|
||||
dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
|
||||
dep -->> handler: Auto forward exception
|
||||
end
|
||||
handler -->> client: HTTP error response
|
||||
end
|
||||
|
|
@ -210,15 +266,23 @@ participant tasks as Background tasks
|
|||
!!! tip
|
||||
This diagram shows `HTTPException`, but you could also raise any other exception that you catch in a dependency with `yield` or with a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
If you raise any exception, it will be passed to the dependencies with yield, including `HTTPException`, and then **again** to the exception handlers. If there's no exception handler for that exception, it will then be handled by the default internal `ServerErrorMiddleware`, returning a 500 HTTP status code, to let the client know that there was an error in the server.
|
||||
If you raise any exception, it will be passed to the dependencies with yield, including `HTTPException`. In most cases you will want to re-raise that same exception or a new one from the dependency with `yield` to make sure it's properly handled.
|
||||
|
||||
## Dependencies with `yield`, `HTTPException` and Background Tasks
|
||||
## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks
|
||||
|
||||
!!! warning
|
||||
You most probably don't need these technical details, you can skip this section and continue below.
|
||||
|
||||
These details are useful mainly if you were using a version of FastAPI prior to 0.106.0 and used resources from dependencies with `yield` in background tasks.
|
||||
|
||||
### Dependencies with `yield` and `except`, Technical Details
|
||||
|
||||
Before FastAPI 0.110.0, if you used a dependency with `yield`, and then you captured an exception with `except` in that dependency, and you didn't raise the exception again, the exception would be automatically raised/forwarded to any exception handlers or the internal server error handler.
|
||||
|
||||
This was changed in version 0.110.0 to fix unhandled memory consumption from forwarded exceptions without a handler (internal server errors), and to make it consistent with the behavior of regular Python code.
|
||||
|
||||
### Background Tasks and Dependencies with `yield`, Technical Details
|
||||
|
||||
Before FastAPI 0.106.0, raising exceptions after `yield` was not possible, the exit code in dependencies with `yield` was executed *after* the response was sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} would have already run.
|
||||
|
||||
This was designed this way mainly to allow using the same objects "yielded" by dependencies inside of background tasks, because the exit code would be executed after the background tasks were finished.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
# Sorgu Parametreleri
|
||||
|
||||
Fonksiyonda yol parametrelerinin parçası olmayan diğer tanımlamalar otomatik olarak "sorgu" parametresi olarak yorumlanır.
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
Sorgu, bağlantıdaki `?` kısmından sonra gelen ve `&` işareti ile ayrılan anahtar-değer çiftlerinin oluşturduğu bir kümedir.
|
||||
|
||||
Örneğin, aşağıdaki bağlantıda:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
...sorgu parametreleri şunlardır:
|
||||
|
||||
* `skip`: değeri `0`'dır
|
||||
* `limit`: değeri `10`'dır
|
||||
|
||||
Parametreler bağlantının bir parçası oldukları için doğal olarak string olarak değerlendirilirler.
|
||||
|
||||
Fakat, Python tipleri ile tanımlandıkları zaman (yukarıdaki örnekte `int` oldukları gibi), parametreler o tiplere dönüştürülür ve o tipler çerçevesinde doğrulanırlar.
|
||||
|
||||
Yol parametreleri için geçerli olan her türlü işlem aynı şekilde sorgu parametreleri için de geçerlidir:
|
||||
|
||||
* Editör desteği (şüphesiz)
|
||||
* Veri "<abbr title="HTTP isteği ile birlikte gelen string'i Python verisine dönüştürme">ayrıştırma</abbr>"
|
||||
* Veri doğrulama
|
||||
* Otomatik dokümantasyon
|
||||
|
||||
## Varsayılanlar
|
||||
|
||||
Sorgu parametreleri, adres yolunun sabit bir parçası olmadıklarından dolayı isteğe bağlı ve varsayılan değere sahip olabilirler.
|
||||
|
||||
Yukarıdaki örnekte `skip=0` ve `limit=10` varsayılan değere sahiplerdir.
|
||||
|
||||
Yani, aşağıdaki bağlantıya gitmek:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
şu adrese gitmek ile aynı etkiye sahiptir:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
Ancak, mesela şöyle bir adresi ziyaret ederseniz:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
```
|
||||
|
||||
Fonksiyonunuzdaki parametre değerleri aşağıdaki gibi olacaktır:
|
||||
|
||||
* `skip=20`: çünkü bağlantıda böyle tanımlandı.
|
||||
* `limit=10`: çünkü varsayılan değer buydu.
|
||||
|
||||
## İsteğe Bağlı Parametreler
|
||||
|
||||
Aynı şekilde, varsayılan değerlerini `None` olarak atayarak isteğe bağlı parametreler tanımlayabilirsiniz:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!> ../../../docs_src/query_params/tutorial002_py310.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!> ../../../docs_src/query_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
Bu durumda, `q` fonksiyon parametresi isteğe bağlı olacak ve varsayılan değer olarak `None` alacaktır.
|
||||
|
||||
!!! check "Ek bilgi"
|
||||
Ayrıca, dikkatinizi çekerim ki; **FastAPI**, `item_id` parametresinin bir yol parametresi olduğunu ve `q` parametresinin yol değil bir sorgu parametresi olduğunu fark edecek kadar beceriklidir.
|
||||
|
||||
## Sorgu Parametresi Tip Dönüşümü
|
||||
|
||||
Aşağıda görüldüğü gibi dönüştürülmek üzere `bool` tipleri de tanımlayabilirsiniz:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!> ../../../docs_src/query_params/tutorial003_py310.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!> ../../../docs_src/query_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
Bu durumda, eğer şu adrese giderseniz:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=1
|
||||
```
|
||||
|
||||
veya
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=True
|
||||
```
|
||||
|
||||
veya
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=true
|
||||
```
|
||||
|
||||
veya
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=on
|
||||
```
|
||||
|
||||
veya
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=yes
|
||||
```
|
||||
|
||||
veya adres, herhangi farklı bir harf varyasyonu içermesi durumuna rağmen (büyük harf, sadece baş harfi büyük kelime, vb.) fonksiyonunuz, `bool` tipli `short` parametresini `True` olarak algılayacaktır. Aksi halde `False` olarak algılanacaktır.
|
||||
|
||||
|
||||
## Çoklu Yol ve Sorgu Parametreleri
|
||||
|
||||
**FastAPI** neyin ne olduğunu ayırt edebileceğinden dolayı aynı anda birden fazla yol ve sorgu parametresi tanımlayabilirsiniz.
|
||||
|
||||
Ve parametreleri, herhangi bir sıraya koymanıza da gerek yoktur.
|
||||
|
||||
İsimlerine göre belirleneceklerdir:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
```Python hl_lines="6 8"
|
||||
{!> ../../../docs_src/query_params/tutorial004_py310.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="8 10"
|
||||
{!> ../../../docs_src/query_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
## Zorunlu Sorgu Parametreleri
|
||||
|
||||
Türü yol olmayan bir parametre (şu ana kadar sadece sorgu parametrelerini gördük) için varsayılan değer tanımlarsanız o parametre zorunlu olmayacaktır.
|
||||
|
||||
Parametre için belirli bir değer atamak istemeyip parametrenin sadece isteğe bağlı olmasını istiyorsanız değerini `None` olarak atayabilirsiniz.
|
||||
|
||||
Fakat, bir sorgu parametresini zorunlu yapmak istiyorsanız varsayılan bir değer atamamanız yeterli olacaktır:
|
||||
|
||||
```Python hl_lines="6-7"
|
||||
{!../../../docs_src/query_params/tutorial005.py!}
|
||||
```
|
||||
|
||||
Burada `needy` parametresi `str` tipinden oluşan zorunlu bir sorgu parametresidir.
|
||||
|
||||
Eğer tarayıcınızda şu bağlantıyı:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
```
|
||||
|
||||
...`needy` parametresini eklemeden açarsanız şuna benzer bir hata ile karşılaşırsınız:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "missing",
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "Field required",
|
||||
"input": null,
|
||||
"url": "https://errors.pydantic.dev/2.1/v/missing"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`needy` zorunlu bir parametre olduğundan dolayı bağlantıda tanımlanması gerekir:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
```
|
||||
|
||||
...bu iş görür:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item_id": "foo-item",
|
||||
"needy": "sooooneedy"
|
||||
}
|
||||
```
|
||||
|
||||
Ve elbette, bazı parametreleri zorunlu, bazılarını varsayılan değerli ve bazılarını tamamen opsiyonel olarak tanımlayabilirsiniz:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!> ../../../docs_src/query_params/tutorial006_py310.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../../docs_src/query_params/tutorial006.py!}
|
||||
```
|
||||
|
||||
Bu durumda, 3 tane sorgu parametresi var olacaktır:
|
||||
|
||||
* `needy`, zorunlu bir `str`.
|
||||
* `skip`, varsayılan değeri `0` olan bir `int`.
|
||||
* `limit`, isteğe bağlı bir `int`.
|
||||
|
||||
!!! tip "İpucu"
|
||||
Ayrıca, [Yol Parametrelerinde](path-params.md#predefined-values){.internal-link target=_blank} de kullanıldığı şekilde `Enum` sınıfından faydalanabilirsiniz.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("Oops, we didn't raise again, Britney 😱")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: str = Depends(get_username)):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("Oops, we didn't raise again, Britney 😱")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("Oops, we didn't raise again, Britney 😱")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("We don't swallow the internal error here, we raise again 😎")
|
||||
raise
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: str = Depends(get_username)):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("We don't swallow the internal error here, we raise again 😎")
|
||||
raise
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except InternalError:
|
||||
print("We don't swallow the internal error here, we raise again 😎")
|
||||
raise
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id == "portal-gun":
|
||||
raise InternalError(
|
||||
f"The portal gun is too dangerous to be owned by {username}"
|
||||
)
|
||||
if item_id != "plumbus":
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Item not found, there's only a plumbus here"
|
||||
)
|
||||
return item_id
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.109.2"
|
||||
__version__ = "0.110.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
|
|
|||
|
|
@ -216,19 +216,14 @@ def get_request_handler(
|
|||
actual_response_class = response_class
|
||||
|
||||
async def app(request: Request) -> Response:
|
||||
exception_to_reraise: Optional[Exception] = None
|
||||
response: Union[Response, None] = None
|
||||
async with AsyncExitStack() as async_exit_stack:
|
||||
# TODO: remove this scope later, after a few releases
|
||||
# This scope fastapi_astack is no longer used by FastAPI, kept for
|
||||
# compatibility, just in case
|
||||
request.scope["fastapi_astack"] = async_exit_stack
|
||||
async with AsyncExitStack() as file_stack:
|
||||
try:
|
||||
body: Any = None
|
||||
if body_field:
|
||||
if is_body_form:
|
||||
body = await request.form()
|
||||
async_exit_stack.push_async_callback(body.close)
|
||||
file_stack.push_async_callback(body.close)
|
||||
else:
|
||||
body_bytes = await request.body()
|
||||
if body_bytes:
|
||||
|
|
@ -260,18 +255,17 @@ def get_request_handler(
|
|||
],
|
||||
body=e.doc,
|
||||
)
|
||||
exception_to_reraise = validation_error
|
||||
raise validation_error from e
|
||||
except HTTPException as e:
|
||||
exception_to_reraise = e
|
||||
except HTTPException:
|
||||
# If a middleware raises an HTTPException, it should be raised again
|
||||
raise
|
||||
except Exception as e:
|
||||
http_error = HTTPException(
|
||||
status_code=400, detail="There was an error parsing the body"
|
||||
)
|
||||
exception_to_reraise = http_error
|
||||
raise http_error from e
|
||||
try:
|
||||
errors: List[Any] = []
|
||||
async with AsyncExitStack() as async_exit_stack:
|
||||
solved_result = await solve_dependencies(
|
||||
request=request,
|
||||
dependant=dependant,
|
||||
|
|
@ -280,59 +274,53 @@ def get_request_handler(
|
|||
async_exit_stack=async_exit_stack,
|
||||
)
|
||||
values, errors, background_tasks, sub_response, _ = solved_result
|
||||
except Exception as e:
|
||||
exception_to_reraise = e
|
||||
raise e
|
||||
if not errors:
|
||||
raw_response = await run_endpoint_function(
|
||||
dependant=dependant, values=values, is_coroutine=is_coroutine
|
||||
)
|
||||
if isinstance(raw_response, Response):
|
||||
if raw_response.background is None:
|
||||
raw_response.background = background_tasks
|
||||
response = raw_response
|
||||
else:
|
||||
response_args: Dict[str, Any] = {"background": background_tasks}
|
||||
# If status_code was set, use it, otherwise use the default from the
|
||||
# response class, in the case of redirect it's 307
|
||||
current_status_code = (
|
||||
status_code if status_code else sub_response.status_code
|
||||
)
|
||||
if current_status_code is not None:
|
||||
response_args["status_code"] = current_status_code
|
||||
if sub_response.status_code:
|
||||
response_args["status_code"] = sub_response.status_code
|
||||
content = await serialize_response(
|
||||
field=response_field,
|
||||
response_content=raw_response,
|
||||
include=response_model_include,
|
||||
exclude=response_model_exclude,
|
||||
by_alias=response_model_by_alias,
|
||||
exclude_unset=response_model_exclude_unset,
|
||||
exclude_defaults=response_model_exclude_defaults,
|
||||
exclude_none=response_model_exclude_none,
|
||||
is_coroutine=is_coroutine,
|
||||
)
|
||||
response = actual_response_class(content, **response_args)
|
||||
if not is_body_allowed_for_status_code(response.status_code):
|
||||
response.body = b""
|
||||
response.headers.raw.extend(sub_response.headers.raw)
|
||||
if errors:
|
||||
validation_error = RequestValidationError(
|
||||
_normalize_errors(errors), body=body
|
||||
)
|
||||
exception_to_reraise = validation_error
|
||||
raise validation_error
|
||||
else:
|
||||
try:
|
||||
raw_response = await run_endpoint_function(
|
||||
dependant=dependant, values=values, is_coroutine=is_coroutine
|
||||
)
|
||||
except Exception as e:
|
||||
exception_to_reraise = e
|
||||
raise e
|
||||
if isinstance(raw_response, Response):
|
||||
if raw_response.background is None:
|
||||
raw_response.background = background_tasks
|
||||
response = raw_response
|
||||
else:
|
||||
response_args: Dict[str, Any] = {"background": background_tasks}
|
||||
# If status_code was set, use it, otherwise use the default from the
|
||||
# response class, in the case of redirect it's 307
|
||||
current_status_code = (
|
||||
status_code if status_code else sub_response.status_code
|
||||
)
|
||||
if current_status_code is not None:
|
||||
response_args["status_code"] = current_status_code
|
||||
if sub_response.status_code:
|
||||
response_args["status_code"] = sub_response.status_code
|
||||
content = await serialize_response(
|
||||
field=response_field,
|
||||
response_content=raw_response,
|
||||
include=response_model_include,
|
||||
exclude=response_model_exclude,
|
||||
by_alias=response_model_by_alias,
|
||||
exclude_unset=response_model_exclude_unset,
|
||||
exclude_defaults=response_model_exclude_defaults,
|
||||
exclude_none=response_model_exclude_none,
|
||||
is_coroutine=is_coroutine,
|
||||
)
|
||||
response = actual_response_class(content, **response_args)
|
||||
if not is_body_allowed_for_status_code(response.status_code):
|
||||
response.body = b""
|
||||
response.headers.raw.extend(sub_response.headers.raw)
|
||||
# This exception was possibly handled by the dependency but it should
|
||||
# still bubble up so that the ServerErrorMiddleware can return a 500
|
||||
# or the ExceptionMiddleware can catch and handle any other exceptions
|
||||
if exception_to_reraise:
|
||||
raise exception_to_reraise
|
||||
assert response is not None, "An error occurred while generating the request"
|
||||
if response is None:
|
||||
raise FastAPIError(
|
||||
"No response object was returned. There's a high chance that the "
|
||||
"application code is raising an exception and a dependency with yield "
|
||||
"has a block with a bare except, or a block with except Exception, "
|
||||
"and is not raising the exception again. Read more about it in the "
|
||||
"docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
|
||||
)
|
||||
return response
|
||||
|
||||
return app
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)):
|
|||
yield state["/async_raise"]
|
||||
except AsyncDependencyError:
|
||||
errors.append("/async_raise")
|
||||
raise
|
||||
finally:
|
||||
state["/async_raise"] = "asyncgen raise finalized"
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ def generator_state_try(state: Dict[str, str] = Depends(get_state)):
|
|||
yield state["/sync_raise"]
|
||||
except SyncDependencyError:
|
||||
errors.append("/sync_raise")
|
||||
raise
|
||||
finally:
|
||||
state["/sync_raise"] = "generator raise finalized"
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ async def get_database():
|
|||
fake_database.update(temp_database)
|
||||
except HTTPException:
|
||||
state["except"] = True
|
||||
raise
|
||||
finally:
|
||||
state["finally"] = True
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,33 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.dependencies.tutorial008b_an import app
|
||||
|
||||
client = TestClient(app)
|
||||
from ...utils import needs_py39
|
||||
|
||||
|
||||
def test_get_no_item():
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008b_an_py39 import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found"}
|
||||
|
||||
|
||||
def test_owner_error():
|
||||
@needs_py39
|
||||
def test_owner_error(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 400, response.text
|
||||
assert response.json() == {"detail": "Owner error: Rick"}
|
||||
|
||||
|
||||
def test_get_item():
|
||||
@needs_py39
|
||||
def test_get_item(client: TestClient):
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"description": "Gun to create portals", "owner": "Rick"}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import pytest
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008c import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
def test_fastapi_error(client: TestClient):
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert "No response object was returned" in exc_info.value.args[0]
|
||||
|
||||
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008c import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import pytest
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008c_an import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
def test_fastapi_error(client: TestClient):
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert "No response object was returned" in exc_info.value.args[0]
|
||||
|
||||
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008c_an import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import pytest
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008c_an_py39 import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_fastapi_error(client: TestClient):
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert "No response object was returned" in exc_info.value.args[0]
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008c_an_py39 import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008d import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
def test_internal_error(client: TestClient):
|
||||
from docs_src.dependencies.tutorial008d import InternalError
|
||||
|
||||
with pytest.raises(InternalError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert (
|
||||
exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
|
||||
)
|
||||
|
||||
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008d import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008d_an import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
def test_internal_error(client: TestClient):
|
||||
from docs_src.dependencies.tutorial008d_an import InternalError
|
||||
|
||||
with pytest.raises(InternalError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert (
|
||||
exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
|
||||
)
|
||||
|
||||
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008d_an import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.dependencies.tutorial008d_an_py39 import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_get_no_item(client: TestClient):
|
||||
response = client.get("/items/foo")
|
||||
assert response.status_code == 404, response.text
|
||||
assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_get(client: TestClient):
|
||||
response = client.get("/items/plumbus")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "plumbus"
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_internal_error(client: TestClient):
|
||||
from docs_src.dependencies.tutorial008d_an_py39 import InternalError
|
||||
|
||||
with pytest.raises(InternalError) as exc_info:
|
||||
client.get("/items/portal-gun")
|
||||
assert (
|
||||
exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
|
||||
)
|
||||
|
||||
|
||||
@needs_py39
|
||||
def test_internal_server_error():
|
||||
from docs_src.dependencies.tutorial008d_an_py39 import app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
response = client.get("/items/portal-gun")
|
||||
assert response.status_code == 500, response.text
|
||||
assert response.text == "Internal Server Error"
|
||||
Loading…
Reference in New Issue