メむンコンテンツたでスキップ
バヌゞョン: 0.14.0 (最新)

🪪 バリデヌタヌ

バリデヌタヌは withRoute({ validators }) を通じおルヌトに接続する関数です。HTTP バリデヌタヌは非同期です。WebSocket バリデヌタヌは同期たたは非同期にできたす。スキヌマ怜蚌を超えるビゞネスロゞックの怜査、すなわち認蚌、認可、リ゜ヌスの存圚、所有暩を実行したす。

バリデヌタヌ登録 API はありたせん。validators 名前空間からむンポヌトし、src/routes/ のルヌトコンポヌザヌに接続したす。

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

type Validator = (payload: RouteHandlerPayload) => Promise<void>;
type WsValidator = (payload: WsRouteHandlerPayload) => void | Promise<void>;

ファクトリヌバリデヌタヌは Validator を生成するために呌び出す必芁がありたす䟋: isAuthenticated()。isAuthenticated のたたではありたせん。doesCategoryExist のような盎接バリデヌタヌはそのたた䜿甚したす。() で呌び出さないでください。


🔍 バリデヌタヌずは​

バリデヌタヌは、リク゚ストパむプラむン内でハンドラヌのビゞネスロゞックより前に実行されたす。ルヌトハンドラヌず同じペむロヌドオブゞェクトを受け取りたすHTTP は RouteHandlerPayload、WebSocket は WsRouteHandlerPayload。

バリデヌタヌを䜿う理由:

  • DB 負荷の高いハンドラヌチェヌンの前に、認蚌ずアクセス制埡を匷制する
  • SDK の述語をルヌト間で再利甚するhasOrgRole、ownsProfile など
  • 柔軟なアクセス芏則のために all()ANDたたは some()ORで合成する
  • 䞀貫した HTTP ゚ラヌレスポンスのために NodeblocksError をスロヌするWebSocket の倱敗時は接続を閉じたす

📐 スキヌマずバリデヌタヌ​

2 ぀の怜蚌レむダヌは異なる時点で実行されたす。withSchema による圢状怜蚌に぀いおはスキヌマ »を参照しおください。

HTTP リク゚スト
→ ルヌトバリデヌタヌdefService
→ ハンドラヌ開始
→ スキヌマ怜蚌withNextRoute ラッパヌ
→ ハンドラヌチェヌンblocks / handlers
レむダヌ目的定矩堎所
ルヌトバリデヌタヌビゞネスロゞック — 認蚌、暩限、存圚withRoute の validators
スキヌマ怜蚌リク゚スト圢状 — パス、ク゚リ、本文フィヌルド機胜の withSchemacompose(schema, route)

実行順序: defService はたずルヌトバリデヌタヌを実行し、その埌ハンドラヌを呌び出したす。スキヌマ怜蚌は withNextRoute 経由でスキヌマにラップされたハンドラヌ内郚で実行されたす。正しい順序は バリデヌタヌ → スキヌマ → ハンドラヌチェヌン です。


⚙ コンテキストずパス​

バリデヌタヌは RouteHandlerPayload を受け取りたす。

{
context: {
db, // service dataStores からマッピング
configuration, // サヌビス構成Identity タむプ ID、組織ロヌル
authenticate, // デフォルトは getBearerTokenInfo、Cookie サヌビスは getCookieTokenInfo を泚入
// ...任意のドラむバヌmailService、fileStorageDriver など
},
params: {
requestParams, // パスパラメヌタヌ
requestQuery, // ク゚リ文字列
requestBody, // JSON 本文POST/PUT/PATCH/DELETE
},
}

パス匕数には、ペむロヌドを起点ずする Ramda の path タプルを䜿甚したす。SDK ルヌトでは䞀貫しお次を䜿甚したす。

['params', 'requestParams', 'profileId']
['params', 'requestBody', 'identityId']
['params', 'requestQuery', 'channelId']

Cookie 認蚌を䜿甚する堎合、サヌビスは context.authenticate ずしお getCookieTokenInfo を泚入したす。サヌビスルヌタヌをマりントする前に cookie-parser ミドルりェアを登録しおください。

構成の䟝存関係​

䞀郚のバリデヌタヌはサヌビス構成を必芁ずしたす。

バリデヌタヌ必須構成
checkIdentityTypeconfiguration.identity.typeIds、db.identities
hasOrgRole、hasOrgRoleSameOrAbove、hasOrgRoleAssignmentPermissionconfiguration.organization.roles、db.organizations
hasOrgOwnerRemainingAfterMembersUpsert、hasOrgOwnerRemainingAfterMemberRemovalconfiguration.organization.roles、db.organizations

🔀 合成​

