SWEet

A Software Engineer Is Eating Technologies

Goのプロジェクト内でgRPCで自分で定義したprotoファイルをimportする

自分で作ったprotoファイルを他のprotoファイルから参照する時にハマったのでメモ

サンプルプロジェクトの構成

.
├── Makefile
├── team
│   └── handler
│       └── grpc
│           └── team
│               ├── team.pb.go
│               └── team.proto
└── user
    └── handler
        └── grpc
            └── user
                ├── user.pb.go
                └── user.proto

8 directories, 5 files

構成はクリーンアーキテクチャライクにしています

proto ファイル

userから

syntax = "proto3";

package user;


service UserAPI {
    rpc GetUsers(User) returns (Users) {}
    rpc Show(User) returns (User) {}
    rpc Delete(User) returns (Empty) {}
    rpc Invite(User) returns (Empty) {}
    rpc Activate(ActivateRequest) returns (ActivateResponse) {}
}

message User {
    int64 id = 1;
    int64 team_id = 2;
    string name = 3;
    string email = 4;
    string password = 5;
    bool isOwner = 8;
}



message ActivateRequest {
    string code = 1;
}

message ActivateResponse {
    string token = 1;
}

message Users {
    repeated User Users = 1;
}

message Empty {}

普通のprotoファイルです

次はteam

syntax = "proto3";
package team;
import "github.com/Bo0km4n/go-protobuf-ref-sample/user/handler/grpc/user/user.proto";
service TeamAPI {
}

message Team {
    int64 id = 1;
    string name = 2;
    user.Users users = 3;
}

message InviteRequest {
    string team = 1;
    string email = 2;
    string password = 3;
}

message ActivateRequest {
    string code = 1;
}

message ActivateResponse {
    string token = 1;
}

message Empty {}

userを内部で参照しています。

コンパイル

最初は以下のページを参考にコンパイルを行っていましたが生成されるpbファイルのimportパスが相対パスになっており go build 時に参照できません

qiita.com

そこで上記のように github.com/... のように通常のgoのimportパスと同様にすることでこの問題を解決します

ビルドに使用するmakefileをつぎのように書きました

PROTO_TARGETS = user team
PROJECT_PATH = github.com/Bo0km4n/go-protobuf-ref-sample 
proto: 
   @echo $(PROTO_TARGETS); \
      cd $$GOPATH/src; \
  for t in $(PROTO_TARGETS); do \
      echo "protobuf build ... $$t"; \
      protoc --go_out=plugins=grpc:. $(PROJECT_PATH)/$$t/handler/grpc/$$t/$$t.proto; \
  done

最初にechoしているのはしないと cd のせいなのか Nothing to done って言われるからです

上記のリンクではプロジェクトのルート以下のパスが生成されるimportパスになっていました。 つまり、$GOPATH/src で上記のビルドを行えば生成されるimportパスが正常になります。

実際に生成されたteamのpbファイルは次のようになります

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/Bo0km4n/go-protobuf-ref-sample/team/handler/grpc/team/team.proto

package team

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import user "github.com/Bo0km4n/go-protobuf-ref-sample/user/handler/grpc/user"

import (
    context "golang.org/x/net/context"
    grpc "google.golang.org/grpc"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package

type Team struct {
    Id                   int64      `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
    Name                 string     `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
    Users                *user.Users `protobuf:"bytes,3,opt,name=users" json:"users,omitempty"`
    XXX_NoUnkeyedLiteral struct{}   `json:"-"`
    XXX_unrecognized     []byte     `json:"-"`
    XXX_sizecache        int32      `json:"-"`
}

... 以下省略

これでプロジェクトのビルドも上手くいきます

$GOPATH/src に移動するのは少々スマートではない気がしますが色々調べて他に良いやり方がなかったので今回は妥協しました

一応今回のサンプルをgithubにあげておきます

github.com