メインコンテンツまでスキップ
バージョン: 0.13.0 (Previous)

🛠️ サービス

サービスは、ドメインの機能を合成し、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 を介して注入され、グローバル状態はありません。
  • 合成可能です。同じパターンで機能をサービス間で再利用したり、カスタムファクトリーを構築したりできます。
  • サービスごとに型付けされた dataStoresconfiguration(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 ルート(GETPOSTPUTPATCHDELETE)を登録します。バリデーターはハンドラーより先に実行されます。
  5. 存在する場合、WebSocket ルートを指定の webSocketServer にバインドします。

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

検証または処理中にスローされたエラーは 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,
},
]
)
);
};

partialdefService の動作:

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

一般的に注入されるフィールド: dataStoresconfigurationauthenticate

任意のドライバー(ファクトリーの第 3 引数で受け取り、サービスコンテキストに転送): mailServicefileStorageDriver、OAuth ドライバー(googleOAuthDrivertwitterOAuthDriverlineOAuthDriver)、findAddressDriverwebSocketServer は別途処理されます。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 ストリーミングfileStorageDriverwebSocketServerドキュメント »
NotificationnotificationService通知の一覧、既読化(単一/一括)ドキュメント »
AddressaddressService住所検索findAddressDriverドキュメント »

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

設定に関する注意:

  • authServicePartial<AuthenticationServiceConfiguration> を受け取ります。デフォルトは getMergedAuthConfig() により内部でマージされます。完全な設定範囲は認証サービスのドキュメントを参照してください。
  • dataStores の型では、一部の MongoDB コレクションが任意としてマークされています(例: 認証用の invitationsonetimetokens、製品用の 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(
{
identities: 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 経由で認証とドライバーを注入する — グローバルを避け、依存関係オブジェクトに authenticatemailServicefileStorageDriver などを渡します。
  4. エラーミドルウェアをアプリケーションレベルでマウントするnodeBlocksErrorMiddleware() はサービスファクトリーの一部ではなく、ホストアプリの責務です。
  5. ドライバー要件を確認する — ファイルアップロードルートには fileStorageDriver、OAuth およびメールフローにはそれぞれのドライバー、チャット WebSocket ストリーミングには webSocketServer が必要です。

➡️ 次へ

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