sqlmodel/docs/tutorial/fastapi/session-with-dependency.md
Sebastián Ramírez 6d1d86ab85 📝 Add docs
2021-08-24 15:02:48 +02:00

6.8 KiB

Session with FastAPI Dependency

Before we keep adding things, let's change a bit how we get the session for each request to simplify our life later.

Current Sessions

Up to now, we have been creating a session in each path operation, in a with block.

# Code above omitted 👆

{!./docs_src/tutorial/fastapi/delete/tutorial001.py[ln:50-57]!}

# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/fastapi/delete/tutorial001.py!}

That's perfectly fine, but in many use cases we would want to use FastAPI Dependencies, for example to verify that the client is logged in and get the current user before executing any other code in the path operation.

These dependencies are also very useful during testing, because we can easily replace them, and then, for example, use a new database for our tests, or put some data before the tests, etc.

So, let's refactor these sessions to use FastAPI Dependencies.

Create a FastAPI Dependency

A FastAPI dependency is very simple, it's just a function that returns a value.

It could use yield instead of return, and in that case FastAPI will make sure it executes all the code after the yield, once it is done with the request.

# Code above omitted 👆

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:42-44]!}

# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}

Use the Dependency

Now let's make FastAPI execute a dependency and get its value in the path operation.

We import Depends() from fastapi. Then we use it in the path operation function in a parameter, the same way we declared parameters to get JSON bodies, path parameters, etc.

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:42-44]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-61]!}

# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}

!!! tip Here's a tip about that *, thing in the parameters.

Here we are passing the parameter `session` that has a "default value" of `Depends(get_session)` before the parameter `hero`, that doesn't have any default value.

Python would normally complain about that, but we can use the initial "parameter" `*,` to mark all the rest of the parameters as "keyword only", which solves the problem.

You can read more about it in the FastAPI documentation <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#order-the-parameters-as-you-need-tricks" class="external-link" target="_blank">Path Parameters and Numeric Validations - Order the parameters as you need, tricks</a>

The value of a dependency will only be used for one request, FastAPI will call it right before calling your code, and will give you the value from that dependency.

If it had yield, then it will continue the rest of the execution once you are done sending the response. In the case of the session, it will finish the cleanup code from the with block, closing the session, etc.

Then FastAPI will call it again for the next request.

Because it is called once per request, we will still get a single session per request as we should, so we are still fine with that.

And because dependencies can use yield, FastAPI will make sure to run the code after the yield once it is done, including all the cleanup code at the end of the with block. So we are also fine with that.

The with Block

This means that in the main code of the path operation function, it will work equivalently to the previous version with the explicit with block.

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:42-44]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-61]!}

# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}

In fact, you could think that all that block of code inside of the create_hero() function is still inside a with block for the session, because this is more or less what's happening behind the scenes.

But now, the with block is not explicitly in the function, but in the dependency above:

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:42-44]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-61]!}

# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}

We will see how this is very useful when testing the code later.

Update the Path Operations to Use the Dependency

Now we can update the rest of the path operations to use the new dependency.

We just declare the dependency in the parameters of the function, with:

session: Session = Depends(get_session)

And then we remove the previous with block with the old session.

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:42-44]!}

# Code here omitted 👈

{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-107]!}
👀 Full file preview
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}

Recap

You just learned how to use FastAPI dependencies to handle the database session. This will come in handy later when testing the code.

And you will see how much these dependencies can help the more you work with FastAPI, to handle permissions, authentication, resources like database sessions, etc. 🚀

If you want to learn more about dependencies, checkout the FastAPI docs about Dependencies.