Photo by Alex Andrews from Pexels

In almost all cases Microservice requires a communication protocol. When it is designed, it is required to remember that other services will need to integrate with it. The Microservices definitions do not indicate what technology or what style of communication should be used. In practice you need to find the best solutions for the problems you are solving.

In the following blogpost we’ll discuss different approaches and technologies often used in Microservices world, analyzing their pros and cons.

Take a look also on my other blogpost “Are you sure you’re using microservices?”

Web Services — SOAP

A Web service is a software system designed to support interoperable machine-to-machine interaction over a network. It has an interface described in a machine-processable format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP-messages, typically conveyed using HTTP with an XML serialization in conjunction with other Web-related standards. W3C, Web Services Glossary

Probably you have heard before about SOAP and WSDL in SOA (Service Oriented Architecture). But isn’t SOA Microservices? All those technologies are usually recognized as “Enterprise” approach. They include a lot of XMLs and schemas defining how communication protocols look like. There are also a lot of related standards and specifications. Just take a look at this huge list! Would I consider leveraging SOAP for brand new Microservice? Probably not. Usually it’s overcomplicated, but has its applications. There are companies using ESBs (Enterprise Service Bus) where communication usually happens using SOAP, but not always.

It’s worth to remember that SOAP exists, it has its applications, but probably you won’t use it for a brand new simple Microservice.

Short info:

Often XMLs over HTTP, but supports many protocols

Pros:

Very powerful

Requests and responses have a predefined schema

Cons:

Overcomplicated, e.g. to transfer a file you may need to base64 encode it and include in the XML

Less and less popular

Example:

POST /InStock HTTP/1.1

Host: www.example.org

Content-Type: application/soap+xml; charset=utf-8

Content-Length: 299

SOAPAction: "http://www.w3.org/2003/05/soap-envelope"



<?xml version="1.0"?>

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://www.example.org">

<soap:Header>

</soap:Header>

<soap:Body>

<m:GetStockPrice>

<m:StockName>GOOG</m:StockName>

</m:GetStockPrice>

</soap:Body>

</soap:Envelope>

Source: https://en.wikipedia.org/wiki/SOAP

REST (REpresentational State Transfer)

Nowadays almost everybody is using REST everywhere (or is claiming their JSON over HTTP is REST). It became an industry standard. Often people even don’t think or discuss, just use REST with JSON as a default.

REST was defined by Roy Fielding in 2000 in his PhD dissertation “Architectural Styles and the Design of Network-based Software Architectures”. In the following years, the number of web APIs thrived.

If you’d like to learn more about REST history, check the “The History of REST APIs” blogpost.

REST generally provides a concept of resources, represented by HTTP URIs, where standard HTTP methods can be used to operate on them. It’s quite simple and provides a very nice learning curve.

However in practice there are many topics which can be realized in multiple ways or are just often discussed in every project:

API versioning — version presented in the path, query param, custom header or content type?

GET with body — allowed by HTTP RFCs, but not supported by many HTTP client libraries. When would you like to use it? E.g. for typical complex “search” queries.

Avoiding verbs — REST should operate on resources, so /account/close is rather not fully correct, instead you can use PATCH method providing, e.g. { "state": "closed" } JSON. Similarly /account/search contains the verb.

is rather not fully correct, instead you can use method providing, e.g. JSON. Similarly contains the verb. JSON representation of polymorphism, e.g. let’s say that you have a resource which one field may contain array containing two different types. This can be represented as "field": [{ "type": "TypeA", "field1": ... }] or "field": [{ "TypeA" : { "field1": ...}}] . There is no single answer, and different JSON libraries behaves differently.

or . There is no single answer, and different JSON libraries behaves differently. JSON fields casing — camel case or snake case?

Nevertheless, most of those topics can be agreed during a single day.

Short info:

Usually JSON or XML over HTTP (but this can be any other format)

Leverages HTTP methods and status codes

Pros:

Simple, doesn’t require huge knowledge to start working with it

Industry “standard” (because everybody is using something a bit differently)

Requests and responses are usually human readable

Supported by huge number of libraries (both for client and server)

Cons:

A lot of “not standardized” topics — how to model specific queries, API versioning, “Search” endpoint, etc

Streaming is often difficult

