How to make HTTP API in Go? In this article, we examine two approaches and several tools to make HTTP API in Go: REST and gPRC.
REST
Some people don’t understand the REST, so they continue to make API in RPC style. The reason for that is wiki information is not enough to feel the whole power of the approach. Therefore, the topic is popular and there will be more and more articles about it in blogs and talks at conferences.
Zalando's guide helped me to understand what REST is. This document appeared together with the OpenAPI initiative and Design First approach. According to it, firstly you need to describe API and then start implementing the business logic. You can find the documentation here.
Swagger helps to build REST API. It is simple to use if you write on node.js. Yet, in the case of Go the situation is much more complicated. You have to design quick solutions like tests, that check if there is the documentation for an endpoint or a data structures generator for Go from the swagger.yml file.
How to develop a full and supported REST API in Go without swagger support?
One of the options is to:
Write swagger.yml
Describe a model
Implement CRUD from the API side and database work layer
Cover the model with API tests
Unify and make a generator based on it
As a result, we get the following algorithm: describe the model, write the code, and implement the business logic.
We can also generate models from swagger.yml as an additional way.
All apps with REST API are built on the usual 3-tier architecture.
I used to create apps using the echo framework. It has a good design and speed. We use SQL for the database layer. Using this set and self-written code generators, we can build an API very quickly. However, I still recommend to use Python from Django or Flask and build the API with them. This solution works only if you do not expect a high load.
gRPC
gRPC — Google tool, which is actively being promoted both in the Go community and beyond it. gRPC allows you to create good internal APIs over HTTP/2 by default.
gRPC functionality is good in general, but the most important features are code generation and propaganda of the Design first approach by default.
When you use swagger, there is a big temptation not to support the documentation, because it is often an additional problem. When you use gRPC, it will not happen, this improved tool makes the developer's life easier because it is impossible to write the code without a proto file, and without sharing with development teams.
An ideal way to use gRPC is a connection between microservices and communication with a server for mobile apps.
How is gRPC different from REST?
gRPC is primarily an RPC framework and it refers to UpdateBalance, GetClient methods.
REST is about resources such a GET /users, POST /users and etc.
In gRPC, you can create a lot of methods until you meet the limitation of the Go interfaces (512 methods/1 interface).
Since the article is mostly about gRPC, let's take a simple "hello, world" example from the grpc-go documentation, and let's improve it with plugins. We'll add data validation and REST API to gRPC service and generate swagger.json with its documentation :
The structure of the project is the following:
- pb — package to store proto files and generated code
- main.go — a service that will configure and run our app
- server — package to implement the logic of our app
- Makefile — makefile to automate routine
In order to generate a code, you should run:
protoc --go_out=plugins=grpc:.
At first, some commands described in Makefile are enough to automate routine:
We need Makefile in order to enter make proto to generate code from the protofiles. Moreover, this part will be expanded, the commands will become longer and their number will increase.
If we generate code, implement the main interfaces for the server, make an API, we will get the code below:
It runs from main.go in the following way:
gRPC-gateway
Recently, in one of the projects, we decided to use gRPC for communication between services. We also needed good REST for external clients.
We were aware of this tool, we even made a project using this plugin. There was an unpleasant prospect of supporting several services that do the same things. But in this case, gRPC-gateway is very helpful, because we will have both gRPC and REST descriptions in one proto file.
Let's install it according to the instruction described in README and then let's convert our proto file into the following form:
Also, we should change the command to generate a code from the proto file to the following form:
Now the proto command will generate us rest gateway, swagger, and interfaces for the implementation of logic.
Now there is a small problem—our server will listen two TCP sockets. One is to ensure the operation of the gRPC mechanisms, and the second is to ensure REST. In addition, the gateway will be released as an intermediary, converting the JSON HTTP REST representation into gRPC on the proto files.
Let's modify our code to run the server and bring it to the form:
Now run our server and the REST requests on it
$ curl -XGET http://localhost:8090/api/hello/Mike{"message":"Hello, Mike!"}
Thus, we get the REST API on top of the gRPC. But in this example, there isn't enough validation. For the validation, we will use https://github.com/lyft/protoc-gen-validate. Following the examples in the documentation, we will bring our proto file into this form :
Let's add another command to generate the code
After the code regeneration, we can see that now the validation works for us.
$ curl -XGET http://localhost:8090/api/hello/ {"error":"invalid HelloRequest.Name: value length must be 3 runes","message":"invalid HelloRequest.Name: value length must be 3 runes","code":2}
Conclusion
gRPC ecosystem is very friendly for the web services in Go. Thanks to that, we can speed up the development process by generating most of the repetitive code. You can see the full code of the project here.
If you write REST API and do not know how to describe your API, then go to gRPC and save time on developing web services in Go!