JSON Toolkit

কোয়েরি ও ভ্যালিডেশন FAQ: JSONPath ও Schema

সংক্ষেপে: পাথ কোয়েরিতে JSONPath নাকি Pointer, Patch বনাম Merge Patch কীভাবে বাছবেন, Schema আসলে কী আটকায়, আর draft সংস্করণ কীভাবে বাছবেন — সব একসঙ্গে ব্যাখ্যা।

মধ্যবর্তী~12 মিনিট পড়াপ্রকাশ 2026-10-30আপডেট 2026-10-30
কোয়েরি ও ভ্যালিডেশন FAQ-র কভার

মূল কথা: শর্ত দিয়ে নোড খুঁজতে JSONPath, নির্দিষ্ট অবস্থান সম্বোধন ও সম্পাদনায় JSON Pointer বা JSON Patch, আর কনফিগ মার্জে Merge Patch ব্যবহার করুন; নতুন Schema 2020-12-তে পিন করুন আর allErrors চালু করুন যাতে একবারেই সব ব্যর্থতা ফিরে আসে।

কোয়েরি মানে "খুঁজে বের করা"; ভ্যালিডেশন মানে "সঠিক কি না নিশ্চিত করা"। প্রতিটির নিজস্ব স্ট্যান্ডার্ড, তাই মিশাবেন না।

১. পাথ কোয়েরি

JSONPath ও JSON Pointer-এর মধ্যে কীভাবে বাছাই করব?

এটি নির্ভর করে আপনি "শর্ত দিয়ে খুঁজছেন" নাকি "অবস্থান দিয়ে নিচ্ছেন"।

মাত্রা JSONPath JSON Pointer
স্ট্যান্ডার্ড RFC 9535 (২০২৪) RFC 6901 (২০১৩)
এক্সপ্রেশন $.users[?(@.age > 18)].id /users/0/id
ওয়াইল্ডকার্ড ও পুনরাবৃত্তি *, .. সমর্থন করে সমর্থিত নয়
শর্তাধীন ফিল্টার সমর্থিত সমর্থিত নয়
ফল একটি নোড সেট (হয়তো কয়েকটি) একটি একক অবস্থান
প্রকাশক্ষমতা শক্তিশালী, তবে বাস্তবায়নের পার্থক্যের ভারী উত্তরাধিকার দুর্বল, কিন্তু সম্পূর্ণ নির্ধারক
সাধারণ ব্যবহার লগ এক্সট্রাকশন, ডিবাগিং, ডেটা অন্বেষণ JSON Patch, কনফিগ সম্বোধন, এরর পাথ

বাছাইয়ের নিয়ম সরল:

  • "শর্ত মেলে এমন সব নোড আনতে হবে" → JSONPath;
  • "একটি নির্দিষ্ট অবস্থান পিন করে যোগ, মোছা বা বদলাতে হবে" → JSON Pointer;
  • একসঙ্গে ব্যবহার করুন: JSONPath দিয়ে নোড খুঁজুন, Pointer দিয়ে তার অবস্থান বর্ণনা করুন।

API চুক্তিতে সম্বোধনের জন্য JSONPath ব্যবহার করবেন না। JSONPath একটি সেট ফেরত দেয়, আর খালি, একক-এলিমেন্ট ও বহু-এলিমেন্ট ফলের তিন শাখা প্রোটোকল জটিল করে তোলে; Pointer মানে "হয় বিদ্যমান অবস্থানে ইশারা করে, নয় অস্তিত্ব নেই", যা চুক্তিতে ভালো মানায়।

$.. ও $.*-এর পার্থক্য কী?

$.. পুনরাবৃত্ত ডিসেন্ট আর প্রতিটি স্তর হাঁটে; $.* কেবল চলতি স্তরের প্রত্যক্ষ শিশু ফেরত দেয়।

{
  "a": { "id": 1, "child": { "id": 2 } },
  "b": { "id": 3 }
}
  • $.* → দুই অবজেক্ট {id:1, child:{...}} ও {id:3};
  • $..id → তিন মান: 1, 2, 3;
  • $.*.id → 1 ও 3, নেস্টেড 2 বাদ দিয়ে।

পুনরাবৃত্ত ডিসেন্ট সুবিধাজনক কিন্তু দামি: $.. পুরো ট্রি হাঁটে, বড় ডকুমেন্টে O(n), আর আপনি না চাওয়া গভীর ফিল্ড সহজেই তুলে আনে। নির্দিষ্ট স্তর কাজ করলে .. এড়ান।

ফিল্টার কি স্ট্রিং তুলনা করতে পারে? রেগুলার এক্সপ্রেশন মেলাতে পারে?

স্ট্রিং তুলনা কাজ করে; রেগুলার বাস্তবায়নের উপর নির্ভর করে।

স্ট্যান্ডার্ড সিনট্যাক্স (RFC 9535):

$.items[?(@.status == "active")]
$.items[?(@.price > 10 && @.stock > 0)]
$.items[?(@.name == $.target)]      // compare with another node

স্ট্রিং তুলনা ডাবল কোট ব্যবহার করে (RFC 9535-এ সিঙ্গেল কোটও অনুমোদিত, কিন্তু কিছু পুরোনো বাস্তবায়ন কেবল ডাবল কোট গ্রহণ করে)। সংখ্যিক তুলনা সংখ্যার সেমান্টিক্স অনুসরণ করে; স্ট্রিং ও সংখ্যা মেশানো, যেমন "10" > 9, স্ট্যান্ডার্ডে অনির্ধারিত আচরণ, তাই নির্ভর করবেন না।

রেগুলার এক্সপ্রেশনের জন্য RFC 9535 match() ও search() ফাংশন সংজ্ঞায়িত করে, কিন্তু বাস্তবায়নভেদে সমর্থন বেশ আলাদা। নিরাপদ পথ: JSONPath দিয়ে মোটা ফিল্টার করুন, আর ফল আনার পর কোডে রেগুলার মেলান।

JSON Patch নাকি Merge Patch ব্যবহার করব?

দুটোই "কীভাবে কিছু বদলাবে" বর্ণনা করে, কিন্তু প্রকাশক্ষমতা ও সেমান্টিক্স সম্পূর্ণ আলাদা।

মাত্রা JSON Patch (RFC 6902) Merge Patch (RFC 7386)
রূপ অপারেশনের অ্যারে [{"op":"add",...}] আংশিক অবজেক্ট
সমর্থিত অপারেশন add / remove / replace / move / copy / test কেবল মার্জ (null দিয়ে মোছা)
অ্যারে এলিমেন্ট সম্বোধন হ্যাঁ, ইনডেক্স দিয়ে না, পুরো অ্যারে প্রতিস্থাপিত
পারমাণবিকতা test অপ্টিমিস্টিক লকিং দেয় নেই
ডকুমেন্ট আকার বড় কিন্তু নির্দিষ্ট ছোট কিন্তু প্রকাশক্ষমতায় সীমিত
উপযুক্ত সূক্ষ্ম সম্পাদনা, আংশিক API হালনাগাদ কনফিগ মার্জ, আংশিক ফর্ম জমা

সিদ্ধান্তের মানদণ্ড:

  • অ্যারের তৃতীয় এলিমেন্টের একটি ফিল্ড বদলাতে → JSON Patch;
  • কয়েকটি কনফিগ এন্ট্রি বিদ্যমান কনফিগে মার্জ করতে → Merge Patch;
  • "মূল মান X না হলে ব্যর্থ" কনকারেন্সি কন্ট্রোল চাইলে → JSON Patch-এর test।

Merge Patch-এর null সেমান্টিক্সের ফাঁদ খেয়াল করুন: null মানে "এই কি মুছুন", "মান null করুন" নয়। Merge Patch দিয়ে মান null করা অসম্ভব।

২. Schema ভ্যালিডেশন

JSON Schema কী সমস্যা সমাধান করে?

এটি "ডেটা কেমন দেখতে হবে" মৌখিক চুক্তি থেকে মেশিন-চেকযোগ্য চুক্তিতে বদলায়। যে এররগুলো সত্যিই আটকাতে পারে:

  • বাধ্যতামূলক ফিল্ড অনুপস্থিত (required);
  • ভুল টাইপ, যেমন সংখ্যা প্রত্যাশিত জায়গায় স্ট্রিং (type);
  • রেঞ্জের বাইরের মান (minimum / maximum / minLength);
  • অনুমোদিত সেটের বাইরের মান (enum);
  • অসামঞ্জস্যপূর্ণ অ্যারে এলিমেন্ট টাইপ বা ভুল অ্যারে দৈর্ঘ্য (items / minItems);
  • নেস্টেড কাঠামোয় অনুপস্থিত ফিল্ড (properties দিয়ে রিকার্সিভ ভ্যালিডেশন);
  • বাড়তি ফিল্ড (additionalProperties: false)।

যা সমাধান করতে পারে না: ব্যবসায়িক নিয়ম ("শেষ সময় শুরুর সময়ের পরে হতে হবে"), ক্রস-ফিল্ড শর্ত (কিছু if/then দিয়ে প্রকাশ করা যায়, কিন্তু পাঠযোগ্যতা ভোগে), ডেটাবেস অনন্যতা, অনুমতি চেক।

