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

🔧 Nodeblocks Backend SDK

Nodeblocks Backend SDK は、堅牢で型安全な REST API を数分で構築するための、組み合わせ可能なユーティリティのコレクションです。
この SDK は、関数型合成依存性注入 を基盤として設計されており、すべてのレイヤーを独立してテスト・再利用することができます。


🧠 核心哲学

Nodeblocks Backend SDK は、バックエンドサービスに対して関数型・合成的なアプローチを採用しています。大規模で意見の多いフレームワークに依存するのではなく、小さな独立した関数とモジュールを合成してアプリケーションを構築します。

SDK の中核には、複雑なシステムは単純な純粋関数から構築できるという考え方があります。多くの状態やロジックを持つ大規模なクラスやオブジェクトを作成する代わりに、小さく焦点を絞った関数を定義し、それらをより複雑な関数に合成します。

このアプローチにより、以下の利点が得られます:

  • モジュール性: アプリケーションの各部分は小さく自己完結しているため、理解・テスト・再利用が容易です。
  • 宣言的スタイル: サービスがどのように構築されるかを段階的に指定するのではなく、サービスが何であるかを宣言します。
  • 予測可能性: 関数型の原則を基盤とすることで、システムの挙動はより予測可能になり、推論しやすくなります。

🏗️ 階層化アーキテクチャ

Nodeblocks Backend SDK は、各レイヤーが特定の責任を持ち、独立して合成できる明確な階層化アーキテクチャに従っています。この関心の分離により、コードはより保守可能・テスト可能・再利用可能になります。

  1. Schema – リクエスト検証用の JSON-Schema 定義。スキーマはデータの形状を定義し、受信したリクエストを検証します。

  2. Blocks – 純粋なビジネスロジック関数(例: findChatMessages)。Blocks は再利用可能でテスト可能なビジネスロジックを含む基盤的なビルディングブロックであり、合成するために設計されています。

  3. Handler – 非同期のアプリケーションロジック(例: createProfile)。Handler は blocks と副作用(データベース I/O など)をオーケストレーションし、検証された入力を受け取って結果またはエラーを返します。

  4. Route – HTTP メソッド + パス + ハンドラー + バリデータ。Route は API エンドポイントを定義し、受け付ける HTTP メソッド、応答するパス、検証の適用方法を指定します。

  5. Featureスキーマ + ルート(または複数のルート)の合成。Feature は関連する機能をまとめてバンドルし、検証ルールと対応するエンドポイントを結合します。

  6. Service – 関連する feature をグループ化し、外部依存性を配線します(例: Mongo Collection)。Service は複数の feature を組み合わせ、データベース接続などの依存性を注入するトップレベルのコンテナです。

アーキテクチャ図

Backend Flow Schema

リクエストフロー

典型的なリクエストが階層化アーキテクチャを通過する流れは以下の通りです:

リクエスト → Route → Handler → DB / 外部API → Terminator → レスポンス

各ユニットが_純粋関数_であるため、他のレイヤーに触れることなく、どのレイヤーも交換・装飾・拡張できます。


🔧 核心概念

階層化アーキテクチャを理解したところで、Nodeblocks Backend SDK を使用してアプリケーションを構築する際に扱う主要な概念を見ていきましょう。これらの概念は API のビルディングブロックを形成し、保守可能でスケーラブルなバックエンドサービスを作成するのに役立ちます。

サービス

サービス は、アプリケーションの組み合わせ可能な要素で、HTTP エンドポイントと、オプションで WebSocket ルートを提供します。Express ミドルウェアとして実装され、Express アプリケーションにマウントできます。defService 関数を使用してサービスを作成します。この関数は合成された feature のセット(とオプションの WebSocketServerws ルートの場合))を受け取り、ミドルウェアとして直接使用できる Express ルーターを返します。

パッケージエクスポート

@nodeblocks/backend-sdk名前空間エクスポートのみ公開しています(例: services, primitives, drivers, validators)。パッケージルートからインポートしてください:

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

フラットな import { authService } from '@nodeblocks/backend-sdk'@nodeblocks/backend-sdk/drivers サブパスはありません。

合成

