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

🛠️ サービス

サービスは、ドメインの機能を合成し、defService を介して Express ルーターとしてマウントするファクトリー関数の命名規則です。サービス登録 API はありません。SDK は src/services/ からすぐに利用できるファクトリーをエクスポートします。

各ファクトリーは、HTTP(および任意で WebSocket)エンドポイントを持つ express.Router を返します。サービスは、アプリケーションコードから直接呼び出すインプロセスのドメイン API ではありません。


🔍 サービスとは​

サービスは、1 つ以上の機能を 1 つのマウント可能なルーターへ束ねます。各機能は compose(withSchema(...), withRoute(...)) です。

schemas/*.ts + routes/*.ts → features/*.ts → services/*.ts → defService()
(withSchema/withRoute) (compose) (compose many) (router)
┌─────────────┐
│ Service │ identitiesService(dataStores, configuration)
├─────────────┤
│ Features ▷ getIdentityFeature
│ ▷ findIdentitiesFeature
│ ▷ updateIdentityFeature
│ ▷ ...
└─────────────┘

サービスを使用する理由:

  • ドメインごとに 1 つのファクトリー。完全な REST(および任意の WS)サーフェスを 1 行でマウントできます。
  • 依存関係は partial を介して注入され、グローバル状態はありません。
  • 合成可能です。同じパターンで機能をサービス間で再利用したり、カスタムファクトリーを構築したりできます。
  • サービスごとに型付けされた dataStores と configuration(MongoDB Collection インターフェース)を使用します。

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

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

const { identitiesService, authService, chatService } = services;

機能の定義と合成については機能 »を参照してください。


⚙️ 仕組み(defService)​

defService は合成された Composable を稼働する Express ルーターに変換します。提供されるすべてのサービスファクトリーは、同じ内部接続に従います。

defService(
partial(compose(...features), [{ dataStores, configuration, authenticate, ...drivers }]),
webSocketServer? // 現在これを渡すのは chatService のみ
);

サービスファクトリーの呼び出し時に、defService は次を行います。

  1. 合成済みアダプターを実行し、ServiceDefinition(ルート、スキーマ、ミドルウェア、注入済み依存関係)を構築します。
  2. express.json() の本文解析を備えた Express ルーターを作成します。
  3. 合成済み定義にある任意の service.middleware を適用します。
  4. HTTP ルート(GET/POST/PUT/PATCH/DELETE)を登録します。バリデーターはハンドラーより先に実行されます。
  5. 存在する場合、WebSocket ルートを指定の webSocketServer にバインドします。

defService に webSocketServer を渡さない場合、WebSocket ルートはアサートします。chatService は、任意の第 3 引数にある webSocketServer プロパティを defService の第 2 引数として転送します。これは drivers 名前空間のエクスポートではありません。

HTTP リクエストでは、検証または処理中のエラーを NodeblocksError に正規化し、next 経由で Express に渡します。defService は最終エラーレスポンスを送信しません。アプリケーションレベルで nodeBlocksErrorMiddleware() を登録してください。

応答処理({ statusCode, data } ターミネーター)についてはルート »、チャットストリーミングのセットアップについてはWebSocket サービスガイド »を参照してください。


🧑‍💻 標準ファクトリーパターン​

すべての SDK サービスは同じ構造を共有します。

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';
identity?: { typeIds?: { admin: string; guest: string; regular: string } };
}
) => {
return defService(
partial(
compose(
getIdentityFeature,
findIdentitiesFeature,
updateIdentityFeature,
deleteIdentityFeature,
lockIdentityFeature,
unlockIdentityFeature
),
[
{
dataStores,
configuration,
authenticate:
configuration.authMode === 'cookie'
? getCookieTokenInfo
: getBearerTokenInfo,
},
]
)
);
};

partial と defService の動作:

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

一般的に注入されるフィールド: dataStores、configuration、authenticate。

任意のドライバー(ファクトリーの第 3 引数で受け取り、サービスコンテキストに転送): mailService、fileStorageDriver、OAuth ドライバー(googleOAuthDriver、twitterOAuthDriver、lineOAuthDriver)、findAddressDriver。webSocketServer は別途処理されます。chatService はリクエストコンテキストに注入せず、defService の第 2 引数として渡します。

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


📑 SDK サービスカタログ​

サービスは src/services/index.ts に対応する SDK の services 名前空間で、ドメインごとに整理されています。

サービスエクスポート責務ドライバー(第 3 引数)ドキュメント
AuthenticationauthService登録、ログイン/ログアウト、MFA、トークン、招待、OAuthmailService、OAuth ドライバードキュメント »
IdentityidentitiesServiceID の CRUD、ロック/ロック解除—ドキュメント »
ProfileprofileServiceプロファイル、アバター、フォロー、「いいね」fileStorageDriverドキュメント »
OrganizationorganizationService組織、メンバー、変更リクエストfileStorageDriverドキュメント »
ProductproductService製品 CRUD、バッチ/コピーfileStorageDriverドキュメント »
AttributesattributesService属性とグループ—ドキュメント »
CategorycategoryServiceカテゴリ CRUD とステータス—ドキュメント »
LocationlocationService階層的なロケーション—ドキュメント »
OrderorderService注文管理—ドキュメント »
ChatchatServiceチャンネル、メッセージ、テンプレート、添付ファイル、WS ストリーミングfileStorageDriver、webSocketServerドキュメント »
NotificationnotificationService通知の一覧、既読化(単一/一括)—ドキュメント »
AddressaddressService住所検索findAddressDriverドキュメント »

ℹ️ @nodeblocks/backend-sdk からは services 名前空間経由でサービスをインポートします。import { services } from '@nodeblocks/backend-sdk'。

設定に関する注意:

  • authService の公開型 AuthenticationService は AuthenticationServiceConfiguration を要求します。実装は内部でデフォルトをマージします。設定全体は認証サービスを参照してください。
  • dataStores の型では、一部の MongoDB コレクションが任意としてマークされています(例: 認証用の invitations、onetimetokens、製品用の productVariants、組織用の organizationChangeRequests)。必要なコレクションは各サービスのドキュメントを参照してください。

🧑‍💻 サービスのマウント​

すべてのサービスは、次のシグネチャを持つファクトリー関数です。

(dataStores, configuration, drivers?) => express.Router

任意の第 3 引数 drivers はサービスによって異なります。上記のカタログ表を参照してください。

基本 HTTP サービス​

import express from 'express';

import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';

const { nodeBlocksErrorMiddleware } = middlewares;
const { identitiesService } = services;
const { withMongo } = drivers;

const connectToDatabase = withMongo(
'mongodb://localhost:27017',
'dev',
'user',
'password'
);

express()
.use(
'/api/identities',
identitiesService(
await connectToDatabase('identities'),
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
authMode: 'bearer', // または 'cookie' — cookie-parser ミドルウェアが必要
identity: {
typeIds: {
admin: 'admin-type-id',
guest: 'guest-type-id',
regular: 'regular-type-id',
},
},
}
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));

ドライバーを使用するサービス​

外部ドライバーを第 3 引数として渡す必要があるサービスもあります。

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

const { authService, chatService, profileService } = services;

app.use('/api/auth', authService(dataStores, config, {
mailService,
googleOAuthDriver,
twitterOAuthDriver,
lineOAuthDriver,
}));

app.use('/api/profiles', profileService(dataStores, config, {
fileStorageDriver,
}));

app.use('/api/chat', chatService(dataStores, config, {
fileStorageDriver,
webSocketServer, // streamChatMessagesFeature には必須
}));

🔧 カスタムサービスの構築​

任意の機能サブセットを自身のファクトリーへ合成できます。SDK 提供のサービスも同じパターンを使用しています。

import { partial } from 'ramda';

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

const { getIdentityFeature, findIdentitiesFeature } = features;
const { compose, defService } = primitives;
const { getBearerTokenInfo } = utils;

export const myIdentityService = (dataStores, configuration) =>
defService(
partial(
compose(getIdentityFeature, findIdentitiesFeature),
[{ dataStores, configuration, authenticate: getBearerTokenInfo }]
)
);

features 名前空間から機能を選択し、選択したルートで必要なドライバーのみを注入して、返されたルーターを Express にマウントします。機能合成の詳細は機能 »を参照してください。


📐 推奨事項​

  1. サービスファクトリーごとに 1 ドメイン — 各 SDK 提供サービスは 1 つのビジネス領域を対象にします。
  2. 機能を合成し、ルートを手動で登録しない — defService により、合成済み機能のバリデーターとハンドラーを接続します。
  3. partial 経由で認証とドライバーを注入する — グローバルを避け、依存関係オブジェクトに authenticate、mailService、fileStorageDriver などを渡します。
  4. エラーミドルウェアをアプリケーションレベルでマウントする — nodeBlocksErrorMiddleware() はサービスファクトリーの一部ではなく、ホストアプリの責務です。
  5. ドライバー要件を確認する — ファイルアップロードルートには fileStorageDriver、OAuth およびメールフローにはそれぞれのドライバー、チャット WebSocket ストリーミングには webSocketServer が必要です。

➡️ 次へ​

認証サービスから始めるか、上記カタログの他のサービスを確認してください。コンポーネントレベルの詳細は、機能 »、ルート »、スキーマ »、ブロック »を参照してください。リアルタイムチャットについてはWebSocket サービスガイド »を確認してください。