メインコンテンツまでスキップ
バージョン: 0.14.0 (最新)

🚀 機能

機能は、リクエスト検証と 1 つのルートを対にするための命名規約です。SDK では各機能は compose(withSchema(...), withRoute(...))、すなわち Express ルーターではなく ServiceDefinition を変換する Composable です。

defFeature の登録 API はありません。機能は src/features/ からエクスポートされ、compose でサービスに結合されてから defService でマウントされます。


🔍 機能とは

エクスポートされた各機能は、1 つのスキーマコンポーザーと 1 つのルートコンポーザーを対にします。複数エンドポイントには、サービス内で合成する複数の機能が必要です。

// 1 つの機能 = 1 つのスキーマ + 1 つのルート
export const getIdentityFeature = compose(getIdentitySchema, getIdentityRoute);

サービスは多数の機能を結合します。

compose(getIdentityFeature, findIdentitiesFeature, updateIdentityFeature, ...)

単一の名前空間エクスポートから機能をインポートします。

import { features } from '@nodeblocks/backend-sdk';

// features 名前空間から(identity モジュール):
// getIdentityFeature, findIdentitiesFeature, updateIdentityFeature,
// deleteIdentityFeature, lockIdentityFeature, unlockIdentityFeature

const { getIdentityFeature, findIdentitiesFeature } = features;

機能を使用する理由:

  • 検証とルーティングを再利用可能な単位にまとめる
  • グローバル状態なしに compose でサービスへ合成できる
  • defService によるマウント時、partial で依存関係を注入できる
  • 異なる機能を合成してカスタムサービスで置き換えられる

機能のライフサイクル

