Microservices - Dollar functions
In a CrudService any function starting with $
may be replaced by an HTTP call, depending on your msOptions
.
For example with the following configuration :
msOptions.microServices = {
"ms-A": {
services: [MyUser],
openMsLink: true, openController: true,
url: "http://localhost:3005",
},
"ms-B": {
services: [Profile],
openMsLink: true, openController: true,
url: "http://localhost:3006",
},
}
-
Calling
myUserService.$find
on ms-A will directly run the function implementation. -
Calling
myUserService.$find
on ms-B will perform an HTTP request to ms-A (passing the arguments), then the function implementation will be run, and the result returned to ms-B.
This means you must be careful when defining $
functions inside your CrudServices since the behavior of the function might change depending on where it is called.
Here are a few guidelines that will make your transition from monolithic to microservices simple.
Treat all functions as async
Make sure to treat all $
functions as async
and to await
them if needed.
The above code will display 4
on ms-A but display [object Promise]
on ms-B.
$
functions should always be defined async:
Ensure arguments and return value can be serialized
In javascript, functions are not serialized, for example:
// somewhere else
const fun = () => return 5;
const res = await myUserService.$methodB(fun);
console.log(res())
5
on ms-A, but throw an error on ms-B.
Failure
Error: res is not a function
Additionally, passing or returning circular references will throw an error:
const objA = { };
const objB = { objA: objA }
objA['objB'] = objB
await myUserService.$methodB(objA);
Failure
Error: Converting circular structure to JSON
You can call JSON.stringify(obj)
to test what can and can't be serialized. Note that passing very large objects will impact your performance when switching to microservices.
Always return by value
Since arguments are not returned by the HTTP method. Any "return by reference" logic will stop working if called from another ms.
// somewhere else
const obj = { value: 1 };
const res = await myUserService.$methodC(obj);
console.log(obj.value)
2
on ms-A but display 1
on ms-B.
You can return the obj
to make it work on both ms:
// somewhere else
let obj = { value: 1 };
obj = await myUserService.$methodC(obj);
console.log(obj.value) // displays 2
Context propagation
Argument name ctx
is reserved in $
functions and should only be used to pass the CrudContext.
If you want to propagate parameters from the context back to the caller, you can use the following context properties:
These properties are sent back even with HTTP requests, allowing bidirectional communication between services.
Note
You should pass the CrudContext to every $
function to enable reliable logging in ms-link hooks.
Use getEntityId for consistent ID extraction
When working with entity relations, ID serialization can vary depending on your configuration:
- With MikroORM, non-populated entity relations are stored as
{ id: relationId }
but get serialized torelationId
(string) - MongoDB ObjectIds are converted to strings when serialized
Use getEntityId
to extract the correct ID regardless of your microservices configuration:
This utility ensures consistent ID handling across different database types and serialization contexts.