grpc-gateway-wrapper 0.1.0
GRPC Gateway Wrapper
License: MIT
Requires Python: ~=3.8

# grpc-gateway-wrapper

The goal of this project is to generates a REST gateway wrapper layer for a grpc server with minimal customization, along with `swagger` definitions conforming to `OpenAPI 2.0`.

The `gRPC-gateway`(https://github.com/grpc-ecosystem/grpc-gateway) is a plugin of the Google protocol buffers compiler protoc. It reads protobuf service definitions and generates a reverse-proxy server which translates a RESTful HTTP API into gRPC.

This repo, the `grpc-gateway-wrapper` is a python library and executable that builds a `go` binary that encapsulates the reverse proxy server along with `swagger` definitions conforming to `OpenAPI 2.0`.

- [gRPC Gateway Wrapper](#grpc-gateway-wrapper)
  - [Installation instructions](#installation-instructions)
    - [Build from source](#build-from-source)
    - [Pull from pypi](#pull-from-pypi)
  - [Usage](#usage)
    - [CLI options](#cli-options)
  - [Prerequisite](#prerequisite)
  - [Build a Gateway](#build-a-gateway)
    - [gRPC Metadata](#grpc-metadata)
  - [Use a Gateway](#use-a-gateway)
    - [Dockerized integration example](#dockerized-integration-example)
  - [Call a Gateway](#call-a-gateway)
  - [References](#references)

## Installation instructions

### Build from source

```py
python setup.py bdist_wheel
```

### Pull from pypi

```py
pip install grpc-gateway-wrapper
```

## Usage

```py
python -m grpc_gateway_wrapper
```

**or**:

```sh
grpc-gateway-wrapper
```

_(it should be installed on the system path)_.

This is the main entrypoint script which can generate a working gRPC gateway server that can proxy between an equivalent REST API and a set of gRPC services.

### CLI options

```py
╰$ python -m grpc_gateway_wrapper --help

optional arguments:
  -h, --help            show this help message and exit
  --proto_files PROTO_FILES [PROTO_FILES ...], -p PROTO_FILES [PROTO_FILES ...]
                        The proto file to generate from
  --working_dir WORKING_DIR, -w WORKING_DIR
                        Location for intermediate files. If none, random will be generated
  --no_cleanup, -c      Don't clean up working dir
  --output_dir OUTPUT_DIR, -o OUTPUT_DIR
                        Location for output files
  --metadata [METADATA ...], -m [METADATA ...]
                        gRPC metadata name(s) to add to the swagger
  --install_deps, -d    Install go dependencies if they're missing
  --gateway_version GATEWAY_VERSION, -g GATEWAY_VERSION
                        Version of the grpc-gateway tools to install if installing dependencies
  --log_level LOG_LEVEL, -l LOG_LEVEL
                        Log level for informational logging
```

## Prerequisite

1. go: https://go.dev/doc/install
1. protoc: https://grpc.io/docs/protoc-installation/

There are additional `go` dependencies which the library needs which you can directly install by passing the `--install_deps` argument.

## Build a Gateway

To build a gateway for your server, you need to collect the full set of `proto` files used to create the server interface, including files containing type definitions (the script is not smart enough to find them for you). With that, simply call `grpc_gateway_wrapper` with the `--protos` argument. For example:

```py
python -m grpc_gateway_wrapper \
  --proto_files example/sample-messages.proto example/sample-service.proto
```

### gRPC Metadata

Some gRPC APIs rely on the presence of certain [metadata](https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md) entries (e.g. [kserve model-mesh](https://github.com/kserve/modelmesh#quick-start) requires the `mm-model-id` or `mm-vmodel-id` header). These headers are not represented in the `proto` file, so they're not automatically represented in the `swagger` API generated by this template. In order to add them, you can use the `--metadata` argument to `grpc_gateway_wrapper`. For example:

```py
python -m grpc_gateway_wrapper \
  --proto_files example/sample-messages.proto example/sample-service.proto \
  --metadata foo bar:default_value
```

## Use a Gateway

Once you build the gateway using the commands above, a `build` directory will be generated with the contents:

```sh
build
├── app
└── swagger
```

The generated `binary` is the `app`, along with the `swagger` directory along side it.

To see the flags that can be passed to the built binary, you can run:

```sh
╰$ ./build/app --help

Usage of ./build/app:
  -mtls_client_ca="": CA certificate to use to enable mutual TLS
  -proxy_cert="": Cert to use when making the proxy rpc call
  -proxy_cert_hname="": Hostname override for proxy cert
  -proxy_endpoint="localhost:8004": Endpoint for the server being proxied to
  -proxy_no_cert_val=false: Ignore certificate validation
  -serve_cert="": Public cert to use when serving proxy calls
  -serve_key="": Private key to use when serving proxy calls
  -serve_port=8080: Port to serve the gateway on
  -swagger_path="/swagger": Absolute path to swagger assets
```

You can run it anywhere (locally, or within a deployment) and simply point it at the running `gRPC` server:

```sh
./build/app \
  --swagger_path $PWD/build/swagger \
  --proxy_endpoint localhost:8004 \
  --serve_port 8080
```

(**TODO** - add TLS specific example)

## Call a Gateway

Once a gateway is running, you can access it directly using any HTTP client you like (`curl`, `postman`, etc...). You can also visit its swagger documentation by hitting the `/swagger` endpoint (e.g. `http://localhost:8080/swagger`).

## References

This project relies heavily on a few external libraries.

- [`grpc-gateway`](https://github.com/grpc-ecosystem/grpc-gateway): This project provides the guts of the gateway implementation, as well as the swagger spec generation
- [`google api service`](https://cloud.google.com/endpoints/docs/grpc/grpc-service-config): In order to avoid forcing annotations into the protobuf files, this project side-loads the REST spec using the `google api service` definition.