JSON Toolkit

FAQ k dotazování a validaci: JSONPath a Schema

Shrnutí: Zda má dotazování cest používat JSONPath, nebo Pointer, jak volit mezi Patch a Merge Patch, co Schema umí zablokovat a jak vybrat verzi návrhu – vše v jednom průchodu.

Středně pokročilý~12 min čteníPublikováno 2026-10-30Aktualizováno 2026-10-30
Titulní obrázek článku FAQ k dotazování a validaci

Stručně: JSONPath použijte k nalezení uzlů podle podmínky, JSON Pointer nebo JSON Patch k adresování a úpravě přesných umístění a Merge Patch ke sloučení konfigurace; nová Schema zafixujte na 2020-12 a zapněte allErrors, aby se všechny poruchy vrátily v jednom průchodu.

Dotazování je „najdi to“; validace je „potvrď, že to je správně“. Každé má svůj standard, takže je nemíchejte.

1. Dotazování cest

Jak volit mezi JSONPath a JSON Pointer?

Záleží na tom, zda „hledáte podle podmínky“, nebo „načítáte podle pozice“.

Dimenze JSONPath JSON Pointer
Standard RFC 9535 (2024) RFC 6901 (2013)
Výraz $.users[?(@.age > 18)].id /users/0/id
Zástupné znaky a rekurze Podporuje *, .. Nepodporováno
Podmíněné filtrování Podporováno Nepodporováno
Výsledek Množina uzlů (možná několik) Jedno umístění
Vyjádřivost Silná, ale s těžkým dědictvím rozdílů mezi implementacemi Slabá, ale plně deterministická
Typické použití Extrakce z logů, ladění, průzkum dat JSON Patch, adresování konfigurace, cesty chyb

Pravidlo volby je přímočaré:

  • Potřebujete „získat všechny uzly odpovídající podmíně“ → JSONPath;
  • Potřebujete „určit jedno přesné umístění a přidat, odebrat nebo upravit ho“ → JSON Pointer;
  • Použijte je spolu: najděte uzel pomocí JSONPath a popište jeho umístění pomocí Pointer.

Nepoužívejte JSONPath pro adresování ve smlouvě API. JSONPath vrací množinu a tři větve pro prázdný, jednočlenný a vícečlenný výsledek protokol komplikují; Pointer znamená „buď ukazuje na existující umístění, nebo neexistuje“, což se ke smlouvě hodí lépe.

Jaký je rozdíl mezi $.. a $.*?

$.. je rekurzivní sestup a prochází každou úroveň; $.* vrací jen přímé potomky aktuální úrovně.

{
  "a": { "id": 1, "child": { "id": 2 } },
  "b": { "id": 3 }
}
  • $.* → dva objekty {id:1, child:{...}} a {id:3};
  • $..id → tři hodnoty: 1, 2, 3;
  • $.*.id → 1 a 3, bez vnořeného 2.

Rekurzivní sestup je šikovný, ale drahý: $.. prochází celý strom, což je u velkého dokumentu O(n), a snadno sebere hluboká pole, která jste nezamýšleli. Pokud funguje konkrétní úroveň, vyhněte se ...

Umějí filtry porovnávat řetězce? Umějí párovat regulárním výrazem?

Porovnání řetězců funguje; regulární výraz závisí na implementaci.

Standardní syntaxe (RFC 9535):

$.items[?(@.status == "active")]
$.items[?(@.price > 10 && @.stock > 0)]
$.items[?(@.name == $.target)]      // porovnání s jiným uzelm

Porovnání řetězců používá dvojité uvozovky (RFC 9535 povoluje i jednoduché, ale některé starší implementace přijímají jen dvojité). Číselné porovnání se řídí číselnou sémantikou; míchání řetězce s číslem, například "10" > 9, je ve standardu nedefinované chování, takže se na něj nespoléhejte.

