Arch
Installation#
- npm
- Yarn
Use cases#
In archimedes we differentiate between queries and commands.
In order to have a query or command you must implement the internalExecute method and extend from the base class Query or Command. This method always returns a promise.
The responsibility of use cases is to orchestrate and call other use cases and business logic. Every action a user can perform should be represented with a use case.
important
To execute a use case you must call the execute method instead of the internalExecute.
Queries#
A query is a use case that gets information from the system (immutable). Queries can have parameters and return something.
You can specify what parameters you can pass as follows:
In case you want to pass more than one parameter you can pass it as an object:
Commands#
A command is a use case that performs an action or a side effect in the system (mutable). Commands can have parameters and should not return anything
Subscribe#
Sometimes you might want to execute some logic whenever a Query or a Command has executed:
In the subscribe callback you can receive additional information like the param used to execute the use case, the result and the executionOptions:
When you subscribe a unique id is returned. This id is used to unsubscribe.
important
Remember to unsubscribe when finished with a use case, if not you might have memory leaks!
Execution Options#
When you execute a use case you can pass options as the second parameter:
If query or command does not have any parameters you have to pass undefined:
You can define your own execution options typings by creating a archimedes.d.ts in the root of your project with the following contents:
If you do so, you can have a type safe way to pass custom options:
Chain of responsibility#
Archimedes configures a chain of responsibility which allows a use case to be processed through links.
This means that for each action the user performs in your app you can execute arbitrary code, like for example: logging the request, caching data, handling errors and much more in a flexible yet robust way.
In order to create the chain you have to do this as soon as possible in your app:
You can configure the chain however you want, even dynamically:
A complete chain looks like this:
Now, when you create a use case like follows:
And execute it:
The use case will be cached, executed, a log will be shown with the result, the date and if an error happens, the notification center will be notified. And there is even more! You can create custom links.
Links#
ExecutorLink#
This link merely executes the use case. It is always needed if you want to execute the use cases.
LoggerLink#
This link logs information about the execution of the use case, like parameters, result and name of the use case:
It receives an object that conforms the Logger interface:
For example, the window.console conforms that interface, so you can either use that:
or any other implementation, like a custom remote logger:
NotificationLink#
This link is meant to capture errors occurred when executing a use case. This link should be placed after ExecutorLink. When an error occurs it will notify the NotificationCenter. From the UI you can subscribe to the NotificationCenter in order to show the user an error message:
If you want a use case not to show an error when it fails you can execute the use case with the inlineError defined in the execution options
CacheLink#
This link caches the results for all queries with all parameters combination. To learn more about cache move to cache section.
important
The ExecutorLink is always required, even if you use the CacheLink.
important
If you want to use CacheLink and your framework mangles the name of the classes (like Angular does) you should either disable that option or use the @UseCaseKey decorator in all your use cases (queries and commands).
For example, to disable name mangling in Angular when you build the application set NG_BUILD_MANGLE=false in the package.json's script.
To learn more about cache move to cache section.
NullLink#
This link throws an error when is called.
EmptyLink#
This link does nothing when called.
Custom links#
You can create your own custom links by extending the BaseLink class. For instance imagine if we wanted to create a link that starts a spinner when executing an use case:
And then register it in the chain of responsibility:
Cache#
important
It's important to activate emitDecoratorMetadata to true in the tsconfig.json compiler's options. See the examples directory for more information.
UseCaseKey#
To manage properly the cache using CacheLink it is necessary to set a key that identifies each use case. To do this we must use the UseCaseKey decorator passing as parameter the name we want to give to our use case (we recommend using the same name of the class to simplify).
Invalidate cache decorator#
You can automatically invalidate the cache of dependant use cases using the InvalidateCache decorator in conjunction with the CacheLink link. If use case a depends on use case b, and use case b depends on use case c (a ➡ b ➡ c️) if we invalidate the cache of use case a we should invalidate the cache of use case b and c too. We should add this decorator to all use cases we want this handled.
Cache invalidations#
If you want to set that certain commands or queries invalidate the cache of other commands and queries you can set the cache invalidations with CacheInvalidations.set method. You should indicate the key of the use case that will invalidate the cache and the invalidations that this use case will perform when executed.
These invalidations can be a list of use case keys to invalidate when the first one is executed, for example:
Or you can also use some one of these invalidation policies:
- ALL: The use case will invalidate all the cache of all the use cases
- NO_CACHE: The use case will never be cached
Invalidate cache in runtime#
Sometimes you want to execute a Query invalidating the cache for this specific execution, for example, refresh an email list. To do that, you can use invalidateCache: true in the execution options object.