An open API service indexing awesome lists of open source software.

https://github.com/tembleking/test-grpc-gateway


https://github.com/tembleking/test-grpc-gateway

Last synced: 9 months ago
JSON representation

Awesome Lists containing this project

README

          

# Test of gRPC-gateway

This is a POC of a server listening to both HTTP and gRPC with autogenerated server and client implementations, and swagger documentation.

## Protobuf definition

The definition is stored in `pkg/application/proto/service.proto`. It has some annotations for swagger documentation, but the definition is as minimum as follows:

```protobuf
syntax = "proto3";

import "google/api/annotations.proto";
import "google/protobuf/empty.proto";

option go_package = "github.com/tembleking/test-grpc-gateway/pkg/application/proto";

// The description of the test service
service TestService {
// The description of the method
rpc Test(google.protobuf.Empty) returns (TestResponse) {
option (google.api.http) = {
get: "/test"
};
}
}

// TestResponse is the response message for the Test method.
message TestResponse {
// Message is the test message.
string message = 1;
}
```

As you can see this is a minimum hello world service that will listen to `/test` and will return a response with a `message` field.

The three files in `pkg/application/proto/.*pb.*go` are autogenerated. The other three `pkg/application/proto/buf.*` files are for [`buf`](https://buf.build) to generate the code.

## Swagger documentation

The swagger definition is automatically generated in `pkg/application/http/docs/swagger.swagger.yaml`.

## HTTP server
The HTTP router implementation in `pkg/application/http/router.go` just registers the endpoints defined in the Proto definition and will redirect them to the gRPC server:

```go
options := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := proto.RegisterTestServiceHandlerFromEndpoint(ctx, mux, grpcListenAddress, options)
```

## gRPC server

The gRPC server is implemented in `pkg/application/grpc/grpc.go`. Contains the actual logic that will be executed in the application.
In case of an HTTP request to `/test`, this will be processed here as well.

```go
type server struct {
}

func (s *server) Test(ctx context.Context, empty *emptypb.Empty) (*proto.TestResponse, error) {
return &proto.TestResponse{Message: "Hello world!"}, nil
}

func NewServer() *grpc.Server {
grpcServer := grpc.NewServer()
server := &server{}
proto.RegisterTestServiceServer(grpcServer, server)
reflection.Register(grpcServer)

return grpcServer
}
```

It will just answer with a `TestResponse` with a `message` field set to `Hello world!`.

## Execution

The server can be launched with `go run ./cmd/test-grpc-gateway/`. It will listen to both HTTP and gRPC on `:8080` and `:9090`.

### HTTP Request
If you perform an HTTP request to `/test`, you will get the response:

```
$ http localhost:8080/test
HTTP/1.1 200 OK
Content-Length: 26
Content-Type: application/json
Date: Fri, 12 Aug 2022 10:33:30 GMT
Grpc-Metadata-Content-Type: application/grpc

{
"message": "Hello world!"
}
```

### gRPC Request
There is a gRPC client implementation in `cmd/grpc-client/` that uses the autogenerated code in `pkg/application/proto` that
will contact the server on `:9090`.

```go
func main() {
conn, err := grpc.Dial("localhost:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil { ... }
defer conn.Close()

client := proto.NewTestServiceClient(conn)

response, err := client.Test(context.Background(), &emptypb.Empty{})
if err != nil { ... }

log.Printf("%s", response.Message)
}
```

After executing it, with the server listening, you should see the following:
```
$ go run ./cmd/grpc-client/
2022/08/12 10:33:30 Hello world!
```