3 min read
Interact With Protobuf Endpoints in Human-Readable Text Formats Using protoCURL
Do you have difficulties debugging Protocol-Buffers-based HTTP REST endpoints? Since Protobuf uses binary payloads, we face the problem, that we cannot easily write or read our Protobuf payloads with curl directly on the terminal. Ideally, we would like to to use curl with Protobuf just like we use curl with JSON or XML with classic text-based HTTP REST endpoints. 1
To this problem, we present protoCURL - cURL for Protobuf: The command line tool to quickly and easily write requests in human-readable text formats on the command line against Protocol Buffer over HTTP endpoints and view the output in a text-based format as well.
This can become handy when debugging Protobuf-based HTTP endpoints when they are used instead of JSON.2
The tool was created by myself (GollyTicker) with initial sponsorship from QAware, because of the need for debugging Protobuf REST APIs in our projects.
An Example with protoCURL
With protoCURL a request can be as simple as this:3
protocurl -I test/proto -i ..HappyDayRequest -o ..HappyDayResponse \
-u http://localhost:8080/happy-day/verify \
-d 'includeReason: true'
The command line arguments have this meaning:
-I test/protopoints to proto files in the filesystem-i ..HappyDayRequestand-o ..HappyDayResponsetell which message types are used for the input and expected for the output- The
..instructs protocurl to automatically infer the (unique) full package path of the message types
- The
-u <url>is the HTTP REST endpoint url to send the request to-d 'includeReason: true'describes the input data in the Protobuf Text Format
The Protobuf endpoint uses the proto file happyday.proto - which consists of these (condensed) request and response messages:
package happyday;
message HappyDayRequest {
google.protobuf.Timestamp date = 1;
bool includeReason = 2;
}
message HappyDayResponse {
bool isHappyDay = 1;
string reason = 2;
string formattedDate = 3;
}
The server will tell us whether the UTC day of a specific timestamp is a happy day or not. We simply say, that everyday, except for Wednesdays, is a happy day.4
Concretely, given a HappyDayRequest,
- the server converts the
datetoUTCand sets the booleanisHappyDayif and only if the weekday of the date is Wednesday. - If
includeReasonis set, then a reason for theisHappyDayboolean is given as a string. - The server will also format the date to UTC as
formattedDate.
The above protoCURL command will produce this output:
=========================== Request Text =========================== >>>
includeReason: true
=========================== Response Text =========================== <<<
isHappyDay: true
reason: "Thursday is a Happy Day! ⭐"
formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT"
We can now easily see the request and response in the Protobuf Text Format without needing to use protoc or a full-blown programming language to manually (de-) serialize the content. Since we didn’t provide a date, the Protobuf server implicitly assumes all of the timestamp.proto fields to be zero - which corresponds to epoch time 0.
Explanation
In the background, protocurl essentially does the following:
- encode the textual Protobuf message to a binary request payload (using a bundled
protoc) - send the binary payload in a POST request to the HTTP REST endpoint (via
curl, if possible) and receive the binary response payload - decode the binary response payload back to text and display it
More Examples
As a second example, let’s see, what happens, when we set the date to the first Wednesday in 2023:
protocurl -I test/proto -i ..HappyDayRequest -o ..HappyDayResponse \
-u http://localhost:8080/happy-day/verify \
-d 'includeReason: true, date: { seconds: 1672790400 }'
Note, the syntax for the text format above.
This will produce:
=========================== Request Text =========================== >>>
date: {
seconds: 1672790400
}
includeReason: true
=========================== Response Text =========================== <<<
reason: "Tough luck on Wednesday... 😕"
formattedDate: "Wed, 04 Jan 2023 00:00:00 GMT">
Furthermore, we can also use JSON as the text format:
protocurl -I test/proto -i ..HappyDayRequest -o ..HappyDayResponse \
-u http://localhost:8080/happy-day/verify \
-d "{ \"date\": \"2023-01-01T00:00:00Z\", \"includeReason\": true }"
The JSON format is automatically detected and also used for the output:
=========================== Request JSON =========================== >>>
{"date":"2023-01-01T00:00:00Z","includeReason":true}
=========================== Response JSON =========================== <<<
{"isHappyDay":true,"reason":"Sunday is a Happy Day! ⭐","formattedDate":"Sun, 01 Jan 2023 00:00:00 GMT"}
Reproducing the Examples yourselves
Want to try this out? You can reproduce these examples by taking the following steps:
-
Clone repository and start the test server
In your macOS / Linux or Windows MinGW terminal, run:
# Clone the repository and enter the directory
git clone protocurlcd protocurl
# Ensure these are installed and available to you: bash, jq, zip, unzip and curl
# e.g. sudo apt install bash jq zip unzip curl
# Download the latest protoc binaries for the tests
./release/10-get-protoc-binaries.sh
# Start server
(source test/suite/setup.sh && startServer) -
Install protocurl from GitHub
Simply follow the command line installation instructions.
When using windows, runprotocurl.exein Powershell or cmd instead of MinGW.
If you use docker, then use the commanddocker run -v /path/to/proto:/proto qaware/protocurl [...ARGS]
instead ofprotocurl -I /path/to/proto [...ARGS]
Now you can send requests like the examples above
Summary
We can use protocurl as a quick and ergonomic command line tool to interact with Protobuf-based HTTP REST endpoints while working with human-readable text formats.
Head over to protocurl on GitHub and
- look at the examples,
- download the releases,
- read the command line usage
- contribute by creating issues for bugs or feature requests!
The photo is by Edgard Motta from Pexels.
-
In theory, we could manually decode and encode the request and response via
protocusing the Protobuf Text Format. But this becomes cumbersome quickly. ↩︎ -
In specific scenarios, Protobuf is used instead of JSON, because the built-in schema format as well as the ability to generate code make it a viable choice for keeping consumers and producers of REST APIs consistent with each other and documented. It can also be the serialization for RPC frameworks such as Twirp. ↩︎
-
For Powershell, we need to replace
/by\in the path and use a backtick ` instead of\as line separators. ↩︎