ホーム自己紹介ブログ
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 が、型補完として使えるようになります。 良い感じです!

終わりに

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

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

-

シェアする

フォローする

次のページ

CI/CDのDaggerで、GithubActionsとCircleCIにシュッと連携してみた

前のページ

urqlでデータ変換(transform)してみた

関連する記事

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

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
バックエンド
成果物

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

ヒューマンインターフェース ガイドライン という言葉を知りました。

最近、ヒューマンインターフェース ガイドライン(HIG)という言葉を知りました。 「ヒューマンインターフェイスガイドライン」には、どのAppleプラットフォームでも優れた体験を設計できるようにするためのガイドとベストプラクティスが含まれてい

2026-01-24

フロントエンド
AIの利用上限に達した時にすることを残しておく

主にWeb関連の個人開発をしている際に心がけていることを書きます。 月末に近づくにつれ、AIの利用上限に達してしまうことがあります。 その状況になった時、以下のいずれかの選択肢が私の中では残っています。 課金して利用上限を増やす 無料モデル

2026-01-22

フロントエンド
AI
CSSで頑張らなくても、SVGで楽にできるときもある

個人サイトをリニューアルをしています。 ノート風のデザインを目指して、スタイルを調整していました。 ノートの見た目は、現実にあるノートを再現しようとCSSを書いていました。 現在、以下の画像のようなノートになっています。 ノート風デザインの

2026-01-20

フロントエンド

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

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

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