Skip to content

Instantly share code, notes, and snippets.

@SnewsButton
Last active July 21, 2018 14:41
Show Gist options
  • Save SnewsButton/91901ac8a0ea63c474ac673457d05e45 to your computer and use it in GitHub Desktop.
Save SnewsButton/91901ac8a0ea63c474ac673457d05e45 to your computer and use it in GitHub Desktop.
Pact gRPC Implementation Investigation

Purpose

Add gRPC support to Pact.

Intro

gRPC

We should note that there are four kinds of services:

  • Unary RPCs
  • Server streaming RPCs
  • Client streaming RPCs
  • Bidirectional streaming

Protos

Should they be included in the formulation of the consumer contract?

Problem Statement

TODO: Specify what a successful implemtation of gRPC support in Pact looks like

Options

grpc-gateway

As suggested by @bootstraponline, we should look into https://github.com/grpc-ecosystem/grpc-gateway. Since grpc-gateway converts to rest, it seems that some of the streaming services may not translate well. Additionally, this requires existence of protos and annotations.

Would be used in provider tests

Consumer

Provider

@bootstraponline
Copy link

I wonder if https://github.com/grpc-ecosystem/grpc-gateway would allow us to more easily pact test gRPC by using the JSON/REST version.

@SnewsButton
Copy link
Author

@bootstraponline that looks very promising. It would seem that mefellow's option 1 should be the option that we pursue. We just need to explore that plugin a bit more, see what it yields, and how much work is needed to get it working.

@mecavity
Copy link

mecavity commented Jul 9, 2018

@bootstraponline that's the service we use in our micro service architecture. That would fit our use case perfectly.

@SnewsButton
Copy link
Author

SnewsButton commented Jul 9, 2018

Inspired from the graphQL interaction, here is what a basic consumer build (without use of a proto file) can look like in js:

const provider = new Pact({
    port: 4000,
    log: path ...,
    dir: path.resolve(process.cwd(), "pacts"),
    consumer: "gRPCConsumer",
    provider: "gRPCProvider",
});

// would need to convert to something grpc friendly and need to preserve var name
var HelloRequest = {
    requestType: "HelloRequest",
    steam: false,
    body: {
         name: StringType
    }
};

var HelloReply = {
    responseType: "HelloReply",
    steam: false,
    body: {
         message: StringType
    }
};

const gRPCHelloRequest = new gRPCInteraction()
    .uponReceiving("Hello Request")
    .withRequest({
        rpcName: "SayHello",
        gRPCRequest: HelloRequest
    })
    .willRespondWith(HelloReply);

provider.addInteraction(gRPCHelloRequest);

With use of protos and grpc-gateway:

//hello.proto

syntax = "proto3";
// The greeting service definition.
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {} // Sends a greeting
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}
const provider = new Pact({
    port: 8080, // rest endpoint
    log: path ...,
    dir: path.resolve(process.cwd(), "pacts"),
    protos: hello.proto, // or just the path containing all pact files
    consumer: "gRPCConsumer",
    provider: "gRPCProvider",
});

// Specify the targeted rpc, desired rest port, path, method, and body as per grpc-gateway: manual at this point
var sayHelloToJsonRest = {
    protoFile: "/path/to/hello.proto", (? maybe choose within designated proto directory)
    rpcName: "SayHello",
    restPort: 8080,
    path: "/v1/sayHello",
    method: "GET",
    body: StringType //body for rest endpoint
};

var HelloRequest = {
    requestName: "HelloRequest",
    steam: false,
    body: {
         name: StringType
    }
};

var HelloReply = {
    responseName: "HelloReply",
    steam: false,
    body: {
         message: StringType
    }
};

const gRPCHelloRequest = new gRPCInteraction()
    .uponReceiving("Hello Request")
    .withRequest({
        proxyFields: sayHelloToJsonRest,
        gRPCRequest: HelloRequest
    })
    .willRespondWith(HelloReply);

provider.addInteraction(gRPCHelloRequest);

Let me know if it is missing anything or format could be improved.

@SnewsButton
Copy link
Author

SnewsButton commented Jul 9, 2018

grpc-gateway requires existence of proto files and annotations. We could generate the annotations semi automatically, first specifying the proto files to be included and methods for each associated rpc (see above). If that can be accomplished, then I think that we can still test via REST in the consumer side.

@SnewsButton
Copy link
Author

Seems that we do not have to annotate the proto file: this would be a better option. See https://grpc-ecosystem.github.io/grpc-gateway/docs/grpcapiconfiguration.html

@SnewsButton
Copy link
Author

@mecavity
Copy link

Very cool @SnewsButton! Really excited by this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment