JSON Toolkit

JSON Schema: মূল বিষয় থেকে প্রোডাকশন

সংক্ষেপে: কি-ওয়ার্ড অনেক, কিন্তু প্রতিদিন ব্যবহৃত হয় কেবল ডজনখানেক। type/properties/required/$ref ঠিক করুন, এরর মেসেজ ভালো সামলান, তাহলে বাস্তবের আশি শতাংশ ঢাকা পড়ে।

মধ্যবর্তী~14 মিনিট পড়াপ্রকাশ 2026-10-30আপডেট 2026-10-30
JSON Schema: মূল বিষয় থেকে প্রোডাকশন নিবন্ধের কভার

মূল কথা: আগে $schema-কে 2020-12-তে পিন করুন, তারপর $defs + $ref দিয়ে ভাগ করা কাঠামো বের করুন; oneOf কেবল যখন ঠিক একটি শাখা মিলতেই হবে তখন ব্যবহার করুন, বাকি সব জায়গায় discriminator বা anyOf-কে অগ্রাধিকার দিন।

স্কিমা ডকুমেন্টেশনের পরিশিষ্ট নয়; এটি এমন সম্পদ যা চালানো, পরীক্ষা ও জেনারেট করা যায়।

১. আগে সংস্করণ ঠিক করুন

সংস্করণ $schema মান অবস্থা নোট
draft-04 http://json-schema.org/draft-04/schema# পুরোনো লিগ্যাসি প্রকল্প ও কিছু OpenAPI 2.0 টুলিং
draft-07 http://json-schema.org/draft-07/schema# বহুল ব্যবহৃত OpenAPI 3.0-এর বাস্তব ভিত্তি
2019-09 https://json-schema.org/draft/2019-09/schema প্রাপ্য $defs ও টীকা শব্দভাণ্ডার চালু
2020-12 https://json-schema.org/draft/2020-12/schema বর্তমানে সুপারিশকৃত prefixItems চালু, items-এর সেমান্টিক্স বদলেছে

নতুন প্রকল্পে 2020-12 ব্যবহার করুন। খেয়াল করুন 2020-12-তে items কেবল "বাকি এলিমেন্ট" বাধ্যতামূলক করে — টাপল-শৈলীর ঘোষণা prefixItems-এ সরেছে। draft-07 থেকে মাইগ্রেশনে এটাই সবচেয়ে সাধারণ ফাঁদ।

২. একটি ন্যূনতম ব্যবহারযোগ্য স্কিমা

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://bbdrug.com/schemas/user.json",
  "type": "object",
  "required": ["id", "name"],
  "properties": {
    "id": { "type": "string", "minLength": 1 },
    "name": { "type": "string", "minLength": 1, "maxLength": 64 },
    "age": { "type": "integer", "minimum": 0, "maximum": 150 },
    "tags": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }
  },
  "additionalProperties": false
}

এই স্কিমা চারটি সবচেয়ে সাধারণ চিন্তা ঢাকে: টাইপ বাধ্যবাধকতা, বাধ্যতামূলক ফিল্ড, রেঞ্জ সীমা, ও অ্যারে এলিমেন্ট বাধ্যবাধকতা।

৩. কি-ওয়ার্ড ম্যাপ

৩.১ সাধারণ

কি-ওয়ার্ড উদ্দেশ্য সতর্কতা
type টাইপ; অ্যারে হতে পারে "type": ["string", "null"] মানে nullable
enum এনাম মান মান অবশ্যই অনন্য হতে হবে
const একক-মান বাধ্যবাধকতা সংস্করণ সংখ্যার মতো স্থির মানের জন্য ভালো
$ref অন্য স্কিমা রেফারেন্স করে পুরো স্কিমা রেফারেন্স করে, রেফারেন্সকারী অবজেক্টের পাশের কি-ওয়ার্ডের সঙ্গে মার্জ হয় না

৩.২ সংখ্যা

multipleOf, maximum, exclusiveMaximum, minimum, exclusiveMinimum। খেয়াল করুন draft-04-তে exclusiveMaximum ছিল বুলিয়ান (maximum-এর সঙ্গে ব্যবহৃত); কেবল draft-07 থেকে এটি স্বতন্ত্র সংখ্যিক কি-ওয়ার্ড — যার ফলে "পুরোনো ডক থেকে কপি করা স্কিমা" অনেকগুলো strict মোডে ব্যর্থ হয়।

৩.৩ স্ট্রিং

minLength, maxLength, pattern (একটি ECMA-262 রেগুলার এক্সপ্রেশন), আর format (একটি টীকা)।

minLength ইউনিকোড কোড পয়েন্ট গোনে, UTF-16 একক নয়, বাইটও নয়। JavaScript-এর string.length দিয়ে যাচাই করলে অমিল হবে।