schemas/*.ts + routes/*.ts → features/*.ts → services/*.ts → defService()
(withSchema/withRoute) (compose) (複数を合成) (router)
  1. 定義src/schemas/src/routes/withSchemawithRoute コンポーザーを作成
  2. 合成src/features/<domain>.ts から compose(schema, route) をエクスポート
  3. バンドル — サービスファクトリー(src/services/)で機能を結合
  4. 提供defService(partial(compose(...), [deps])) でマウント。必要な場合は WebSocket サーバーを defService の第 2 引数に渡す

⚙️ 仕組み

機能は (service: ServiceDefinition) => ServiceDefinition という関数です。内部では primitives.compose は Ramda の pipe です。

スキーマの付加には withNextRoute フックを使用します。

  1. withSchemaservice.withNextRoute を設定します。これは次のルートハンドラーを検証でラップする関数です。
  2. withRoute はルート登録時に withNextRoute を使用してから消去します。
  3. compose(...) ではスキーマをルートより前に置く必要があります。
// スキーマは、検証するルートより前に合成する
export const getIdentityFeature = compose(getIdentitySchema, getIdentityRoute);

HTTP ルートでは、検証はルートハンドラーの前に実行されます。無効なリクエストは、ハンドラーの実行前にステータス 400NodeblocksError をスローします。WebSocket スキーマは代わりにクライアントメッセージを検証し、無効なメッセージをストリーム経由で通知します。

withSchema の詳細は Schema »withRoute の詳細は Route » を参照してください。


🧑‍💻 機能を定義する

機能は登録手順のない通常の compose エクスポートです。合成プリミティブは SDK からインポートします。ルートおよびスキーマコンポーザーはアプリケーションで定義したものです。

import { primitives } from '@nodeblocks/backend-sdk';

import { getIdentityRoute } from './routes';
import { getIdentitySchema } from './schemas';

const { compose } = primitives;

export const getIdentityFeature = compose(getIdentitySchema, getIdentityRoute);

機能が返すのは Express ルーターではなく Composable です。ルーターを生成するには defService を使用します。


🔀 条件付きスキーマ

一部の機能は、サービス構成に基づき合成時にスキーマを選択します。認証機能は primitivesifElsematch を使用して configuration.authMode を分岐します。

import { primitives, utils } from '@nodeblocks/backend-sdk';

import { logoutRoute } from './routes';
import { logoutBearerSchema, logoutCookieSchema } from './schemas';

const { compose, ifElse, match } = primitives;
const { isCookieMode } = utils;

export const logoutFeature = compose(
ifElse(
match(isCookieMode, ['configuration', 'authMode']),
logoutCookieSchema,
logoutBearerSchema
),
logoutRoute
);

同じパターンは refreshTokenFeature でも使用されます。authMode'cookie' の場合は Cookie スキーマ、それ以外では Bearer スキーマが合成されます。


🧑‍💻 サービスで機能を使用する

機能は defService を通じて利用されます。開始 ServiceDefinition として依存関係を事前適用するには Ramdapartial を使用します。

import { partial } from 'ramda';
import { Collection } from 'mongodb';

import { features, primitives, utils } from '@nodeblocks/backend-sdk';

const {
getIdentityFeature,
findIdentitiesFeature,
updateIdentityFeature,
deleteIdentityFeature,
lockIdentityFeature,
unlockIdentityFeature,
} = features;
const { compose, defService } = primitives;
const { getBearerTokenInfo, getCookieTokenInfo } = utils;

export const identitiesService = (
dataStores: { identities: Collection },
configuration: {
authSecrets: { authEncSecret: string; authSignSecret: string };
authMode?: 'bearer' | 'cookie';
}
) => {
return defService(
partial(
compose(
getIdentityFeature,
findIdentitiesFeature,
updateIdentityFeature,
deleteIdentityFeature,
lockIdentityFeature,
unlockIdentityFeature
),
[
{
dataStores,
configuration,
authenticate:
configuration.authMode === 'cookie'
? getCookieTokenInfo
: getBearerTokenInfo,
},
]
)
);
};

partialdefService の動作:

  1. partial(compose(...features), [deps]) は、初期 ServiceDefinition として dataStoresconfigurationauthenticate、省略可能な非 WebSocket ドライバーを事前適用します。
  2. 各機能コンポーザーが、その定義にルート(およびスキーマメタデータ)を追加します。
  3. defService が最終 ServiceDefinition を Express ルーターに変換します。

一般的に注入するフィールドは dataStoresconfigurationauthenticate です。省略可能なドライバーには mailServicefileStorageDriver、OAuth ドライバー(googleOAuthDrivertwitterOAuthDriverlineOAuthDriver)、findAddressDriver があります。

WebSocket ルートは例外です。webSocketServer はサービスコンテキストに置きません。defService の第 2 引数として渡します。組み込みの chatService は、第 3 drivers 引数でこれを受け取り、defService に転送します。

Cookie 認証(authMode: 'cookie')を使用する場合は、サービスルーターをマウントする前に cookie-parser Express ミドルウェアを登録してください。

SDK は同じ合成パターンを持つ完成済みの services.identitiesService ファクトリーを提供します。


📐 良い実践

  1. 機能ごとに 1 操作 — 作成、読み取り、更新、削除には別々の機能を作成します。
  2. 一貫した命名<verb><Entity>Feature にすると見つけやすくなります(getIdentityFeaturefindIdentitiesFeature)。
  3. スキーマをルートより前に置くwithNextRoute のため、検証はルート登録より前である必要があります。
  4. サービスで多くの機能を合成する — サービスは compose(featureA, featureB, ...) であり、多数のルートを持つ 1 機能ではありません。

📦 SDK 機能モジュール

機能は SDK の features 名前空間でドメイン別に整理され、src/features/index.ts と対応しています。

モジュール説明リファレンス
Address住所検索エンドポイントSDK のみ — ドキュメント準備中
Attributes属性管理Attribute 機能 »
Authenticationログイン、ログアウト、MFA、トークンAuthentication 機能 »
Categoryカテゴリ CRUDCategory 機能 »
Chatチャンネル、メッセージ、サブスクリプションChat 機能 »
Identityアイデンティティライフサイクル(CRUD、ロック/ロック解除)Identity 機能 »
Invitation招待管理Invitation 機能 »
Location階層的な場所管理Location 機能 »
Notification通知エンドポイントSDK のみ — ドキュメント準備中
OAuthGoogle、Twitter、LINE の OAuth フローOAuth 機能 »
Order注文管理Order 機能 »
Organization組織およびワークスペースのロジックOrganization 機能 »
Productプロダクト管理Product 機能 »
Profileプロフィール、アバター、ソーシャルエンゲージメントProfile 機能 »

これらの機能を合成する完成済みサービスファクトリーは services 名前空間にあります。Service » を参照してください。


➡️ 次

完成済みサービスファクトリーについては Service »、検証については Schema »、ハンドラー配線については Route » を確認してください。