Architecture design: good practices for creating microserives API

When you decide on microservices architecture then important aspect becomes communication between microservices. You should:

  • know API in every microservice,
  • know about relationship between microservices,
  • be able to correlate request and response,
  • tracking entire flow for the outside request.

Remembering about that makes project developing easier and searching bugs shorter. In that reason you should consider below things in your project:

1. Choice between synchronous and asynchronous communication

It’s important which type of communication you choose. For fast and non performance-critical messages you can use synchronize REST api. For asynchronous messages you rather should use the ‘streams’ from HTTP2 or messages brokers. If you want have many consumers for that same messages you also should use messages brokers like Kafka.

2. Documentation

For REST api you can use Swagger. It’s very complex tool and the most IDE’s have support for it. Nonetheless you can use online editor:

For asynchronous API you can use AsyncAPI standard. AsyncAPI is comparatively new, so some IDE’s cannot support it, but you can also using online editor.

3. Versioning

In the both cases: REST and messages sending through brokers, you should have information about version of using API. It will be helpful in the future development. In REST API you can put version information into URL path, query parameter or headers. In case of message brokers you can put information into headers (if they’re supported) or at least in the sending data structure.

4. Correlation ID

You should have unique id for request and response pairs. It’s important because on production you could have a lot of requests in this same time and sometimes you will be must pair responses with them. In rest and mostly message brokers you can put correlation id in the header. Then it will be transparent for application logic.

5. Tracing

The common use case is that external service asks one of our microservices, and then our microservice asks other our microserices, and so on. We should be able to tract the entire flow. For this purpose we should have unique id for any flow which we want to tracking. It could be simple id propagate between microservices, but better option will be use OpenTracing standard. This library give you universal API which you can implement or use external provider like Jaeger:

6. Logs

You should log all request and responses with correlation and tracing information. If this information will be too much then you can decrease log level. You can also separate request and response information on many information. For example you can log on INFO level important information like request path, tracing, correlations but headers, body data, response can be log on DEBUG level:

2019-07-23 18:10:45.118 INFO com.example.app.AppController: request POST /api/example-request?param=test [correlation-id: e470a86575fc, trace-id: 35cbb08b-3287]
2019-07-23 18:10:45.150 DEBUG com.example.app.AppController: request body: {"json": "example"} [correlation-id: e470a86575fc]
...
2019-07-23 18:10:47.132 INFO com.example.app.AppController: response status: 200 [correlation-id: e470a86575fc]
2019-07-23 18:10:47.178 DEBUG com.example.app.AppController: response body: {"response-details": "all is fine!"} [correlation-id: e470a86575fc]

As you see, correlation id is important to joining all logs together.

Summary

If you will be following the above advises then your project will be easy to analyse and management. It will be also easier to finding bugs and tracking the flow.

If you have another good practices for creating API, please write it in the comment.