৩.৪ অ্যারে

কি-ওয়ার্ড উদ্দেশ্য
prefixItems 2020-12-এর টাপল-শৈলী বাধ্যবাধকতা, ইনডেক্স অনুযায়ী এলিমেন্ট মেলায়
items বাকি এলিমেন্টের সমান বাধ্যবাধকতা (2020-12)
contains + minContains/maxContains অন্তত/সর্বোচ্চ কতটি মিলে যাওয়া আইটেম থাকতে হবে
uniqueItems এলিমেন্ট সবাই আলাদা হতে হবে (গভীর তুলনা; বড় অ্যারেতে এড়ান)
minItems / maxItems দৈর্ঘ্য বাধ্যবাধকতা

৩.৫ অবজেক্ট

properties, required, patternProperties, additionalProperties, propertyNames, minProperties, maxProperties, dependentRequired, dependentSchemas।

তিনটি উচ্চ-কম্পাঙ্কের ভুল ধারণা:

  1. required কেবল কি থাকা দাবি করে: {"name": ""} বৈধ। খালি স্ট্রিং প্রত্যাখ্যান করতে minLength: 1 যোগ করতে হবে;
  2. additionalProperties: false সামঞ্জস্য সমস্যাকে বড় করে: ক্লায়েন্টের একটি বাড়তি ফিল্ড পুরো পেললোড ব্যর্থ করে, তাই API বিবর্তনে প্রতিটি কলারকে একসঙ্গে আপগ্রেড করতে বাধ্য করে;
  3. properties অঘোষিত কি সীমিত করে না — ডিফল্টে সেগুলো অনুমোদিত।

৩.৬ লজিক গঠন

{
  "oneOf": [
    { "type": "object", "required": ["cardNumber"], "properties": { "cardNumber": { "type": "string" } } },
    { "type": "object", "required": ["accountId"], "properties": { "accountId": { "type": "string" } } }
  ]
}
কি-ওয়ার্ড সেমান্টিক্স সাধারণ ব্যর্থতা
allOf সবই পূরণ করতে হবে একাধিক শাখা একই ফিল্ডে পরস্পরবিরোধী বাধ্যবাধকতা চাপায়
anyOf অন্তত একটি পূরণ করতে হবে এরর মেসেজ নির্দিষ্ট শাখায় ট্রেস করা কঠিন
oneOf ঠিক একটি পূরণ করতে হবে ডেটা দুই শাখা মেলে ব্যর্থ হয়, অথচ "স্পষ্টভাবে সঠিক" দেখায়
not পূরণ করা যাবে না কম ব্যবহৃত, এরর মেসেজ সবচেয়ে প্রতিকূল

oneOf "বৈধ ডেটা ভ্যালিডেশনে ব্যর্থ" উৎপন্ন করার সবচেয়ে সম্ভাব্য কি-ওয়ার্ড। শাখা বাধ্যবাধকতা ওভারল্যাপ করলে (যেমন দুইটিই বাড়তি ফিল্ড অনুমোদন করে), একটি রেকর্ড কয়েকটি শাখা মেলে আর oneOf সরাসরি ব্যর্থ হয়। সেক্ষেত্রে anyOf-তে যান, বা শাখাগুলোর ভেতরে const-যুক্ত discriminator ফিল্ড ব্যবহার করুন।

{
  "type": "object",
  "required": ["kind"],
  "properties": { "kind": { "enum": ["text", "image"] } },
  "if": { "properties": { "kind": { "const": "image" } } },
  "then": { "required": ["url", "width", "height"] },
  "else": { "required": ["content"] }
}

Discriminator শৈলী oneOf-এর চেয়ে বেশি পাঠযোগ্য, আর ভালো এরর দেয়।

৪. ভাগ ও পুনরায় ব্যবহার

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://bbdrug.com/schemas/order.json",
  "$defs": {
    "money": { "type": "string", "pattern": "^-?\\d+\\.\\d{2}$" },
    "address": {
      "type": "object",
      "required": ["city"],
      "properties": { "city": { "type": "string" }, "detail": { "type": "string" } }
    }
  },
  "type": "object",
  "required": ["total", "shipTo"],
  "properties": {
    "total": { "$ref": "#/$defs/money" },
    "shipTo": { "$ref": "#/$defs/address" }
  }
}
  • $defs 2019-09-এ চালু রূপ; draft-07 definitions ব্যবহার করে;
  • ফাইল-ছাড়ানো রেফারেন্স আপেক্ষিক $id ব্যবহার করে, কিন্তু প্রোডাকশনে রানটাইমে রিমোট স্কিমা ফেচের উপর নির্ভর করবেন না — স্ট্যাটিক ফাইল হিসেবে বান্ডল করুন;
  • রেফারেন্সের পাশে বাধ্যবাধকতা যোগ করা যায় না ($ref-এর পাশের কি-ওয়ার্ডের আচরণ সংস্করণভেদে আলাদা)। গঠন দরকার হলে allOf ব্যবহার করুন।

৫. Ajv দিয়ে রানটাইম ভ্যালিডেশন

import Ajv2020 from 'ajv/dist/2020';
import addFormats from 'ajv-formats';
import orderSchema from './order.json' with { type: 'json' };

const ajv = new Ajv2020({
  allErrors: true,
  strict: true,
  allowUnionTypes: true,
});
addFormats(ajv);

const validateOrder = ajv.compile(orderSchema);

export function assertOrder(input: unknown): void {
  if (validateOrder(input)) {
    return;
  }
  const detail = (validateOrder.errors ?? []).map((errorItem) => ({
    path: errorItem.instancePath || '/',
    keyword: errorItem.keyword,
    message: errorItem.message,
    params: errorItem.params,
  }));
  throw new Error(`অর্ডার ডেটা ভ্যালিডেশনে ব্যর্থ: ${JSON.stringify(detail)}`);
}

মূল বিষয়:

  • compile কেবল একবার কল করুন, মডিউল টপ লেভেলে; প্রতিটি রিকোয়েস্টে আবার কম্পাইল করলে ১০ ms ভ্যালিডেশন শত মিলিসেকেন্ডে বদলায়;
  • strict: true ভুল বানানের কি-ওয়ার্ড আগেই প্রকাশ করে (যেমন minLength-এর বদলে minlength), তাই চালু করা মূল্যবান;
  • কেবল ajv-formats দিলেই format: "email" ও format: "date-time" সত্যিই কার্যকর হয়;
  • 2020-12-এর জন্য ajv/dist/2020 এন্ট্রি পয়েন্ট দরকার — ডিফল্ট এক্সপোর্ট ব্যবহার করবেন না।

৬. এরর মেসেজ কীভাবে নকশা করবেন

ভ্যালিডেটর যা দেয় তা "কোন কি-ওয়ার্ড ব্যর্থ হয়েছে"; ব্যবহারকারী যা চায় তা "কোন ইনপুট বক্স ভুল"। একটি ম্যাপিং স্তর যোগ করা মূল্যবান:

const FIELD_LABEL: Record<string, string> = {
  '/name': 'Name',
  '/age': 'Age',
  '/tags': 'Tags',
};

/**
 * Convert Ajv errors into display-ready messages.
 * @param errors The list of Ajv errors
 * @returns An array of display messages
 */
function toMessages(errors: Array<{ instancePath: string; keyword: string; params: unknown }>): string[] {
  return errors.map((errorItem) => {
    const label = FIELD_LABEL[errorItem.instancePath] ?? errorItem.instancePath;
    if (errorItem.keyword === 'required') {
      const missing = (errorItem.params as { missingProperty: string }).missingProperty;
      return `${label} is missing the required field ${missing}`;
    }
    if (errorItem.keyword === 'minLength') {
      return `${label} is too short`;
    }
    return `${label} failed validation (${errorItem.keyword})`;
  });
}

API দিকে মেশিন-পাঠযোগ্য কাঠামো রাখুন যাতে ফ্রন্টএন্ড কীভাবে উপস্থাপন করবে ঠিক করতে পারে:

{
  "type": "https://bbdrug.com/problems/validation",
  "title": "রিকোয়েস্ট ডেটা ভ্যালিডেশনে ব্যর্থ",
  "status": 422,
  "errors": [
    { "path": "/items/0/price", "keyword": "pattern", "message": "দুই দশমিক স্থানের টাকার স্ট্রিং হতে হবে" }
  ]
}

৭. পারফরম্যান্স ও ফাঁদ

  • ভ্যালিডেশনের খরচ স্কিমা জটিলতা ও ডেটা আকারের সঙ্গে বাড়ে; একাধিক oneOf শাখা combinatorial explosion ঘটায়, যা কয়েক হাজার রেকর্ডে খুব লক্ষণীয় হয়;
  • uniqueItems অ্যারের উপর O(n²) গভীর তুলনা করে; বড় অ্যারেতে ব্যবসায়িক স্তরে ডুপ্লিকেটমুক্ত করুন;
  • pattern-এ catastrophic backtracking প্যাটার্ন (যেমন (a+)+$) এড়ান; এটি ReDoS-এর ক্লাসিক প্রবেশবিন্দু;
  • additionalProperties: false allOf-এর সঙ্গে মিললে উপ-স্কিমায় ঘোষিত ফিল্ড প্যারেন্টে "বাড়তি" ধরা পড়ে, তাই সেগুলো একক স্কিমায় মার্জ করতে হবে বা unevaluatedProperties ব্যবহার করতে হবে।

