A useful test resource when developing or generating a REST client for CRUD operations is JSONPlaceholder, a free online REST API. We’ll use it for the example on this page, as JSONPlaceholder provides example APIs that adhere perfectly to established REST conventions.
There are two concepts that need to be represented in the domain model:
- a domain class (the data entity, or data transfer object)
- the API itself
In your domain model:
- Define the API as an Interface (a UML Class with an Interface stereotype)
- Add a
<<REST>>stereotype to the interface
- Add a
urltagged value to the interface, containing the root URL of the REST API
- Draw a Dependency arrow from the class to the API
For example, to model the To-Do List REST interface from JSONPlaceholder:
Because the JSONPlaceholder API follows exact REST conventions, there’s nothing else that needs to be defined. When you generate the above model, you’ll get the following…
If you recall from earlier, the generated REST API consists of a layered design, with an API layer for “database-agnostic”, application-level operations, and a Data Access Layer (DAL) consisting of a DAO for each domain class. The DAOs map database operations to the MongoDB (or Oracle, or…) database. To recap:
The external REST API code fits into this layered structure. Any time a domain class is mapped to a REST Interface, instead of the usual MongoDB DAO, CodeBot instead creates a “REST” DAO:
In other words, no MongoDB DAO is created for the domain class. The data isn’t stored in the “local” application at all, but instead all data access is delegated to the mapped REST interface.
The Domain Logic layer (and by extension the API layer) know nothing of this switcheroo, however. They don’t know (or care!) where the data is written to or retrieved from, just that the data can be written and retrieved.
It’s possible (likely, even) that the data returned by the external API won’t precisely match your own domain data. So in some cases you’ll need to define a mapping, or transform, between the two.
CodeBot “natively” supports the node-json-transform library for this purpose. (TODO: more details to follow…)
If the differences are more extreme, however, you can also transform the data by writing server event handlers.
- For data being written, create
onUpdateOperations on your domain class. This code should map your data structure to the external API’s data structure.
- For data being read, create an
onReadOperation on your domain class. This code should map the external API’s data structure to your data structure.
Of course, REST itself isn’t a standard as such, just a well-known set of conventions. Not every system your app integrates with will follow the same conventions precisely - many APIs can be considered “merely REST-like”, or “JSON (or XML) over HTTP”. So some level of tailoring will almost certainly be needed.
To tailor each individual CRUD endpoint:
- Add an empty Operation (no code required) to the Interface (NB: not the domain class!)
- Give the Operation a tagged value
e.g. to tailor the “create” endpoint:
path tag will result in the full URL for “create” (POST) calls being:
Note the “/add” appended to the base URL. The URL itself was defined as a tag on the parent Interface.
You can also override the entire URL for each endpoint, by using
url for the Operation tag instead of