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

🛣️ 通知ルート

通知ルートは Express ミドルウェアではなく SDK コンポーザーです。すべてのルートで最初に認証を行い、次に所有権または本人確認のバリデーションを実行します。

一覧

ルートメソッド / プロトコルパススキーマバリデーター成功ステータス
updateNotificationToReadRoutePOST / HTTP/notifications/:notificationId/readupdateNotificationToReadSchemaisAuthenticated()ownsNotification204
findNotificationsRouteGET / HTTP/notifications/identities/:identityIdfindNotificationsSchemaisAuthenticated()isSelf(['params', 'requestParams', 'identityId'])200
updateNotificationToReadBatchRoutePOST / HTTP/notifications/identities/:identityId/readupdateNotificationToReadBatchSchemaisAuthenticated()isSelf(['params', 'requestParams', 'identityId'])204

詳細

updateNotificationToReadRoute

実装

エンドポイント: POST /notifications/:notificationId/read

POST /notifications/:notificationId/read は、所有する通知を既読にして 204 を返します。すでに既読のドキュメントも、更新を行わずに成功します。

アクセス: isAuthenticated()、続いてパス ID を渡した ownsNotification

リクエスト: updateNotificationToReadSchema はパスの notificationId を必須とします。本文およびクエリはありません。デフォルトでは Bearer 認証を、Cookie モードでは accessToken Cookie を送信します。

パイプライン: buildNotificationReadbuildGetNotificationFiltergetNotification → 条件付きの updateNotificationorThrow

成功: undefined データを含む明示的な 204 ディスクリプター。

失敗: このルートは NotificationNotFoundBlockError404、データベースエラーを 500 にマッピングします。ただし、マウントされたルートでは ownsNotification が先に実行されます。存在しない通知には通常 receiverId がないため、ルートパイプラインの前に所有権確認で 403 になります。他のバリデーターの失敗も先に発生します。

完全なソースを表示
export const updateNotificationToReadRoute = withRoute({
handler: compose(
applyPayloadArgs(buildNotificationRead, [], 'notification'),
flatMapAsync(
applyPayloadArgs(
buildGetNotificationFilter,
[['params', 'requestParams', 'notificationId']],
'getNotificationFilter',
),
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getNotification,
[
['context', 'db', 'notifications'],
['context', 'data', 'getNotificationFilter'],
],
'existingNotification',
),
),
),
flatMapAsync(
ifElse(
match(Boolean, ['context', 'data', 'existingNotification', 'isRead']),
applyPayloadArgs(noop, [[]]),
compose(
withLogging(
applyPayloadArgs(
updateNotification,
[
['context', 'db', 'notifications'],
['params', 'requestParams', 'notificationId'],
['context', 'data', 'notification'],
],
'isUpdated',
),
),
),
),
),
lift(
orThrow(
[
[NotificationNotFoundBlockError, 404],
[NotificationDbError, 500],
],
[[''], 204],
),
),
),
method: 'POST',
path: '/notifications/:notificationId/read',
validators: [isAuthenticated(), ownsNotification(['params', 'requestParams', 'notificationId'])],
});

findNotificationsRoute

実装

エンドポイント: GET /notifications/identities/:identityId

GET /notifications/identities/:identityId は、認証済みアイデンティティの正規化されたページネーション済み通知を 200 で返します。

アクセス: isAuthenticated()、続いて isSelf(['params', 'requestParams', 'identityId'])

リクエスト: findNotificationsSchema はパスの identityId を必須とし、整数クエリ page11000)と limit150)を受け付けます。本文はありません。デフォルトでは Bearer 認証を、Cookie モードでは accessToken Cookie を送信します。withPagination は省略値をページ 1、上限 10 に設定し、下流クエリの前にこれらのキーを削除して、得られた skip/limit を適用します。

パイプライン: buildFindNotificationsFilterfindNotifications を囲む withPaginationnormalizeDocumentsapplySpecorThrow

成功: 明示的な 200{ data, metadata: { pagination } }normalizeDocuments は Mongo の _id を削除します。