তাই Schema "ডেটার আকৃতি"-র দ্বাররক্ষী, ব্যবসায়িক লজিকের প্রতিস্থাপন নয়।

draft-07 নাকি 2020-12 ব্যবহার করব?

নতুন প্রকল্পে 2020-12; বিদ্যমান সিস্টেমে ভ্যালিডেটর কী সমর্থন করে দেখুন।

সংস্করণ অবস্থা মূল পরিবর্তন
draft-04 পুরোনো অনেক পুরোনো লাইব্রেরি এখনও ডিফল্টে এটি ব্যবহার করে
draft-07 বাস্তব মান সবচেয়ে বিস্তৃত সমর্থন, সমৃদ্ধতম ইকোসিস্টেম
2019-09 রূপান্তরকালীন $defs, unevaluatedProperties চালু
2020-12 বর্তমানে সুপারিশকৃত items prefixItems + items-এ ভাগ, $dynamicRef সমর্থন

দুটি মাইগ্রেশন ফাঁদ:

  1. টাপল সিনট্যাক্স বদলেছে: draft-07-এ অ্যারে-মানযুক্ত items টাপল প্রকাশ করত; 2020-12 তা prefixItems-এ সরিয়েছে;
  2. $ref ও পাশের কি-ওয়ার্ড: draft-07-এ $ref থাকলে পাশের কি-ওয়ার্ড উপেক্ষিত; 2020-12 সহাবস্থানের অনুমতি দেয়।

ভ্যালিডেটর কেবল draft-07 সমর্থন করলে 2020-12 সিনট্যাক্স লিখলে নীরবে উপেক্ষিত হয় — আর সবচেয়ে বিপজ্জনক ক্ষেত্র "ভ্যালিডেশন পাস" যখন কিছুই যাচাই হয়নি।

Schema থেকে TypeScript টাইপ কীভাবে জেনারেট করব?

দুই পথ: Schema থেকে টাইপ বের করা, বা টাইপ থেকে Schema জেনারেট করা।

Schema থেকে টাইপে (ব্যাকএন্ড চুক্তি সংজ্ঞায়িত করে, ফ্রন্টএন্ড ভোগ করে):

import type { FromSchema } from 'json-schema-to-ts';

const userSchema = {
  type: 'object',
  properties: {
    id: { type: 'string' },
    age: { type: 'integer' },
  },
  required: ['id'],
  additionalProperties: false,
} as const;

type User = FromSchema<typeof userSchema>;
// { id: string; age?: number }

মূল হলো as const: এটি ছাড়া type: 'string' লিটেরাল 'string' নয় বরং string হিসেবে অনুমিত হয়, আর অনুমান ভেঙে পড়ে।

টাইপ থেকে Schema (ফ্রন্টএন্ডের টাইপ আগেই আছে, রানটাইম ভ্যালিডেশন দরকার):

import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';

const userSchema = z.object({ id: z.string(), age: z.number().int().optional() });
const jsonSchema = zodToJsonSchema(userSchema);

এই পথের সুবিধা "এক সংজ্ঞা থেকেই টাইপ ও রানটাইম ভ্যালিডেশন"; দাম হলো একটি DSL আনা, আর জেনারেট করা Schema বাস্তবায়নের খুঁটিনাটি বহন করতে পারে (যেমন অপছন্দনীয় $ref কাঠামো)।

ভ্যালিডেশন ব্যর্থ হলে নির্দিষ্ট ফিল্ড কীভাবে লোকেট করব?

ভ্যালিডেটরের ফেরত দেওয়া instancePath (2020-12) বা dataPath (draft-07) দেখুন; এটি এরর লোকেশনের JSON Pointer।

[
  {
    "instancePath": "/items/2/price",
    "schemaPath": "#/properties/items/items/properties/price/type",
    "keyword": "type",
    "message": "must be number"
  }
]

instancePath: "/items/2/price" সোজা বলে দেয়: items অ্যারের তৃতীয় এলিমেন্টের price ফিল্ডের টাইপ ভুল।

দুটি ব্যবহারিক পরামর্শ:

  1. একবারে সব এরর ফেরত দিন, প্রথমটায় throw না করে — ফ্রন্টএন্ড একবারে সব ঠিক করলে বারবার চেষ্টার চেয়ে দ্রুত;
  2. শেষ ব্যবহারকারীকে দেখানোর আগে Pointer-কে সাধারণ ভাষায় বদলান; /items/2/price ডেভেলপারের কাজে লাগে, ব্যবহারকারীর অকেজো।

allErrors: true অধিকাংশ ভ্যালিডেটরে সুইচ (Ajv স্পষ্টভাবে চালু করতে হয়); ডিফল্ট প্রায়ই fail-fast মোড।

additionalProperties: false চালু করা উচিত?

