Generic Repository Pattern
Talking about the Repository pattern, it is a representation where you can keep all operations of your database (like a Create, Read, Update and Delete Operations) in one local per Business Entity, when you need to do operations with Database, don’t call directly database drivers and if you have more one database, or differently databases to one transaction, you application only calls the method of repository and is transparently for who calls.
Therefore, the Generic Repository is similar but now you have only one abstraction, one Base Class which have all common operations and your EntityRepository only extends the base class with all implementations of database operations. Following the SOLID principles, that pattern follows the Open / Closed principle, when your baseClass is open for extension, but closed for modification.
When to use a Generic Repository ?
Depends on your Business Model, and critical level of your applications. My opinion about this pattern it’s about the extensibility and enabling you to create only one class to write all common operations, such CRUDs, when all Entities of your application should have a CRUD or similar operations.
When don’t use Generic Repository ?
The same way that you have a power, you have dangerous implicit codes, an clean example for that is:
- You have two Entity Classes: People and Account.
- Users can remove People.
- Users can’t update information about Account (like add more money to account)
- If both classes extends from BaseClass, that haves update() and remove() methods, the programmer should remember of that rule and not expose remove or update methods to service, or your business case is wrong and dangerous.
Generics with Typescript
Components that are capable of working on the data of today as well as the data of tomorrow will give you the most flexible capabilities for building up large software systems — typescriptlang.org/docs/handbook/generics.html
Following the Typescript's documentation, generics gives the power to build flexible and generic components (or types). From their docs, we have a better example about how it works:
So, we have a concrete method, which receives one number and returns the same type. If you want pass one string to this method you need to create another method with the same implementation and repeat your code.
With the Generics Implementation, we have the aleatory word to says what is the generic implementation (for convention, uses T to say that is a generic type)
Creating a real project with Generic Repository and Node.js
Lets go! If you don’t understated yet, with the next section you’ll be able be to get the idea.
Testing your environment
After install all environment requirements, test in your terminal if it is all ok.
npm --v && node --version
To verify if your MongoDB is fine, run on another terminal tab,
Then, in another tab run
mongo to enter em your database.
Then, install the global package
typescript, to compile your typescript projects. Run
npm install -g typescript
Once you’re done with that, we are ready to move forward :D
Now, we need to create one folder and initializate a Node.js project.
npm init -y #to init nodejs app without wizard
tsc --init #to init config file to typescript
After that, should open the vscode within your project folder. To create our project, you need create some folders for better organization of our application. We are going to use the folder structure bellow:
│ ├── base
│ └── interfaces
tsconfig.json file, in the section of property
"lib":  modify the value to
"lib": [ “es2015”
], we alter that property of a json file, to work with es2015 modules, like Promises in Typescript. Alter the
outDir property to “outDir”: “lib” to generate .js files in a separated folder.
About our folders, when
entities folder is about your data models,
repositories folder is about our database operations and
interfaces our operations' contracts. Now, we should create our entities, in entities folder, create a
Spartan.ts file with the following code:
Now, on repositories/interfaces folder, we'll create two files, following the single responsability, these files will have our contracts that the abstract classes must be. Our contracts, should follow the generic pattern, that can be written without a fixed type, but, when anyone implements this interfaces, should pass the type for them.
After creating our interface, we should create the BaseClass, an abstract class that implements all generic interfaces and has our common implementation for all entities. In base folder, create a
BaseRepository.ts with following code
After you importing the interfaces you need to implements the signature of your interfaces, for that, you can press
ctrl . to show options of vscode to show options to fix problems and click in “Implements Interface IWrite<T> (Fix all in file)” to add all implementations.
Now we have a class similar to code bellow
We should now create the implementations for all methods. Our BaseRepository class, should know how is the database and collection that you can access. At this point, you need to install the mongodb driver package, for that, return to your terminal on project folder and runs
npm i -S mongodb @types/mongodb to add mongodb driver and typescript definition of package.
In constructor, we add two arguments, db and collectionName. Your class implementation should like a following code
Now, we created the Repository file to specific entity in repositories folder.
Now, to test our repository and all logic event. We need in root of project, create a
Index.ts file, that call all repositories.
tsc command from terminal, you have now in
lib folder all
To you see the power of Generic Repositories, we go to create more one repository for
Heroes with name
HeroesRepository.ts and one entity class, that represents a Hero.
Now, we just call that repository in our Index.ts, following the complete code below.
With one class, we have many implementations to use and to work more easily, for me, the Generics feature in TypeScript is one of most powerful features to work. All the code that you see here is available in the GitHub repo that you can find in the links section below, don’t forget to check it out :D
If you got up to this point, don’t forget to comment, share with your friends and leave some feedback. Please be mindful that this is my first English post so feel free to correct me with some private notes if you happen to spot any error :D
Don’t forget too, to click and claps on post.
See ya 🤘