If you work with Node.js/Javascript and you have many replicated codes for different data models or create CRUDs (Create, Read, Update and Delete) at all times, then this post is for you!
Working with Javascript applications, we have some problems to share similar code between the application, and in many times we create the same code for different applications. That pattern gives to you a power to write an abstraction of data, when we have one abstract class (or many classes) and reuse the implementations independent of your Data Model, passing only your types to someone classes.
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.
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.
The same way that you have a power, you have dangerous implicit codes, an clean example for that is:
Thinking About
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:
One method that receives one number argument and returns your argument
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)
Same method, refactored to Generic implementation
Lets go! If you don’t understated yet, with the next section you’ll be able be to get the idea.
Requirements:
Testing your environment
After install all environment requirements, test in your terminal if it is all ok.
npm --v && node --version
Output of commands to view Node.js version and npm versions
To verify if your MongoDB is fine, run on another terminal tab, sudo mongod
MongoDB Instance Starting
Then, in another tab run mongo
to enter em your database.
Entering em MongoDB database
Then, install the global package typescript
, to compile your typescript projects. Run npm install -g typescript
Output of typescript globally package installed
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.
mkdir warriors-projectcd warriors-pŕojectnpm init -y #to init nodejs app without wizardtsc --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:
.├── entities├── package.json├── repositories│ ├── base│ └── interfaces└── tsconfig.json
Entering in 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:
Entity Classe of a Spartan
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.
IWrite Generic Interface with our manipulation methods operations
IRead Generic Interface with our read methods operations
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
Creating BaseRepository with Interfaces imported
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.
After open options and select fix all in files
Now we have a class similar to code bellow
Our code after fix all interface errors
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.
Implementation of main code of our application
You need to transpile your Typescript to Javascript files, running the tsc
command from terminal, you have now in lib
folder all javascript files
and now, you can run your application with node lib/Index.js.
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.
Entity Created to represents a Hero
Implementation of HeroRepository without specific operations
Now, we just call that repository in our Index.ts, following the complete code below.
Complete implementation
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.
https://github.com/ErickWendel/generic-repository-nodejs-typescript-articlehttps://erickwendel.com.brfb.com/page.erickwendel
http://deviq.com/repository-pattern/http://hannesdorfmann.com/android/evolution-of-the-repository-patternhttps://www.pluralsight.com/courses/domain-driven-design-fundamentalshttps://en.wikipedia.org/wiki/Open/closed_principlehttps://en.wikipedia.org/wiki/SOLID_(object-oriented_design)https://medium.com/@cramirez92/s-o-l-i-d-the-first-5-priciples-of-object-oriented-design-with-javascript-790f6ac9b9fahttps://www.typescriptlang.org/docs/handbook/generics.html
See ya 🤘