📐 スキーマ
スキーマは形状を形成し、データの検証を提供します。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
}
};
➡️ 次へ
バリデーターについて学習して、カスタム検証ロジックをルートに追加する方法を理解しましょう!