mirror of https://github.com/tiangolo/fastapi.git
✨ Add mermaid.js support in Markdown fenced blocks for diagrams (#985)
This commit is contained in:
parent
26c345b766
commit
25e94d6344
|
|
@ -102,6 +102,74 @@ You can have any combinations of dependencies that you want.
|
|||
|
||||
**FastAPI** uses them internally to achieve this.
|
||||
|
||||
## Dependencies with `yield` and `HTTPException`
|
||||
|
||||
You saw that you can use dependencies with `yield` and have `try` blocks that catch exceptions.
|
||||
|
||||
It might be tempting to raise an `HTTPException` or similar in the exit code, after the `yield`. But **it won't work**.
|
||||
|
||||
The exit code in dependencies with `yield` is executed *after* [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. There's nothing catching exceptions thrown by your dependencies in the exit code (after the `yield`).
|
||||
|
||||
So, if you raise an `HTTPException` after the `yield`, the default (or any custom) exception handler that catches `HTTPException`s and returns an HTTP 400 response won't be there to catch that exception anymore.
|
||||
|
||||
This is what allows anything set in the dependency (e.g. a DB session) to, for example, be used by background tasks.
|
||||
|
||||
Background tasks are run *after* the response has been sent. So there's no way to raise an `HTTPException` because there's not even a way to change the response that is *already sent*.
|
||||
|
||||
But if a background task creates a DB error, at least you can rollback or cleanly close the session in the dependency with `yield`, and maybe log the error or report it to a remote tracking system.
|
||||
|
||||
If you have some code that you know could raise an exception, do the most normal/"Pythonic" thing and add a `try` block in that section of the code.
|
||||
|
||||
If you have custom exceptions that you would like to handle *before* returning the response and possibly modifying the response, maybe even raising an `HTTPException`, create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
!!! tip
|
||||
You can still raise exceptions including `HTTPException` *before* the `yield`. But not after.
|
||||
|
||||
The sequence of execution is more or less like this:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant handler as Exception handler
|
||||
participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,tasks: Can raise exception for dependency, handled after response is sent
|
||||
Note over client,operation: Can raise HTTPException and can change the response
|
||||
client ->> dep: Start request
|
||||
Note over dep: Code up to yield
|
||||
opt raise
|
||||
dep -->> handler: Raise HTTPException
|
||||
handler -->> client: HTTP error response
|
||||
dep -->> dep: Raise other exception
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> handler: Raise HTTPException
|
||||
handler -->> client: HTTP error response
|
||||
operation -->> dep: Raise other exception
|
||||
end
|
||||
operation ->> client: Return response to client
|
||||
Note over client,operation: Response is already sent, can't change it anymore
|
||||
opt Tasks
|
||||
operation -->> tasks: Send background tasks
|
||||
end
|
||||
opt Raise other exception
|
||||
tasks -->> dep: Raise other exception
|
||||
end
|
||||
Note over dep: After yield
|
||||
opt Handle other exception
|
||||
dep -->> dep: Handle exception, can't change response. E.g. close DB session.
|
||||
end
|
||||
```
|
||||
|
||||
!!! tip
|
||||
This diagram shows `HTTPException`, but you could also raise any other exception that you create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} for. And that exception would be handled by that custom exception handler instead of the dependency exit code.
|
||||
|
||||
But if you raise an exception that is not handled by the exception handlers, it will be handled by the exit code of the dependency.
|
||||
|
||||
## Context Managers
|
||||
|
||||
### What are "Context Managers"
|
||||
|
|
|
|||
|
|
@ -82,6 +82,19 @@ Whenever a new request arrives, **FastAPI** will take care of:
|
|||
* Get the result from your function.
|
||||
* Assign that result to the parameter in your *path operation function*.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
common_parameters(["common_parameters"])
|
||||
read_items["/items/"]
|
||||
read_users["/users/"]
|
||||
|
||||
common_parameters --> read_items
|
||||
common_parameters --> read_users
|
||||
```
|
||||
|
||||
This way you write shared code once and **FastAPI** takes care of calling it for your *path operations*.
|
||||
|
||||
!!! check
|
||||
Notice that you don't have to create a special class and pass it somewhere to **FastAPI** to "register" it or anything similar.
|
||||
|
||||
|
|
@ -154,7 +167,39 @@ Although the hierarchical dependency injection system is very simple to define a
|
|||
|
||||
You can define dependencies that in turn can define dependencies themselves.
|
||||
|
||||
In the end, a hierarchical tree of dependencies is built, and the **Dependency Injection** system takes care of solving all these dependencies for you (and your dependencies) and providing (injecting) the results at each step.
|
||||
In the end, a hierarchical tree of dependencies is built, and the **Dependency Injection** system takes care of solving all these dependencies for you (and their sub-dependencies) and providing (injecting) the results at each step.
|
||||
|
||||
For example, let's say you have 4 API endpoints (*path operations*):
|
||||
|
||||
* `/items/public/`
|
||||
* `/items/private/`
|
||||
* `/users/{user_id}/activate`
|
||||
* `/items/pro/`
|
||||
|
||||
then you could add different permission requirements for each of them just with dependencies and sub-dependencies:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
current_user(["current_user"])
|
||||
active_user(["active_user"])
|
||||
admin_user(["admin_user"])
|
||||
paying_user(["paying_user"])
|
||||
|
||||
public["/items/public/"]
|
||||
private["/items/private/"]
|
||||
activate_user["/users/{user_id}/activate"]
|
||||
pro_items["/items/pro/"]
|
||||
|
||||
current_user --> active_user
|
||||
active_user --> admin_user
|
||||
active_user --> paying_user
|
||||
|
||||
current_user --> public
|
||||
active_user --> private
|
||||
admin_user --> activate_user
|
||||
paying_user --> pro_items
|
||||
```
|
||||
|
||||
## Integrated with **OpenAPI**
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,17 @@ Then we can use the dependency with:
|
|||
|
||||
But **FastAPI** will know that it has to solve `query_extractor` first, to pass the results of that to `query_or_cookie_extractor` while calling it.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
|
||||
query_extractor(["query_extractor"])
|
||||
query_or_cookie_extractor(["query_or_cookie_extractor"])
|
||||
|
||||
read_query["/items/"]
|
||||
|
||||
query_extractor --> query_or_cookie_extractor --> read_query
|
||||
```
|
||||
|
||||
## Using the same dependency multiple times
|
||||
|
||||
If one of your dependencies is declared multiple times for the same *path operation*, for example, multiple dependencies have a common sub-dependency, **FastAPI** will know to call that sub-dependency only once per request.
|
||||
|
|
|
|||
|
|
@ -469,6 +469,8 @@ Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in
|
|||
|
||||
This way we make sure the database session is always closed after the request. Even if there was an exception while processing the request.
|
||||
|
||||
But you can't raise another exception from the exit code (after `yield`). See more in [Dependencies with `yield` and `HTTPException`](./dependencies/dependencies-with-yield.md#dependencies-with-yield-and-httpexception){.internal-link target=_blank}
|
||||
|
||||
And then, when using the dependency in a *path operation function*, we declare it with the type `Session` we imported directly from SQLAlchemy.
|
||||
|
||||
This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`:
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ markdown_extensions:
|
|||
- admonition
|
||||
- codehilite
|
||||
- extra
|
||||
- pymdownx.superfences:
|
||||
custom_fences:
|
||||
- name: mermaid
|
||||
class: mermaid
|
||||
format: !!python/name:pymdownx.superfences.fence_div_format
|
||||
|
||||
extra:
|
||||
social:
|
||||
|
|
@ -137,4 +142,5 @@ extra_css:
|
|||
- 'css/custom.css'
|
||||
|
||||
extra_javascript:
|
||||
- 'https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js'
|
||||
- 'js/custom.js'
|
||||
|
|
|
|||
Loading…
Reference in New Issue