No schema for endpoints — people try to fix this using e.g. OpenAPI (Swagger) or RAML.

Example:

gRPC

Usually when I start describing gRPC, people think CORBA! Well, yes, there are some similarities, but gRPC is simpler. gRPC, like the name, indicates is a Remote Procedure Call framework. It leverages Protobuf (Protocol Buffers) and HTTP/2.

Workflow with gRPC is quite simple, first you need to define .proto file defining services, requests and response formats, and then you copy this file to all projects which will communicate with each other. gRPC lib will generated basing on the file the appropriate client or server endpoints. The only thing you need to do is to convert your domain objects to the generated classes.

Short info:

RPC (Remote procedure call)

Binary (Protobuf) over HTTP/2

Probuf is used to define endpoints schemas

Developed and used by Google. Also used e.g. by Dropbox

Pros:

Fast (binary!)

Supported by many languages (you can communicate e.g. Java with Python)

Supports streaming, both for method parameters and as responses

Provides generators which based on .proto definition generates serializers and deserializers.

definition generates serializers and deserializers. Build in support for API changes —Protobuf schema evolution

Cons:

Less known, higher learning curve due to need to learn Protobuf etc.

Not human readable, additional tools are needed e.g. to manually test API

Example .proto :

syntax = "proto3"; service Stocks {

rpc GetStock(GetStockRequest) returns (GetStockResponse){ }

} message GetStockRequest {

string stock_name = 1;

} message GetStockResponse {

string price = 1;

}

GraphQL

GraphQL is a much newer solution than the ones presented before. Have you ever had a problem in REST where you needed to implement two separate endpoints returning more simple and more complex responses? If yes then GraphQL is a solution to that. From technical perspective usually it’s a single REST endpoint /grapqhl taking on input JSON requests with special query DSL. For every query you need to specify, which fields from requested entities should be included in the response.

Short info:

Query language for APIs, but supports Mutations

Pros:

During query it is possible to define which fields should be returned in the response. This allows to query only for data needed for specific view/service.

Strong typing, resources have predefined schemas

Supported by many languages

More and more popular, but…

Cons:

First initial release was in 2015 and a stable one in June 2018, so it’s quite fresh.

Not all client libraries are already mature

No HTTP caching support

Queries always return status code 200

Example:

Definition: type Stock {

name: String,

price: String

} Query: {

stock(name: "GOOG") {

price

}

} Response: {

"stock": {

"price": "23.50"

}

}

This means we’re fetching entity stocks by name GOOG and the response should include the field price .

Apache Kafka

Kafka is a totally different choice. It’s a message broker, so it embraces asynchronous message-based communication. Instead of making synchronous HTTP request, waiting for the response, in this case we could be just consuming a Kafka topic. Modelling processes with asynchronous communication is more complicated but has its advantages. You don’t depend directly on other services, if they were offline, you can still operate, e.g. post messages to Kafka.

Reminder: Reactive Manifesto embraces the Message Driven systems. Message passing can ensure loose coupling and isolation.

Kafka supports various message types. It of course supports good old JSONs, but also Avro and Protobuf. What is more, it integrates with Confluence Schema Registry, so you can keep your message schemas in external service.

Various different message queues were described and benchmarked here by Adam Warski.

Kafka can be used also with Even Sourcing, where events are distributed among various topics and dependent services can build current data view from them. You can read more about Event sourcing using Kafka here.

Short info:

Asynchronous, message based communication

Pros:

Async communication has its big advantages

Supports different message formats: JSON, Avro, Protobuf, …

Cons:

Modelling application using messages is more complicated

You need to setup a Kafka cluster

Example:

Let’s see how can we model the case of querying specific stock price. First, we would create a stock_prices topic. Other services could post messages containing stock prices changes to it. Our service would consume this topic and put the value e.g. in local “cache” (depends on the use case). Message on the topic could be in Avro (but of course could be in JSON, Protobuf or anything else you’d like to).

Schema: {

"namespace": "example.avro",

"type": "record",

"name": "Stock",

"fields": [

{"name": "name", "type": "string"},

{"name": "price", "type": "string"}

]

}

Conclusion

There are a lot of options! However you don’t need to make a single choice for communication between all of your services. Every service may choose something else, of course if there are strong reasons for that, not just developer “fun”. Generally, what to choose when?