失敗: 通知データベースエラーは 500 にマッピングされ、バリデーターの失敗は先に発生します。空の結果は 200 です。

完全なソースを表示
export const findNotificationsRoute = withRoute({
handler: compose(
applyPayloadArgs(buildFindNotificationsFilter, [['params', 'requestParams', 'identityId']], 'filter'),
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(
findNotifications,
[
['context', 'db', 'notifications'],
['context', 'data', 'filter'],
['context', 'data', 'options'],
],
'rawNotifications',
),
),
),
),
flatMapAsync(
applyPayloadArgs(
normalizeDocuments,
[['context', 'data', 'rawNotifications', 'data']],
'normalizedNotifications',
),
),
flatMapAsync(
applyPayloadArgs(
applySpec({data: nthArg(0), metadata: {pagination: nthArg(1)}}),
[
['context', 'data', 'normalizedNotifications'],
['context', 'data', 'rawNotifications', 'metadata'],
],
'normalizedBody',
),
),
lift(orThrow([[NotificationDbError, 500]], [['context', 'data', 'normalizedBody'], 200])),
),
method: 'GET',
path: '/notifications/identities/:identityId',
validators: [isAuthenticated(), isSelf(['params', 'requestParams', 'identityId'])],
});

updateNotificationToReadBatchRoute

実装

エンドポイント: POST /notifications/identities/:identityId/read

POST /notifications/identities/:identityId/read は、受信者が所有するアンカーを基準に未読通知を既読にし、204 を返します。アンカー以降に未読の一致がない場合も、正常な no-op です。

アクセス: isAuthenticated()、続いて isSelf(['params', 'requestParams', 'identityId'])

リクエスト: updateNotificationToReadBatchSchema はパスの identityId と、厳格な application/json{ lastReadNotificationId } 本文を必須とします。デフォルトでは Bearer 認証を、Cookie モードでは accessToken Cookie を送信します。

パイプライン: アンカーをフィルター → getNotificationassertHasCreatedAtbuildNotificationsReadFilterbuildNotificationRead → 条件付きの updateNotificationBatchorThrow

成功: undefined データを含む明示的な 204 ディスクリプター。バッチ更新から後で発生する NotificationNotFoundBlockErrorok(false) になります。

失敗: アンカーの不在は 404createdAt の欠落またはデータベースエラーは 500 です。バリデーターの失敗は先に発生します。

完全なソースを表示
export const updateNotificationToReadBatchRoute = withRoute({
handler: compose(
applyPayloadArgs(
buildGetNotificationFilter,
[
['params', 'requestBody', 'lastReadNotificationId'],
['params', 'requestParams', 'identityId'],
],
'filterForLatestReadNotification',
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getNotification,
[
['context', 'db', 'notifications'],
['context', 'data', 'filterForLatestReadNotification'],
],
'latestReadNotification',
),
),
),
flatMapAsync(
withLogging(
applyPayloadArgs(assertHasCreatedAt, [['context', 'data', 'latestReadNotification']], 'hasCreatedAtTimestamp'),
),
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildNotificationsReadFilter,
[
['params', 'requestParams', 'identityId'],
['context', 'data', 'latestReadNotification', 'createdAt'],
],
'filterForNotificationsToMarkRead',
),
),
),
flatMapAsync(withLogging(applyPayloadArgs(buildNotificationRead, [], 'notification'))),
flatMapAsync(
withLogging(
applyPayloadArgs(
compose(
updateNotificationBatch,
lift(
ifElse(
result => result.isErr() && result.error instanceof NotificationNotFoundBlockError,
() => ok(false),
noop,
),
),
),
[
['context', 'db', 'notifications'],
['context', 'data', 'notification'],
['context', 'data', 'filterForNotificationsToMarkRead'],
],
'hasUpdated',
),
),
),
lift(
orThrow(
[
[CommonUnexpectedBlockError, 500],
[NotificationNotFoundBlockError, 404],
[NotificationDbError, 500],
],
[[''], 204],
),
),
),
method: 'POST',
path: '/notifications/identities/:identityId/read',
validators: [isAuthenticated(), isSelf(['params', 'requestParams', 'identityId'])],
});