Pro regulární výrazy RFC 9535 definuje funkce match() a search(), ale jejich podpora se mezi implementacemi značně liší. Bezpečný přístup: nechte JSONPath na hrubé filtrování a párování regulárním výrazem udělejte v kódu po získání výsledků.

Mám použít JSON Patch, nebo Merge Patch?

Oba popisují „jak něco změnit“, ale jejich vyjádřivost a sémantika jsou zcela odlišné.

Dimenze JSON Patch (RFC 6902) Merge Patch (RFC 7386)
Forma Pole operací [{"op":"add",...}] Částečný objekt
Podporované operace add / remove / replace / move / copy / test Jen sloučení (smazání pomocí null)
Adresování prvků pole Ano, podle indexu Ne, celé pole se nahradí
Atomicita test umožňuje optimistické zamykání Žádná
Velikost dokumentu Velká, ale přesná Malá, ale omezená vyjádřivost
Hodí se pro Jemnozrnné úpravy, částečné aktualizace API Slučování konfigurace, částečné odeslání formuláře

Kritéria rozhodování:

  • Změnit pole třetího prvku v poli → JSON Patch;
  • Sloučit několik konfiguračních položek do existující konfigurace → Merge Patch;
  • Získat řízení souběžnosti „selhat, když původní hodnota není X“ → test v JSON Patch.

Pozor na past sémantiky null v Merge Patch: null znamená „smaž tento klíč“, nikoli „nastav hodnotu na null“. Nastavit hodnotu na null je v Merge Patch nemožné.

2. Validace schématem

Jaké problémy JSON Schema řeší?

Mění „jak mají data vypadat“ z verbální dohody na strojově kontrolovatelnou smlouvu. Chyby, které skutečně umí zablokovat:

  • Chybějící povinná pole (required);
  • Špatný typ, například řetězec tam, kde se čeká číslo (type);
  • Hodnoty mimo rozsah (minimum / maximum / minLength);
  • Hodnoty mimo povolenou množinu (enum);
  • Nekonzistentní typy prvků pole nebo špatná délka pole (items / minItems);
  • Chybějící pole ve vnořených strukturách (rekurzivní validace přes properties);
  • Nadbytečná pole (additionalProperties: false).

Co neumí vyřešit: obchodní pravidla („čas konce musí být pozdější než čas začátku“), podmínky napříč poli (některé lze vyjádřit pomocí if/then, ale čitelnost trpí), jedinečnost v databázi a kontroly oprávnění.

Schema je tedy vrátný pro „tvar dat“, nikoli náhrada obchodní logiky.

Mám použít draft-07, nebo 2020-12?

Pro nové projekty použijte 2020-12; u existujících systémů zkontrolujte, co validátor podporuje.

Verze Stav Klíčové změny
draft-04 Zastaralý Mnoho starších knihoven ho stále používá jako výchozí
draft-07 De facto standard Nejširší podpora, nejbohatší ekosystém
2019-09 Přechodný Zavedl $defs, unevaluatedProperties
2020-12 Aktuálně doporučený items rozděleno na prefixItems + items, podporuje $dynamicRef

Dvě migrační pasti:

  1. Syntaxe n-tic se změnila: v draft-07 pole-hodnota items vyjadřovalo n-tici; 2020-12 to přesunulo do prefixItems;
  2. $ref a související klíčová slova: v draft-07 se související klíčová slova ignorují, když je přítomno $ref; 2020-12 umožňuje jejich koexistenci.

Pokud validátor podporuje jen draft-07, psaní syntaxe 2020-12 i přesto je tiše ignorováno – a nejnebezpečnější případ je „validace prošla“, když se nevalidovalo vůbec nic.

Jak generovat typy TypeScript ze Schema?

Dvě cesty: odvodit typy ze Schema, nebo generovat Schema z typů.

Ze Schema do typů (backend definuje kontrakt, frontend ho konzumuje):

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 }

Klíčové je as const: bez něj se type: 'string' odvodí jako string, nikoli jako literál 'string', a odvozování se rozpadne.

Z typů do Schema (frontend už typy má a potřebuje validaci za běhu):

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);

