📑

Bufを利用して、Grpcサーバ(Go)を爆速で作成する!

2024/07/03に公開

目的

以前まで、protoc のみ利用して proto ファイルから Go への変換を行なっていた。しかし,パスが間違ったり、記述方法(変数名など)がわかなかったり、複数の proto ファイルを一度に go に変換することが大変だった(makefile などに記述する必要があった). そのため proto ファイルを管理するパッケージとして Buf を利用することにした.

Buf とは

一言で言うと
proto ファイルを管理する CLI(高性能な Protocbuf コンパイラ)

  • 文法のエラー検出
  • lint 機能(チームでルールを統一することができる)
  • 設定可能なテンプレートに基づいて protoc プラグインを呼び出すコードジェネレーター

github

https://github.com/nagisa599/Go-Grpc-Template

実装

package のインストール

brew install bufbuild/buf/buf

buf.yaml ファイルの生成

buf.yaml
version: v1
# モジュール名
name: buf.build/tutorials/lint
# lint設定
lint:
  use:
    - DEFAULT # デフォルトルールを使用

Protobuf ファイルの作成(schema の作成)

todo.proto
syntax = "proto3";

package proto.todo.v1;

// Defines the Todo service
service TodoService {
    // Defines a method to get a todo item
    rpc GetTodo (GetTodoRequest) returns (GetTodoResponse);
    // Defines a method to create a todo item
    rpc CreateTodo (CreateTodoRequest) returns (CreateTodoResponse);
}

// Response message for getting a todo item
message GetTodoResponse {
    int32 id = 1;
    string title = 2;
    string description = 3;
}

// Request message for getting a todo item
message GetTodoRequest {
    int32 id = 1;
}

// Response message for creating a todo item
message CreateTodoResponse {
    int32 id = 1;
    string title = 2;
    string description = 3;
}

// Request message for creating a todo item
message CreateTodoRequest {
    string title = 1;
    string description = 2;
}

buf.gen.yaml ファイルの作成

buf.gen.yaml
version: v1
# マネージドモードを有効
managed:
  enabled: true
  go_package_prefix:
    default: github.com/JY8752/buf-demo/example/gen # デフォルトのpackage名を指定。これは必須
plugins:
  # protoc-gen-goプラグイン
  # - plugin: go
  #   out: gen/go
  #   opt: paths=source_relative
  # リモートプラグインを使用
  - plugin: buf.build/protocolbuffers/go:v1.31.0
    out: gen/go
    # GoのモジュールパスがProtobufファイルから相対的に解決されるよう指定
    # なくてもいいがないと上で指定したdefaultのフルパスが使われる
    opt: paths=source_relative
  # protoc-gen-go-grpcプラグイン
  - plugin: buf.build/grpc/go:v1.3.0
    out: gen/go
    opt: paths=source_relative

proto ファイルから go を生成

buf generate proto

gRPC サーバの実装

main.go
package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"

	"todoService/cmd/server/controller"
	todov1 "todoService/gen/go/todo/v1"

	"google.golang.org/grpc"
)

// 自作サービス構造体のコンストラクタを定義

func main() {
	// 1. 8080番portのLisnterを作成
	port := 8080
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		panic(err)
	}
	grpcTaskController := controller.NewGrpcController()
	// 2. gRPCサーバーを作成
	s := grpc.NewServer()
	todov1.RegisterTodoServiceServer(s, grpcTaskController)
	// 3. 作成したgRPCサーバーを、8080番ポートで稼働させる
	go func() {
		log.Printf("start gRPC server port: %v", port)
		s.Serve(listener)
	}()

	// 4.Ctrl+Cが入力されたらGraceful shutdownされるようにする
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("stopping gRPC server...")
	s.GracefulStop()
}
todo_controller.go
package controller

import (
	"context"
	todov1 "todoService/gen/go/todo/v1"
)

type grpcTodoController struct {
	todov1.UnimplementedTodoServiceServer
}

func NewGrpcController() *grpcTodoController {
	return &grpcTodoController{}
}

func (s *grpcTodoController) GetTodo(ctx context.Context, req *todov1.GetTodoRequest) (*todov1.GetTodoResponse, error) {
	return &todov1.GetTodoResponse{
		Id: 1,
		Title: "title",
		Description: "description",
	}, nil
}

postman によるテスト

GitHubで編集を提案

Discussion