🔍

シンプルで使いやすい新たなRPCライブラリ~oRPCとは何者か?~

はじめに

こんにちは、エンジニアの籏野です。

先日、oRPCというライブラリのV1がリリースされました。
https://x.com/unnoqcom/status/1912153521060987057

oRPCはTypeScriptを利用するシステムにおいてRPC(Remote Procedure Call)を実現するためのライブラリです。
RPCの特徴は、クライアント側からはメソッドを呼び出すような感覚でAPIを利用することができ、REST APIのようにエンドポイントを意識する必要がなくなることが挙げられます。
RPCを実現する有名なライブラリとしてtRPCがありますが、どのような違いがあるのかが気になり調べてみました。

今回はブログに投稿されたV1発表記事を参考にどのような特徴があるのかをまとめていきます。

https://orpc.unnoq.com/blog/v1-announcement

強力なシンプルさ

ブログではoRPCの理念として、「強力なシンプルさ(powerful simplicity)」を掲げています。
これはどういうことなのか、tRPCとoRPCでプロシージャの定義方法を見比べていきましょう。

IDを指定してユーザーを取得するプロシージャを定義する場合、tRPCでは以下のように定義します。

server/trpc.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;
server/index.ts
import { z } from 'zod';
import { router, publicProcedure } from './trpc';
 
const appRouter = router({
  userById: publicProcedure
    .input(
      z.object({
        id: z.string()
      })
    )
    .query(async (opts) => {
      const { input } = opts;
      // do something
      return user;
    }),
  ...
});

一方、oRPCでは以下のように定義します。

import { os } from '@orpc/server'
import { z } from 'zod'

export const getUserById = os
  .input(
    z.object({
      id: z.string()
    }),
  )
  .handler(async ({ input }) => {
    // do something
    return user;
  })

export const router = {
  user: {
    get: getUserById,
  ...
  }
}

作者はtRPCのセットアップの複雑さに対して課題感を掲げており、インポートしたosというオブジェクトを利用して即座にRPCを構築できる点にこだわりを感じます。

またクライアント側での利用方法も比較しておきましょう。

tRPCの場合は以下のようになります。

import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';

const trpc = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000',
    }),
  ],
});

trpc.userById(...)

oRPCの場合は以下のようになり、ここについては大きな違いはなく同じような使用感で利用できそうです。

import type { RouterClient } from '@orpc/server'
import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'

const link = new RPCLink({
  url: 'http://127.0.0.1:3000',
})

export const orpc: RouterClient<typeof router> = createORPCClient(link);

orpc.user.get(...)

OpenAPIサポート

ブログではOpenAPIのサポートも大きな特徴として挙げています。
tRPCでもtrpc-openapiを利用することでOpenAPIサポートが可能でしたが、このライブラリは現在メンテナンスされていません。
oRPCでは以下のようにOpenAPIHandlerを利用することですぐにOpenAPI定義を生成可能です。

import { OpenAPIHandler } from "@orpc/openapi/node";
import { CORSPlugin } from "@orpc/server/plugins";

const handler = new OpenAPIHandler(router, {
  plugins: [new CORSPlugin()],
});

ベンチマーク

oRPCとtRPCを比較したベンチマークも示されており、以下のような結果となっています。

評価項目 oRPC tRPC 改善率
型チェック速度 5.9秒 9.3秒 1.6倍高速
ランタイム性能 295,000リクエスト/20秒 104,000リクエスト/20秒 2.8倍高速
最大CPU使用率 102% 129% 1.26倍低減
最大RAM使用量 103MB 268MB 2.6倍低減
バンドルサイズ 32.3kB 65.5kB 2倍小型化

まとめ

ドキュメントを見てみると分かるのですが、oRPCは非常に多くの機能を持っておりこの記事で挙げたもの以外にも様々なポイントを推しだしています。

  • End-to-End Type Safety
  • First-Class OpenAPI
  • Contract-First Development
  • Framework Integrations
  • Server Actions
  • Standard Schema Support
  • Native Types
  • Lazy Router
  • SSE & Streaming
  • Multi-Runtime Support
  • Extendability
  • Reliability

またドキュメントの「Integrations」の欄を見ると、Next.js/Honoなど様々なフレームワーク上で動かせるのも個人的には嬉しいポイントであると感じています。
今後のAPI構築の際の選択肢として、大きく発展していくことを期待しています。

この記事を書いた人

籏野 拓
2018年新卒入社

FORCIA Tech Blog

Discussion