内容简介:Your next API doesn’t need to be built with REST and JSON. How about gRPC and Protocol Buffers for better performance and structure?Nowadays, when people want to implement backend API, they go straight to creating applications with RESTful API that communi
Your next API doesn’t need to be built with REST and JSON. How about gRPC and Protocol Buffers for better performance and structure?
May 15 ·7min read
Nowadays, when people want to implement backend API, they go straight to creating applications with RESTful API that communicate using JSON, without even considering other options. In recent years though, gRPC and its protobufs started to get some traction and popularity thanks to many of their advantages. So, let’s see what’s all the buzz/hype about and implement gRPC server using Python!
TL;DR: Here is my repository with grpc
branch with all the sources from this article: https://github.com/MartinHeinz/python-project-blueprint/tree/grpc
What is gRPC, Anyway?
gRPC is Remote Procedure Call (RPC) protocol, that leverages Protocol Buffers (protobufs) as its message format. Using gRPC, the client application can directly call method available on a remote server using method stubs. It doesn’t matter in what language the server-side application is implemented as long as you have stubs (generated) for your client-side language. gRPC supports many languages, including Go, Java, Ruby, C# or our language of choice — Python. You can find more info in this overview .
Now, what are Protocol Buffers (protobufs) ? Protobufs are alternative to formats like JSON or XML. They are a smaller, simpler and more efficient way of serializing data. To use protobufs , you need to define how you want the exchanged messages to look, for example (for more specifics see this language guide ):
Aside from messages, we also need to define service
s and their rpc
methods that will be implemented on server-side and called from client-side:
Why Should I Care, Anyway?
There are quite a few advantages to using gRPC over REST. First off, gRPC is much better when it comes to performance, thanks to the tight packing of protobufs , which reduces the size of payloads being sent. It also uses HTTP/2, instead of HTTP/1.1 as REST does. For these reasons, it’s a great choice for IoT, mobile devices or other constrained/low-power environments.
Another reason to choose gRPC over REST is that REST doesn’t mandate any real structure. You might define the format of requests and responses using OpenAPI, but that’s loose and optional. gRPC contracts, on the other hand, are stricter and clearly defined.
As already mentioned gRPC is using HTTP/2 and it’s good to mention that it’s taking full advantage of its features. To name a few: concurrent requests, streaming instead of request-response, smaller sensitivity to latency.
That said, there are also disadvantages and the biggest one being adoption. Not all clients (browsers) support the use of HTTP/2 making it problematic for external use. Considering performance advantages though, it’s clearly a great choice for internal services and communication, which you have control over.
Setting Up
To do anything with gRPC and protobufs , we need to install its compiler:
Considering that we are using python to build our application, we will also need grpcio
and grpcio-tools
libraries:
Let’s Build Something
With all tools ready we can now actually move onto building the application. For this example, I chose a simple echo server that sends you back your own messages.
The first thing we should talk about though is project layout. I chose the following directory/file structure:
This layout helps us clearly separate protobuf files ( .../proto
), generated sources ( .../generated
), actual source code and our test suite. To learn more about how to set up a Python project with this kind of layout you can check out my previous article:
So, to build the gRPC server, we — first and foremost — need to define messages and service(s) it will use you to communicate with clients:
In this echo.proto
file we can see a very simple definition of message types - one for request ( EchoRequest
) and one for reply ( EchoReply
) from the server. These messages are then used by Echo
service, which consists of one RPC method called Reply
.
To be able to use these definitions in Python code, we need to generate server and client interfaces. To do so, we can run this command:
We specified quite a few arguments. First of them — -I blueprint/proto
, tells grpc_tools
where to look for our .proto
files (it defines PATH
). Next two, --python-out
and --grpc_python_out
specify where to output generated *_pb2.py
and *_grpc_pb2.py
files respectively. Last argument - ./blueprint/proto/*.proto
is the actual path to .proto
files - this might seem like redundant as we specified PATH
with -I
, but you need both to make this work.
When you run this one command however, you will end up with some broken imports in these generated files. There are multiple raised issues in grpc
and protobuf
repositories and the easiest solution is to just fix those imports with sed
.
Writing this command out would not be very enjoyable nor efficient, so I wrapped it in make
target to make your (and mine) life easier. You can find complete Makefile
in my repository here .
There’s quite a bit of code that gets generated using this command, so I won’t go over every little bit, but there are a few important things to look out for. Each of these *_pb2_grpc.py
files has the following 3 things:
- Stub — First of them — Stub and in our case
EchoStub
- is a class used by the client to connect to gRPC service - Servicer — In our case
EchoServicer
- is used by the server to implement the gRPC service - Registration Function — Finally piece,
add_EchoServicer_to_server
that is needed to register servicer with gRPC server.
So, let’s go over the code to see how to use this generated code.
The first thing we want to do is implement the actual service. We will do that in grpc.py
file, where we will keep all gRPC specific code:
Above, we create Echoer
class which inherits from generated EchoServicer
class, which contains all the methods defined in .proto
file. All these methods are intended to be overridden in our implementation and here we do just that. We implement the only method Reply
by returning EchoReply
message that we also previously defined in the .proto
file. I want to point out that the request
parameter here is an instance of EchoReply
- that's why we can get the message
out of it. We don't use the context
parameter here, but it contains some useful RPC-specific information, like timeout limits for example.
One neat feature I also want to mention is that in case you wanted to leverage the response-streaming you could replace return
with yield
and return multiple responses (in for
cycle).
Now that we implemented the gRPC service, we want to run it. To do so, we need a server:
All this is, is just a single static method. It creates server from grpc
library with a few workers - in this case, 10. After that it uses previously mentioned registration function ( add_EchoServicer_to_server
) to bind our Echoer
service to the server. Remaining 3 lines just add listening port, start the server and wait for interrupt.
All that remains for the server-side is __main__.py
, so that we can start it as Python module:
With that, we are all set to start the server. You can do that with python -m blueprint
or if you are using my template, then just make run
.
We have a server running, but we have no way of calling it… That’s where the client comes it. For demonstration purposes, we will create the client in Python using the stubs generated for us, but you could write the client in a completely different language.
For the client, we need only one function, which we call run
. After connecting the server, it creates stub that will allow us to call the server method, which is the next step. It calls Reply
method implemented on server-side by passing in EchoRequest
message with some payload. All that's left is to just print it.
Now, let’s run the client and see if everything works as expected:
And it does work!
Testing with Pytest
As with all my little projects and articles, we are not done until there are unit tests for all the code. To write sample test for this gRPC server, I will use Pytest and its plugin pytest-grpc
.
Let’s first have a look at the fixtures used to simulate request-response exchange between client and server:
I think these are all pretty simple. Just make sure to use these specific names for these fixtures, as that’s what the plugin looks for. One thing to notice is the grpc_channel
argument in grpc_stub
. This is a fake channel supplied by pytest-grpc
plugin. For more info, I recommend going directly to pytest-grpc
source code , as the plugin is pretty simple. With that, let's move on to the actual test:
We create this test by leveraging grpc_stub
fixture which we wrote in the previous step. We create EchoRequest
which is passed to the grpc_stub.Reply
, followed by simple assert
. And, when we run the test ( make run
):
We passed! Aaaand we are done!
Conclusion
If you take away just one thing from this article, then I think it should be the fact that we should always consider possible alternatives when deciding on solution/technology we want to use for some project. It doesn’t always need to be REST and JSON. Sometimes gRPC might fit the requirements way better. This kind of thinking also applies to any other technology or tool. To see full code listings with Makefile
automation, prepared Docker images and even set up for deployment to Kubernetes, please check out grpc
branch in my repository here: https://github.com/MartinHeinz/python-project-blueprint/tree/master . Any feedback is appreciated, as is star or fork in case you like this kind of content. :wink:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++ Primer Plus
Stephen Prata / Addison Wesley / 2011-10-18 / GBP 39.99
C++ Primer Plus, Sixth Edition New C++11 Coverage C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible an......一起来看看 《C++ Primer Plus》 这本书的介绍吧!