🔰GraphQLについて　〜TS/React/Nextjs/Goサンプルコード付き〜

# はじめに
最近のWeb開発では、SPAとBFFの組み合わせが採用されていることが増えています。このブログでは、Next.jsを使用したSPAとGoで実装されたGraphQLサーバーを使用したBFFを連携させる方法を解説します。

# BFFとは
BFFは「Backend for Frontend」の略で、特定のフロントエンド（例: モバイルアプリ、Webページ）のためにカスタマイズされたバックエンドインターフェースのことを指します。従来の一般的なAPIは、多くの異なるクライアントに対応することを目的としていますが、BFFは特定のクライアントの要件に特化して設計されるため、そのクライアントに最適化されたデータや機能を提供することが可能です。

BFFはマイクロサービスアーキテクチャの中で人気を集め、各フロントエンドが独自のBFFを持つことで、フロントエンドチームがバックエンドのサービスの詳細や変更から独立して動けるようになりました。

# GraphQLとは
GraphQLはFacebookが2015年に公開したデータクエリ言語およびランタイムです。RESTful APIの代わりとして使うことができ、クライアントが必要なデータだけを正確に取得することが可能です。これにより、過剰または不足するデータの取得を防ぐことができ、ネットワーク使用量の効率化やパフォーマンスの向上が期待できます。

### GraphQLの特徴
+ 強力な型システム
スキーマ定義により、APIの形状とデータ型を明確に定義。
+ 柔軟なクエリ
クライアントが必要なデータだけをリクエストし、サーバーはそれに応じたデータを返す。
+ 単一のエンドポイント
複数のRESTエンドポイントの代わりに、1つのエンドポイントですべてのクエリと変更を処理。

# 基本概念
+ SPA (Single Page Application)
ブラウザ内で動的に再描画されるWebアプリ。サーバーから新しいページ全体を取得するのではなく、必要なデータだけを取得して表示内容を更新。
+ BFF (Backend for Frontend)
特定のフロントエンド（モバイル、ウェブなど）のためのバックエンド層。フロントエンドの要件に合わせてAPIを提供。
+ マイクロサービス
小さなサービスに分割されたシステム。それぞれのサービスは独立して動作・デプロイが可能。

# 技術スタックの選択
+ React + Next.js
JavaScriptフレームワーク。SSRやISR、静的サイト生成が可能。
+ GraphQL
クエリ言語とサーバーサイドランタイム。データの取得や変更を効率的に行う。
+ Go
パフォーマンスが高く、簡潔で読みやすい言語。マイクロサービスの開発に適している。

# プロジェクトのセットアップ
+ SPA
```bash
npx create-next-app my-app --typescript
```

+ マイクロサービス
1.Goプロジェクトの初期化
```bash
go mod init bff
```

2.gqlgen（GoのためのGraphQLサーバーツールキット）をインストール
```bash
go get github.com/99designs/gqlgen
```

3.gqlgenの初期セットアップ
```bash
go run github.com/99designs/gqlgen init
```

# GraphQLサーバーの実装
### スキーマ定義
```graphql:schema.graphql
type Query {
  hello: String!
}

type Mutation {
  setHello(message: String!): String!
}
```

### リゾルバ
```go:resolver.go
package main

import (
  "context"
)

type Resolver struct{
  message string
}

func (r *Resolver) Query() QueryResolver {
  return &queryResolver{r}
}

func (r *Resolver) Mutation() MutationResolver {
  return &mutationResolver{r}
}

type queryResolver struct{ *Resolver }

func (r *queryResolver) Hello(ctx context.Context) (string, error) {
  return r.message, nil
}

type mutationResolver struct{ *Resolver }

func (r *mutationResolver) SetHello(ctx context.Context, message string) (string, error) {
  r.message = message
  return message, nil
}
```

### サーバ
```go:main.go

import (
	"log"
	"net/http"
	"github.com/99designs/gqlgen/graphql/handler"
	"github.com/99designs/gqlgen/graphql/playground"
)

const defaultPort = "8080"

func main() {
	port := defaultPort

	srv := handler.NewDefaultServer(NewExecutableSchema(New()))

	http.Handle("/graphql", srv)
	http.Handle("/", playground.Handler("GraphQL playground", "/graphql"))

	log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

# SPAとBFFの連携
1.Apollo Clientのセットアップ(SPA)
```bash
npm install @apollo/client graphql
```

2.app.tsxでApollo Clientを設定
```tsx:app.tsx
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/graphql',
  cache: new InMemoryCache()
});

function MyApp({ Component, pageProps }) {
  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  );
}

export default MyApp;
```

# マイクロサービスとの連携
1.GoでHTTPクライアントを使用
```go
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	response, err := http.Get("http://localhost:5000/service-endpoint")
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(body))
}
```
エンドポイント：http://localhost:5000/service-endpoint

各種サーバを起動します
+ SPA
```bash
npm run dev
```

+ BFF
```bash
go run main.go
```

+ マイクロサービス
```bash
go run main.go
```

# まとめ
BFFとSPAの組み合わせは現代のWeb開発で非常に重要です。特にGraphQLを使用することで、データの取得や操作が非常に柔軟になります。Next.jsとGoを用いてこの組み合わせを実現する方法を紹介しましたが、実際のプロジェクトに応じてさまざまな拡張やカスタマイズが考えられます。