Golang grpc-gateway에서 RESTful API 만들기

소개



"gRPC를 사용해 보았지만 REST-API를 사용할 수 없습니까?"
"gRPC 외에도 REST-API를 사용하고 싶습니다."
"gRPC로 만든 것을 쉽게 검증하고 싶다"

라고 생각해 조사하면grpc-gateway 라는 것이 있었으므로, 사용해 보겠습니다.
htps : // 기주 b. m / grpc 에코 sys m / grpc가 주름 y

gRPC



gRPC에 대해서는 별도 기사를 작성하고 있으므로 여기를 참조하십시오.
htps : // m / 류 3 / ms / d5 ~ c28 a 412 a 06 e 17 e f98

grpc-gateway 개요



grpc-gateway는 gRPC로 작성된 API를 JSON over HTTP API로 변환합니다. 코드 생성기 역할을 하며 특정 역방향 프록시 서버를 생성합니다. 아래 그림을 참조하십시오.



설치



아래 명령으로 설치하십시오.
$ go get -u -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
$ go get -u -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$ go get -u -v github.com/golang/protobuf/protoc-gen-go

사용해 보자.



1.gRPC 서비스 정의



proto/service.proto
syntax = "proto3";
package example;

import "google/api/annotations.proto";

service HelloWorldService {
  rpc SayHello (HelloRequest) returns (HelloReply) {
  }

  rpc GetUser(GetUserRequest) returns (User) {
  }

  rpc CreateUser(CreateUserRequest) returns (User) {
  }
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

message GetUserRequest {
  string id = 1;
}

message CreateUserRequest {
  string name = 1;
}

message User {
  string id = 1;
  string name = 2;
}

2. google.api.http를 추가합니다.



service.proto
syntax = "proto3";
package example;

import "google/api/annotations.proto";

service HelloWorldService {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/example/sayhello/{name}"
    };
  }

  rpc GetUser(GetUserRequest) returns (User) {
    option (google.api.http) = {
        get: "/v1/example/users/{id}"
    };
  }

  rpc CreateUser(CreateUserRequest) returns (User) {
      option (google.api.http) = {
          post: "/v1/example/users"
          body: "*"
      };
  }
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

message GetUserRequest {
  string id = 1;
}

message CreateUserRequest {
  string name = 1;
}

message User {
  string id = 1;
  string name = 2;
}


3.gRPC stub 생성


protoc 컴파일러를 사용하여 .proto 파일을 빌드하고 .pb.go 파일을 만듭니다.
protoc -I/usr/local/include -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --go_out=plugins=grpc:. \
  service.proto
path/to/your_service.pb.go가 생성됩니다.

4. reverse-proxy 생성


protoc 컴파일러를 사용하여 .proto 파일을 빌드하고 .pb.gw.go 파일을 만듭니다.
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:. \
  service.proto

5. Gateway / 서버 생성



gateway/서버를 아래와 같이 작성합니다.

greeter_server/main.go
package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "../proto"
)

const (
    port = ":5001"
)

// server is used to implement HelloWorldServer.
type server struct{}

// SayHello implements HelloWorldServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v", in.Name)
    return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

// GetUser
func (s *server) GetUser(ctx context.Context, in *pb.GetUserRequest) (*pb.User, error) {
    log.Printf("Received: %v", in.Id)
    return &pb.User{
        Id: in.Id,
        Name: "SampleUser"}, nil
}

// CreateUser
func (s *server) CreateUser(ctx context.Context, in *pb.CreateUserRequest) (*pb.User, error) {
    log.Printf("Received: %v", in.Name)
    return &pb.User{
        Id: "123",
        Name: in.Name}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterHelloWorldServiceServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}


greeter_gateway/main.go
package main

import (
  "flag"
  "fmt"
  "net/http"

  "github.com/golang/glog"
  "golang.org/x/net/context"
  "github.com/grpc-ecosystem/grpc-gateway/runtime"
  "google.golang.org/grpc"

  gw "../proto"
)

func run() error {
  ctx := context.Background()
  ctx, cancel := context.WithCancel(ctx)
  defer cancel()

  mux := runtime.NewServeMux()
  opts := []grpc.DialOption{grpc.WithInsecure()}
  endpoint := fmt.Sprintf("localhost:5001")
  err := gw.RegisterHelloWorldServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
  if err != nil {
    return err
  }

  return http.ListenAndServe(":5000", mux)
}

func main() {
  flag.Parse()
  defer glog.Flush()

  if err := run(); err != nil {
    glog.Fatal(err)
  }
}

동작 확인



게이트웨이와 서버를 실행해 봅시다.
go run greeter_gateway/main.go

다른 터미널을 열고 다음을 수행합니다.
go run greeter_server/main.go
curl 명령으로 REST API를 실행해 봅시다.
예상대로 데이터를 얻을 수 있습니다.

사용자 이름 (nakata)을 넣고 sayhello로 GET합니다.
curl -X GET http://localhost:5000/v1/example/sayhello/nakata

{"message":"Hello nakata"}

사용자 ID(10)를 넣고 users로 GET합니다.
curl -X GET http://localhost:5000/v1/example/users/10

{"id":"10","name":"SampleUser"}

사용자 이름 (nakata)을 넣고 users로 POST합니다.
curl -X POST http://localhost:5000/v1/example/users -d '{"name":"nakata"}'

{"id":"123","name":"nakata"}

결론



gRPC에 해당하는 RESTful API를 자동 생성했습니다.
gRPC 서버의 구현을 curl 명령으로 확인할 수있었습니다.

좋은 웹페이지 즐겨찾기