Dynamic Reference Data in NestJS
Implement a Future-Proof Solution for Your Reference Data Needs
In most API applications, providing reference data is a common need and best practices. The provision of reference data ensures we use consistent values across our application. These data include countries, product categories, or any other categorized information needed by our application.
A common approach for implementing a reference data API endpoint involves using a switch case within a single service to handle different data types. However, it can quickly become cumbersome and inflexible as the application grows.
I will explore building a dynamic and maintainable reference data endpoint in NestJS in the article.
The Switch Case Dilemma
Let’s imagine a scenario where a switch case is used within our ReferenceDataService to handle different data types. Here’s a simplified example:
1 | // app.controller.ts |
While this works for a few data types, it becomes messy and less maintainable as more types are added. Here are the two main issues:
- Code Clutter: With each new data type, we need to inject a new service into the constructor and add a corresponding case in the switch statement within getReferenceData. This leads to a bloated constructor and cluttered logic, making the code harder to read and maintain.
- Tight Coupling: The service becomes tightly coupled to the specific concrete services (CountryService, IndustryService). If we introduce new data types with different service implementations, we’d need to modify the ReferenceDataService constructor and switch-case statements, making the code harder to read and reason about.
Improved reference data service with ModuleRef and Token Providers
A more scalable and flexible approach is to leverage NestJS’s dependency injection capabilities and dynamic service retrieval. Here’s how we can achieve this:
Interface and Concrete Services
Firstly, we define an interface for our reference data service.
1 | export interface ReferenceDataService<T extends ReferenceDataItem> { |
We can implement the concert services based on the ReferenceDataService interface whenever a new data type is introduced.
Register the concert services with token providers
In NestJS, we can define token providers to identify services dynamically. Here, we define two constants for token identifiers (COUNTRY_DATA_TOKEN
and INDUSTRY_DATA_TOKEN
), and register a token for each concrete service:
1 | const COUNTRY_DATA_TOKEN = 'country'; |
By registering services with specific tokens, we decouple the service implementation from its usage.
Reference Data Service Refactoring
Now, we can refactor our ReferenceDataService to retrieve the specific service based on the requested data type as below.
1 | () |
In the above code, we inject ModuleRef into the service constructor. Then we use moduleRef.get with the retrieved token to dynamically get the corresponding service instance, and the instance is used to fetch the actual data.
By utilizing ModuleRef and token providers to dynamically retrieve a specific reference data service instance, we eliminate the need for individual service injection in the constructor and the switch case. When introducing a new data type, we don’t need to change the ReferenceDataFactory service!
Consuming the Service:
Now, in our controller, we can inject the ReferenceDataFactory and dynamically retrieve the desired data:
1 | ':dataType') ( |
This approach is much easier to maintain, allowing us to handle new data types as our application evolves.
Although NestJS is used in this article, the same pattern applies to other programming languages and frameworks. I will write a new post to provide a similar implementation using .Net later. You can find the source code in the post here .
I hope you find this post useful. Happy programming!
- Title: Dynamic Reference Data in NestJS
- Author: Sunny Sun
- Created at : 2024-07-04 00:00:00
- Updated at : 2024-07-15 19:23:28
- Link: http://coffeethinkcode.com/2024/07/04/dynamic-referencedata/
- License: This work is licensed under CC BY-NC-SA 4.0.