Using the Repository Pattern for better data access encapsulation (in Python)

preview_player
ะŸะพะบะฐะทะฐั‚ัŒ ะพะฟะธัะฐะฝะธะต

This tutorial explains
๐Ÿ‘‰ What the Repository Pattern is
๐Ÿ‘‰ When to use the Repository Pattern
๐Ÿ‘‰ How to implement the Repository Pattern

You'll learn to use the Repository Pattern by refactoring an application in which the data access layer is tightly coupled with the API layer. To keep things simple, we use a SQLite database for demonstration, but the same strategies can be applied with any other database engine.

The starter code is an API built with FastAPI and it uses SQLAlchemy to manage interactions with the database. The video doesn't explain how FastAPI and SQLAlchemy work, so if you need a ๐ซ๐ž๐Ÿ๐ซ๐ž๐ฌ๐ก๐ž๐ซ, check out the following videos:

๐Ÿšจ๐–๐€๐‘๐๐ˆ๐๐†๐Ÿšจ The content in this tutorial is fairly ๐š๐๐ฏ๐š๐ง๐œ๐ž๐. If you're a ๐›๐ž๐ ๐ข๐ง๐ง๐ž๐ซ developer, you can still benefit from watching this video, but don't get frustrated if not everything makes sense. I highly recommend you ๐ฉ๐ซ๐š๐œ๐ญ๐ข๐œ๐ž along with the code, and try out all the commands I run in the terminal. If you encounter any issues with the code or something doesn't make sense, feel free to ping me or feel free to raise an issue in the GitHub repo for this video. My contact details are at the bottom of this description.

๐Ÿ’ก๐ƒ๐ข๐ฌ๐œ๐ฅ๐จ๐ฌ๐ฎ๐ซ๐ž๐Ÿ’ก The implementation of the Repository Pattern shown in this video is fairly standard. The idea of the repositories registry is my opinionated. You don't need to use both patterns together. The strategy used to make dependencies injectable is also opinionated, and you may be able to use alternative dependency injection strategies. These are the strategies and patterns that I generally use with my clients.

Chapters:
0:00 Introduction
0:29 Startup code and clone and checkout
1:22 Presenting the startup code, API and db models
3:00 How the API is tightly coupled to the data layer and why tight coupling is bad
4:32 How repository helps avoid tight coupling with the data layer and what are the benefits
6:50 How do you implement the repository pattern?
8:45 Implementing the bookings repository
10:22 Moving database logic from the API layer to the repository
11:41 Using the repository in the API layer
12:50 Setting up the environment, installing the dependencies
13:30 Running the database migrations
13:54 Running the server and testing the changes using the Swagger UI
15:07 Introducing the test suite and running it
16:12 Making SQLAlchemy's session maker an injectable dependency
18:15 Testing the changes
18:41 Updating the test suite to inject SQLAlchemy's session maker
19:32 Mocking SQLAlchemy's session maker
20:06 Adding a bookings business object
25:07 Returning business objects from the repository
27:12 Testing the changes
27:50 Injecting the repositories into the FastAPI app using a registry
30:58 Injecting a dummy repository in the test and running the test suite
33:19 Wrapping up (show images of the books here)

๐–๐ก๐š๐ญ ๐ข๐ฌ ๐ญ๐ก๐ž ๐‘๐ž๐ฉ๐จ๐ฌ๐ข๐ญ๐จ๐ซ๐ฒ ๐๐š๐ญ๐ญ๐ž๐ซ๐ง?
Repository is ๐๐š๐ญ๐š ๐š๐œ๐œ๐ž๐ฌ๐ฌ ๐š๐›๐ฌ๐ญ๐ซ๐š๐œ๐ญ๐ข๐จ๐ง pattern. It helps you build a bridge between your business layer and your data access layer. Typically, Repository offers an in-memory list or ๐œ๐จ๐ฅ๐ฅ๐ž๐œ๐ญ๐ข๐จ๐ง-like interface to your data. It ๐ž๐ง๐œ๐š๐ฉ๐ฌ๐ฎ๐ฅ๐š๐ญ๐ž๐ฌ the implementation details of your data management system, hence ๐๐ž๐œ๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐  your business layer from your databases. By using a repository, saving or deleting data from your database looks like adding or removing elements from a list. Using the Repository pattern makes it easier to maintain, test, and debug all the layers of your application in isolation from the database layer.

