ホーム自己紹介ブログ
NO.87
DATE2022. 08. 20

connect-webやってみた

connect-web の記事が、はてブでトレンドになっていました。気になったので、試してみました。

サンプルコードは、次のリポジトリに置いています。

  • https://github.com/silverbirder/playground/tree/main/node/connect-web-example/frontend

前置き: gRPC と connect-web の雑な理解

RPC (Remote Procedure Call) を実現するためのプロトコルとして、gRPC があります。 このプロトコルは、ブラウザ側からは使えない(?)ため、gRPC-Web というブラウザ向けの gRPC というものを使うことになります。 その場合、ブラウザとサーバーとの間に、プロキシを建てる必要があるようです。(たぶん)

そこで、Connect という gRPC 互換の HTTP API を構築するためのライブラリ群が開発されました。 これのおかげで、プロキシを建てる必要がなく、ブラウザ側から gRPC を使うことが可能になります。

  • https://connect.build/docs/introduction

上記ページに、バックエンドは connect-go、フロントエンドは connect-web という項目があります。 connect-web は、ブラウザから RPC を動かすための小さなライブラリです。タイプセーフなライブラリなため、 型補完が効きます。 connect-go は、go で Connect のサービスを作ることができます。

そのため、フロントエンドの開発は、connect-web を使うことになります。 以降は、フロントエンドの作業を、紹介します。ちなみに、React を使います。

やってみた

フロントエンド側は、主に、次の 2 つの作業になります。

  1. Protocol Buffer スキーマから TypeScript ファイルを生成
  2. 生成された TypeScript ファイルから gRPC クライアントを実装

1. Protocol Buffer スキーマから TypeScript ファイルを生成

gRPC で通信するためのスキーマ、ProtocolBuffer スキーマが必要です。 これは、すでにあるものを使います。

  • https://buf.build/bufbuild/eliza

具体的には、次のようなスキーマです。

syntax = "proto3";
 
service ElizaService {
  rpc Say(SayRequest) returns (SayResponse) {}
}
 
message SayRequest {
  string sentence = 1;
}
 
message SayResponse {
  string sentence = 1;
}

TypeScript コードを生成するために、buf という CLI を使います。 buf で利用する、次の定義ファイルを書きます。

## buf.gen.yaml
 
## buf.gen.yaml defines a local generation template.
## For details, see https://docs.buf.build/configuration/v1/buf-gen-yaml
version: v1
plugins:
  - name: es
    path: node_modules/.bin/protoc-gen-es
    out: gen
    # With target=ts, we generate TypeScript files.
    # Use target=js+dts to generate JavaScript and TypeScript declaration files
    # like remote generation does.
    opt: target=ts
  - name: connect-web
    path: node_modules/.bin/protoc-gen-connect-web
    out: gen
    # With target=ts, we generate TypeScript files.
    opt: target=ts

これは、後述する buf generate するときにどういう出力をするかの設定情報です。 codegen の yaml ファイルみたいなものかなと思います。 これを動かすために、次の module をインストールしましょう。

## plugin
yarn add --dev @bufbuild/protoc-gen-connect-web @bufbuild/protoc-gen-es
## runtime
yarn add @bufbuild/connect-web @bufbuild/protobuf
  • plugin
    • protoc-gen-es
      • リクエストやレスポンスメッセージのような基本型を生成
    • protoc-gen-connect-web
      • Protocol Buffer スキーマからサービスを生成
  • runtime
    • bufbuild/connect-web
      • Connect および gRPC-web プロトコルのクライアントを提供
    • bufbuild/protobuf
      • 基本型に対するシリアライズなどを提供

次に、bufをインストールしましょう。 私は、brew でインストールしました。

brew install bufbuild/buf/buf
## ref: https://github.com/bufbuild/buf#installation

では、ProtocolBuffer スキーマから TypeScript ファイルを生成しましょう。

buf generate --template buf.gen.yaml buf.build/bufbuild/eliza

成功すると、次の 2 つの TypeScript ファイルが生成されます。

  • gen/buf/connect/demo/eliza/v1/eliza_connectweb.ts
  • gen/buf/connect/demo/eliza/v1/eliza_pb.ts

eliza_connectweb.tsは、次のコードが含まれています。

// eliza_connectweb.ts
import { SayRequest, SayResponse } from "./eliza_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
 
export const ElizaService = {
  typeName: "ElizaService",
  methods: {
    say: {
      name: "Say",
      I: SayRequest,
      O: SayResponse,
      kind: MethodKind.Unary,
    },
  },
} as const;

eliza_pb.tsは、次のコードが含まれています。

export class SayRequest extends Message<SayRequest> {
  /**
   * @generated from field: string sentence = 1;
   */
  sentence = "";
 
  constructor(data?: PartialMessage<SayRequest>) {
    super();
    proto3.util.initPartial(data, this);
  }
 
  static readonly runtime = proto3;
  static readonly typeName = "buf.connect.demo.eliza.v1.SayRequest";
  # ... 省略 ...
}
 
/**
 * SayResponse describes the sentence responded by the ELIZA program.
 *
 * @generated from message buf.connect.demo.eliza.v1.SayResponse
 */
