メインコンテンツまでスキップ
バージョン: 0.4.2

📐 スキーマ

スキーマは形状を形成し、データの検証を提供します。NodeblocksはJSON Schema Draft-07に依存しており、これは言語に依存せず、ツールフレンドリーです。スキーマを定義するには、withSchemaプリミティブ関数を使用します。


1️⃣ 構造

src/schemas/review.ts
import { primitives } from '@nodeblocks/backend-sdk';

const { withSchema } = primitives;

const reviewIdPathParameter: primitives.OpenAPIParameter = {
in: 'path',
name: 'reviewId',
required: true,
schema: {
type: 'string',
},
};

export const reviewSchema: primitives.SchemaDefinition = {
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
properties: {
productId: { type: 'string' },
rating: { type: 'number', minimum: 1, maximum: 5 },
comment: { type: 'string' },
},
type: 'object',
};

export const createReviewSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: { ...reviewSchema, required: ['productId', 'rating'] },
},
},
required: true,
},
});

export const updateReviewSchema = withSchema({
parameters: [{ ...reviewIdPathParameter }],
requestBody: {
content: {
'application/json': {
schema: {
additionalProperties: false,
properties: {
comment: { type: 'string' },
},
required: [],
type: 'object',
},
},
},
required: true,
},
});
  • withSchema(...)はJSON定義をラップし、ランタイム検証を注入します。

2️⃣ フィールド要件

必須フィールド

スキーマのrequired配列は、どのフィールドを提供する必要があるかを決定します:

// このスキーマはproductIdとratingを必要とします
export const createReviewSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
...reviewSchema,
required: ['productId', 'rating'] // 必須フィールド
},
},
},
required: true,
},
});

// このスキーマは必須フィールドがありません(部分更新用)
export const updateReviewSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
properties: {
comment: { type: 'string' },
rating: { type: 'number', minimum: 1, maximum: 5 }
},
required: [], // すべてオプション
type: 'object',
},
},
},
required: true,
},
});

データ型と検証

JSON Schemaは豊富な検証オプションを提供します:

export const userSchema: primitives.SchemaDefinition = {
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
properties: {
email: {
type: 'string',
format: 'email' // メール形式の検証
},
age: {
type: 'number',
minimum: 18, // 最小値
maximum: 120 // 最大値
},
name: {
type: 'string',
minLength: 2, // 最小文字数
maxLength: 50 // 最大文字数
},
status: {
type: 'string',
enum: ['active', 'inactive', 'pending'] // 許可された値
},
tags: {
type: 'array',
items: { type: 'string' },
uniqueItems: true // 重複を許可しない
}
},
type: 'object',
};

3️⃣ パラメーター検証

パスパラメーター

URLパスのパラメーターを検証:

const userIdPathParameter: primitives.OpenAPIParameter = {
in: 'path',
name: 'userId',
required: true,
schema: {
type: 'string',
pattern: '^[a-f\\d]{24}$' // MongoDB ObjectId形式
},
};

export const getUserSchema = withSchema({
parameters: [userIdPathParameter]
});

クエリパラメーター

URLクエリパラメーターを検証:

const paginationParameters: primitives.OpenAPIParameter[] = [
{
in: 'query',
name: 'page',
required: false,
schema: {
type: 'number',
minimum: 1,
default: 1
}
},
{
in: 'query',
name: 'limit',
required: false,
schema: {
type: 'number',
minimum: 1,
maximum: 100,
default: 20
}
}
];

export const findUsersSchema = withSchema({
parameters: paginationParameters
});

4️⃣ 再利用可能なスキーマ

ベーススキーマの定義

// ベースユーザースキーマ
export const baseUserSchema: primitives.SchemaDefinition = {
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
properties: {
email: { type: 'string', format: 'email' },
name: { type: 'string', minLength: 2, maxLength: 50 },
status: { type: 'string', enum: ['active', 'inactive'] }
},
type: 'object',
};

// 作成用(すべて必須)
export const createUserSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
...baseUserSchema,
required: ['email', 'name', 'status']
},
},
},
required: true,
},
});

// 更新用(すべてオプション)
export const updateUserSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
...baseUserSchema,
required: []
},
},
},
required: true,
},
});

スキーマコンポジション

// 共通アドレススキーマ
const addressSchema = {
type: 'object',
properties: {
street: { type: 'string' },
city: { type: 'string' },
country: { type: 'string' },
postalCode: { type: 'string' }
},
required: ['street', 'city', 'country']
};

// ユーザースキーマにアドレスを含める
export const userWithAddressSchema: primitives.SchemaDefinition = {
...baseUserSchema,
properties: {
...baseUserSchema.properties,
address: addressSchema
}
};

5️⃣ ベストプラクティス

1. 厳密な検証

// 良い - 厳密な検証
export const userSchema = {
additionalProperties: false, // 追加プロパティを許可しない
properties: {
email: { type: 'string', format: 'email' },
age: { type: 'number', minimum: 0, maximum: 150 }
},
required: ['email'],
type: 'object'
};

// 悪い - 緩い検証
export const userSchema = {
additionalProperties: true, // 任意のプロパティを許可
properties: {
email: { type: 'string' }, // フォーマット検証なし
age: { type: 'number' } // 範囲制限なし
}
};

2. 意味のあるエラーメッセージ

export const userSchema = {
properties: {
email: {
type: 'string',
format: 'email',
errorMessage: '有効なメールアドレスを入力してください'
},
password: {
type: 'string',
minLength: 8,
errorMessage: 'パスワードは8文字以上である必要があります'
}
}
};

3. スキーマの再利用

// 共通プロパティを定義
const timestampProperties = {
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' }
};

// 複数のスキーマで再利用
export const userSchema = {
properties: {
...userProperties,
...timestampProperties
}
};

export const productSchema = {
properties: {
...productProperties,
...timestampProperties
}
};

➡️ 次へ

バリデーターについて学習して、カスタム検証ロジックをルートに追加する方法を理解しましょう!