RoyalZSoftware
Back to Blog

The Repository Pattern

Alexander Panov 2023-05-31 3 min read
The Repository Pattern

Building web software will always include some kind of database access. For this guide, it does not matter, whether the data access is done via SQL or NoSQL, Google Sheets, whatsoever. Since this post is all about the repository pattern. An often encountered set of classes and interfaces. Let me explain!

What is it used for?

  1. The repository pattern is used to encapsulate data access, so you don't have to spin up a database connection in your controllers or views.

  2. It's often built with the Adapter Pattern in mind. To the extent, that you can swap out the implementation for the database calls. Allowing you to either use a NoSQL, SQL or SQLite database.

How often will I find it?

From my experience, every backend application that talks to some sort of database is using the repository concept in some way. It may not be named that way (which it actually should be), but the concept remains the same.

What are the benefits?

How is it accomplished?

The most basic implementation just consists of one class, with five CRUD operations.

class UserRepository
  def create(model_payload); end
  def read(id); end
  def list(); end
  def update(id, model_payload); end
  def delete(id); end
end

More generic approaches introduce a superclass, to make building repositories for specific models easier and DRY (Don't repeat yourself).

Please note: We will have a repository for each of our models.

I have built a factory method for a javascript application, that looks like this.

export const StubRepositoryFor = (formDefinition, sampleData = []) => {
    const items = sampleData; 
    return {
        create: (data) => {
            const item = {id: sampleData.length + 1, ...data};
            items.push(item);
            console.log("Created ", item);
            return item;
        },
        delete: (id) => {
            const index = items.findIndex(c => c.id == id);
            items.splice(index, 1);
            return true;
        },
        update: (id, updatePayload) => {
            console.log("updating " + id + " with payload", updatePayload);
            const itemIndex = items.findIndex(c => c.id == id);
            items[itemIndex] = {
                ...items[itemIndex],
                ...updatePayload,
            };
            return {id, ...updatePayload};
        },
        list: () => {
            return items;
        },
        get: (id) => {
            return items.find(c => c.id === id);
        },
        count: () => {
            return items?.length;
        },
    }
}

With this factory, one can easily create a new repository for a model, like this:

export const UserRepository = StubRepositoryFor([{username: 'IJustDev', first_name: 'Alexander', last_name: 'Panov'}]);

You may have already noticed, that there will be one problem...

Limitations of the Repository factory/superclass

It only works for CRUD resources, which are all managed in the same way.

If you were to introduce this pattern to your front end (which is what I did), you need to make sure, that the API requests are all the same for each model. In other words, there has to be a:

for every resource (student,user, post, what-ever).

Using a serverless backend, eg. Firebase, Supabase or AppWrite, will allow you to easily do it.

Having a different backend, which does not conform to the REST standard will make this approach unusable.

Conclusion

A repository is more than just a concept on GitHub. It takes care of keeping your code clean from random database access scattered around hundreds and thousands of files.

Did you learn something new from this post? Never miss valuable knowledge about clean software development by subscribing to my free newsletter.

More articles

Building a Web Server in Go: A Beginner's Guide

Building a Web Server in Go: A Beginner's Guide

Oleksandr Vlasov 2024-11-26 3 min read
React Hooks — createContext, useContext, useMemo

React Hooks — createContext, useContext, useMemo

Oleksandr Vlasov 2024-10-23 4 min read
Mastering Git Rebase Interactive: Squashing Commits for a Clean History

Mastering Git Rebase Interactive: Squashing Commits for a Clean History

Alexander Panov 2024-10-21 2 min read