অভ্যন্তরীণ চুক্তিতে চালু; পাবলিক API-তে সতর্ক।

চালু হলে properties-এর অধীনে অঘোষিত যেকোনো ফিল্ড ভ্যালিডেশনে ব্যর্থ। সুবিধা টাইপো (userNmae) ও অপ্রত্যাশিত pass-through ধরা; অসুবিধা হলো আপস্ট্রিমের একটি ফিল্ড যোগ ডাউনস্ট্রিম ভোক্তা ভাঙে, পশ্চাৎ-সামঞ্জস্য নষ্ট করে।

মধ্যবর্তী পথ:

পরিস্থিতি সুপারিশ
অভ্যন্তরীণ সার্ভিসের মধ্যে চালু। ফিল্ড পরিবর্তন সংস্করণ ব্যবস্থাপনার মধ্য দিয়ে যাক
পাবলিক বাহ্যিক API বন্ধ। আপস্ট্রিমকে ফিল্ড যোগ করতে দিন
তৃতীয়-পক্ষ ডেটা ভোগ বন্ধ। অন্যপক্ষ আপনার নিয়ন্ত্রণে নয়
কনফিগারেশন ভ্যালিডেশন চালু। কনফিগে টাইপো সঙ্গে সঙ্গে ব্যর্থ হওয়া উচিত

অ্যারে এলিমেন্ট অনন্য কি না কীভাবে যাচাই করব?

দুই ভিন্ন সেমান্টিক্স — গুলাবেন না:

{ "uniqueItems": true }

এটি পুরো এলিমেন্ট ডুপ্লিকেটমুক্ত করে, অ্যারেতে দুইটি গভীরভাবে সমান এলিমেন্ট না থাকা দাবি করে।

{
  "type": "array",
  "items": { "type": "object", "properties": { "id": { "type": "string" } } },
  "uniqueItems": true
}

উপরের অংশটি কেবল নিশ্চিত করে অবজেক্টগুলো সামগ্রিকভাবে ডুপ্লিকেট নয়; {"id":"a","name":"x"} ও {"id":"a","name":"y"} ডুপ্লিকেট হিসেবে গোনা হয় না।

নির্দিষ্ট ফিল্ড দিয়ে ডুপ্লিকেটমুক্ত করতে Schema প্রকাশ করতে পারে না; ব্যবসায়িক স্তরে যাচাই করতে হবে:

const ids = items.map((item) => item.id);
if (new Set(ids).size !== ids.length) {
  throw new Error('id ডুপ্লিকেট');
}

format কি সত্যিই ইমেইল ও তারিখ যাচাই করে?

অগত্যা নয়। স্পেসিফিকেশনে format ডিফল্টে "assertion" নয়, "annotation", তাই ভ্যালিডেটর এটি সংগ্রহ করে যাচাই নাও করতে পারে।

  • Ajv-তে আলাদা ajv-formats প্যাকেজ ইনস্টল ও কনফিগ করতে হয়, নাহলে format: "email" কার্যত নিষ্ক্রিয়;
  • কিছু ভ্যালিডেটর format-কে ডিফল্টে চালু assertion ধরে, তাই আচরণ অসামঞ্জস্যপূর্ণ;
  • চালু থাকলেও email রেগুলার এক্সপ্রেশন খুব শিথিল — a@b পাস করে।

উপসংহার: format-কে কঠোর ভ্যালিডেশন ধরবেন না। ইমেইল, URL ও তারিখের কঠোর ভ্যালিডেশন ব্যবসায়িক কোডে করুন; Schema-তে ডকুমেন্টেশন হিসেবে format রাখা মূল্যবান, কিন্তু নোংরা ডেটা আটকাবে প্রত্যাশা করবেন না।

৩. দ্রুত রেফারেন্স

প্রশ্ন উপসংহার
শর্ত দিয়ে নোড খোঁজা JSONPath
নির্দিষ্ট সম্বোধন, প্যাচ প্রয়োগ JSON Pointer
অ্যারে এলিমেন্ট বদলানো JSON Patch, Merge Patch পারে না
কনফিগারেশন মার্জ Merge Patch
নতুন প্রকল্পে Schema সংস্করণ 2020-12, prefixItems খেয়াল করুন
Schema থেকে TS টাইপ json-schema-to-ts + as const
ভ্যালিডেশন এরর লোকেট instancePath পড়ুন, allErrors চালু করুন
ফিল্ড দিয়ে ডুপ্লিকেটমুক্ত Schema পারে না; ব্যবসায়িক স্তরে Set ব্যবহার করুন
format: email বেশিরভাগ ভ্যালিডেটর ডিফল্টে চেক করে না, তাই নির্ভর করবেন না