Somnium
Somnium

Reputation: 383

How can a gRPC server make calls to REST endpoints

I'm currently new to gRPC technology and have been reading up on it.

My current understanding is that gRPC is just another protocol just like how REST is one. Now lets say I spin up a gRPC server that I want clients to consume, but in that gRPC server I'd like to be able to get information from outside consumer RESTful Apis, (for example https://developer.riotgames.com/api-methods/) is that still possible?

Upvotes: 1

Views: 9932

Answers (2)

Ulas Keles
Ulas Keles

Reputation: 1771

Yes, it is possible. You can make calls to other APIs and services from your own gRPC service code.

Just let your client make a call to your gRPC service. Then, your service makes a REST call to external API (possibly using arguments from client request to your gRPC service) and processes it. Return the result to your client however your gRPC service responds.

Upvotes: 2

elcomendante
elcomendante

Reputation: 1161

You would need to use grcp-gateway to generate proxy full code available on go-grpc-tutorial thanks to phuongdoenter image description here

  1. install deps:

    $sudo apt install libprotobuf-dev
    
    go get google.golang.org/grpc
    
    go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
    
    go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
    
  2. define service, pb/service.proto:

    syntax = "proto3";
    
    option go_package = "echo";
    
    package echo;
    
    import "google/api/annotations.proto";
    
      //Message represents a simple message sent to the Echo service.
    
     message Message {
    
     string id = 1;
    
    string msg = 2;
    }
    
    
     //Echo service responds to incoming echo requests.
    
    service EchoService {
    
      //Echo method receives a simple message and returns it.
    
       //The message posted as the id parameter will also be returned.
    
    rpc Echo(Message) returns (Message) {
    
    option (google.api.http) = {
    
        post: "/v1/example/echo/{id}/{msg}"
    };
    }
    }
    
  3. generate stub for server and clinet

    $ protoc -I/usr/local/include -I. \
    -I$GOPATH/src \
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis \
     --go_out=google/api/annotations.proto=github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis/google/api,plugins=grpc:. \
     pb/service.proto
    
  4. and reverse proxy for REST API

    $ protoc -I/usr/local/include -I. \
    -I$GOPATH/src \
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-
     gateway/third_party/googleapis \
    --grpc-gateway_out=logtostderr=true:. \
    pb/service.proto
    
  5. server/server.go:

    package main
    
    import (
    "flag"
    
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "net"
    )
    
    // Implements of EchoServiceServer
    
    type echoServer struct{}
    
    func newEchoServer() pb.EchoServiceServer {
    return new(echoServer)
    }
    
    func (s *echoServer) Echo(ctx context.Context, msg *pb.Message) 
     (*pb.Message, error) {
    glog.Info(msg)
    return msg, nil
    }
    
    func Run() error {
    listen, err := net.Listen("tcp", ":50051")
    if err != nil {
        return err
    }
    server := grpc.NewServer()
    pb.RegisterEchoServiceServer(server, newEchoServer())
    server.Serve(listen)
    return nil
    }
    
    func main() {
    flag.Parse()
    defer glog.Flush()
    
    if err := Run(); err != nil {
        glog.Fatal(err)
    }
    }
    
  6. write rest api, server/server-rproxy.go:

    package main
    
     import (
    "flag"
    "net/http"
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
     )
    
     var (
    echoEndpoint = flag.String("echo_endpoint", "localhost:50051", 
    "endpoint of EchoService")
     )
    
    func RunEndPoint(address string, opts ...runtime.ServeMuxOption) 
     error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    
    mux := runtime.NewServeMux(opts...)
    dialOpts := []grpc.DialOption{grpc.WithInsecure()}
    err := pb.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, dialOpts)
    if err != nil {
        return err
    }
    
    http.ListenAndServe(address, mux)
    return nil
     }
    
    func main() {
    flag.Parse()
    defer glog.Flush()
    
    if err := RunEndPoint(":8080"); err != nil {
        glog.Fatal(err)
    }
     }
    
  7. build client server/client.go:

     package main
    
    import (
    "log"
    "os"
    
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    pb "github.com/go-grpc-tutorial/pb"
    )
    
     const (
    address = "localhost:50051"
     defaultName = "PhuongDV"
    )
    
    func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewEchoServiceClient(conn)
    
    // Contact the server and print out its response.
    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    r, err := c.Echo(context.Background(), &pb.Message{Id: "1", Msg: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Msg)
    }
    
  8. finally run server, client, rest and call rest:

    $ go run server/server.go
    
    $ go run client/client.go
    
    
    $go run server/server-rproxy.go
    
     $ curl -X POST "http://localhost:8080/v1/example/echo/1/PhuongDV"
    

    1: https://github.com/phuongdo/go-grpc-tutorial 2: https://i.sstatic.net/C4s7s.png

Upvotes: 0

Related Questions