This tool enables the automated creation of Merode-based REST APIs and applications:
- You design a Merode model using the Merlin tool, and download the model
- You start the Merode Interpreter providing the model file as input
- You get a fully functional REST API based on the model that enables
- Submitting business events (this is how business objects are created, modified and ended)
- Retrieving the list of valid events
- Retrieving business objects
This is an easy way to implement Merode-based APIs or application back-ends. Unlike the traditional Merode approach, this tool does not rely on code generation. Instead, the Merode model is interpreted at runtime, and the API is dynamically created. This approach has several benefits:
- Faster Development: There is no need to re-generate a Merode application for each change in the model. Instead, you just need to restart the Merode Interpreter with the updated model file as input.
- Easier Deployment: Once your Merode Interpreter is deployed, there is no need to de-reploy it for each model change.
- Smaller Software Size: The size of the software (interpreter) does increase with the size of the model.
It also has several potential drawbacks:
- Increased Memory Usage: As the Merode Interpreter interprets the model at runtime, the memory usage increases with the size of the model. This is not necessarily the case of generated code.
- Lower Performance: As the Merode model is interpreted at runtime for event handling and object instantiation, the interpreter may require more computational resources than generated code.
These are general trade-offs between interpretation vs. code generation approaches. The performance and memory trade-offs depend among others on the implementation of the interpreter and the of the generated code, respectively. We did not yet evaluate or compare the performance of the REST APIs generated from Merode models vs. REST APIs using the Merode Interpreter.
The following video shows how to use the Merode Interpreter
POST /event
The expected request body is a JSON specifying the name of the event type, and the properties used to set attribute values in the created/modified/ended business object. Example:
{
"type": "EVcrCustomer",
"properties": {
"email": "[email protected]",
"premium": false
}
}
{
"type": "EVcrOrder",
"properties": {
"date": "2021-01-03"
},
"masters": {
"Customer_Order": 0
}
}
When the event is modifying or ending business objects, the id of the object must be specified as "objectId". For example, to ban Customer with 0, updating its premium status at the same time, the following body request can be sent:
{
"type": "EVendCustomer",
"objectId": 0,
"properties": {
"premium": false
}
}
The properties are optional. The following would just end the Customer with id 0, without updating its attributes values:
{
"type": "EVendCustomer",
"objectId": 0
}
When an event is successfully handled and stored, the API answers with a list of affected business objects, in JSON format. Example of response for EVcrOrder
event:
[
{
"masters": {
"Customer_Order": {
"masters": {},
"id": 0,
"state": "orderInProgress",
"type": "Customer",
"properties": {
"premium": false,
"email": "[email protected]"
}
}
},
"id": 1,
"state": "placed",
"type": "Order",
"properties": {
"date": "2021-01-03"
}
},
{
"masters": {},
"id": 0,
"state": "orderInProgress",
"type": "Customer",
"properties": {
"email": "[email protected]",
"premium": false
}
}
]
The successfully executed business events can be retrieved using:
GET /event
It returns a (possibly empty) list of events in a JSON format. Example:
[
{
"eventId": 0,
"masters": {},
"type": "EVcrCustomer",
"objectId": 0,
"properties": {
"premium": false,
"email": "[email protected]"
}
},
{
"eventId": 1,
"masters": {
"Customer_Order": 0
},
"type": "EVcrOrder",
"objectId": 1,
"properties": {
"date": "2021-01-03"
}
}
]
To retrieve all the business objects of a given type (e.g. Customer), use the following endpoint:
GET /customer
The name of the business object type in the URL must start with a lower-case. Example of (successful) response:
[
{
"masters": {},
"id": 0,
"state": "orderInProgress",
"type": "Customer",
"properties": {
"email": "[email protected]",
"premium": false
}
},
{
"masters": {},
"id": 2,
"state": "registered",
"type": "Customer",
"properties": {
"email": "[email protected]",
"premium": true
}
}
]
To retrieve a specific business object based on its id (e.g. 0), use the following endpoint:
GET /customer/0
Example of successful response:
{
"id": 0,
"state": "ended",
"type": "Customer",
"properties": {
"email": "[email protected]",
"premium": false
}
}
In case a request sent to the API is not successfully handled, it will respond with a list of (Merode)Error messages.
- Clone this repository
git clone [email protected]:AmaVic/merode.git
- Get into the project directory
cd merode
- Install the project distribution
./gradlew installDist
This will build the application in the build/install/merode/bin
directory.
- Get into the build directory
cd build/install/merode/bin
- Run the application
./merode -m <path-to-mxp-file>
Where <path-to-mxp-file>
is the path to the Merode model file (.mxp
).
- Download the latest package from the releases
- Unzip the downloaded file
- Get into the unzipped directory (merode/bin)
cd merode/bin
- Run the application
./merode -m <path-to-mxp-file>
Where <path-to-mxp-file>
is the path to the Merode model file (.mxp
).
- The Merode (.mxp) model file must be the XML file (not the .mxp archive that contains another .mxp (actually, xml) file).
- The .mxp files generated by Merlin cannot yet be used as-is. Before using a Merlin-generated .mxp, remove the
dependentrole
andmasterrole
attributes from the .mxp (.xml) file. - The file model2.mxp can be used as an example of valid file for the Merode Interpreter.
Merode Interpreter API © 2023 by Victor Amaral De Sousa is licensed under CC BY-NC-SA 4.0.