In this small epic, we will be able to follow some basics about micro-services and engage in effectively deploying them.
The objective here is to deliver a pragmatic architecture perspective as well as a technical capability demonstration.
In the above image, we can see a very small set of files for what is typically a java service application.
In fact, the micro-service project here represents a set of three (3) stateless entity relationship model:
- person;
- project;
- project-member relationship;
This image shows it to be a single-module, very light project.
On a mature legacy project you usually have: multi-module solutions with sub-modules (ie: not uncommon to find projects consisting of 40 modules).
Where you usually find a huge number of classes:
- models:
- data transfer objects (DTOs) to represent the JSON objects;
- internal application/project model (ie: the model);
- data access objects (DAOs) to represent the data-model entities;
- application events;
- application exceptions;
- converters and parsers:
- to pass from DTOs to the model and vice-versa;
- to pass from the model to DAOs and vice-versa;
- configurations:
- networking;
- security;
- database;
- file storage;
- logging;
- documentation (open-api, swagger, etc);
- a whole bunch of service-oriented proxies to define, per each kind of entity:
- controllers (one per rest-api entity group);
- services (one per data entity, to implement transactionability);
- handlers such as commands or operators (multiple per data entity);
- repositories (typically one per data entity);
The application above have most of the configurations in yaml files, being able to use an external spring-cloud-config to manage them automatically and configure the application in run-time.
Also, the DTO, model and DAO are the same files.
The REST-API controllers are coupled with the Repositories and Services, still letting customizations in some cases.
Therefore, we may have a set of around 20 endpoints having only explicitely programmed around 3.
In the modern world, many developers, teams, organizations are preferring the most semantic-oriented way to develop their interfaces using the beautiful REST-API instead of the legacy, contrained and slow SOAP-WS.
REST-API allows you to deliver the service with both contract-first or implementation-first solutions, and support a huge variety of formats (MediaTypes) whilst at the same time gives a slight performance boost to the application.
Notice that it is true that REST-APIs are typically written to handle JSON formats (read: external representation). But notice also you can transfer binary files, you can mix requests using multipart formats, and you can eventually even customize the whole format to a new one rather easily, by creating proper parsers.
Modern world-class apis should be contract-first, or have at least a formal definition of the APIs. This would ensure proper legal binding and/or a service-level-agreements contract. For this we have used OpenAPI and expose an UI to browse these APIs (formerly known as Swagger-UI). Notice that - in our lightweight app - we do this in a implementation-first strategy.
Notice that these endpoints are HATEOAS-compliant, meaning the APIs will operate on a semantic level, thus providing even more rich results. We also leave a HAL explorer so you can easily navigate and paginate through the semantics and resulting data relationships.
What is also a very standard, but legacy approach, is to use SOAP WebServices. These do require contract-first setups, by using XML files: WSDLs for services and operation specifications and XSDs for the DTO model files.
SOAP is also able to pass binary data through the services and domain, but unfortunately it must do so by using XML, and internally a base64 representation of the file is done, then consuming around 233% of the file in-memory (eg: uploading a 100M file ? you will need 233M just to convert and start uploading it, same goes to download or fetch).
More to come..
OpenAPI Definition HAL Explorer (REST-API HATEOAS browser)