🥗
【Go】gRPCをJavaScriptからHTTP経由で接続できるようにする
概要
最近gRPCを個人的に触ってみて、Webのページから呼び出しを試してみました。
GolangでgRPCの記事はけっこうあるのですが、Webから使用できるようにするのに少し手間取ったので、今回メモ書きしてみます。
前提など
- protoファイルの定義など、gRPCに必要な前準備の詳細はGo言語で簡単なgRPCサーバーを作成を参照ください。
- フロントエンドから使用するgRPCのjsはgrpc-webを使って.protoファイルからWEBブラウザ用JSコードを自動生成するを参考に、出力します。
実装サンプル
<protoの定義>
以下のようなprotoをサンプルとして準備します。
メソッドとして、認証コードをリクエストとして設定しユーザ情報を返すものにしています。
authenticationUser.proto
syntax = "proto3";
option go_package = "pb";
package pb;
service AuthenticationUserService {
// 認証コードの検証
rpc VerifyAuthCode (VerifyAuthCodeRequest) returns (UserResponse) {}
}
message VerifyAuthCodeRequest {
string authCode = 1;
}
message UserResponse {
string id = 1;
string name = 2;
}
<サーバサイド>
improbable-eng/grpc-webのライブラリをインストールします。今回使用したバージョンは0.15.0
です。
また、CORSの設定も実装する必要があります。詳細はGolangのgrpcwebでCORSエラーが出る時はOriginFuncを確認しようの記事を参照ください。
main.go
package main
import (
"fmt"
"log"
"net/http"
"os"
"sample-api/src/pb"
"sample-api/src/service"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"google.golang.org/grpc"
)
func main() {
grpcServer := grpc.NewServer()
// サービスの設定(サービスの実装は内容割愛)
pb.RegisterAuthenticationUserServiceServer(grpcServer, service.NewAuthenticationUserService())
// HTTP経由で接続できるようラップする
wrappedServer := grpcweb.WrapServer(
grpcServer,
// CORSの設定
grpcweb.WithOriginFunc(func(origin string) bool {
return origin == "http://localhost:3000"
}),
)
mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(wrappedServer.ServeHTTP))
// ポート8080で起動
hs := &http.Server{
Addr: ":8080",
Handler: mux,
}
log.Fatal(hs.ListenAndServe())
}
<フロントエンド>
google-protobufとgrpc-webのライブラリをインストールします。今回使用したバージョンはgoogle-protobufは3.20.0
、grpc-webは1.3.1
を使用しました。
また、接続部分の実装にあたりこちらのGitHubのissueの内容を参考にしました。実装してみた内容を以下に記載します。
authenticationUserGrpc.js
import { VerifyAuthCodeRequest } from "../pb/authenticationUser_pb";
import { AuthenticationUserServiceClient } from "../pb/authenticationUser_grpc_web_pb";
// サーバサイドの接続先を設定
const authenticationUserService = new AuthenticationUserServiceClient(
"http://localhost:8080"
);
// authCodeからgRPC経由でユーザ情報を取得
export async function getUserFromAuthCodeApi(authCode) {
const request = new VerifyAuthCodeRequest();
request.setAuthcode(authCode);
try {
// 通信部分をPromiseで包む
const verifyAuthCodePromise = new Promise((resolve, reject) => {
authenticationUserService.verifyAuthCode(
request,
null,
(err, response) => {
if (err) {
// エラーの場合は成功フラグfalseのオブジェクトを返す
reject({
succcess: false,
});
} else {
// 成功の場合はresponseからユーザ情報を取得
resolve({
succcess: true,
user: {
id: response.getId(),
name: response.getName(),
},
});
}
}
);
});
// Promiseの実行
return await verifyGoogleAuthCodePromise;
} catch (_) {
return { succcess: false };
}
}
Discussion