Supporting REST and HTML with a gRPC Microservice
Any microservice can become a gRPC microservice. gRPC and protobuf work together to bring more structure to building out APIs, even if your service has to work across different clients or support streams of data. The system generates model and networking code for the protocol — you define the API using a .proto file which […] By Walter Tyree.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Supporting REST and HTML with a gRPC Microservice
20 mins
- Getting Started
- Exercising the Server with Evans
- Setting Up Envoy Proxy
- Creating a Docker Container for Envoy
- Annotating the API Definition
- Including Dependencies
- Transcoding HTTP GET Verbs
- Transcoding an HTTP POST Verb
- Transcoding Other Verbs
- Generating an Annotated Protobuf File
- Configuring Envoy for Transcoding
- Adding a Transcoding Filter
- Running the Servers
- Other Options with protoc
- Generating Concurrency Code
- Where to Go from Here?
Configuring Envoy for Transcoding
Open the envoy directory then open grpc-envoy.yml in a text editor. This file is a sample taken from the Envoy documentation and is a basic, bare configuration to support transcoding.
The first entry for admin
assigns the administration website to port 9901
. In the section for static_resouces
there are listeners
and clusters
.
Envoy uses one listener
for one port. Skim through the configuration to take note of a few more attributes:
- There’s a single listener watching port
8082
. - There’s an entry for
stat_prefix
, which is just the prefix that any log entries will have. - In the
routes
section, note that the server is going to match using the “/” prefix, meaning it’ll match everything. - You can also see that it’ll send traffic to a cluster named
grpc
, which is defined further down. - And before Envoy routes any traffic, it’ll apply the
http_filters
.
Adding a Transcoding Filter
The first filter you need to set up is the transcoding filter. Its important keys are name
and typed_config
, and they signal that your filter is a gRPC to HTTP/JSON transcoder.
Your first step is to tell the filter about your API.
Set the proto_descriptor
to the file path of todo.pb. Additionally, set the services
to the name of your service in the todo.proto file.
Your finished entry should look like this:
proto_descriptor: "data/todo.pb"
services: ["todos.TodoService"]
Leave the other values in this section as their defaults, but there are a couple of items to note:
-
Scroll down to the definition for
clusters
. At the end, you’ll find an entry foraddress: host.docker.internal
, which is something you need when running Envoy in Docker as you are right now. - Your gRPC server
port
value is set to1234
, so no need to make changes there.
Running the Servers
If your servers aren’t running, use Docker commands to start them. And even if your Envoy server is running, bring it up again to reload the configuration files you have just modified. Open a new Terminal, navigate to the starter project root directory and enter the following commands:
docker compose up db -d
docker compose up app -d
docker compose up envoy -d
These commands bring up your application containers again, re-reading their configuration files to pick up any changes.
Now that the configurations are set, you should be able to send gRPC or HTTP traffic to port 8082
. The requests will get rerouted to your gRPC server.
The next step is to use Postman to send a GET
request to localhost:8082/v1/todos
. If you created any TODOs earlier they should appear. Otherwise, you’ll recieve an empty JSON array.
The animated screenshot below shows retrieving the Todo list, creating a Todo, completing a Todo, and deleting a Todo with Postman.
If you’ve installed Evans you can now use it with port 8082
.
Envoy routes both kinds of traffic — gRPC traffic passes through to the server untouched, and HTTP traffic gets transcoded.
Now do it: To point Evans to the new port, change the command from before:
evans repl --host localhost --port 8082 --proto ./todo.proto
Now Evans knows to use the new port you created.
Other Options with protoc
Swift server code is moving from using Futures based on SwiftNIO to Async/Await. Recently, the grpc-swift team updated the protoc plugins to generate both code patterns.
In the next few sections, you’ll learn how to switch to Async/Await patterns in your concurrency code.
Generating Concurrency Code
In this tutorial, the grpc-swift plugin uses EventLoopFuture
but not the Async/Await concurrency pattern. You can ignore part of the documentation at the repo.
In the past either ExperimentalAsyncClient
or the ExperimentalAsyncServicer
flag could generate experimental Aysnc/Await code, but neither currently work.
In Spring of 2022, Async/Await support was moved to a different branch, but was merged back to main in the Summer.
With these updates to the plugins, you don’t need to provide any special options or flags. They generate Async/Await code and the SwiftNIO style code.
Starting with the release of grpc-swift 1.8 in June 2022, generated .swift files no longer use the same naming convention for Swift compilers 5.6 and above for clients. For servers, the SwiftNIO naming convention is the same.
To take advantage of the Async/Await structure, new implementations are available to you. For example, consider the code generated by the todo.proto:
For Swift 5.5 and older compilers, the service provider is `Todos_TodoServiceProvider`
For Swift 5.6 and newer compilers, the SwiftNIO service provider is `Todos_TodoServiceProvider`. Additionally a `Todos_TodoServiceAsyncProvider` protocol appears in the todo.grpc.swift file.
The signature of the fetchTodos
changes from:
func fetchTodos(request: Todos_Empty, context: StatusOnlyCallContext) -> EventLoopFuture<Todos_TodoList>
To this:
func fetchTodos(request: Todos_Empty, context: GRPCAsyncServerCallContext) async throws -> Todos_TodoList
Though this tutorial doesn’t focus on writing Swift Service Clients, there is similar change worthy of note.
For 5.6 and later compilers, any instances of `Todos_TodoServiceClient` will be marked as deprecated and will use the SwiftNIO code.
In order to continue using SwiftNIO style code, you need to change instances of `Todos_TodoServiceClient` to `Todos_TodoServiceNIOClient`.
To switch to Async/Await, update your client code to use `Todos_TodoServiceAsyncClient`.
This part of the grpc-swift project is under active development. Be sure to check the repository and GitHub if you encounter issues or unexpected warnings as you work.
Where to Go from Here?
Download the completed project files by clicking the Download Materials button at the top or bottom of this tutorial.
In this tutorial you learned a few things:
- How to generate a protocol definition file that mapped HTTP URLs to gRPC services.
- How to configure an Envoy proxy to transcode HTTP/JSON to gRPC.
- How to use some of the optional features of the protoc command.
Now you’re well-equipped to enable services to use multiple protocols at the same endpoint. You can upgrade your servers to enjoy more efficient communication with new clients, without forcing your older applications to update. This means that existing REST clients, like web front ends or iOS applications, don’t need to be changed. Your back end applications can now support gRPC clients seamlessly.
Visit the Envoy documentation website to access the full documentation for how to configure Envoy to transcode HTTP/gRPC.
You can also find the main documentation for Envoy on that same site.
Over on Github, the grpc-swift project contains information about support for Async/Await, and it has the full documentation for the Swift plugin and its options.
Finally, Google offers guidance for designing APIs that support gRPC and HTTP transcoding.
We hope you enjoyed this tutorial. Please join the forum discussion below if you have any questions or comments!