GoでgRPCサーバーを立ててみる4（service.go、server.goの実装）

お疲れ様です。

今日は「service.go、server.goの実装」について部分いたします。

# service.goの実装

repositoryでやり取りしたデータをもとにgRPCのレスポンスを返すservice.goの実装をしていきます。

```article/service/service.go
package service

import (
	"context"

	"github.com/k88t76/GraphQL-gRPC-demo/article/pb"
	"github.com/k88t76/GraphQL-gRPC-demo/article/repository"
)

type Service interface {
	CreateArticle(ctx context.Context, req *pb.CreateArticleRequest) (*pb.CreateArticleResponse, error)
	ReadArticle(ctx context.Context, req *pb.ReadArticleRequest) (*pb.ReadArticleResponse, error)
	UpdateArticle(ctx context.Context, req *pb.UpdateArticleRequest) (*pb.UpdateArticleResponse, error)
	DeleteArticle(ctx context.Context, req *pb.DeleteArticleRequest) (*pb.DeleteArticleResponse, error)
	ListArticle(req *pb.ListArticleRequest, stream pb.ArticleService_ListArticleServer) error
}

type service struct {
	repository repository.Repository
}

func NewService(r repository.Repository) Service {
	return &service{r}
}

func (s *service) CreateArticle(ctx context.Context, req *pb.CreateArticleRequest) (*pb.CreateArticleResponse, error) {
	// 記事のCREATE処理
}

func (s *service) ReadArticle(ctx context.Context, req *pb.ReadArticleRequest) (*pb.ReadArticleResponse, error) {
	// 記事のREAD処理
}

func (s *service) UpdateArticle(ctx context.Context, req *pb.UpdateArticleRequest) (*pb.UpdateArticleResponse, error) {
	// 記事のUPDATE処理
}

func (s *service) DeleteArticle(ctx context.Context, req *pb.DeleteArticleRequest) (*pb.DeleteArticleResponse, error) {
	// 記事のDELETE処理
}

func (s *service) ListArticle(req *pb.ListArticleRequest, stream pb.ArticleService_ListArticleServer) error {
	// 記事の全取得処理
}
```

## CREATE

```article/service/service.go
func (s *service) CreateArticle(ctx context.Context, req *pb.CreateArticleRequest) (*pb.CreateArticleResponse, error) {
	// INSERTする記事のInput(Author, Title, Content)を取得
	input := req.GetArticleInput()

	// 記事をDBにINSERTし、INSERTした記事のIDを返す
	id, err := s.repository.InsertArticle(ctx, input)
	if err != nil {
		return nil, err
	}

	// INSERTした記事をレスポンスとして返す
	return &pb.CreateArticleResponse{
		Article: &pb.Article{
			Id:      id,
			Author:  input.Author,
			Title:   input.Title,
			Content: input.Content,
		},
	}, nil
}
```

## READ

```article/service/service.go
func (s *service) ReadArticle(ctx context.Context, req *pb.ReadArticleRequest) (*pb.ReadArticleResponse, error) {
	// READする記事のIDを取得
	id := req.GetId()

	// DBから該当IDの記事を取得
	a, err := s.repository.SelectArticleByID(ctx, id)
	if err != nil {
		return nil, err
	}

	//　取得した記事をレスポンスとして返す
	return &pb.ReadArticleResponse{
		Article: &pb.Article{
			Id:      id,
			Author:  a.Author,
			Title:   a.Title,
			Content: a.Content,
		},
	}, nil
}
```

## UPDATE

```
func (s *service) UpdateArticle(ctx context.Context, req *pb.UpdateArticleRequest) (*pb.UpdateArticleResponse, error) {
	// UPDATEする記事のIDを取得
	id := req.GetId()

	// UPDATEする記事の変更内容(Author, Title, Content)を取得
	input := req.GetArticleInput()

	//　該当IDの記事をUPDATE
	if err := s.repository.UpdateArticle(ctx, id, input); err != nil {
		return nil, err
	}

	// UPDATEした記事をレスポンスとして返す
	return &pb.UpdateArticleResponse{
		Article: &pb.Article{
			Id:      id,
			Author:  input.Author,
			Title:   input.Title,
			Content: input.Content,
		},
	}, nil
}
```

## DELETE

```article/service/service.go
func (s *service) DeleteArticle(ctx context.Context, req *pb.DeleteArticleRequest) (*pb.DeleteArticleResponse, error) {
	// DELETEする記事のIDを取得
	id := req.GetId()

	// 該当IDの記事をDELETE
	if err := s.repository.DeleteArticle(ctx, id); err != nil {
		return nil, err
	}

	// DELETEした記事のIDをレスポンスとして返す
	return &pb.DeleteArticleResponse{Id: id}, nil
}
```

## 全取得

```article/service/service.go
func (s *service) ListArticle(req *pb.ListArticleRequest, stream pb.ArticleService_ListArticleServer) error {
	// 記事を全取得
	rows, err := s.repository.SelectAllArticles()
	if err != nil {
		return err
	}
	defer rows.Close()

	// 取得した記事を１つ１つレスポンスとしてServer Streamingで返す
	for rows.Next() {
		var a pb.Article
		err := rows.Scan(&a.Id, &a.Author, &a.Title, &a.Content)
		if err != nil {
			return err
		}
		stream.Send(&pb.ListArticleResponse{Article: &a})
	}
	return nil
}
```

これでarticleサービスの実装は完了です！

# server.goの実装

gRPCサーバーを起動するserver.goの実装をしていきます。
今回gRPCサーバーはgRPCのデフォルトポートである50051に立てることにします。

```article/server/server.go
package main

import (
	"log"
	"net"

	"github.com/k88t76/GraphQL-gRPC-demo/article/pb"
	"github.com/k88t76/GraphQL-gRPC-demo/article/repository"
	"github.com/k88t76/GraphQL-gRPC-demo/article/service"
	"google.golang.org/grpc"
)

func main() {

	// articleサーバーに接続
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v\n", err)
	}
	defer lis.Close()

	// Repositoryを作成
	repository, err := repository.NewsqliteRepo()
	if err != nil {
		log.Fatalf("Failed to create sqlite repository: %v\n", err)
	}
	
	// Serviceを作成
	service := service.NewService(repository)

	//サーバーにarticleサービスを登録
	server := grpc.NewServer()
	pb.RegisterArticleServiceServer(server, service)

	//articleサーバーを起動
	log.Println("Listening on port 50051...")
	if err := server.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
```

上記のようにしてarticleサービスを実装したgRPCサーバーを立てることができます。
試しに起動してみましょう。

```terminal
go run article/server/server.go
```

起動するとDBが作成され、articleディレクトリにarticle.sqlが現れたはずです。

次はclient.goの実装をしていきましょう！

今日は以上です。

ありがとうございました。

よろしくお願いいたします。