export class SayResponse extends Message<SayResponse> {
  /**
   * @generated from field: string sentence = 1;
   */
  sentence = "";
 
  constructor(data?: PartialMessage<SayResponse>) {
    super();
    proto3.util.initPartial(data, this);
  }
 
  static readonly runtime = proto3;
  static readonly typeName = "buf.connect.demo.eliza.v1.SayResponse";
  # ... 省略 ...
}

これで、準備はできました。

2. 生成された TypeScript ファイルから gRPC クライアントを実装

では、gRPC のクライアントを実装しましょう。 gRPC のクライント生成は、createPromiseClient でできます。 生成時の引数に、サービスとトランスポート(?)というものを渡す必要があります。 コードを見たほうがわかりやすいと思うので、次のコードを見てください。

// client.ts
import { useMemo } from "react";
import { ServiceType } from "@bufbuild/protobuf";
import {
  createConnectTransport,
  createPromiseClient,
  PromiseClient,
  Transport,
} from "@bufbuild/connect-web";
 
const transport = createConnectTransport({
  baseUrl: "https://demo.connect.build", # バックエンド側のURL
});
 
export function useClient<T extends ServiceType>(service: T): PromiseClient<T> {
  return useMemo(() => createPromiseClient(service, transport), [service]);
}

このクライアントを、使ってみましょう。

// App.tsx
 
import { createConnectTransport, Interceptor } from "@bufbuild/connect-web";
import { ElizaService } from "../gen/buf/connect/demo/eliza/v1/eliza_connectweb";
import { useClient } from "./client";
 
function App() {
  const client = useClient(ElizaService);
  client
    .say({
      sentence: "hello",
    })
    .then(({ sentence }) => {
      console.log(sentence);
    });
  // ...
}

このように、ProtocolBuffers の ElizaService が、型補完として使えるようになります。 良い感じです!

終わりに

意外とあっさり動いて、びっくりしました。

バックエンド
フロントエンド
クローリング

-

読者になる

|

シェアする

|

silverbirders

silverbirder

Webソフトウェアエンジニア

ブログを応援する

この記事がよかったら、お布施という形で応援してもらえるとうれしいです。

おふせぼたん

※ ログイン不要で投稿できます。

※ 同じブラウザから投稿を削除できます。

0

読み込み中...

次の記事へ前の記事へ

関連する記事

タグ「バックエンド」の記事

Storybook上で tRPC通信をMSWでモックする方法

はじめに tRPCは、型安全なAPIを簡単に構築できるフレームワークです。開発中、バックエンドの実装を待たずに、Storybook上でフロントエンドの開発を進めたい場合、Mock Service Worker (MSW) を使用してAPIのモックを行うことができます。この記事では、maloguertin/msw-trpc を用いて、tRPC通信をMSWでモックする方法について解説します。実用例として、サンプルコードをGitHubリポジトリ silverbirder/trpc-msw-storybook-nextjs で共有しています。

2024年03月07日

テスト
バックエンド
GraphQL Guildのエコシステムって便利だね

GraphQL Guild ってご存知ですか?GraphQL 界隈だと、Code Generator が有名と思いますが

2022年10月15日

バックエンド
Stable Diffusion API 開発

Stable Diffusion は、文章を渡すと画像を生成してくれる AI で OSS です。これを自前で動かそうとすると、GPU が必要になります。

2022年09月03日

AI
バックエンド
成果物

タグ「フロントエンド」の記事

Webフロントエンドのコードレビューメモ2

また、以下の記事の続きを書こうと思います。 https://silverbirder.github.io/blog/contents/20260312/ ビジネスロジック アプリケーションのビジネスロジックに関することについて書きます。 複

2026年03月18日

フロントエンド
Webフロントエンドのコードレビューメモ

Webフロントエンドのコードレビューをしているときに考えていることについて書きます。 毎日1記事投稿、1記事30分という制約を課していますので、本記事は完璧ではありません。(言い訳) また希望的な考えもあるので、実践していないものもあります

2026年03月12日

フロントエンド
AIの書いたコードの手直しを減らすお作法

AI にコードを書かせた後、余計なコードを見つけて消す作業があります。 不毛なことなので、それらの作業を減らすためのお作法を紹介します。 未使用コードを消す 以下でも書きましたが、未使用コードの検査に knip を使うことが多いです。 ht

2026年02月25日

AI
フロントエンド

タグ「クローリング」の記事

zodのrefineにあるpathにハマった

zodのrefineを使っていたのですが、pathの使い方を全く理解できておらず、小一時間ほどハマってしまったことがあったので、備忘録として残しておきます。

2023年01月07日

フロントエンド
クローリング
JavaScript
ObsidianでiPhoneからGit Commitする

WikiWikiWeb というコンセプトが好きで、そのコンセプトが含まれている Obsidian や Scrapbox が好きです。Obsidian には、obsidian-gitという Git 連携のプラグインがあります。こちらには、デスクトップだけでなく、モバイルからでも Git Commit できるようになりました。

2022年10月18日

開発ツール
クローリング
クローリングをシュッとやるのに、Crawleeが便利だった

スクレイピングしたいときって、あると思います。Crawlee という OSS が便利だったので、共有します。

2022年09月14日

クローリング
← ブログ一覧へ