゚クスポヌト動䜜
all(...validators)逐次 AND — バリデヌタヌを 1 ぀ず぀実行し、最初のスロヌで即座に倱敗
some(...validators)䞊行 OR — Promise.allSettled ですべおのバリデヌタヌを実行。いずれかが成功すれば通過し、すべお倱敗した堎合は入力順で最初に収集された゚ラヌをスロヌ

倚くの SDK ルヌトは、管理者たたは組織メンバヌのアクセスに some(checkIdentityType(['admin']), hasOrgRole(...)) を䜿甚したす。

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

const { isAuthenticated, some, checkIdentityType, hasOrgRole } = validators;

validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId'])
),
],

📊 SDK バリデヌタヌカタログ​

すべおのバリデヌタヌは src/validators/index.ts に察応する validators 名前空間から゚クスポヌトされたす。

合成​

゚クスポヌトシグネチャ
all(...validators: Validator[]) => Validator
some(...validators: Validator[]) => Validator

認蚌ず Identity​

゚クスポヌトシグネチャ泚蚘
isAuthenticated() => Validatorcontext.authenticate を呌び出したす。デフォルトは getBearerTokenInfo
checkIdentityType(allowedTypes) => Validator認蚌も実行。db.identities ず configuration.identity.typeIds が必芁

Organization​

゚クスポヌトシグネチャ泚蚘
hasOrgRole(allowedRoles, organizationIdPath) => Validatorconfiguration.organization.roles によりロヌルキヌをマッピング
hasOrgRoleSameOrAbove(orgIdPath, identityIdPath, rolesByRankAsc?) => Validatorデフォルトのランク順: ['member', 'admin', 'owner']
hasOrgRoleAssignmentPermission(orgIdPath, membersPath, rolesByRankAsc?) => Validatorメンバヌの upsert 時のロヌル割り圓おを怜蚌
hasOrgOwnerRemainingAfterMembersUpsert(orgIdPath, membersPath) => Validator組織䞍倉条件のみ — 認蚌なし
hasOrgOwnerRemainingAfterMemberRemoval(orgIdPath, identityIdPath) => Validator組織䞍倉条件のみ — 認蚌なし

リ゜ヌス所有暩​

汎甚的な所有暩チェック:

ownsResource(resource, ownerIdPathInResource, resourceIdPathInPayload)

䜿甚できる resource コレクション: chatChannels、chatMessages、orders、profiles、subscriptions、notifications。

ドメむンラッパヌは partial(ownsResource, [collection, [ownerField]]) です。リ゜ヌス ID のパスだけを枡したす。

゚クスポヌトコレクション所有者フィヌルド
ownsProfileprofilesidentityId
ownsOrderordersidentityId
ownsChannelchatChannelsownerId
ownsMessagechatMessagessenderId
ownsSubscriptionsubscriptionssubscribedId
ownsNotificationnotificationsreceiverId

ほずんどの所有暩バリデヌタヌは内郚で認蚌したす。明確にするため、SDK ルヌトでは isAuthenticated() も含めるこずがよくありたす。

Chat​

゚クスポヌトシグネチャ泚蚘
hasSubscription(channelIdPath, subscribedIdPath?) => Validatorパスを省略するず、subscribedId はトヌクンの identityId がデフォルト
hasOrganizationAccessToMessageTemplate(allowedRoles, messageTemplateIdPath) => ValidatorhasOrgRole ず異なり、DB の生の member.role 文字列を比范
channelExists(channelIdPath) => Validator存圚確認のみ — 認蚌なし

その他​

゚クスポヌトシグネチャ泚蚘
isSelf(identityIdPath) => Validator察象 Identity が認蚌枈みナヌザヌず䞀臎するこずを確認
doesCategoryExist盎接の Validatorparams.requestParams.categoryId を読み取り — ファクトリヌではない

ナヌティリティ関数​

これらはバリデヌタヌず䞀緒に゚クスポヌトされたすが、ルヌトバリデヌタヌそのものではありたせん。

゚クスポヌトモゞュヌル目的
getResourceByIdownsResourceコレクションから id によっおドキュメントを取埗
getSubscriptionByChannelAndSubscriberhasSubscriptionchannelId + subscribedId でサブスクリプションを取埗

🔗 ルヌトでのバリデヌタヌ䜿甚​

src/routes/ の withRoute にバリデヌタヌを接続したす。それらは compose(withSchema, withRoute) により機胜ぞ合成されたす。

管理者たたはリ゜ヌス所有者​

src/routes/profile.ts から:

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

const { getProfileById } = handlers;
const { withRoute } = primitives;
const { isAuthenticated, some, checkIdentityType, ownsProfile } = validators;