Výhodou této cesty je, že „jedna definice vydá jak typy, tak validaci za běhu“; cenou je zavádění DSL a vygenerované Schema může nést detaily implementace (například neatraktivní strukturu $ref).

Jak při selhání validace lokalizovat konkrétní pole?

Podívejte se na instancePath (2020-12) nebo dataPath (draft-07), které validátor vrátil; je to JSON Pointer na místo chyby.

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

instancePath: "/items/2/price" vám přímo řekne: pole price třetího prvku v poli items má špatný typ.

Dvě praktické rady:

  1. Vracejte všechny chyby najednou, místo abyste vyhazovali u první – oprava všeho frontendem v jednom průchodu je rychlejší než zkoušení tam a zpět;
  2. Přeložte Pointer do běžného jazyka, než ho ukážete koncovým uživatelům; /items/2/price je užitečné pro vývojáře a pro uživatele zbytečné.

allErrors: true je přepínač ve většině validátorů (Ajv ho vyžaduje explicitně zapnout); výchozí nastavení je často režim fail-fast.

Má se zapnout additionalProperties: false?

Zapněte ho pro interní kontrakty; u veřejných API buďte opatrní.

Po zapnutí selže validace každého pole, které není deklarováno pod properties. Přínosem je zachycení překlepů (userNmae) a nečekaného procházení; nevýhodou je, že přidání pole upstreamem rozbije downstream konzumenty a zničí zpětnou kompatibilitu.

Kompromis:

Scénář Doporučení
Mezi interními službami Zapnout. Změny polí procházejí verzováním
Veřejná externí API Vypnout. Nechte upstream přidávat pole
Konzumace dat třetích stran Vypnout. Protější stranu nekontrolujete
Validace konfigurace Zapnout. Překlep v konfiguraci má selhat okamžitě

Jak validovat, že prvky pole jsou jedinečné?

Dvě různé sémantiky – nezaměňujte je:

{ "uniqueItems": true }

Toto deduplikuje celý prvek, tedy vyžaduje, aby pole neobsahovalo dva hluboce shodné prvky.

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

Úryvek výše zaručuje jen, že objekty jako celek nejsou duplikované; {"id":"a","name":"x"} a {"id":"a","name":"y"} se za duplikáty nepovažují.

Deduplikaci podle konkrétního pole Schema vyjádřit neumí; musíte validovat v obchodní vrstvě:

const ids = items.map((item) => item.id);
if (new Set(ids).size !== ids.length) {
  throw new Error('id 重复');
}

Validuje format skutečně e-maily a data?

Ne nutně. Ve specifikaci je format ve výchozím nastavení „anotace“, nikoli „assertion“, takže validátor ho může sbírat, aniž by ho validoval.

  • Ajv vyžaduje instalaci a konfiguraci samostatného balíčku ajv-formats, jinak je format: "email" fakticky neúčinný;
  • Některé validátory považují format za assertion zapnutý ve výchozím nastavení, takže chování je nekonzistentní;
  • I když je zapnutý, regulární výraz pro email je velmi volný – a@b projde.

Závěr: nepovažujte format za silnou validaci. Přísnou validaci e-mailů, URL a dat dělejte v obchodním kódu; držet format ve Schema jako dokumentaci má smysl, ale nečekejte, že zastaví špinavá data.

3. Rychlý přehled

Otázka Závěr
Najít uzly podle podmínky JSONPath
Přesné adresování, aplikace patchů JSON Pointer
Změnit prvky pole JSON Patch, Merge Patch to neumí
Sloučení konfigurace Merge Patch
Verze Schema pro nové projekty 2020-12, pozor na prefixItems
Generovat typy TS ze Schema json-schema-to-ts + as const
Lokalizovat validační chyby Přečtěte instancePath, zapněte allErrors
Deduplikace podle pole Schema neumí; použijte Set v obchodní vrstvě
format: email Většina validátorů ho ve výchozím nastavení nekontroluje, nespoléhejte se na něj