৮. চেকলিস্ট

  • [ ] 2020-12 পিন করুন ও ফাইলের উপরে $schema ঘোষণা করুন;
  • [ ] কপি-পেস্ট না করে $defs + $ref দিয়ে ভাগ করা কাঠামো বের করুন;
  • [ ] oneOf-এর বদলে discriminator-কে অগ্রাধিকার দিন;
  • [ ] ভ্যালিডেটরের compile ফল পুনরায় ব্যবহার করুন ও strict মোড চালু করুন;
  • [ ] format বলবৎ হয় কি না স্পষ্টভাবে ডকুমেন্ট করুন;
  • [ ] এরর রেসপন্স পাথ, কি-ওয়ার্ড ও ব্যবহারকারী-মুখী মেসেজ দেয়;
  • [ ] স্কিমা CI-তে রাখুন: JSON Schema Test Suite কেস রিগ্রেশন টেস্ট হিসেবে চালান।

সাধারণ প্রশ্ন

JSON Schema draft কীভাবে বাছাই করব?

নতুন প্রকল্পে 2020-12 ব্যবহার করুন আর ফাইলের উপরে $schema ঘোষণা করুন। স্কিমা OpenAPI 3.1-এ গেলে তাও 2020-12 হতে হবে, কারণ 3.1 সেই সংস্করণ সরাসরি এম্বেড করে; পুরোনো টুলচেইনে আটকে থাকা প্রকল্পে কেবল draft-07 রাখুন। items ও $ref-এর পাশের কি-ওয়ার্ডে দুইটির আচরণ আলাদা, তাই এক স্কিমা সেটে মিশাবেন না।

additionalProperties: false সামঞ্জস্য সমস্যাকে বড় করে কেন?

এটি প্রতিটি অঘোষিত কি-কে এরর ধরে, তাই ক্লায়েন্টের একটি বাড়তি ফিল্ড পুরো পেললোড ব্যর্থ করে। তখন API বিবর্তনে প্রতিটি কলারকে একসঙ্গে আপগ্রেড করতে হয়, নাহলে পুরোনো ক্লায়েন্ট প্রত্যাখ্যাত হয়। কনফিগ-শৈলীর স্কিমায় বাড়তি ফিল্ড স্পষ্টভাবে বন্ধ করা উচিত, অথচ পাবলিক API-তে সামঞ্জস্যের দাম বিবেচনা করতে হয়।

oneOf নাকি anyOf ব্যবহার করব?

ডেটা ঠিক একটি শাখা মিলতেই হবে কেবল তখন oneOf ব্যবহার করুন। শাখা বাধ্যবাধকতা একসঙ্গে সত্য হতে পারলে একটি রেকর্ড কয়েকটি শাখা মেলে আর oneOf সরাসরি ব্যর্থ হয়; anyOf-তে যান, বা প্রতিটি শাখার ভেতরে const discriminator যোগ করুন।

তথ্যসূত্র

সম্পর্কিত নিবন্ধ

স্কিমা ও TypeScript টাইপের দুইমুখী সিঙ্ক

টাইপ ও স্কিমা প্রতিটি একটি অংশ ঢাকে: একটি কম্পাইল সময়ে, একটি রানটাইমে। প্রশ্ন কোনটি বাছবেন তা নয়, বরং দুইটিকে কীভাবে স্বয়ংক্রিয়ভাবে সিঙ্কে রাখবেন।

মধ্যবর্তী~11 মিনিট পড়াআপডেট 2026-10-30

JSON API ডেটা চুক্তি নকশার মূল বিষয়

প্রকাশের পর বদলানো খুব কঠিন এমন ছয়টি জিনিস: রেসপন্স এনভেলপ, এরর ফরম্যাট, পেজিনেশনের আকৃতি, ID ও সময়ের উপস্থাপন, null বনাম অনুপস্থিতের সেমান্টিক্স, আর সংস্করণ বিবর্তন।

মধ্যবর্তী~13 মিনিট পড়াআপডেট 2026-10-30

additionalProperties ছাড়া Schema যাচাই কিছুই যাচাই করে না

যাচাই পাস মানে পরিষ্কার ডেটা নয়। Pydantic ডিফল্টভাবে অজানা ফিল্ড উপেক্ষা করে, Zod সেগুলো সরিয়ে দেয়, Ajv ছেড়ে দেয় — ভুল প্যারামিটার ও টাইপো কী নীরবে পার হয়ে যায়। এই নিবন্ধ নীরব গ্রহণের তিনটি রূপ দেখায় এবং সম্পূর্ণ পদ্ধতি দেয়: অবজেক্ট বন্ধ করা, কোয়ার্সন নিয়ন্ত্রণ, প্রতিটি নেস্টিং স্তর শক্ত করা।

Intermediate~8 মিনিট পড়াআপডেট 2026-11-02