Implement data store service to fetch entity data from HTTP or file system #156
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR introduces the data store service responsible for fetching data from various stores based on the tenant's configuration.
Image 1: part of the diagram done in this PR.
The goals were to allow data to be stored in any store you'd like, plus simple extensibility for new protocols.
Image 2: data store design.
This PR doesn't solve any specific configuration per data store. For example, authentication will be likely different from repository to repository (e.g. basic auth for HTTP).
Note on key-value storage model
The simplicity of key-value storage comes with a few trade-offs:
Note on Dependency Inversion Principle (DIP)
The design of the data store service follows the DIP, making it the most hexagonal/clean architecture implementation in our codebase today.
A quick refresher on DIP: high-level modules should not depend on low-level modules. Both should depend on abstractions.
Applied to our structure, this means the core should not depend on anything outside the core. You can see an example of this in
core/repository/data-store.repository.ts
, which is just an interface, but in other places where we just need one repository the interface step is ditched.By now, you might be wondering why we don't apply this approach everywhere. The reason is simplicity. It's tedious and difficult to abstract something when you have only a single sample. More importantly, code navigation becomes challenging.
Regarding code navigation, if your services only depend on interfaces, attempting to navigate to the implementation of an interface will lead you to the interface itself—which is correct but probably not what you want. You're likely interested in the actual implementation at runtime. However, to find the actual implementation, you'll have to figure out how the runtime injects the right implementation in the abstraction.