合成は SDK の中核的なパターンです。compose 関数を使用して、アプリケーションの異なる部分を左から右へとチェーンでつなぐことができます(従来の関数合成が右から左に行くのと対照的です)。単純な関数から始め、 progressively より複雑な関数に構築していきます。各関数は合成チェーン内に出現する順序で適用されます。

カスタム合成の例では ramdapartial を使用しています。組み込みファクトリ(例: services.authService)はすでにこのパターンを内部で適用しているため、通常のアプリケーションは @nodeblocks/backend-sdk だけで十分です。カスタムサービスを合成する場合のみ、ramda(および通常 @types/ramda)をインストールしてください。

import {primitives} from '@nodeblocks/backend-sdk';
import {partial} from 'ramda'; // カスタム合成用のコンシューマー依存性

const {compose, defService} = primitives;

// 複数の feature を単一のサービス定義に合成
const serviceDefinition = compose(feature1, feature2, feature3);

// 合成された定義からサービスを作成。
// partial deps オブジェクトには通常 { dataStores, configuration, authenticate?, ...drivers } が含まれます。
const service = defService(partial(serviceDefinition, [{dataStores, configuration}]));

プリミティブ

プリミティブ は、サービスの block を構築するために使用する低レベルのヘルパー関数です。よく使われるプリミティブの 2 つが withSchemawithRoute です。これらを @nodeblocks/backend-sdkprimitives ネームスペースからインポートしてください。

withSchema

withSchema プリミティブはデータ検証用の JSON Schema を定義します。その強力さは withRoute との相互作用にあります — withSchema を合成すると、次のルートに対して自動的に検証が設定されます。

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

const {compose, withSchema} = primitives;

// 再利用可能なスキーマを定義(JSON Schema draft-07 オブジェクト)。
// アプリで型付きスキーマを使用するには、`@types/json-schema` をインストールして `JSONSchema7` を使用してください。
const profileSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
properties: {
name: {type: 'string'},
identityId: {type: 'string'},
},
type: 'object',
};

export const createProfileSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
...profileSchema,
required: ['name', 'identityId'],
},
},
},
required: true,
},
});

// 同じスキーマを複数のルートに適用
const createProfileFeature = compose(createProfileSchema, createProfileRoute);
const updateProfileFeature = compose(createProfileSchema, updateProfileRoute);

withRoute

withRoute プリミティブは HTTP および WebSocket エンドポイントを定義します。プロトコル、HTTP メソッド(HTTP ルートの場合)、パス、バリデータ、ハンドラー関数を指定する設定オブジェクトを受け取ります。

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

const {compose, flatMapAsync, lift, orThrow, withLogging, withRoute} = primitives;
const {isAuthenticated, checkIdentityType, isSelf, some} = validators;

// 簡略化した例 — 本番の profile ルートはアバター/ドキュメントも正規化します。
const createProfileRoute = withRoute({
handler: compose(
withLogging(createProfile),
flatMapAsync(withLogging(getProfileById)),
lift(withLogging(orThrow([], [['context', 'data', 'normalizedProfile']]))),
),
method: 'POST',
path: '/profiles',
validators: [isAuthenticated(), some(checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'identityId']))],
});

Feature

Feature は関連する機能を論理的にグループ化したもので、通常は 1 つ以上のルートとそれに関連するスキーマで構成されます。その部分を合成することで feature を作成します。

// スキーマとルートを合成して完全な feature を作成
export const createProfileFeature = compose(createProfileSchema, createProfileRoute);

⚡ クイックスタート

最初の API をすぐに立ち上げたいですか?ステップバイステップのクイックスタートチュートリアルに従って、インストール、サーバーの初期設定、最初のリクエストのテストを順番に実行してください。

クイックスタートチュートリアルを開く →


📑 利用可能なドキュメント

How-To ガイド

一般的な開発タスクと高度なカスタマイズシナリオをステップバイステップで案内するチュートリアル。

コンポーネント

各アーキテクチャコンポーネントの詳細な解説。API リファレンス、使用パターン、ベストプラクティスを含む。

組み込みサービス

すぐに使用できるサービスで、基本的な機能をそのまま提供し、完全なカスタマイズオプション付き。


🙌 コントリビューション

バグを見つけた、またはアイデアがありますか?GitHub で issue や PR をオープンしてください。コントリビューションを歓迎します。