fontcolor_theme
Deepkit RPC

はじめに

Deepkit RPC を使用するには、ランタイム型に基づいているため @deepkit/type を正しくインストールしておく必要があります。 ランタイム型のインストール を参照してください。

これが完了したら、ライブラリを内部で既に使用している @deepkit/rpc または Deepkit Framework をインストールできます。

npm install @deepkit/rpc

なお、@deepkit/rpc の Controller クラスは TypeScript のデコレーターに基づいており、この機能を使用するには experimentalDecorators を有効にする必要があります。

サーバーとクライアントがそれぞれ独自の package.json を持つ場合は、@deepkit/rpc パッケージを両方にインストールする必要があります。

サーバーと TCP で通信するには、クライアントとサーバーの両方に @deepkit/rpc-tcp パッケージをインストールする必要があります。

npm install @deepkit/rpc-tcp

WebSocket 通信を行う場合、サーバー側にもこのパッケージが必要です。一方で、ブラウザー内のクライアントは標準の WebSocket を使用します。

クライアントを WebSocket が利用できない環境(例: NodeJS)でも使用する場合は、クライアント側に ws パッケージが必要です。

npm install ws

使い方

以下は、WebSocket と @deepkit/rpc の低レベル API に基づく完全に動作するサンプルです。Deepkit Framework を使用する場合、Controller はアプリのモジュール経由で提供され、RpcKernel を手動でインスタンス化する必要はありません。

ファイル: server.ts

import { rpc, RpcKernel } from '@deepkit/rpc';
import { RpcWebSocketServer } from '@deepkit/rpc-tcp';

@rpc.controller('/main')
export class Controller {
    @rpc.action()
    hello(title: string): string {
        return 'Hello ' + title;
    }
}

const kernel = new RpcKernel();
kernel.registerController(Controller);
const server = new RpcWebSocketServer(kernel, 'localhost:8081');
server.start({
    host: '127.0.0.1',
    port: 8081,
});
console.log('Server started at ws://127.0.0.1:8081');

ファイル: client.ts

import { RpcWebSocketClient } from '@deepkit/rpc';
import type { Controller } from './server';

async function main() {
    const client = new RpcWebSocketClient('ws://127.0.0.1:8081');
    const controller = client.controller<Controller>('/main');

    const result = await controller.hello('World');
    console.log('result', result);

    client.disconnect();
}

main().catch(console.error);

サーバーの Controller

Remote Procedure Call における「Procedure」という用語は、「Action」とも一般的に呼ばれます。Action はクラス内で定義されたメソッドで、@rpc.action デコレーターでマークされます。クラス自体は @rpc.controller デコレーターで Controller としてマークされ、一意の名前が与えられます。この名前は、クライアントで正しい Controller にアクセスするために参照されます。必要に応じて複数の Controller を定義して登録できます。

import { rpc } from '@deepkit/rpc';

@rpc.controller('/main');
class Controller {
    @rpc.action()
    hello(title: string): string {
        return 'Hello ' + title;
    }

    @rpc.action()
    test(): boolean {
        return true;
    }
}

クライアントから呼び出せるのは、@rpc.action() が付与されたメソッドのみです。

型は明示的に指定しなければならず、型推論は使用できません。これは、シリアライザーがデータをバイナリ(BSON)や JSON に変換して送信するために、型の構造を正確に把握する必要があるためです。

クライアントの Controller

RPC の一般的な流れでは、クライアントがサーバー上の関数を実行します。しかし Deepkit RPC では、サーバーがクライアント上の関数を実行することも可能です。これを実現するために、クライアント側でも Controller を登録できます。

TODO

依存性注入

Deepkit Framework を使用する場合、クラスは依存性注入コンテナによってインスタンス化され、アプリケーション内の他のすべてのプロバイダーに自動的にアクセスできます。

あわせて 依存性注入 も参照してください。

RxJS のストリーミング

TODO

名目型

クライアントが関数呼び出しのデータを受け取る際、そのデータはまずサーバーでシリアライズされ、クライアントでデシリアライズされます。関数の戻り値の型にクラスが含まれている場合、これらのクラスはクライアント側で再構築されますが、名目上の同一性や関連するメソッドを失います。この問題に対処するには、クラスに一意の ID/名前を付けて名目型として登録してください。この手法は、RPC-API 内で使用されるすべてのクラスに適用するべきです。

クラスを登録するには、@entity.name('id') デコレーターを使用します。

import { entity } from '@deepkit/type';

@entity.name('user')
class User {
    id!: number;
    firstName!: string;
    lastName!: string;
    get fullName() {
        return this.firstName + ' ' + this.lastName;
    }
}

このクラスが関数の結果として使用されると、その同一性が保持されます。

const controller = client.controller<Controller>('/main');

const user = await controller.getUser(2);
user instanceof User; // @entity.name が使用されていれば true、そうでなければ false
English中文 (Chinese)한국어 (Korean)日本語 (Japanese)Deutsch (German)