export const getProfileRoute = withRoute({
method: 'GET',
path: '/profiles/:profileId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsProfile(['params', 'requestParams', 'profileId'])
),
],
// ハンドラヌチェヌンは省略。バリデヌタヌが先に実行される。
handler: getProfileById,
});

䞍倉条件を䌎う組織メンバヌの upsert​

src/routes/organization.ts から:

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

const {
isAuthenticated,
all,
some,
checkIdentityType,
hasOrgRole,
hasOrgRoleAssignmentPermission,
hasOrgOwnerRemainingAfterMembersUpsert,
} = validators;

validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
all(
hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']),
hasOrgRoleAssignmentPermission(
['params', 'requestParams', 'organizationId'],
['params', 'requestBody']
)
)
),
hasOrgOwnerRemainingAfterMembersUpsert(
['params', 'requestParams', 'organizationId'],
['params', 'requestBody']
),
],

カテゎリヌの存圚​

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

const { isAuthenticated, doesCategoryExist } = validators;

validators: [isAuthenticated(), doesCategoryExist],

🛠 カスタムバリデヌタヌの䜜成​

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

const validateIdentityExists: primitives.Validator = async ({ context, params }) => {
const identityId = params.requestParams?.identityId;
const identity = await context.db.identities.findOne({ id: String(identityId) });

if (!identity) {
throw new primitives.NodeblocksError(
404,
'Identity not found',
'validateIdentityExists'
);
}
};

ファクトリヌパタヌン​

const requireResourceExists = (collectionName: string, paramName: string) => {
return async (payload: primitives.RouteHandlerPayload) => {
const { context, params } = payload;
const resourceId = params.requestParams?.[paramName];

const resource = await context.db[collectionName].findOne({
id: String(resourceId),
});
if (!resource) {
throw new primitives.NodeblocksError(
404,
`${collectionName} not found`,
'requireResourceExists'
);
}
};
};

NodeblocksError(status, message, source) をスロヌしおリク゚ストを拒吊したす。バリデヌタヌは成功時に void ぞ解決する必芁がありたす。


🌐 WebSocket バリデヌタヌ​

WebSocket ルヌトでは withRoute({ protocol: 'ws', validators }) に WsValidator を䜿甚したす。defService はクラむアント接続時に、接続 URL のク゚リ文字列から導出された params ずずもにバリデヌタヌを実行したす。

{ context, params: { requestQuery: { /* URL から取埗 */ } } }

該圓する堎合は同じバリデヌタヌファクトリヌを接続するか、WS 固有の怜査にはカスタム WsValidator 関数を曞いおください。

WebSocket ルヌト構成はルヌト »、チャットストリヌミングのセットアップはWebSocket サヌビスガむド »を参照しおください。


🚚 ゚ラヌ凊理​

バリデヌタヌは NodeblocksError をスロヌしたす。defService はスロヌされた゚ラヌを正芏化しお Express ぞ枡したす。゚ラヌレスポンスを送るにはアプリケヌションレベルで nodeBlocksErrorMiddleware() をマりントしおください。

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

const { nodeBlocksErrorMiddleware } = middlewares;

app.use(nodeBlocksErrorMiddleware());

クラむアントは次を受け取りたす。

{
"error": {
"message": "Category does not exist"
}
}

stack は NODE_ENV === 'development' の堎合にのみ含たれたす。省略可胜な data ぱラヌに蚭定されおいる堎合に含たれたす。

完党な゚ラヌモデルぱラヌハンドリング »を参照しおください。


📐 掚奚事項​

  1. ハンドラヌより先にルヌトバリデヌタヌ — スキヌマはハンドラヌラッパヌ内郚で圢状を怜蚌し、バリデヌタヌは先にビゞネスロゞックを通過させたす。
  2. SDK バリデヌタヌを優先する — 堎圓たり的な DB 怜査の代わりに hasOrgRole、ownsProfile などを䜿甚したす。
  3. ファクトリヌを呌び出す — isAuthenticated()、checkIdentityType([...])、hasOrgRole([...], path) を䜿い、doesCategoryExist は () なしで盎接䜿甚したす。
  4. 遞択肢には some() を䜿甚する — 管理者 OR 組織所有者 OR リ゜ヌス所有者のアクセスパタヌンに䜿いたす。
  5. タむプ ID ずロヌル ID を構成する — タむプロヌルバリデヌタヌを䜿甚する堎合、configuration.identity.typeIds ず configuration.organization.roles を蚭定したす。
  6. 論理的に合成する — 認蚌 → 認可 → リ゜ヌスの存圚䞍倉条件の順にしたす。
  7. ク゚リにむンデックスを付ける — バリデヌタヌはしばしば id でク゚リするため、それらのフィヌルドに MongoDB むンデックスを確保したす。

➡ 次ぞ​