0% found this document useful (0 votes)
64 views

Documenting A GRPC API With OpenAPI

The document discusses how to generate OpenAPI documentation for a gRPC API defined using protocol buffers. It involves: 1. Defining the gRPC service and messages in a protocol buffer file. 2. Generating Go code from the protocol buffer using protoc and plugins. 3. Annotating the protocol buffer with OpenAPI options to populate the documentation. This allows generating OpenAPI/Swagger documentation for the gRPC API that can provide documentation and examples.

Uploaded by

ShortShot
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views

Documenting A GRPC API With OpenAPI

The document discusses how to generate OpenAPI documentation for a gRPC API defined using protocol buffers. It involves: 1. Defining the gRPC service and messages in a protocol buffer file. 2. Generating Go code from the protocol buffer using protoc and plugins. 3. Annotating the protocol buffer with OpenAPI options to populate the documentation. This allows generating OpenAPI/Swagger documentation for the gRPC API that can provide documentation and examples.

Uploaded by

ShortShot
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

Libelli archive categories search about

Documenting a gRPC API with


OpenAPI
January 21, 2021 · 6 min · Benjamin Bengfort

gRPC makes the specification and implementation of networked APIs a snap. But
what is the simplest way to document a gRPC API? There seem to be some hosted
providers by Google, e.g. SmartDocs, but I have yet to find a gRPC-specific tool. For
REST API frameworks, documentation is commonly generated along with live
examples using OpenAPI (formerly swagger). By using grpc-gateway it appears to
be pretty straight forward to generate a REST/gRPC API combo from protocol
buffers and then hook into the OpenAPI specification.

In this post, I’ll go through the creation of docs from gRPC protocol buffers. In a
following post, I’ll go through the creation of a live gRPC/REST service with Swagger
documentation.

Step 1: Define the service.

We’ll create a simple “notes” service that has two endpoints: create a note and fetch
notes, optionally filtered.

syntax = "proto3";

package notes.v1;

option go_package = "github.com/bbengfort/notes/v1";

