はじめに
最近の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
npx create-next-app my-app --typescript
- マイクロサービス
1.Goプロジェクトの初期化
go mod init bff
2.gqlgen(GoのためのGraphQLサーバーツールキット)をインストール
go get github.com/99designs/gqlgen
3.gqlgenの初期セットアップ
go run github.com/99designs/gqlgen init
GraphQLサーバーの実装
スキーマ定義
type Query {
hello: String!
}
type Mutation {
setHello(message: String!): String!
}
リゾルバ
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
}
サーバ
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)
npm install @apollo/client graphql
2.app.tsxでApollo Clientを設定
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クライアントを使用
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
npm run dev
- BFF
go run main.go
- マイクロサービス
go run main.go
まとめ
BFFとSPAの組み合わせは現代のWeb開発で非常に重要です。特にGraphQLを使用することで、データの取得や操作が非常に柔軟になります。Next.jsとGoを用いてこの組み合わせを実現する方法を紹介しましたが、実際のプロジェクトに応じてさまざまな拡張やカスタマイズが考えられます。