This is the last post of the series Microservices in Go: REST APIs!
- Part 1 - HTTP Handlers
- Part 2 - Testing
- Part 3 - Custom JSON Types
- Part 4 - OpenAPI / Swagger
- Part 5 - Versioning
- Part 6 - Putting it all together (this post)
Putting it All Together
The last five posts covered all steps I consider necessary for building the barebones of a REST API, it’s not a complete list for sure, it’s missing things like deployment, infrastructure and other important details we must consider before making the API live, like scalability, reliability, instrumentation, monitoring and logging, but I will cover those in detail in future posts.
The following are the concrete decisions I like to follow when building brand new API from scratch:
Types to match HTTP resources
This was covered when I talked about HTTP Handlers where I mentioned implementing a type to take care of everything related to Tasks. I like following this guideline because the Go types can easily be categorized and organized accordingly to the HTTP resources they represent.
Custom Go Types to describe JSON payloads
Implementing Custom JSON Types is extra work for sure, but I believe making the user experience better for our costumers always matter, sure it’s more work for the team in charge of building the APIs but defining more humanized types allows defining much more clearer values for the fields used in the payloads.
Considering JSON is the de facto format used for HTTP-based APIs it’s important we take advantage of the verbosity we have and be as explicit as we can. The common use case would be to define custom Go types representing enum values in JSON.
Document your APIs
OpenAPI is a great way to create a standardized documentation, we can share it with our costumers as well as with the team in charge of implementing the actual APIs in code.
The process I described in the post works but I like following a different approach to make sure the different services depending on that documentation don’t have circular relationships.
To do that the actual document is generated outside of the project implementing it, and the project meant to implement the code can enforce the rules defined by the document as well as reusing the code that was could be generated from it.
Finally, regarding the most difficult topic IMO: versioning, I like keeping it simple and use path-based APIs; technically in the end using any of the possible options is easy to do thanks to existing gateways that could route requests to different implementations as needed.
In future posts I will cover more things to consider when Building Microservices in Go, until then I will talk to you later.