In a microservice architecture, what is the good way of sharing the request and response contracts among the internal clients of one service
I have 4 services as given below -
- Notes-service -- takes NotesRequest and produces NotesResponse
- Reminder-service -- takes ReminderRequest and produces ReminderResponse
- Todo-service -- takes TodoRequest and produces TodoResponse
- Personal-assistant service -- takes AssistantRequest and AssistantResponse
Personal-assistant service calls the 3 services internally, the Notes-service, Reminder-service and the Todo-service. Notes-service will contain these two request and response pojos inside it --
- NotesRequest.java
- NotesResponse.java
But to call this with the help of a Rest client, Personal-assistant will also require these pojos. A possible way could be to create a common module with the name of common-service and put the sharable request response objects for each service in common-service. Each of the service modules will have a dependency to common-service.
Is there any good approach to put the code clean and modular and make the deployments independent.
Solution 1:
I would consider 2 possibilities:
1.- Use a framework like swagger (or similiar) to expose the API specification(through OpenAPI for instance). This can be used with code generation tools to generate the client. And make the client generation part of the build process in the projects that need to use a client of that service. Do not version control generated code, that's a bad practice.
2.- Create in each service project a contract module, in which you will have just the contract (requests, responses, and api interface, like JAX-RS interface, or Spring interfaces). This module can be used as a dependency in the projects that need a client for that service.
Which one to use depends on the technologies you use and the clients requirements and standards used.
Update with examples
For instance, with the option 2 you will have the following project structure for the notes
project:
-notes-parent
-notes-contract
-notes-service
Each one with its pom.xml.:
- parent would be just a container root module
- contract contains the requests, responses, and services intrfaces. This would be used as a dependency for the project that want to query the notes-service
- service the deployable service itself. This will use the contract as a dependency too.
And do this with all the services. Every xxx-service
submodule will have as dependencies all the yyy-contract
modules of the other services it wants to query.