Benefits of a Microservice Implementation – Concrete Example

In designing a service, there is often a question of how many methods and how granular you want to go.  There is a risk of making the interface too complex, i.e., exposing irrelevant details, versus exposing too little. 

Take for example an elearning microservice.  Say the ultimate responsibility of this service is to produce a URL in which a user accesses a course.  In order to obtain this URL, the course id as well as the identity of the user must be given.   Additionally, a user has to register in order to take the course, and a url would be invalid if the user has not already registered for the course.  In the process of this registration, an optional first and last name is provided for the learner. 

In designing the microservice that encompasses this functionality, the designer has the following questions: Should the updating of the learner information be exposed?  What if the only scenario presently is for the client system to obtain the URL for the course?  Should the course registration mechanism be exposed?  Below is an example of a simple elearning api for the microservice:

Option 1: Hide all registration relevant calls from the client. 

Courses Api, Option 1

GET/api/courses/{customerKey}/userCourse/launchurl/{externalCourseId}

If the course registration and the updating of the first and last name are exposed, the client could in fact ignore these functions, and a GetUrl function can take care of all the details for the client system.  At first glance, this looks like the ideal interface, since at the end of the day all that matters to the client is that the url for the course is returned.  The details of checking if a user has registered and registering a user for a course could be internal to the service, abstracting away the implementation details from the caller.  This is often referred to as the façade design pattern, and is a way to make abstract away complexity from the clients of a function.

Option 2: Expose all low-level registration altering functions

Courses Api, Option 2

GET/api/courses/{customerKey}/userCourse/launchurl/{externalCourseId}

POST/api/courses/{customerKey}/userCourse/register/{externalCourseId}

GET/api/courses/{customerKey}/userCourse/checkregistered/{externalCourseId}

POST/api/courses/{customerKey}/userCourse/ /updateregisteredname/{externalCourseId}/{firstName}/{lastName}

In this implementation, details of the course registration mechanisms are exposed.  The client could then check if a person is registered, register them, and even change the name associated with the registration at a later date via the updateregisteredname method.  This is the microservice way of doing things, in which having this extra functionality exposed allows the application to be extensible.  For example, if a person gets married and changes their name then you could have a process call the updateregisteredname method. This could be done through a batch script, an Azure logic app, or some other mechanism.  In this case the client would have to know a lot more about the system than option number 1, but that this case exemplifies the power of a microservice architecture. 

The client then becomes more of an orchestration system for the elearning service rather than simply relying on the elearning service to manage the details itself.  This could be considered a potential downside, but what if another client wants access to this functionality?  Having the internal workings exposed opens up the possibility of numerous different kinds of apps utilizing the elearning service.  How about an app that checks if a user has registered for a course?  How about a name update event, and update the customers name through the system?

In this option the client would, if attempting to register the user manually, know to orchestrate a registration in order to ultimately obtain that the course url.  How about a light weight GetUrlMethod that just returns the url assuming that the user is registered?  This method for generating a url based on a user having already registered for a course, and the client could use this provided that the user is already registered.

 What if the GetUrlMethod also does the process of checking and registering a user behind the scenes?  The interface could expose a number of methods, ones that are heavy weight that do all the orchestration, and ones that are lightweight and micro-service oriented that have to be called one after the other in order to obatin the desired workflow result.

The interface is open for inifinte extension to meet the needs of many clients.  A client, at the expense of having to shift through the excess functionalicty, has the power to ignore functions it does not need.  If the user has not registered, then the lightweight call to simply generate the course url assuming the user has already registered will fail.   Therefore, the only downside of exposing many different functions to the client is that the user using the API would have to look through and analyze many different types of functions, instead of relying on a simple “GetCourseUrl” function which in the background checks if the user has registered, registers them if necessary, and then returns the URL to the client.