If you have any ๐ช๐ฎ๐ž๐ฌ๐ญ๐ข๐จ๐ง๐ฌ, or if you just would like to ๐œ๐จ๐ง๐ง๐ž๐œ๐ญ with me, feel free to reach out to me in any of the following platforms:
ะ ะตะบะพะผะตะฝะดะฐั†ะธะธ ะฟะพ ั‚ะตะผะต
ะšะพะผะผะตะฝั‚ะฐั€ะธะธ
ะะฒั‚ะพั€

This was super-helpful for me Josรฉ, thank you so much! This is by far the best video on YouTube for repository pattern in Python. I've know the abstract pattern for some time but struggled to interpret it into a Python context. This totally did the trick for me, thanks again so much!

stevecanny
ะะฒั‚ะพั€

great and comprehensive video, thanks!

kevon
ะะฒั‚ะพั€

Great video, very well explained, thanks!! ๐Ÿ˜€

benmolina
ะะฒั‚ะพั€

Ok, this looks good for CRUD. What about beyond CRUD? How do we do joins with this repo pattern? Or a simple subquery? How can we group queries into one instead of hitting the DB several times?

I mean at least you're still tightly coupled to SQLAlchemy and you're returning the sqlalchemy instances as is. I've seen some repo patterns where people serialized those into intermediate objects, creating even bigger problems down the line cause of the need to re-fetch that sqlalchemy object in different functions.

I feel like everyone goes for repository patterns for simple projects which ends up creating way more problems than it solves.

Also, I love the repository registry idea, but am not loving the fact that it's injected into the request object. I think it would we way cleaner as a dependency!๐Ÿ˜

RamiAwar
ะะฒั‚ะพั€

Hola Jose, thank you for your video. As a .NET developer currently working with Python, I feel uneasy when I see global dependencies, loosely typed parameters... I find your more professional demos to be particularly useful.

Have a question: could you explain the purpose of the RepositoriesRegistry? I'm wondering if it would be possible to simply pass the BookingsRepository as a parameter instead of creating a RepositoriesRegistry. What is the benefit of using RepositoriesRegistry in this context?

RicardoGarciaM
ะะฒั‚ะพั€

What if I wanted to save a booking to the DB & also the filesystem, it seems because you bind the repo inside of the api route theres no choice to change it or have multiple?

yslx
ะะฒั‚ะพั€

Is this approach for putting a session object into an app going to work for an async session? I was struggling to make this work but without luck.

szymonf
ะะฒั‚ะพั€

Really good video. I'm starting to learn about FastAPI. One question I have about your design is related to the dependency injection.
Why are you injecting the dependency as part of the "app" object (create_server method) instead of adding them to the dependencies list offered when creating a new "FastAPI" and then using them somehow in the routes of the controller?
Shouldn't the Repository be added only at the Router level for Bookings instead of at the level of the entire application?

Let me know.

lucasalvarezlacasa
ะะฒั‚ะพั€

what is the difference between a repository pattern and DAO ? When to use each ?

whu.
ะะฒั‚ะพั€

Why do you call _id a class property instead of a private property?

giorgioripani
ะะฒั‚ะพั€

Your repository looks like a simple DAO to me. There is like a one-to-one mapping between your (domain) model and the database. A repository can achieve more complex things and more custom mappings between the domain objects and the database. In particular, if the Aggregate Root has multiple Value Objects, the repository is responsible for creating or removing these VOs (and for hiding this complexity). Thanks for the video.

angely
ะะฒั‚ะพั€

Itโ€™s not repository pattern, itโ€™s trash, gl

jcatstreams