service NoteService {

rpc Fetch(NoteFilter) returns (Notebook) {};

rpc Create(Note) returns (Notebook) {};

message Note {

uint64 id = 1;

string timestamp = 2;

string author = 3;

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 1/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

string text = 4;

bool private = 5;

message NoteFilter {

repeated uint64 ids = 1;

repeated string author = 2;

string before = 3;

string after = 4;

bool private = 5;

message Notebook {

Error error = 1;

repeated Note notes = 2;

message Error {

uint32 code = 1;

string message = 2;

So far, this is just a gRPC service definition. If we’re working in a Go project, we can
version our API and structure our project as follows:

Workspace/go/src/github.com/bbengfort/notes

└── cmd

| └── notes

| | └── main.go

├── go.mod

├── go.sum

└── proto

| └── notes

| | └── v1

| | | └── api.proto

Using this directory structure, generate the struct code and server and client
interfaces using protoc with go and grpc plugins:

$ protoc -I ./proto/ \

--go_out=. --go_opt=module=github.com/bbengfort/notes \

--go-grpc_out=. --go-grpc_opt=module=github.com/bbengfort/notes \

proto/notes/v1/*.proto

NOTE: You’ll have to install protoc (I did so with brew ) and the go and grpc
plugins (I used go get ). See the gRPC Go Quickstart for more information on
https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 2/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

the installation process.

In this command the -I flag specifies where protoc can look for included
protocol buffer files (e.g. if they’re imported) - more on this later. The --go_out
and --go-grpc_out flags specify where to write the generated go code and the -

-go_opt=module= and --go-grpc_out=module flags specify the root Go module. If


you run this in the project root, e.g. github.com/bbengfort/notes then a v1

directory will be created with api.pb.go and api_grpc.pb.go inside of it. This is
because of the option go_package = "github.com/bbengfort/notes/v1"; directive
at the top of api.proto which resolves the output path based on all the module
directives.

Step 2: download includes files and install dependencies

In order to use the grpc-gateway and openapiv2 protocol buffer plugins, we’ll
have to modify our proto file with options that allow us to specify how the REST API
is defined and to supply information to the swagger.json generated OpenAPI v2
specification. Custom options are described in third party protocol buffer files that
must be included when we generate our protocol buffers using the -I flag.

NOTE: I believe there is a way to download and “install” third party libraries into
a global includes path, e.g. /usr/local/include/google/protobuf but I have to
investigate this further.

To simplify the use of protoc and to prevent dependency management issues, I


just downloaded the needed third-party from grpc-gateway-boilerplate. This
appears to be a pattern in some of the repos I’ve seen, adding them to a
third_party directory, though I prefer to add them to a include directory. Your
directory should now look like:

Workspace/go/src/github.com/bbengfort/notes

└── cmd

| └── notes

| | └── main.go

├── go.mod

├── go.sum

└── include

| └── googleapis

| | ├── LICENSE

| | └── google

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 3/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

| | | └── api

| | | | ├── annotations.proto

| | | | └── http.proto

| | | └── rpc

| | | | ├── code.proto

| | | | ├── error_details.proto

| | | | └── status.proto

| └── grpc-gateway

| | ├── LICENSE.txt

| | └── protoc-gen-openapiv2

| | | └── options

| | | | ├── annotations.proto

| | | | └── openapiv2.proto

└── proto

| └── notes

| | └── v1

| | | └── api.proto

└── v1

| ├── api.pb.go

| └── api_grpc.pb.go

Finally install the required grpc-gateway plugins so that you have protoc-gen-grpc-

gateway and protoc-gen-openapiv2 in your $GOBIN .

Step 3 (optional): tell vscode where includes are

If you’re using VSCode and the vscode-proto3 extension, then I like to add the
following directives to my workspace settings ( .vscode/settings.json ):

"protoc": {

"path": "/usr/local/bin/protoc",

"compile_on_save": false,
"options": [

"-I=${workspaceRoot}/proto",
"-I=${workspaceRoot}/includes/googleapis",

"-I=${workspaceRoot}/includes/grpc-gateway",

This prevents import error messages in your protocol buffers and enables
autocomplete.

Step 4: annotate our service

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 4/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

Finally, we’re to the part we’ve been waiting for - annotating our proto file with the
REST and OpenAPI v2 options. At the beginning of api.proto add the following:

syntax = "proto3";

package notes.v1;

option go_package = "github.com/bbengfort/notes/v1";

import "google/api/annotations.proto";

import "protoc-gen-openapiv2/options/annotations.proto";

option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {

info: {

title: "Notes";

version: "1.0";

contact: {

name: "bbengfort";

url: "https://github.com/bbengfort/notes";

email: "info@bengfort.com";

};

license: {

name: "BSD 3-Clause License";

url: "https://github.com/bbengfort/notes/LICENSE";

};

};

schemes: HTTP;

schemes: HTTPS;

consumes: "application/json";

produces: "application/json";

};

When the openapiv2 plugin generates a swagger.json file, the information in


this option will be used to populate the info , schemes , consumes , and
produces fields of the specificiation. This will both influence the information in the
generated documentation as well as make it easier to create a live server.

Next we must update the service definition to map gRPC services to REST API calls:

service NoteService {

rpc Fetch(NoteFilter) returns (Notebook) {

option (google.api.http) = {

get: "/api/v1/notes"

};

};

rpc Create(Note) returns (Notebook) {

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 5/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

option (google.api.http) = {

post: "/api/v1/notes"

body: "*"

};

};

These options specify that the Fetch RPC can be accessed with a GET request to
/api/v1/notes and that the Create RPC uses POST to the same endpoint. Note
that the body: "*" flag ensures that the request body is included in endpoint.

Step 5: generate swagger spec and serve

In the final step of this post, we’ll use the openapiv2 plugin to generate the
swagger json specification and use the swagger-ui docker image to serve some
static documentation.

protoc -I ./proto/ \

-I include/googleapis -I include/grpc-gateway \

--go_out=. --go_opt=module=github.com/bbengfort/notes \

--go-grpc_out=. --go-grpc_opt=module=github.com/bbengfort/notes \

--openapiv2_out ./openapiv2 --openapiv2_opt logtostderr=true \

proto/notes/v1/*.proto

This protoc command has been updated to include the third party protocol buffer
files and also adds the openapiv2 plugin, writing a specification file at
openapiv2/notes/v1/api.swagger.json (note you may have to make the
openapiv2 directory before running this command).

To serve the static swagger-ui docs, I used Docker as follows:

$ docker run -p 80:8080 \

-e SWAGGER_JSON=/openapiv2/notes/v1/api.swagger.json \

-v $PWD/openapiv2/:/openapiv2 \

swaggerapi/swagger-ui

This will pull the swaggerapi/swagger-ui image from DockerHub when you run it
for the first time. You can then view the docs at http://localhost/ :

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 6/7
10/14/22, 11:08 AM Documenting a gRPC API with OpenAPI | Libelli

The next steps are to use grpc-gateway to create a server that does both gRPC
hosting and a JSON REST API - complete with live Swagger documentation and
styling.

© 2021 Libelli
Powered by
Hugo &
PaperMod

https://bbengfort.github.io/2021/01/grpc-openapi-docs/ 7/7

You might also like