[{"data":1,"prerenderedAt":3392},["ShallowReactive",2],{"blog-batch-en-json-validation-syntax-vs-schema-how-to-create-json-file":3},[4,1228,2265],{"id":5,"title":6,"author":7,"body":8,"category":1206,"date":1207,"description":1208,"draft":1209,"extension":1210,"h1":15,"image":1211,"lastmod":1207,"locales":1212,"meta":1214,"navigation":1215,"path":1216,"promo":1217,"seo":1221,"stem":1222,"tags":1223,"__hash__":1227},"blog\u002Fen\u002Fblog\u002Fhow-to-create-json-file.md","How to Create a JSON File: Step-by-Step Guide","JSON Toolbox Team",{"type":9,"value":10,"toc":1170},"minimark",[11,16,25,32,35,40,43,49,59,77,80,120,135,139,145,150,155,206,222,226,231,259,264,268,276,292,296,299,345,359,363,366,372,379,385,389,392,539,562,566,710,718,722,725,731,742,748,754,775,783,787,790,811,814,818,821,825,832,850,854,862,868,872,875,881,884,888,893,896,905,911,926,949,963,966,973,977,981,1000,1004,1007,1014,1025,1029,1035,1039,1058,1062,1072,1082,1098,1102,1110,1114,1161,1164],[12,13,15],"h1",{"id":14},"how-to-create-a-json-file-step-by-step-guide-for-beginners","How to Create a JSON File: Step-by-Step Guide for Beginners",[17,18,19,20,24],"p",{},"A JSON file is just a text file with the ",[21,22,23],"code",{},".json"," extension. You do not need special software, a paid tool, or an account — Notepad, TextEdit, and VS Code can all create one.",[17,26,27,28,31],{},"What trips people up is rarely the writing. It is the saving: Windows silently appending ",[21,29,30],{},".txt",", macOS TextEdit saving rich text instead of plain text, and a missing comma that makes the file unreadable to every JSON parser.",[17,33,34],{},"This guide covers what a JSON file is, how to create one on each operating system, the syntax rules that decide whether your file is valid, how to validate it, and how to generate JSON files from code.",[36,37,39],"h2",{"id":38},"what-is-a-json-file","What is a JSON file?",[17,41,42],{},"JSON (JavaScript Object Notation) is a plain-text data format built from two structures — objects and arrays — and six value types: string, number, boolean, null, object, and array.",[17,44,45,46,48],{},"A JSON file is a text file that contains JSON and uses the ",[21,47,23],{}," extension:",[50,51,57],"pre",{"className":52,"code":54,"language":55,"meta":56},[53],"language-json","{\n  \"name\": \"Ada Lovelace\",\n  \"role\": \"engineer\",\n  \"active\": true,\n  \"projects\": [\"analytical-engine\", \"bernoulli-numbers\"]\n}\n","json","",[21,58,54],{"__ignoreMap":56},[17,60,61,62,69,70,73,74,76],{},"Per ",[63,64,68],"a",{"href":65,"rel":66},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc8259",[67],"nofollow","RFC 8259",", the registered media type is ",[21,71,72],{},"application\u002Fjson"," and the file extension is ",[21,75,23],{},". Because it is plain text, you can read and edit it anywhere — and any programming language can parse it.",[17,78,79],{},"JSON files are used for:",[81,82,83,102,108,114],"ul",{},[84,85,86,90,91,94,95,94,98,101],"li",{},[87,88,89],"strong",{},"Configuration:"," ",[21,92,93],{},"package.json",", ",[21,96,97],{},"tsconfig.json",[21,99,100],{},"manifest.json",".",[84,103,104,107],{},[87,105,106],{},"Data exchange:"," API request and response bodies.",[84,109,110,113],{},[87,111,112],{},"Saved data:"," exports, fixtures, and test datasets.",[84,115,116,119],{},[87,117,118],{},"Logs:"," structured one-line records.",[17,121,122,123,126,127,130,131,101],{},"A JSON file has one root value. It is either an object (",[21,124,125],{},"{ }",") or an array (",[21,128,129],{},"[ ]",") in practice, and everything else nests inside it. If you are new to the format itself, start with ",[63,132,134],{"href":133},"\u002Fblog\u002Fwhat-is-json","What Is JSON? Structure, Syntax, and Common Mistakes",[36,136,138],{"id":137},"how-to-create-a-json-file-with-a-text-editor","How to create a JSON file with a text editor",[17,140,141,142,144],{},"Every operating system follows the same three steps: write the JSON, save the file with a ",[21,143,23],{}," extension as UTF-8, then validate it. The default editors differ, and each has one trap.",[146,147,149],"h3",{"id":148},"windows-notepad-or-vs-code","Windows: Notepad or VS Code",[17,151,152],{},[87,153,154],{},"Notepad:",[156,157,158,161,167,184,190],"ol",{},[84,159,160],{},"Open Notepad and paste or type your JSON.",[84,162,163,164,101],{},"Choose ",[87,165,166],{},"File → Save As",[84,168,169,170,173,174,177,178,180,181,101],{},"Set ",[87,171,172],{},"Save as type"," to ",[87,175,176],{},"All Files (*.*)"," — this is the step people skip. If it stays on \"Text Documents (*.txt)\", Notepad appends ",[21,179,30],{}," and you get ",[21,182,183],{},"data.json.txt",[84,185,186,187,101],{},"Enter the full file name including the extension: ",[21,188,189],{},"data.json",[84,191,169,192,173,195,198,199,202,203,101],{},[87,193,194],{},"Encoding",[87,196,197],{},"UTF-8",", then save. Recent versions of Notepad default to UTF-8, but check the dropdown — it is the difference between ",[21,200,201],{},"café"," and ",[21,204,205],{},"cafÃ©",[17,207,208,211,212,215,216,218,219,101],{},[87,209,210],{},"VS Code"," is easier: create a new file, select ",[87,213,214],{},"JSON"," as the language mode, paste the content, and save as ",[21,217,189],{},". VS Code validates as you type and can format the document with ",[87,220,221],{},"Format Document",[146,223,225],{"id":224},"macos-textedit-or-vs-code","macOS: TextEdit or VS Code",[17,227,228],{},[87,229,230],{},"TextEdit:",[156,232,233,244,247,256],{},[84,234,235,236,239,240,243],{},"Open TextEdit and choose ",[87,237,238],{},"Format → Make Plain Text"," (",[87,241,242],{},"Shift + Cmd + T",") before typing. TextEdit defaults to rich text, and saving rich text produces RTF, not JSON.",[84,245,246],{},"Paste or type your JSON.",[84,248,249,250,252,253,255],{},"In the save dialog, type the full name with the extension — ",[21,251,189],{}," — and make sure the option to append ",[21,254,30],{}," when no extension is given is not active.",[84,257,258],{},"Save.",[17,260,261,263],{},[87,262,210],{}," avoids both problems and is the better default on macOS too.",[146,265,267],{"id":266},"linux-nano-gedit-or-vs-code","Linux: nano, gedit, or VS Code",[50,269,274],{"className":270,"code":272,"language":273,"meta":56},[271],"language-bash","nano data.json\n","bash",[21,275,272],{"__ignoreMap":56},[17,277,278,279,202,282,285,286,289,290,101],{},"Type or paste the JSON, then press ",[87,280,281],{},"Ctrl + O",[87,283,284],{},"Enter"," to save, ",[87,287,288],{},"Ctrl + X"," to exit. Desktop editors such as gedit and VS Code work the same way — just make sure the file name ends in ",[21,291,23],{},[146,293,295],{"id":294},"the-saving-checklist","The saving checklist",[17,297,298],{},"Whatever editor you use, confirm three things before you trust the file:",[300,301,302,315],"table",{},[303,304,305],"thead",{},[306,307,308,312],"tr",{},[309,310,311],"th",{},"Check",[309,313,314],{},"Why it matters",[316,317,318,329,337],"tbody",{},[306,319,320,326],{},[321,322,323,324],"td",{},"The name ends in ",[21,325,23],{},[321,327,328],{},"The extension tells editors, servers, and tools how to treat the file.",[306,330,331,334],{},[321,332,333],{},"It is plain text, not rich text",[321,335,336],{},"Word, Google Docs, and TextEdit's rich-text mode add formatting that is not JSON.",[306,338,339,342],{},[321,340,341],{},"The encoding is UTF-8",[321,343,344],{},"Non-UTF-8 files produce garbled characters; a UTF-8 BOM makes some parsers throw.",[17,346,347,348,350,351,354,355,358],{},"If your file might actually be ",[21,349,183],{},", check from a terminal (",[21,352,353],{},"dir"," on Windows, ",[21,356,357],{},"ls"," on macOS and Linux) rather than trusting File Explorer or Finder — both hide known extensions by default.",[36,360,362],{"id":361},"step-by-step-create-your-first-json-file","Step-by-step: create your first JSON file",[17,364,365],{},"Here is a complete first file. It is an object with four keys and one nested array:",[50,367,370],{"className":368,"code":369,"language":55,"meta":56},[53],"{\n  \"project\": \"json-toolbox\",\n  \"version\": \"1.0.0\",\n  \"author\": \"Ada\",\n  \"tags\": [\"json\", \"config\"]\n}\n",[21,371,369],{"__ignoreMap":56},[17,373,374,375,378],{},"Save it as ",[21,376,377],{},"project.json",". An array of objects is equally valid as the root value:",[50,380,383],{"className":381,"code":382,"language":55,"meta":56},[53],"[\n  { \"id\": 1, \"name\": \"Ada\", \"active\": true },\n  { \"id\": 2, \"name\": \"Lin\", \"active\": false }\n]\n",[21,384,382],{"__ignoreMap":56},[146,386,388],{"id":387},"syntax-rules-that-decide-whether-the-file-works","Syntax rules that decide whether the file works",[17,390,391],{},"JSON is strict. These are the rules that cause most first-file failures:",[300,393,394,407],{},[303,395,396],{},[306,397,398,401,404],{},[309,399,400],{},"Rule",[309,402,403],{},"Valid",[309,405,406],{},"Invalid",[316,408,409,424,439,454,468,481,502,526],{},[306,410,411,414,419],{},[321,412,413],{},"Strings use double quotes",[321,415,416],{},[21,417,418],{},"\"name\"",[321,420,421],{},[21,422,423],{},"'name'",[306,425,426,429,434],{},[321,427,428],{},"Keys are quoted",[321,430,431],{},[21,432,433],{},"{ \"name\": \"Ada\" }",[321,435,436],{},[21,437,438],{},"{ name: \"Ada\" }",[306,440,441,444,449],{},[321,442,443],{},"No trailing comma",[321,445,446],{},[21,447,448],{},"{ \"a\": 1, \"b\": 2 }",[321,450,451],{},[21,452,453],{},"{ \"a\": 1, \"b\": 2, }",[306,455,456,459,463],{},[321,457,458],{},"Members separated by commas",[321,460,461],{},[21,462,448],{},[321,464,465],{},[21,466,467],{},"{ \"a\": 1 \"b\": 2 }",[306,469,470,473,476],{},[321,471,472],{},"No comments",[321,474,475],{},"—",[321,477,478],{},[21,479,480],{},"{ \"a\": 1 } \u002F\u002F note",[306,482,483,486,494],{},[321,484,485],{},"Numbers have no leading zeros or hex",[321,487,488,94,491],{},[21,489,490],{},"42",[21,492,493],{},"3.14",[321,495,496,94,499],{},[21,497,498],{},"042",[21,500,501],{},"0x1F",[306,503,504,517,522],{},[321,505,506,507,94,510,513,514],{},"No ",[21,508,509],{},"undefined",[21,511,512],{},"NaN",", or ",[21,515,516],{},"Infinity",[321,518,519],{},[21,520,521],{},"null",[321,523,524],{},[21,525,512],{},[306,527,528,531,536],{},[321,529,530],{},"Escape newlines inside strings",[321,532,533],{},[21,534,535],{},"\"line1\\nline2\"",[321,537,538],{},"a literal line break inside a string",[17,540,541,542,545,546,202,549,552,553,557,558,561],{},"Two of these deserve a note. ",[87,543,544],{},"Comments are not part of JSON"," — ",[21,547,548],{},"\u002F\u002F",[21,550,551],{},"\u002F* *\u002F"," make the file invalid, and only tools that explicitly accept JSONC will read it; see ",[63,554,556],{"href":555},"\u002Fblog\u002Fjson-comments","Comments in JSON",". And ",[87,559,560],{},"trailing commas are invalid"," even though they are fine in JavaScript object literals, which is why copied-and-pasted config so often fails to parse.",[36,563,565],{"id":564},"common-mistakes-and-how-to-fix-them","Common mistakes and how to fix them",[300,567,568,581],{},[303,569,570],{},[306,571,572,575,578],{},[309,573,574],{},"Symptom",[309,576,577],{},"Likely cause",[309,579,580],{},"Fix",[316,582,583,602,613,628,641,661,683,697],{},[306,584,585,590,593],{},[321,586,587,588],{},"File is named ",[21,589,183],{},[321,591,592],{},"Save dialog type was \"Text Documents\", or the extension is hidden",[321,594,595,596,599,600],{},"Re-save with ",[87,597,598],{},"Save as type: All Files"," and type ",[21,601,189],{},[306,603,604,607,610],{},[321,605,606],{},"Parser reports an error at line 1, column 1",[321,608,609],{},"UTF-8 BOM at the start of the file",[321,611,612],{},"Save as UTF-8 without BOM",[306,614,615,622,625],{},[321,616,617,619,620],{},[21,618,201],{}," becomes ",[21,621,205],{},[321,623,624],{},"File saved as ANSI \u002F non-UTF-8",[321,626,627],{},"Re-save with UTF-8 encoding",[306,629,630,633,636],{},[321,631,632],{},"Editor shows formatting or fonts",[321,634,635],{},"File was saved as rich text (RTF\u002FDOCX)",[321,637,638,639],{},"Use a plain-text editor and save as ",[21,640,23],{},[306,642,643,648,658],{},[321,644,645],{},[21,646,647],{},"SyntaxError: Unexpected token }",[321,649,650,651,654,655],{},"Trailing comma before ",[21,652,653],{},"}"," or ",[21,656,657],{},"]",[321,659,660],{},"Remove the last comma in the object or array",[306,662,663,668,676],{},[321,664,665],{},[21,666,667],{},"SyntaxError: Unexpected token \u002F",[321,669,670,671,654,673,675],{},"A ",[21,672,548],{},[21,674,551],{}," comment",[321,677,678,679],{},"Remove comments, or convert with ",[63,680,682],{"href":681},"\u002Ftools\u002Fconvert\u002Fjsonc-to-json","JSONC to JSON",[306,684,685,691,694],{},[321,686,687,690],{},[21,688,689],{},"Unexpected token '"," in JSON`",[321,692,693],{},"Single-quoted strings",[321,695,696],{},"Replace with double quotes",[306,698,699,702,705],{},[321,700,701],{},"Error mentions an unexpected string or colon",[321,703,704],{},"Unquoted key",[321,706,707,708],{},"Quote the key: ",[21,709,433],{},[17,711,712,713,717],{},"When several of these are present at once, fixing them by hand is slow. Paste the file into ",[63,714,716],{"href":715},"\u002Ftools\u002Fformat\u002Fjson-repair","JSON Repair",", which fixes trailing commas, single quotes, unquoted keys, missing brackets, comments, and Python-style constants, then copy or download the valid result.",[36,719,721],{"id":720},"how-to-validate-a-json-file","How to validate a JSON file",[17,723,724],{},"\"Valid\" has one meaning for a JSON file: a strict parser can read it without error. Four ways to check:",[17,726,727,730],{},[87,728,729],{},"1. Editor feedback."," VS Code underlines syntax errors as you type and shows the message on hover. This catches most problems before you save.",[17,732,733,736,737,741],{},[87,734,735],{},"2. In the browser."," Paste or open the file in the ",[63,738,740],{"href":739},"\u002Ftools\u002Fformat\u002Fjson-editor","JSON Editor",". It validates live, highlights syntax, and lets you format or minify the document before you copy or download it — no account and no upload, because it runs in your browser.",[17,743,744,747],{},[87,745,746],{},"3. Command line."," Both of these parse the file and print it, so a parse error means the file is invalid:",[50,749,752],{"className":750,"code":751,"language":273,"meta":56},[271],"jq . data.json\npython -m json.tool data.json\n",[21,753,751],{"__ignoreMap":56},[17,755,756,759,760,764,765,769,770,774],{},[87,757,758],{},"4. Schema validation."," Syntax is only the first layer. If the file has to match an expected structure — required fields, types, ranges — validate it against a JSON Schema. Generate a starting schema from a representative file with the ",[63,761,763],{"href":762},"\u002Ftools\u002Fconvert\u002Fjson-schema-generator","JSON Schema Generator",", then check data against it with the ",[63,766,768],{"href":767},"\u002Ftools\u002Fformat\u002Fjson-schema-validator","JSON Schema Validator",". See ",[63,771,773],{"href":772},"\u002Fblog\u002Fjson-validation-syntax-vs-schema","JSON Validation Explained"," for how the layers differ.",[17,776,777,778,782],{},"If a file fails to parse and you are not sure why, ",[63,779,781],{"href":780},"\u002Fblog\u002Fjson-parse-error-debug","JSON Parse Failed: 10 Common API Errors and How to Debug Them"," walks through the error messages one by one.",[36,784,786],{"id":785},"create-a-json-file-online","Create a JSON file online",[17,788,789],{},"If you would rather not deal with Save As dialogs, a browser-based editor does the same job and hands you a downloadable file:",[81,791,792,802],{},[84,793,794,798,799,801],{},[87,795,796],{},[63,797,740],{"href":739}," — paste or open JSON, edit it in a syntax-highlighted editor with live validation, format or minify it, then copy or download the ",[21,800,23],{}," file. This is the closest equivalent to \"create a JSON file online\" and works on any OS, including Chromebooks and tablets.",[84,803,804,810],{},[87,805,806],{},[63,807,809],{"href":808},"\u002Ftools\u002Fconvert\u002Fjson-array-generator","JSON Array Generator"," — if you need a file full of sample records rather than one hand-written object, set the number of items and the field names and download a pretty-printed array. Useful for test fixtures and demos.",[17,812,813],{},"Both run entirely in your browser, so nothing you paste is sent to a server.",[36,815,817],{"id":816},"generate-json-files-from-code","Generate JSON files from code",[17,819,820],{},"When data already lives in your program, do not hand-write the file — let the code write it.",[146,822,824],{"id":823},"python","Python",[50,826,830],{"className":827,"code":829,"language":823,"meta":56},[828],"language-python","import json\n\ndata = {\n    \"project\": \"json-toolbox\",\n    \"version\": \"1.0.0\",\n    \"author\": \"Ada\",\n    \"tags\": [\"json\", \"config\"],\n}\n\nwith open(\"project.json\", \"w\", encoding=\"utf-8\") as f:\n    json.dump(data, f, indent=2, ensure_ascii=False)\n    f.write(\"\\n\")\n",[21,831,829],{"__ignoreMap":56},[17,833,834,837,838,841,842,845,846,849],{},[21,835,836],{},"indent=2"," produces readable output; drop it for a compact file. ",[21,839,840],{},"ensure_ascii=False"," keeps non-ASCII characters readable instead of escaping them, which is why opening the file with ",[21,843,844],{},"encoding=\"utf-8\""," matters. Use ",[21,847,848],{},"json.dumps(data)"," when you want the JSON as a string rather than a file.",[146,851,853],{"id":852},"nodejs","Node.js",[50,855,860],{"className":856,"code":858,"language":859,"meta":56},[857],"language-js","import { writeFile } from 'node:fs\u002Fpromises'\n\nconst data = {\n  project: 'json-toolbox',\n  version: '1.0.0',\n  author: 'Ada',\n  tags: ['json', 'config'],\n}\n\nawait writeFile('project.json', JSON.stringify(data, null, 2) + '\\n', 'utf8')\n","js",[21,861,858],{"__ignoreMap":56},[17,863,864,867],{},[21,865,866],{},"JSON.stringify(value, null, 2)"," adds two-space indentation; omit the last two arguments for minified output.",[146,869,871],{"id":870},"in-the-browser","In the browser",[17,873,874],{},"To let a user download a file your page generated:",[50,876,879],{"className":877,"code":878,"language":859,"meta":56},[857],"const text = JSON.stringify(data, null, 2)\nconst blob = new Blob([text], { type: 'application\u002Fjson' })\nconst url = URL.createObjectURL(blob)\n\nconst a = document.createElement('a')\na.href = url\na.download = 'project.json'\na.click()\n\nURL.revokeObjectURL(url)\n",[21,880,878],{"__ignoreMap":56},[17,882,883],{},"This never touches a server — the file is assembled in the page and downloaded from memory.",[36,885,887],{"id":886},"what-is-a-manifestjson-file","What is a manifest.json file?",[17,889,670,890,892],{},[21,891,100],{}," is not a different format. It is an ordinary JSON file whose contents are defined by whichever platform reads it — so \"how do I create one\" really means \"what fields does this platform expect\".",[17,894,895],{},"Three common cases:",[17,897,898,901,902,101],{},[87,899,900],{},"Progressive Web App (web app manifest)"," — describes how your app appears when installed: name, icons, start URL, and display mode. Referenced from HTML with ",[21,903,904],{},"\u003Clink rel=\"manifest\" href=\"\u002Fmanifest.json\">",[50,906,909],{"className":907,"code":908,"language":55,"meta":56},[53],"{\n  \"name\": \"JSON Toolbox\",\n  \"short_name\": \"JSON Toolbox\",\n  \"start_url\": \"\u002F\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\",\n  \"theme_color\": \"#0284c7\",\n  \"icons\": [\n    {\n      \"src\": \"\u002Ficons\u002Ficon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\u002Fpng\"\n    },\n    {\n      \"src\": \"\u002Ficons\u002Ficon-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\u002Fpng\"\n    }\n  ]\n}\n",[21,910,908],{"__ignoreMap":56},[17,912,913,914,919,920,925],{},"The specification is the ",[63,915,918],{"href":916,"rel":917},"https:\u002F\u002Fwww.w3.org\u002FTR\u002Fappmanifest\u002F",[67],"W3C Web Application Manifest",", and ",[63,921,924],{"href":922,"rel":923},"https:\u002F\u002Fweb.dev\u002Farticles\u002Fadd-manifest",[67],"web.dev"," has a practical walkthrough.",[17,927,928,931,932,934,935,940,941,948],{},[87,929,930],{},"Chrome extension"," — every extension has a ",[21,933,100],{}," declaring its name, version, and permissions. The current version is ",[63,936,939],{"href":937,"rel":938},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fextensions\u002Fdevelop\u002Fmigrate\u002Fwhat-is-mv3",[67],"Manifest V3","; see MDN's ",[63,942,945,947],{"href":943,"rel":944},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FMozilla\u002FAdd-ons\u002FWebExtensions\u002Fmanifest.json",[67],[21,946,100],{}," reference"," for the key list.",[17,950,951,954,955,958,959,962],{},[87,952,953],{},"Framework manifests"," — frameworks generate or consume their own. Next.js, for example, supports ",[21,956,957],{},"app\u002Fmanifest.json"," (or ",[21,960,961],{},"manifest.ts",") and serves the file for you.",[17,964,965],{},"The syntax rules in this guide apply to all of them: valid JSON first, correct fields second. Many editors accept comments in these files because they read them as JSONC — but the platform that consumes the file may not, so check before shipping comments.",[17,967,968,969,101],{},"For step-by-step examples with the required fields for each spec — PWA web app manifests and Chrome extension Manifest V3 — see ",[63,970,972],{"href":971},"\u002Fblog\u002Fhow-to-create-manifest-json","How to Create a manifest.json File",[36,974,976],{"id":975},"faq","FAQ",[146,978,980],{"id":979},"can-i-create-a-json-file-in-notepad","Can I create a JSON file in Notepad?",[17,982,983,984,986,987,173,989,991,992,994,995,997,998,101],{},"Yes. Write the JSON, choose ",[87,985,166],{},", set ",[87,988,172],{},[87,990,176],{},", type the name as ",[21,993,189],{},", and pick ",[87,996,197],{}," as the encoding. Skipping \"All Files\" is what produces ",[21,999,183],{},[146,1001,1003],{"id":1002},"do-i-need-special-software-to-create-a-json-file","Do I need special software to create a JSON file?",[17,1005,1006],{},"No. Any plain-text editor works — Notepad, TextEdit, nano, VS Code. A code editor adds syntax highlighting and live validation, which is why it is recommended, but it is not required.",[146,1008,1010,1011,1013],{"id":1009},"how-do-i-make-a-json-file-on-a-mac","How do I make a ",[21,1012,23],{}," file on a Mac?",[17,1015,1016,1017,239,1019,1021,1022,1024],{},"Use TextEdit with ",[87,1018,238],{},[87,1020,242],{},") first, then save with the full name ",[21,1023,189],{},". Or use VS Code, which saves plain text with the extension you type and validates as you go.",[146,1026,1028],{"id":1027},"why-does-my-json-file-not-work-even-though-it-looks-correct","Why does my JSON file not work even though it looks correct?",[17,1030,1031,1032,1034],{},"Most often it is one of four things: the file is actually ",[21,1033,183],{},", it was saved as rich text or with a BOM, it contains a trailing comma, or it has comments. Validate the file — an error message with a line and column points straight at the problem.",[146,1036,1038],{"id":1037},"can-a-json-file-have-comments","Can a JSON file have comments?",[17,1040,1041,1042,202,1044,1046,1047,1050,1051,1053,1054,1057],{},"No. Standard JSON has no comment syntax, so ",[21,1043,548],{},[21,1045,551],{}," make the file invalid. Use a ",[21,1048,1049],{},"_comment"," key, keep documentation outside the file, or work in JSONC and strip comments before shipping. Full details in ",[63,1052,556],{"href":555},", and the ",[63,1055,1056],{"href":681},"JSONC to JSON Converter"," removes them for you.",[146,1059,1061],{"id":1060},"is-a-json-file-the-same-as-a-javascript-object","Is a JSON file the same as a JavaScript object?",[17,1063,1064,1065,1068,1069,101],{},"No. A JSON file is text; a JavaScript object literal is code. JavaScript allows unquoted keys, trailing commas, single quotes, and comments — none of which are valid JSON. That is why an object copied out of a ",[21,1066,1067],{},".js"," file often fails ",[21,1070,1071],{},"JSON.parse()",[146,1073,1075,1076,202,1078,1081],{"id":1074},"what-is-the-difference-between-json-and-webmanifest","What is the difference between ",[21,1077,23],{},[21,1079,1080],{},".webmanifest","?",[17,1083,1084,1085,1087,1088,1091,1092,1094,1095,1097],{},"Both contain JSON; only the convention differs. ",[21,1086,1080],{}," is the file extension recommended by the W3C for a web app manifest, served as ",[21,1089,1090],{},"application\u002Fmanifest+json",", while ",[21,1093,23],{}," is the general extension for any JSON document. Many projects still use ",[21,1096,100],{}," with no issue.",[146,1099,1101],{"id":1100},"how-large-can-a-json-file-be","How large can a JSON file be?",[17,1103,1104,1105,1109],{},"JSON itself sets no size limit. Practical limits come from the tool reading the file: editor memory, parser configuration, and server upload caps. For testing how your own tools behave, the ",[63,1106,1108],{"href":1107},"\u002Fblog\u002Ffree-realistic-json-test-data","free realistic JSON test datasets"," range from small demos to large files.",[36,1111,1113],{"id":1112},"whats-next","What's Next?",[81,1115,1116,1128,1136,1144,1153],{},[84,1117,1118,1121,1122,1124,1125,1127],{},[87,1119,1120],{},"Ready to write one?"," Open the ",[63,1123,740],{"href":739}," — paste, validate, format, and download a ",[21,1126,23],{}," file without installing anything.",[84,1129,1130,1133,1134,101],{},[87,1131,1132],{},"Need sample records?"," Generate an array with the ",[63,1135,809],{"href":808},[84,1137,1138,1141,1142,101],{},[87,1139,1140],{},"File already broken?"," Fix trailing commas, quotes, and comments with ",[63,1143,716],{"href":715},[84,1145,1146,1149,1150,101],{},[87,1147,1148],{},"Wondering about comments?"," Read ",[63,1151,1152],{"href":555},"Comments in JSON: Why They're Not Allowed and What to Use Instead",[84,1154,1155,1158,1159,101],{},[87,1156,1157],{},"Debugging a parse error?"," See ",[63,1160,781],{"href":780},[1162,1163],"hr",{},[17,1165,1166],{},[1167,1168,1169],"em",{},"All tools on JSON Toolbox run entirely in your browser. Your data never leaves your device.",{"title":56,"searchDepth":1171,"depth":1171,"links":1172},2,[1173,1174,1181,1184,1185,1186,1187,1192,1193,1205],{"id":38,"depth":1171,"text":39},{"id":137,"depth":1171,"text":138,"children":1175},[1176,1178,1179,1180],{"id":148,"depth":1177,"text":149},3,{"id":224,"depth":1177,"text":225},{"id":266,"depth":1177,"text":267},{"id":294,"depth":1177,"text":295},{"id":361,"depth":1171,"text":362,"children":1182},[1183],{"id":387,"depth":1177,"text":388},{"id":564,"depth":1171,"text":565},{"id":720,"depth":1171,"text":721},{"id":785,"depth":1171,"text":786},{"id":816,"depth":1171,"text":817,"children":1188},[1189,1190,1191],{"id":823,"depth":1177,"text":824},{"id":852,"depth":1177,"text":853},{"id":870,"depth":1177,"text":871},{"id":886,"depth":1171,"text":887},{"id":975,"depth":1171,"text":976,"children":1194},[1195,1196,1197,1199,1200,1201,1202,1204],{"id":979,"depth":1177,"text":980},{"id":1002,"depth":1177,"text":1003},{"id":1009,"depth":1177,"text":1198},"How do I make a .json file on a Mac?",{"id":1027,"depth":1177,"text":1028},{"id":1037,"depth":1177,"text":1038},{"id":1060,"depth":1177,"text":1061},{"id":1074,"depth":1177,"text":1203},"What is the difference between .json and .webmanifest?",{"id":1100,"depth":1177,"text":1101},{"id":1112,"depth":1171,"text":1113},"json_tools","2026-09-30T00:00:00.000Z","Create a JSON file on Windows, macOS, or Linux: write valid JSON, avoid the .json.txt trap, validate the result, and generate files from code.",false,"md","\u002Fblog\u002Fcover\u002Fen\u002Fhow-to-create-json-file-cover.svg",[1213],"en",{},true,"\u002Fen\u002Fblog\u002Fhow-to-create-json-file",{"slug":1218,"text":1219,"btn":1220},"json-editor","Want to write, format, and validate JSON without installing anything?","Open JSON Editor",{"title":6,"description":1208},"en\u002Fblog\u002Fhow-to-create-json-file",[214,1224,740,1225,1226],"Beginners","File Format","Tutorial","i2tDp54BDyFQSPRjbCkSB9YU3FA0Ko8wTFj8gRCufeE",{"id":1229,"title":1230,"author":7,"body":1231,"category":1206,"date":2246,"description":2247,"draft":1209,"extension":1210,"h1":1230,"image":2248,"lastmod":2246,"locales":2249,"meta":2251,"navigation":1215,"path":2252,"promo":2253,"seo":2257,"stem":2258,"tags":2259,"__hash__":2264},"blog\u002Fen\u002Fblog\u002Fjson-validation-syntax-vs-schema.md","JSON Validation Explained: Syntax Checks vs JSON Schema Validation",{"type":9,"value":1232,"toc":2198},[1233,1236,1239,1244,1247,1251,1258,1264,1270,1302,1305,1309,1314,1318,1323,1354,1361,1365,1368,1374,1381,1387,1390,1417,1421,1431,1439,1448,1452,1459,1463,1466,1470,1478,1497,1500,1504,1516,1522,1526,1624,1627,1669,1677,1700,1704,1710,1715,1718,1809,1815,1819,1822,1826,1869,1872,1876,1879,1890,1894,1900,1904,1910,1920,1924,1930,1934,1940,1943,1947,1950,1954,1960,1964,1970,1974,1980,1983,1987,1991,1996,2000,2007,2011,2017,2021,2035,2039,2042,2046,2049,2053,2056,2097,2099,2103,2113,2117,2126,2130,2133,2140,2149,2151,2192,2194],[12,1234,1230],{"id":1235},"json-validation-explained-syntax-checks-vs-json-schema-validation",[17,1237,1238],{},"A JSON string can be parsed without errors and still break your API.",[17,1240,1241,1243],{},[21,1242,1071],{}," only checks whether text follows JSON grammar. It does not check whether required fields exist, whether values match expected types, or whether extra fields should be rejected. For that, you need schema validation and, beyond that, business-rule validation.",[17,1245,1246],{},"This guide explains the three layers of JSON validation and shows how to implement each one in JavaScript.",[36,1248,1250],{"id":1249},"the-short-answer-valid-json-is-not-always-valid-data","The Short Answer: Valid JSON Is Not Always Valid Data",[17,1252,1253,1254,1257],{},"Consider this payload sent to a ",[21,1255,1256],{},"POST \u002Fusers"," endpoint:",[50,1259,1262],{"className":1260,"code":1261,"language":55,"meta":56},[53],"{\n  \"email\": \"not-an-email\",\n  \"age\": -3,\n  \"role\": \"superadmin\",\n  \"marketingOptIn\": \"yes\",\n  \"debug\": true\n}\n",[21,1263,1261],{"__ignoreMap":56},[17,1265,1266,1267,1269],{},"This is valid JSON — ",[21,1268,1071],{}," will succeed. But the data violates nearly every rule your API should enforce:",[81,1271,1272,1278,1284,1290,1296],{},[84,1273,1274,1277],{},[21,1275,1276],{},"email"," is not a valid email address.",[84,1279,1280,1283],{},[21,1281,1282],{},"age"," is negative.",[84,1285,1286,1289],{},[21,1287,1288],{},"role"," is not one of the allowed values.",[84,1291,1292,1295],{},[21,1293,1294],{},"marketingOptIn"," should be a boolean, not a string.",[84,1297,1298,1301],{},[21,1299,1300],{},"debug"," is an unknown field that should not be accepted.",[17,1303,1304],{},"This is why validation must go beyond syntax.",[36,1306,1308],{"id":1307},"layer-1-syntax-validation-can-the-text-be-parsed","Layer 1: Syntax Validation — Can the Text Be Parsed?",[17,1310,1311,1312,101],{},"Syntax validation checks whether a string conforms to the JSON grammar defined in RFC 8259. The simplest way to perform it in JavaScript is ",[21,1313,1071],{},[146,1315,1317],{"id":1316},"what-jsonparse-checks","What JSON.parse() checks",[17,1319,1320,1322],{},[21,1321,1071],{}," verifies that the text is structurally valid JSON:",[81,1324,1325,1336,1339,1342,1345,1348],{},[84,1326,1327,1328,1331,1332,1335],{},"Strings use double quotes (",[21,1329,1330],{},"\"",", not ",[21,1333,1334],{},"'",").",[84,1337,1338],{},"Keys are double-quoted.",[84,1340,1341],{},"No trailing commas.",[84,1343,1344],{},"No comments.",[84,1346,1347],{},"Brackets and braces are balanced.",[84,1349,1350,1351,1353],{},"Numbers, booleans, and ",[21,1352,521],{}," are in correct form.",[17,1355,1356,1357,1360],{},"If any of these rules are violated, JavaScript throws a ",[21,1358,1359],{},"SyntaxError",". Common problems include trailing commas from JavaScript object literals, single-quoted strings, and unquoted keys.",[146,1362,1364],{"id":1363},"common-syntax-errors","Common syntax errors",[17,1366,1367],{},"This JSON looks reasonable but fails to parse:",[50,1369,1372],{"className":1370,"code":1371,"language":55,"meta":56},[53],"{\n  \"email\": \"ada@example.com\",\n  \"age\": 36,\n}\n",[21,1373,1371],{"__ignoreMap":56},[17,1375,1376,1377,1380],{},"The trailing comma after ",[21,1378,1379],{},"36"," makes it invalid. Fix:",[50,1382,1385],{"className":1383,"code":1384,"language":55,"meta":56},[53],"{\n  \"email\": \"ada@example.com\",\n  \"age\": 36\n}\n",[21,1386,1384],{"__ignoreMap":56},[17,1388,1389],{},"Other frequent mistakes:",[81,1391,1392,1399,1405,1411],{},[84,1393,1394,1395,1398],{},"Single quotes instead of double quotes: ",[21,1396,1397],{},"{ 'name': 'Ada' }"," → invalid.",[84,1400,1401,1402,1398],{},"Comments: ",[21,1403,1404],{},"{ \"name\": \"Ada\" \u002F\u002F developer note }",[84,1406,1407,1408,1410],{},"Unquoted keys: ",[21,1409,438],{}," → invalid in JSON (valid in JavaScript object literals).",[84,1412,1413,1414,1398],{},"Unclosed brackets: ",[21,1415,1416],{},"{ \"items\": [1, 2, 3",[146,1418,1420],{"id":1419},"a-safe-syntax-check-helper","A safe syntax-check helper",[17,1422,1423,1424,1426,1427,1430],{},"Instead of wrapping ",[21,1425,1071],{}," in a bare ",[21,1428,1429],{},"try\u002Fcatch",", return a structured result so callers can display meaningful error messages:",[50,1432,1437],{"className":1433,"code":1435,"language":1436,"meta":56},[1434],"language-ts","export type JsonSyntaxResult =\n  | { valid: true; value: unknown }\n  | { valid: false; error: string }\n\nexport function parseJsonSafely(text: string): JsonSyntaxResult {\n  try {\n    return { valid: true, value: JSON.parse(text) }\n  } catch (error) {\n    return {\n      valid: false,\n      error: error instanceof Error ? error.message : 'Invalid JSON',\n    }\n  }\n}\n","ts",[21,1438,1435],{"__ignoreMap":56},[17,1440,1441,1442,1444,1445,101],{},"This only verifies JSON syntax. It does not verify required fields, types, allowed values, or application rules. If ",[21,1443,1071],{}," throws before you can inspect the data, start with our guide to ",[63,1446,1447],{"href":780},"debugging common JSON parse errors in API responses",[146,1449,1451],{"id":1450},"when-to-use-an-online-json-validator","When to use an online JSON Validator",[17,1453,1454,1455,1458],{},"For quick checks during development or when reviewing API responses from logs, paste the raw text into a ",[63,1456,1457],{"href":739},"JSON syntax validator"," to see whether it parses and where errors occur. This is especially useful when the JSON is minified or comes from an unfamiliar source.",[36,1460,1462],{"id":1461},"layer-2-schema-validation-does-the-data-have-the-expected-shape","Layer 2: Schema Validation — Does the Data Have the Expected Shape?",[17,1464,1465],{},"Syntax validation tells you the text is JSON. Schema validation tells you the data matches the structure your application expects.",[146,1467,1469],{"id":1468},"what-json-schema-validates","What JSON Schema validates",[17,1471,1472,1477],{},[63,1473,1476],{"href":1474,"rel":1475},"https:\u002F\u002Fjson-schema.org\u002Fdocs",[67],"JSON Schema"," is a declarative vocabulary for describing the structure, constraints, and data types of JSON documents. A schema can specify:",[81,1479,1480,1485,1488,1491,1494],{},[84,1481,1482,1483,101],{},"The expected type: object, array, string, number, boolean, or ",[21,1484,521],{},[84,1486,1487],{},"Which fields are required.",[84,1489,1490],{},"Allowed values for each field.",[84,1492,1493],{},"Numeric ranges, string patterns, and array lengths.",[84,1495,1496],{},"Whether extra fields are permitted.",[17,1498,1499],{},"The schema is itself a JSON document, which makes it portable across languages and tools.",[146,1501,1503],{"id":1502},"the-user-creation-schema","The user creation schema",[17,1505,1506,1507,1509,1510,1515],{},"Here is a JSON Schema for the ",[21,1508,1256],{}," payload. It uses ",[63,1511,1514],{"href":1512,"rel":1513},"https:\u002F\u002Fjson-schema.org\u002Fdraft\u002F2020-12\u002Fschema",[67],"Draft 2020-12",":",[50,1517,1520],{"className":1518,"code":1519,"language":55,"meta":56},[53],"{\n  \"$schema\": \"https:\u002F\u002Fjson-schema.org\u002Fdraft\u002F2020-12\u002Fschema\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"required\": [\"email\", \"age\", \"role\", \"marketingOptIn\"],\n  \"properties\": {\n    \"email\": {\n      \"type\": \"string\",\n      \"format\": \"email\"\n    },\n    \"age\": {\n      \"type\": \"integer\",\n      \"minimum\": 0,\n      \"maximum\": 150\n    },\n    \"role\": {\n      \"type\": \"string\",\n      \"enum\": [\"user\", \"editor\", \"admin\"]\n    },\n    \"marketingOptIn\": {\n      \"type\": \"boolean\"\n    }\n  }\n}\n",[21,1521,1519],{"__ignoreMap":56},[146,1523,1525],{"id":1524},"how-to-read-this-schema","How to read this schema",[300,1527,1528,1538],{},[303,1529,1530],{},[306,1531,1532,1535],{},[309,1533,1534],{},"Keyword",[309,1536,1537],{},"What it enforces",[316,1539,1540,1550,1560,1570,1580,1596,1609],{},[306,1541,1542,1547],{},[321,1543,1544],{},[21,1545,1546],{},"type: \"object\"",[321,1548,1549],{},"The root value must be a JSON object.",[306,1551,1552,1557],{},[321,1553,1554],{},[21,1555,1556],{},"required",[321,1558,1559],{},"These fields must be present.",[306,1561,1562,1567],{},[321,1563,1564],{},[21,1565,1566],{},"properties",[321,1568,1569],{},"Defines the expected shape for each field.",[306,1571,1572,1577],{},[321,1573,1574],{},[21,1575,1576],{},"format: \"email\"",[321,1578,1579],{},"Declares the expected format. Enforcement depends on the validator (see below).",[306,1581,1582,1591],{},[321,1583,1584,1587,1588],{},[21,1585,1586],{},"minimum"," \u002F ",[21,1589,1590],{},"maximum",[321,1592,1593,1594,101],{},"Numeric boundaries for ",[21,1595,1282],{},[306,1597,1598,1603],{},[321,1599,1600],{},[21,1601,1602],{},"enum",[321,1604,1605,1606,1608],{},"Restricts ",[21,1607,1288],{}," to the listed values.",[306,1610,1611,1616],{},[321,1612,1613],{},[21,1614,1615],{},"additionalProperties: false",[321,1617,1618,1619,654,1621,101],{},"Rejects any field not declared in ",[21,1620,1566],{},[21,1622,1623],{},"patternProperties",[17,1625,1626],{},"Two details that often cause confusion:",[156,1628,1629,1649],{},[84,1630,1631,1636,1637,1639,1640,1642,1643,1645,1646,1648],{},[87,1632,1633,1635],{},[21,1634,1566],{}," does not make fields required."," Listing a field in ",[21,1638,1566],{}," only defines its schema. You must also list it in ",[21,1641,1556],{}," to make it mandatory. A field can appear in ",[21,1644,1566],{}," but be absent from ",[21,1647,1556],{},", making it optional.",[84,1650,1651,1657,1658,1661,1662,1665,1666,1668],{},[87,1652,1653,1656],{},[21,1654,1655],{},"additionalProperties"," defaults to allowing extra fields."," If you do not set it to ",[21,1659,1660],{},"false",", an object with unexpected fields like ",[21,1663,1664],{},"\"debug\": true"," will pass validation. Only an explicit ",[21,1667,1615],{}," rejects undeclared fields.",[146,1670,1672,1673,1676],{"id":1671},"the-format-keyword-caveat","The ",[21,1674,1675],{},"format"," keyword caveat",[17,1678,1672,1679,1681,1682,1687,1688,1695,1696,1699],{},[21,1680,1675],{}," keyword communicates an intended format, but whether it is enforced depends on the JSON Schema validator and its configuration. For example, ",[63,1683,1686],{"href":1684,"rel":1685},"https:\u002F\u002Fajv.js.org\u002Fapi.html",[67],"Ajv"," v7+ provides common format validators through the optional ",[63,1689,1692],{"href":1690,"rel":1691},"https:\u002F\u002Fajv.js.org\u002Fguide\u002Fformats.html",[67],[21,1693,1694],{},"ajv-formats"," package. Without it, ",[21,1697,1698],{},"\"format\": \"email\""," is treated as an annotation, not a validation rule. Always verify your validator's configuration before relying on format checks in production.",[146,1701,1703],{"id":1702},"a-valid-json-document-that-fails-schema-validation","A valid JSON document that fails schema validation",[17,1705,1706,1707,1709],{},"The payload from the introduction passes ",[21,1708,1071],{}," but fails the schema:",[50,1711,1713],{"className":1712,"code":1261,"language":55,"meta":56},[53],[21,1714,1261],{"__ignoreMap":56},[17,1716,1717],{},"A schema validator would report these errors:",[300,1719,1720,1730],{},[303,1721,1722],{},[306,1723,1724,1727],{},[309,1725,1726],{},"Path",[309,1728,1729],{},"Problem",[316,1731,1732,1744,1761,1774,1791],{},[306,1733,1734,1739],{},[321,1735,1736],{},[21,1737,1738],{},"\u002Femail",[321,1740,1741,1742,101],{},"Value does not match format ",[21,1743,1276],{},[306,1745,1746,1751],{},[321,1747,1748],{},[21,1749,1750],{},"\u002Fage",[321,1752,1753,1754,1757,1758,101],{},"Value ",[21,1755,1756],{},"-3"," is less than minimum ",[21,1759,1760],{},"0",[306,1762,1763,1768],{},[321,1764,1765],{},[21,1766,1767],{},"\u002Frole",[321,1769,1753,1770,1773],{},[21,1771,1772],{},"superadmin"," is not one of the allowed enum values.",[306,1775,1776,1781],{},[321,1777,1778],{},[21,1779,1780],{},"\u002FmarketingOptIn",[321,1782,1783,1784,1787,1788,101],{},"Expected ",[21,1785,1786],{},"boolean",", got ",[21,1789,1790],{},"string",[306,1792,1793,1798],{},[321,1794,1795],{},[21,1796,1797],{},"\u002Fdebug",[321,1799,1800,1801,1803,1804,1806,1807,101],{},"Property ",[21,1802,1300],{}," is not allowed when ",[21,1805,1655],{}," is ",[21,1808,1660],{},[17,1810,1811,1812,1814],{},"You can test this interactively with the ",[63,1813,768],{"href":767}," — paste the payload and the schema side by side to see the errors.",[36,1816,1818],{"id":1817},"layer-3-business-validation-can-your-application-accept-this-data","Layer 3: Business Validation — Can Your Application Accept This Data?",[17,1820,1821],{},"Schema validation is powerful, but it cannot express rules that depend on your system's state. Business validation handles those cases with application logic.",[146,1823,1825],{"id":1824},"examples-json-schema-cannot-fully-decide","Examples JSON Schema cannot fully decide",[81,1827,1828,1838,1848,1857,1866],{},[84,1829,1830,1831,1834,1835,1837],{},"The email address ",[21,1832,1833],{},"ada@example.com"," is syntactically valid and matches the ",[21,1836,1276],{}," format, but it may already exist in your database.",[84,1839,1840,1841,1843,1844,1847],{},"An ",[21,1842,1282],{}," of 200 passes the ",[21,1845,1846],{},"minimum: 0"," check but may be rejected by a business rule capping realistic ages.",[84,1849,1850,1851,1853,1854,101],{},"A user's ",[21,1852,1288],{}," may be valid per the enum, but the authenticated caller may not have permission to assign ",[21,1855,1856],{},"admin",[84,1858,670,1859,202,1862,1865],{},[21,1860,1861],{},"startDate",[21,1863,1864],{},"endDate"," may both be valid ISO 8601 strings, but the start may fall after the end.",[84,1867,1868],{},"A product ID may exist in the schema, but the product may be out of stock.",[17,1870,1871],{},"These checks require querying a database, verifying permissions, or running application-specific logic. No JSON Schema can replace them.",[146,1873,1875],{"id":1874},"client-side-versus-server-side-validation","Client-side versus server-side validation",[17,1877,1878],{},"Run schema validation on both the client and the server when it improves user feedback. But always validate again on the backend. Client-side checks:",[81,1880,1881,1884,1887],{},[84,1882,1883],{},"Can be bypassed by modifying network requests.",[84,1885,1886],{},"Cannot safely enforce permissions or database constraints.",[84,1888,1889],{},"Should be treated as a UX convenience, not a security measure.",[36,1891,1893],{"id":1892},"how-to-validate-json-in-javascript","How to Validate JSON in JavaScript",[17,1895,1896,1897,1899],{},"Here is a complete validation pipeline for the ",[21,1898,1256],{}," endpoint.",[146,1901,1903],{"id":1902},"step-1-syntax-validation","Step 1: Syntax validation",[50,1905,1908],{"className":1906,"code":1907,"language":1436,"meta":56},[1434],"import Ajv from 'ajv'\nimport addFormats from 'ajv-formats'\n\nconst ajv = new Ajv({ allErrors: true, strict: true })\naddFormats(ajv)\n\nconst createUserSchema = {\n  type: 'object',\n  additionalProperties: false,\n  required: ['email', 'age', 'role', 'marketingOptIn'],\n  properties: {\n    email: { type: 'string', format: 'email' },\n    age: { type: 'integer', minimum: 0, maximum: 150 },\n    role: { type: 'string', enum: ['user', 'editor', 'admin'] },\n    marketingOptIn: { type: 'boolean' },\n  },\n} as const\n\nconst validateCreateUser = ajv.compile(createUserSchema)\n",[21,1909,1907],{"__ignoreMap":56},[17,1911,1912,1913,1916,1917,101],{},"Ajv compiles the schema into a reusable validation function. It supports multiple JSON Schema drafts and reports all errors when ",[21,1914,1915],{},"allErrors"," is set to ",[21,1918,1919],{},"true",[146,1921,1923],{"id":1922},"step-2-schema-validation","Step 2: Schema validation",[50,1925,1928],{"className":1926,"code":1927,"language":1436,"meta":56},[1434],"export function validateCreateUserPayload(value: unknown) {\n  const valid = validateCreateUser(value)\n  return {\n    valid: Boolean(valid),\n    errors: validateCreateUser.errors ?? [],\n  }\n}\n",[21,1929,1927],{"__ignoreMap":56},[146,1931,1933],{"id":1932},"step-3-the-full-pipeline","Step 3: The full pipeline",[50,1935,1938],{"className":1936,"code":1937,"language":1436,"meta":56},[1434],"export function validateIncomingUserJson(text: string) {\n  \u002F\u002F Layer 1: Syntax\n  const parsed = parseJsonSafely(text)\n  if (!parsed.valid) {\n    return { ok: false as const, stage: 'syntax' as const, errors: [parsed.error] }\n  }\n\n  \u002F\u002F Layer 2: Schema\n  const schemaResult = validateCreateUserPayload(parsed.value)\n  if (!schemaResult.valid) {\n    return { ok: false as const, stage: 'schema' as const, errors: schemaResult.errors }\n  }\n\n  \u002F\u002F Layer 3: Business (example — you would implement this with your DB\u002Flogic)\n  \u002F\u002F if (await emailAlreadyExists(parsed.value.email)) {\n  \u002F\u002F   return { ok: false, stage: 'business', errors: ['Email is already registered'] }\n  \u002F\u002F }\n\n  return { ok: true as const, value: parsed.value }\n}\n",[21,1939,1937],{"__ignoreMap":56},[17,1941,1942],{},"This function runs the cheapest check first. If syntax fails, there is no point running schema validation. If schema fails, there is no point querying the database.",[36,1944,1946],{"id":1945},"api-error-response-design","API Error Response Design",[17,1948,1949],{},"A well-designed API returns different error shapes depending on which validation layer failed.",[146,1951,1953],{"id":1952},"syntax-error-400-bad-request","Syntax error → 400 Bad Request",[50,1955,1958],{"className":1956,"code":1957,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"INVALID_JSON\",\n    \"message\": \"Request body is not valid JSON.\"\n  }\n}\n",[21,1959,1957],{"__ignoreMap":56},[146,1961,1963],{"id":1962},"schema-error-422-unprocessable-entity","Schema error → 422 Unprocessable Entity",[50,1965,1968],{"className":1966,"code":1967,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"VALIDATION_FAILED\",\n    \"message\": \"Request data does not match the expected schema.\",\n    \"fields\": [\n      { \"path\": \"\u002Femail\", \"message\": \"must match format \\\"email\\\"\" },\n      { \"path\": \"\u002Fage\", \"message\": \"must be >= 0\" },\n      { \"path\": \"\u002FmarketingOptIn\", \"message\": \"must be boolean\" }\n    ]\n  }\n}\n",[21,1969,1967],{"__ignoreMap":56},[146,1971,1973],{"id":1972},"business-rule-error-409-conflict-or-422","Business-rule error → 409 Conflict or 422",[50,1975,1978],{"className":1976,"code":1977,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"EMAIL_ALREADY_EXISTS\",\n    \"message\": \"An account already uses this email address.\"\n  }\n}\n",[21,1979,1977],{"__ignoreMap":56},[17,1981,1982],{},"Many APIs use 400 for malformed JSON and 422 for structurally valid data that fails validation, but your API should follow one documented and consistent convention.",[36,1984,1986],{"id":1985},"common-json-validation-mistakes","Common JSON Validation Mistakes",[146,1988,1990],{"id":1989},"mistake-1-treating-jsonparse-success-as-api-validation","Mistake 1: Treating JSON.parse() success as API validation",[17,1992,1993,1995],{},[21,1994,1071],{}," succeeding only means the text is valid JSON. It says nothing about whether the data matches your API contract. Always run schema validation after parsing.",[146,1997,1999],{"id":1998},"mistake-2-relying-on-content-type-alone","Mistake 2: Relying on Content-Type alone",[17,2001,2002,2003,2006],{},"A request with ",[21,2004,2005],{},"Content-Type: application\u002Fjson"," header may still contain a body that is not valid JSON. Always parse and validate the body, not just the header.",[146,2008,2010],{"id":2009},"mistake-3-allowing-unknown-fields-accidentally","Mistake 3: Allowing unknown fields accidentally",[17,2012,2013,2014,2016],{},"If your schema does not include ",[21,2015,1615],{},", unexpected fields pass through silently. This can leak internal debug data into your system or cause subtle bugs when clients send fields you did not expect.",[146,2018,2020],{"id":2019},"mistake-4-coercing-values-without-documenting-it","Mistake 4: Coercing values without documenting it",[17,2022,2023,2024,173,2027,654,2029,173,2032,2034],{},"Some frameworks silently convert ",[21,2025,2026],{},"\"42\"",[21,2028,490],{},[21,2030,2031],{},"\"true\"",[21,2033,1919],{},". If your API does this, document it clearly. Silent coercion can hide client bugs and make debugging harder. When in strict mode, Ajv rejects type mismatches rather than coercing them.",[146,2036,2038],{"id":2037},"mistake-5-validating-only-in-the-browser","Mistake 5: Validating only in the browser",[17,2040,2041],{},"Client-side validation improves UX but can be bypassed. Every request that modifies data must be validated again on the server.",[146,2043,2045],{"id":2044},"mistake-6-logging-raw-invalid-payloads-with-secrets","Mistake 6: Logging raw invalid payloads with secrets",[17,2047,2048],{},"When logging validation failures, strip or redact sensitive fields like tokens, passwords, and API keys before writing to logs.",[36,2050,2052],{"id":2051},"a-practical-api-validation-workflow","A Practical API Validation Workflow",[17,2054,2055],{},"For each incoming JSON request:",[156,2057,2058,2064,2073,2079,2085,2091],{},[84,2059,2060,2063],{},[87,2061,2062],{},"Enforce a body-size limit."," Reject payloads that exceed your expected maximum before parsing.",[84,2065,2066,2069,2070,2072],{},[87,2067,2068],{},"Parse the JSON."," Use ",[21,2071,1071],{}," or an equivalent. If it fails, return a 400 error with the parse error message.",[84,2074,2075,2078],{},[87,2076,2077],{},"Validate against a schema."," Check required fields, types, ranges, and additional properties. If it fails, return a 422 error with the list of schema violations.",[84,2080,2081,2084],{},[87,2082,2083],{},"Apply business rules."," Check database constraints, permissions, and application logic. If it fails, return a 409 or 422 error with a specific error code.",[84,2086,2087,2090],{},[87,2088,2089],{},"Return structured errors."," Include a machine-readable error code, a human-readable message, and field-level details for schema errors.",[84,2092,2093,2096],{},[87,2094,2095],{},"Log safely."," Redact sensitive fields before writing to logs.",[36,2098,976],{"id":975},[146,2100,2102],{"id":2101},"does-jsonparse-validate-json-schema","Does JSON.parse() validate JSON Schema?",[17,2104,2105,2106,2108,2109,2112],{},"No. ",[21,2107,1071],{}," only checks whether a string follows JSON syntax and converts it into a JavaScript value. It does not check whether required fields exist, whether values have expected types, or whether extra fields are allowed. Use a schema validator like ",[63,2110,1686],{"href":1684,"rel":2111},[67]," for that.",[146,2114,2116],{"id":2115},"is-valid-json-always-safe-to-use-as-api-data","Is valid JSON always safe to use as API data?",[17,2118,2119,2120,2122,2123,2125],{},"No. A payload may be syntactically valid JSON but still fail your API contract. For example, an ",[21,2121,1282],{}," field may be negative, a required field may be missing, or a ",[21,2124,1288],{}," may not be one of the allowed values. Syntax validation is only the first layer.",[146,2127,2129],{"id":2128},"should-i-validate-json-in-the-frontend-or-backend","Should I validate JSON in the frontend or backend?",[17,2131,2132],{},"Validate on both when it improves user feedback, but always validate again on the backend. Client-side checks can be bypassed and cannot safely enforce permissions, database constraints, or other server-side business rules.",[146,2134,2136,2137,2139],{"id":2135},"does-format-email-always-validate-email-addresses","Does ",[21,2138,1698],{}," always validate email addresses?",[17,2141,2142,2143,2148],{},"Not necessarily. JSON Schema validators differ in how they implement and enable format checks. With Ajv, common formats are provided through the ",[63,2144,2146],{"href":1690,"rel":2145},[67],[21,2147,1694],{}," package, so confirm your validator configuration before relying on format validation in production.",[36,2150,1113],{"id":1112},[81,2152,2153,2162,2171,2181],{},[84,2154,2155,2158,2159,2161],{},[87,2156,2157],{},"Already have a broken payload?"," Start with ",[63,2160,781],{"href":780}," to find and fix the syntax error.",[84,2163,2164,2167,2168,2170],{},[87,2165,2166],{},"Need to validate JSON against a schema?"," Use the ",[63,2169,768],{"href":767}," to paste your data and schema side by side.",[84,2172,2173,90,2176,2180],{},[87,2174,2175],{},"Want to inspect complex JSON structure?",[63,2177,2179],{"href":2178},"\u002Ftools\u002Fformat\u002Fjson-path-tester","View your JSON as an interactive tree"," to explore nested fields.",[84,2182,2183,2186,2187,2191],{},[87,2184,2185],{},"Building an API from scratch?"," Read our guide to ",[63,2188,2190],{"href":2189},"\u002Fblog\u002Fjson-best-practices","JSON best practices"," for error handling, validation, and response design.",[1162,2193],{},[17,2195,2196],{},[1167,2197,1169],{},{"title":56,"searchDepth":1171,"depth":1171,"links":2199},[2200,2201,2207,2215,2219,2224,2229,2237,2238,2245],{"id":1249,"depth":1171,"text":1250},{"id":1307,"depth":1171,"text":1308,"children":2202},[2203,2204,2205,2206],{"id":1316,"depth":1177,"text":1317},{"id":1363,"depth":1177,"text":1364},{"id":1419,"depth":1177,"text":1420},{"id":1450,"depth":1177,"text":1451},{"id":1461,"depth":1171,"text":1462,"children":2208},[2209,2210,2211,2212,2214],{"id":1468,"depth":1177,"text":1469},{"id":1502,"depth":1177,"text":1503},{"id":1524,"depth":1177,"text":1525},{"id":1671,"depth":1177,"text":2213},"The format keyword caveat",{"id":1702,"depth":1177,"text":1703},{"id":1817,"depth":1171,"text":1818,"children":2216},[2217,2218],{"id":1824,"depth":1177,"text":1825},{"id":1874,"depth":1177,"text":1875},{"id":1892,"depth":1171,"text":1893,"children":2220},[2221,2222,2223],{"id":1902,"depth":1177,"text":1903},{"id":1922,"depth":1177,"text":1923},{"id":1932,"depth":1177,"text":1933},{"id":1945,"depth":1171,"text":1946,"children":2225},[2226,2227,2228],{"id":1952,"depth":1177,"text":1953},{"id":1962,"depth":1177,"text":1963},{"id":1972,"depth":1177,"text":1973},{"id":1985,"depth":1171,"text":1986,"children":2230},[2231,2232,2233,2234,2235,2236],{"id":1989,"depth":1177,"text":1990},{"id":1998,"depth":1177,"text":1999},{"id":2009,"depth":1177,"text":2010},{"id":2019,"depth":1177,"text":2020},{"id":2037,"depth":1177,"text":2038},{"id":2044,"depth":1177,"text":2045},{"id":2051,"depth":1171,"text":2052},{"id":975,"depth":1171,"text":976,"children":2239},[2240,2241,2242,2243],{"id":2101,"depth":1177,"text":2102},{"id":2115,"depth":1177,"text":2116},{"id":2128,"depth":1177,"text":2129},{"id":2135,"depth":1177,"text":2244},"Does \"format\": \"email\" always validate email addresses?",{"id":1112,"depth":1171,"text":1113},"2026-09-03T00:00:00.000Z","Learn the difference between JSON syntax validation and JSON Schema validation. Understand three validation layers with practical JavaScript examples for validating API data safely.","\u002Fblog\u002Fcover\u002Fen\u002Fjson-validation-syntax-vs-schema-cover.svg",[1213,2250],"zh",{},"\u002Fen\u002Fblog\u002Fjson-validation-syntax-vs-schema",{"slug":2254,"text":2255,"btn":2256},"json-schema-validator","Validate your JSON data against a JSON Schema:","Open JSON Schema Validator",{"title":1230,"description":2247},"en\u002Fblog\u002Fjson-validation-syntax-vs-schema",[214,2260,1476,2261,2262,2263],"JSON Validation","JavaScript","API Validation","Data Validation","ZVmiUdPnjatrK0u75M9aYD2o6oxI2AkNmzhzFuX_CVs",{"id":2266,"title":2267,"author":7,"body":2268,"category":1206,"date":2246,"description":3377,"draft":1209,"extension":1210,"h1":2267,"image":3378,"lastmod":2246,"locales":3379,"meta":3380,"navigation":1215,"path":3381,"promo":3382,"seo":3385,"stem":3386,"tags":3387,"__hash__":3391},"blog\u002Fzh\u002Fblog\u002Fjson-validation-syntax-vs-schema.md","JSON 校验详解：语法校验、JSON Schema 与业务规则的区别",{"type":9,"value":2269,"toc":3332},[2270,2273,2279,2286,2289,2294,2297,2327,2330,2350,2360,2370,2374,2377,2439,2442,2450,2453,2457,2460,2466,2471,2477,2486,2490,2495,2501,2505,2511,2515,2520,2524,2530,2533,2544,2550,2556,2604,2610,2614,2617,2620,2626,2629,2634,2640,2643,2761,2764,2788,2794,2797,2803,2806,2830,2833,2849,2855,2859,2862,2865,2870,2873,2898,2901,2904,2910,2914,2918,2928,2934,2941,2945,2951,2954,2960,2963,2969,2972,2978,2981,2985,2992,2996,3002,3008,3012,3023,3029,3032,3035,3041,3044,3048,3055,3060,3067,3072,3080,3084,3087,3093,3096,3100,3102,3108,3114,3117,3121,3124,3138,3141,3145,3148,3151,3165,3169,3172,3178,3188,3191,3197,3203,3207,3210,3216,3229,3233,3236,3240,3243,3246,3249,3267,3272,3282,3285,3325,3327],[12,2271,2267],{"id":2272},"json-校验详解语法校验json-schema-与业务规则的区别",[17,2274,2275,2276,2278],{},"很多开发者会把\"JSON 能被 ",[21,2277,1071],{}," 解析\"理解成\"JSON 数据已经有效\"。但在真实接口开发中，这两件事并不相同。",[17,2280,2281,2282,2285],{},"一段文本能够被解析，只能说明它符合 JSON 的",[87,2283,2284],{},"语法规则","。它仍可能缺少必填字段、字段类型不正确、包含不允许的值，或者在当前业务场景中根本不能被系统接受。",[17,2287,2288],{},"例如，下面这段内容是合法 JSON：",[50,2290,2292],{"className":2291,"code":1261,"language":55,"meta":56},[53],[21,2293,1261],{"__ignoreMap":56},[17,2295,2296],{},"但它很可能不符合\"创建用户\"接口的要求：",[81,2298,2299,2304,2309,2317,2322],{},[84,2300,2301,2303],{},[21,2302,1276],{}," 不符合预期格式；",[84,2305,2306,2308],{},[21,2307,1282],{}," 不应该是负数；",[84,2310,2311,2313,2314,2316],{},[21,2312,1288],{}," 不一定允许 ",[21,2315,1772],{},"；",[84,2318,2319,2321],{},[21,2320,1294],{}," 应该是布尔值，而不是字符串；",[84,2323,2324,2326],{},[21,2325,1300],{}," 可能是接口不允许接收的额外字段。",[17,2328,2329],{},"JSON 校验通常至少包括三个层次：",[156,2331,2332,2338,2344],{},[84,2333,2334,2337],{},[87,2335,2336],{},"语法校验","：这段文本是否为合法 JSON？",[84,2339,2340,2343],{},[87,2341,2342],{},"结构校验","：字段、类型、范围和嵌套结构是否符合接口契约？",[84,2345,2346,2349],{},[87,2347,2348],{},"业务规则校验","：即使结构正确，当前业务是否允许这份数据？",[17,2351,2352,2353,2355,2356,2359],{},"如果你的代码在 ",[21,2354,1071],{}," 阶段就报错，可以先阅读 ",[63,2357,2358],{"href":780},"JSON 解析失败：10 个常见 API 错误与排查方法","。",[2361,2362,2363],"blockquote",{},[17,2364,2365,2366,2369],{},"想先确认一段文本是否为合法 JSON，可以使用 ",[63,2367,2368],{"href":767},"JSON Schema 校验器"," 检查语法错误位置。",[36,2371,2373],{"id":2372},"json-校验不是单一步骤","JSON 校验不是单一步骤",[17,2375,2376],{},"下面这张表可以快速区分三种常见校验。",[300,2378,2379,2395],{},[303,2380,2381],{},[306,2382,2383,2386,2389,2392],{},[309,2384,2385],{},"校验层级",[309,2387,2388],{},"核心问题",[309,2390,2391],{},"常见实现方式",[309,2393,2394],{},"常见失败示例",[316,2396,2397,2412,2426],{},[306,2398,2399,2401,2404,2409],{},[321,2400,2336],{},[321,2402,2403],{},"文本能否被解析为 JSON？",[321,2405,2406,2408],{},[21,2407,1071],{},"、JSON Validator",[321,2410,2411],{},"尾逗号、单引号、注释、缺少括号",[306,2413,2414,2417,2420,2423],{},[321,2415,2416],{},"Schema 结构校验",[321,2418,2419],{},"数据是否符合预期字段、类型与约束？",[321,2421,2422],{},"JSON Schema、Ajv、Zod",[321,2424,2425],{},"缺少必填字段、类型错误、枚举值不合法",[306,2427,2428,2430,2433,2436],{},[321,2429,2348],{},[321,2431,2432],{},"当前系统是否允许接受这份数据？",[321,2434,2435],{},"服务端业务逻辑、权限系统、数据库查询",[321,2437,2438],{},"邮箱已注册、没有资源权限、库存不足",[17,2440,2441],{},"这三层应按顺序执行：",[50,2443,2448],{"className":2444,"code":2446,"language":2447,"meta":56},[2445],"language-text","原始文本\n→ JSON 语法校验\n→ JSON Schema 结构校验\n→ 业务规则校验\n→ 执行业务逻辑\n","text",[21,2449,2446],{"__ignoreMap":56},[17,2451,2452],{},"不要跳过前两层，直接假设客户端或第三方系统传来的数据可信。",[36,2454,2456],{"id":2455},"第一层json-语法校验","第一层：JSON 语法校验",[17,2458,2459],{},"语法校验解决的问题最基础：",[50,2461,2464],{"className":2462,"code":2463,"language":2447,"meta":56},[2445],"这段文本是不是符合 JSON 语法？\n",[21,2465,2463],{"__ignoreMap":56},[17,2467,2468,2469,2359],{},"JavaScript 中最常用的方法是 ",[21,2470,1071],{},[50,2472,2475],{"className":2473,"code":2474,"language":1436,"meta":56},[1434],"export type JsonSyntaxResult =\n  | {\n      valid: true\n      value: unknown\n    }\n  | {\n      valid: false\n      error: string\n    }\n\nexport function parseJsonSafely(text: string): JsonSyntaxResult {\n  try {\n    return {\n      valid: true,\n      value: JSON.parse(text)\n    }\n  } catch (error) {\n    return {\n      valid: false,\n      error: error instanceof Error ? error.message : \"无效 JSON\"\n    }\n  }\n}\n",[21,2476,2474],{"__ignoreMap":56},[17,2478,2479,2480,2482,2483,2485],{},"如果输入不符合 JSON grammar，",[21,2481,1071],{}," 会抛出 ",[21,2484,1359],{},"。常见问题包括尾逗号、使用单引号、对象键未加双引号、注释、未闭合的对象或数组等。",[146,2487,2489],{"id":2488},"常见的无效-json","常见的无效 JSON",[2491,2492,2494],"h4",{"id":2493},"_1-尾逗号","1. 尾逗号",[50,2496,2499],{"className":2497,"code":2498,"language":55,"meta":56},[53],"{\n  \"name\": \"Ada\",\n  \"age\": 36,\n}\n",[21,2500,2498],{"__ignoreMap":56},[2491,2502,2504],{"id":2503},"_2-单引号","2. 单引号",[50,2506,2509],{"className":2507,"code":2508,"language":55,"meta":56},[53],"{\n  \"name\": \"Ada\"\n}\n",[21,2510,2508],{"__ignoreMap":56},[2491,2512,2514],{"id":2513},"_3-注释","3. 注释",[50,2516,2518],{"className":2517,"code":2508,"language":55,"meta":56},[53],[21,2519,2508],{"__ignoreMap":56},[2491,2521,2523],{"id":2522},"_4-未加引号的对象键","4. 未加引号的对象键",[50,2525,2528],{"className":2526,"code":2527,"language":55,"meta":56},[53],"{\n  name: \"Ada\"\n}\n",[21,2529,2527],{"__ignoreMap":56},[17,2531,2532],{},"这些写法在 JavaScript 对象字面量、JSONC 或某些配置格式中可能可以出现，但它们不是标准 JSON。",[2361,2534,2535],{},[17,2536,2537,2538,2540,2541,2543],{},"如果只是想快速查看缩进、括号和嵌套结构，可以先使用 ",[63,2539,740],{"href":739}," 格式化合法 JSON；如果内容本身无法解析，应先使用 ",[63,2542,2368],{"href":767}," 定位语法问题。",[146,2545,2547,2549],{"id":2546},"jsonparse-没有检查什么",[21,2548,1071],{}," 没有检查什么？",[17,2551,2552,2553,2555],{},"下面这些内容即使解析成功，",[21,2554,1071],{}," 也不会判断它们是否符合接口要求：",[81,2557,2558,2571,2576,2590,2595,2598,2601],{},[84,2559,2560,2561,2563,2564,2563,2567,2570],{},"是否缺少 ",[21,2562,1276],{},"、",[21,2565,2566],{},"id",[21,2568,2569],{},"name"," 等必填字段；",[84,2572,2573,2575],{},[21,2574,1282],{}," 是否应该为非负整数；",[84,2577,2578,2580,2581,2563,2584,2587,2588,2316],{},[21,2579,1288],{}," 是否只能是 ",[21,2582,2583],{},"user",[21,2585,2586],{},"editor"," 或 ",[21,2589,1856],{},[84,2591,2592,2594],{},[21,2593,1276],{}," 是否符合邮箱格式；",[84,2596,2597],{},"是否出现了接口未声明的额外字段；",[84,2599,2600],{},"当前用户是否有权限提交这份数据；",[84,2602,2603],{},"数据库中是否已经存在相同邮箱。",[17,2605,2606,2607,2609],{},"因此，",[21,2608,1071],{}," 成功只是校验的起点，不是终点。",[36,2611,2613],{"id":2612},"第二层json-schema-结构校验","第二层：JSON Schema 结构校验",[17,2615,2616],{},"JSON Schema 是一种声明 JSON 数据结构、类型和约束的规则语言。它可以描述\"一个合法请求体应该长什么样\"，并让校验器根据这些规则检查输入。",[17,2618,2619],{},"例如，一个创建用户接口可能希望接收：",[50,2621,2624],{"className":2622,"code":2623,"language":55,"meta":56},[53],"{\n  \"email\": \"ada@example.com\",\n  \"age\": 36,\n  \"role\": \"editor\",\n  \"marketingOptIn\": true\n}\n",[21,2625,2623],{"__ignoreMap":56},[17,2627,2628],{},"对应的 JSON Schema 可以写成：",[50,2630,2632],{"className":2631,"code":1519,"language":55,"meta":56},[53],[21,2633,1519],{"__ignoreMap":56},[17,2635,2636,2639],{},[63,2637,1476],{"href":1474,"rel":2638},[67]," 用于声明与验证 JSON 的结构、类型和约束。",[146,2641,2642],{"id":2642},"关键字段说明",[300,2644,2645,2658],{},[303,2646,2647],{},[306,2648,2649,2652,2655],{},[309,2650,2651],{},"Schema 关键字",[309,2653,2654],{},"作用",[309,2656,2657],{},"示例",[316,2659,2660,2675,2689,2703,2717,2733,2748],{},[306,2661,2662,2667,2670],{},[321,2663,2664],{},[21,2665,2666],{},"type",[321,2668,2669],{},"限制值的数据类型",[321,2671,2672],{},[21,2673,2674],{},"\"type\": \"object\"",[306,2676,2677,2681,2684],{},[321,2678,2679],{},[21,2680,1566],{},[321,2682,2683],{},"定义对象中已知字段的校验规则",[321,2685,2686],{},[21,2687,2688],{},"\"email\": { \"type\": \"string\" }",[306,2690,2691,2695,2698],{},[321,2692,2693],{},[21,2694,1556],{},[321,2696,2697],{},"声明哪些字段必须存在",[321,2699,2700],{},[21,2701,2702],{},"[\"email\", \"age\"]",[306,2704,2705,2709,2712],{},[321,2706,2707],{},[21,2708,1602],{},[321,2710,2711],{},"限制字段只能取指定值之一",[321,2713,2714],{},[21,2715,2716],{},"[\"user\", \"editor\", \"admin\"]",[306,2718,2719,2725,2728],{},[321,2720,2721,1587,2723],{},[21,2722,1586],{},[21,2724,1590],{},[321,2726,2727],{},"限制数字范围",[321,2729,2730],{},[21,2731,2732],{},"\"minimum\": 0",[306,2734,2735,2740,2743],{},[321,2736,2737],{},[21,2738,2739],{},"items",[321,2741,2742],{},"定义数组元素的校验规则",[321,2744,2745],{},[21,2746,2747],{},"\"items\": { \"type\": \"string\" }",[306,2749,2750,2754,2757],{},[321,2751,2752],{},[21,2753,1655],{},[321,2755,2756],{},"是否允许未声明的额外字段",[321,2758,2759],{},[21,2760,1660],{},[17,2762,2763],{},"有两个常见误解需要特别注意：",[156,2765,2766,2774],{},[84,2767,2768,2770,2771,2773],{},[21,2769,1566],{}," 中出现字段，并不表示字段自动必填；必须通过 ",[21,2772,1556],{}," 单独声明。",[84,2775,2776,2777,2780,2781,2587,2785,2787],{},"默认情况下，JSON Schema 允许额外字段。只有显式设置 ",[21,2778,2779],{},"\"additionalProperties\": false","，才会拒绝未被 ",[63,2782,1566],{"href":2783,"rel":2784},"https:\u002F\u002Fjson-schema.org\u002Funderstanding-json-schema\u002Freference\u002Fobject",[67],[21,2786,1623],{}," 声明的属性。",[146,2789,2791,2793],{"id":2790},"format-email-不一定总会强制校验",[21,2792,1576],{}," 不一定总会强制校验",[17,2795,2796],{},"很多 Schema 示例会写：",[50,2798,2801],{"className":2799,"code":2800,"language":55,"meta":56},[53],"{\n  \"type\": \"string\",\n  \"format\": \"email\"\n}\n",[21,2802,2800],{"__ignoreMap":56},[17,2804,2805],{},"但不要假设所有 JSON Schema 校验器都会自动把它当成严格错误。",[17,2807,2808,2810,2811,2814,2815,2820,2821,2563,2823,2563,2826,2829],{},[21,2809,1675],{}," 的具体执行方式取决于你使用的校验器和配置。例如 ",[63,2812,1686],{"href":1684,"rel":2813},[67]," 从 v7 开始不再默认内置常见 format 校验，需要通过 ",[63,2816,2818],{"href":1690,"rel":2817},[67],[21,2819,1694],{}," 提供 ",[21,2822,1276],{},[21,2824,2825],{},"date-time",[21,2827,2828],{},"uri"," 等格式支持。",[17,2831,2832],{},"因此，生产环境中应确认：",[81,2834,2835,2838,2841,2846],{},[84,2836,2837],{},"你使用的是哪一个 JSON Schema draft；",[84,2839,2840],{},"所使用的 validator 是否启用了 format 校验；",[84,2842,2843,2845],{},[21,2844,1675],{}," 是 annotation、warning，还是会直接导致校验失败；",[84,2847,2848],{},"邮箱、URL、日期等规则是否需要更严格的业务层验证。",[17,2850,2851,2852,2854],{},"你可以把上面的 Schema 和请求体粘贴到 ",[63,2853,2368],{"href":767}," 中，实际查看校验结果。",[36,2856,2858],{"id":2857},"第三层业务规则校验","第三层：业务规则校验",[17,2860,2861],{},"即使输入是合法 JSON，也通过了 JSON Schema，它仍然可能无法在当前系统中执行。",[17,2863,2864],{},"例如：",[50,2866,2868],{"className":2867,"code":2623,"language":55,"meta":56},[53],[21,2869,2623],{"__ignoreMap":56},[17,2871,2872],{},"结构完全正确，但服务端仍然可能拒绝它，因为：",[81,2874,2875,2880,2886,2889,2892,2895],{},[84,2876,2877,2879],{},[21,2878,1833],{}," 已被其他账户使用；",[84,2881,2882,2883,2885],{},"当前管理员无权创建 ",[21,2884,2586],{}," 角色；",[84,2887,2888],{},"当前租户不允许新增用户；",[84,2890,2891],{},"用户数量已达到套餐上限；",[84,2893,2894],{},"关联组织不存在或已停用；",[84,2896,2897],{},"请求中的资源 ID 不属于当前用户。",[17,2899,2900],{},"这类规则依赖数据库、权限、租户上下文、库存、时间、状态机或第三方服务结果，通常不能仅凭 JSON Schema 静态判断。",[17,2902,2903],{},"因此，一个可靠的 API 校验流程通常应当是：",[50,2905,2908],{"className":2906,"code":2907,"language":2447,"meta":56},[2445],"1. 限制请求体大小\n2. 解析 JSON\n3. 校验 Schema\n4. 检查权限、资源状态和业务规则\n5. 执行业务逻辑\n6. 返回结构化响应\n",[21,2909,2907],{"__ignoreMap":56},[36,2911,2913],{"id":2912},"如何在-javascript-中校验-json","如何在 JavaScript 中校验 JSON",[146,2915,2917],{"id":2916},"只检查-json-语法","只检查 JSON 语法",[17,2919,2920,2921,2923,2924,2927],{},"如果你的目标只是判断文本能否被解析，使用 ",[21,2922,1071],{}," 和 ",[21,2925,2926],{},"try...catch"," 即可：",[50,2929,2932],{"className":2930,"code":2931,"language":1436,"meta":56},[1434],"export function isValidJson(text: string): boolean {\n  try {\n    JSON.parse(text)\n    return true\n  } catch {\n    return false\n  }\n}\n",[21,2933,2931],{"__ignoreMap":56},[17,2935,2936,2937,2587,2939,2359],{},"但在应用代码中，通常更建议保留错误信息，而不是只返回 ",[21,2938,1919],{},[21,2940,1660],{},[146,2942,2944],{"id":2943},"使用-ajv-进行-json-schema-校验","使用 Ajv 进行 JSON Schema 校验",[17,2946,2947,2950],{},[63,2948,1686],{"href":1684,"rel":2949},[67]," 是 JavaScript 生态中常用的 JSON Schema validator，支持多个 JSON Schema draft，并将 Schema 编译为可复用的校验函数。",[17,2952,2953],{},"安装依赖：",[50,2955,2958],{"className":2956,"code":2957,"language":273,"meta":56},[271],"npm install ajv ajv-formats\n",[21,2959,2957],{"__ignoreMap":56},[17,2961,2962],{},"定义并编译 Schema：",[50,2964,2967],{"className":2965,"code":2966,"language":1436,"meta":56},[1434],"import Ajv from \"ajv\"\nimport addFormats from \"ajv-formats\"\n\nconst ajv = new Ajv({\n  allErrors: true,\n  strict: true\n})\n\naddFormats(ajv)\n\nconst createUserSchema = {\n  type: \"object\",\n  additionalProperties: false,\n  required: [\"email\", \"age\", \"role\", \"marketingOptIn\"],\n  properties: {\n    email: {\n      type: \"string\",\n      format: \"email\"\n    },\n    age: {\n      type: \"integer\",\n      minimum: 0,\n      maximum: 150\n    },\n    role: {\n      type: \"string\",\n      enum: [\"user\", \"editor\", \"admin\"]\n    },\n    marketingOptIn: {\n      type: \"boolean\"\n    }\n  }\n} as const\n\nconst validateCreateUser = ajv.compile(createUserSchema)\n\nexport function validateCreateUserPayload(value: unknown) {\n  const valid = validateCreateUser(value)\n\n  return {\n    valid: Boolean(valid),\n    errors: validateCreateUser.errors ?? []\n  }\n}\n",[21,2968,2966],{"__ignoreMap":56},[17,2970,2971],{},"将语法校验和 Schema 校验组合起来：",[50,2973,2976],{"className":2974,"code":2975,"language":1436,"meta":56},[1434],"export function validateIncomingUserJson(text: string) {\n  const parsed = parseJsonSafely(text)\n\n  if (!parsed.valid) {\n    return {\n      ok: false as const,\n      stage: \"syntax\" as const,\n      errors: [parsed.error]\n    }\n  }\n\n  const schemaResult = validateCreateUserPayload(parsed.value)\n\n  if (!schemaResult.valid) {\n    return {\n      ok: false as const,\n      stage: \"schema\" as const,\n      errors: schemaResult.errors\n    }\n  }\n\n  return {\n    ok: true as const,\n    value: parsed.value\n  }\n}\n",[21,2977,2975],{"__ignoreMap":56},[17,2979,2980],{},"这段流程仍然没有完成业务规则校验。通过 Schema 后，服务端仍应继续检查权限、唯一性和资源状态。",[36,2982,2984],{"id":2983},"api-应如何返回校验错误","API 应如何返回校验错误？",[17,2986,2987,2988,2991],{},"对调用方而言，能看懂错误比只收到一个泛泛的 ",[21,2989,2990],{},"400 Bad Request"," 更有帮助。",[146,2993,2995],{"id":2994},"json-语法错误","JSON 语法错误",[17,2997,2998,2999,3001],{},"许多 API 会将无法解析的请求体视为 ",[21,3000,2990],{},"：",[50,3003,3006],{"className":3004,"code":3005,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"INVALID_JSON\",\n    \"message\": \"请求体不是合法的 JSON。\"\n  }\n}\n",[21,3007,3005],{"__ignoreMap":56},[146,3009,3011],{"id":3010},"schema-结构错误","Schema 结构错误",[17,3013,3014,3015,3018,3019,3022],{},"很多团队会对\"JSON 可解析但不符合请求契约\"的情况使用 ",[21,3016,3017],{},"422 Unprocessable Content","，也有团队统一使用 ",[21,3020,3021],{},"400","。没有一种状态码适合所有 API；更重要的是在整个 API 中保持一致，并在文档中说明规则。",[50,3024,3027],{"className":3025,"code":3026,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"VALIDATION_FAILED\",\n    \"message\": \"请求数据不符合预期的 Schema。\",\n    \"fields\": [\n      {\n        \"path\": \"\u002Femail\",\n        \"message\": \"必须匹配 email 格式\"\n      },\n      {\n        \"path\": \"\u002Fage\",\n        \"message\": \"必须 >= 0\"\n      },\n      {\n        \"path\": \"\u002FmarketingOptIn\",\n        \"message\": \"必须是布尔值\"\n      }\n    ]\n  }\n}\n",[21,3028,3026],{"__ignoreMap":56},[146,3030,3031],{"id":3031},"业务规则错误",[17,3033,3034],{},"对于资源冲突或当前状态不允许操作的情况，可以返回更明确的业务错误：",[50,3036,3039],{"className":3037,"code":3038,"language":55,"meta":56},[53],"{\n  \"error\": {\n    \"code\": \"EMAIL_ALREADY_EXISTS\",\n    \"message\": \"该邮箱地址已被注册。\"\n  }\n}\n",[21,3040,3038],{"__ignoreMap":56},[17,3042,3043],{},"不要在错误响应中暴露密码、访问令牌、数据库连接串、完整第三方响应、内部堆栈或其他敏感信息。",[36,3045,3047],{"id":3046},"常见-json-校验误区","常见 JSON 校验误区",[146,3049,3051,3052,3054],{"id":3050},"误区-1jsonparse-成功等于接口数据有效","误区 1：",[21,3053,1071],{}," 成功等于接口数据有效",[17,3056,3057,3059],{},[21,3058,1071],{}," 只解决语法问题。它不会验证必填字段、类型、枚举值、数值范围或业务规则。",[146,3061,3063,3064],{"id":3062},"误区-2只看-content-type","误区 2：只看 ",[21,3065,3066],{},"Content-Type",[17,3068,3069,3071],{},[21,3070,2005],{}," 说明服务端声称响应是 JSON，但不保证 body 一定能被解析，也不保证解析后的数据符合预期结构。",[17,3073,3074,3075,3077,3078,2359],{},"如果 API 响应在 ",[21,3076,1071],{}," 阶段失败，可以先阅读 ",[63,3079,2358],{"href":780},[146,3081,3083],{"id":3082},"误区-3没有明确处理额外字段","误区 3：没有明确处理额外字段",[17,3085,3086],{},"如果接口只应接受固定字段，应考虑：",[50,3088,3091],{"className":3089,"code":3090,"language":55,"meta":56},[53],"{\n  \"additionalProperties\": false\n}\n",[21,3092,3090],{"__ignoreMap":56},[17,3094,3095],{},"但这并非所有 API 都适合。对于需要向前兼容、允许客户端传递扩展字段，或使用动态字段映射的接口，拒绝所有额外字段可能会过于严格。",[146,3097,3099],{"id":3098},"误区-4自动类型转换却没有记录规则","误区 4：自动类型转换，却没有记录规则",[17,3101,2864],{},[50,3103,3106],{"className":3104,"code":3105,"language":2447,"meta":56},[2445],"\"age\": \"36\"\n",[21,3107,3105],{"__ignoreMap":56},[17,3109,3110,3111,3113],{},"有的框架或工具会把它自动转换为数字 ",[21,3112,1379],{},"，有的则直接校验失败。",[17,3115,3116],{},"自动转换可以改善部分表单体验，但也会让接口契约变模糊。若要启用，必须写入 API 文档并在前后端保持一致；对于安全、财务或关键业务字段，通常应更严格。",[146,3118,3120],{"id":3119},"误区-5只在前端校验","误区 5：只在前端校验",[17,3122,3123],{},"前端校验可以快速提示用户，但不能作为信任边界：",[81,3125,3126,3129,3132,3135],{},[84,3127,3128],{},"客户端 JavaScript 可以被绕过；",[84,3130,3131],{},"API 可以被脚本、curl、Postman 或其他客户端直接调用；",[84,3133,3134],{},"请求可能来自旧版本应用；",[84,3136,3137],{},"攻击者可以构造任意请求体。",[17,3139,3140],{},"因此，后端必须重新校验所有不可信输入。",[146,3142,3144],{"id":3143},"误区-6将完整无效请求体写入日志","误区 6：将完整无效请求体写入日志",[17,3146,3147],{},"排查问题时记录上下文很重要，但完整 payload 可能包含邮箱、电话、地址、Cookie、Authorization header、API Key 或其他隐私数据。",[17,3149,3150],{},"建议：",[81,3152,3153,3156,3159,3162],{},[84,3154,3155],{},"限制日志长度；",[84,3157,3158],{},"对 token、密码、邮箱等字段脱敏；",[84,3160,3161],{},"只记录必要的错误路径和请求 ID；",[84,3163,3164],{},"为敏感数据设置更严格的访问控制与保留策略。",[36,3166,3168],{"id":3167},"一个实用的-api-校验流程","一个实用的 API 校验流程",[17,3170,3171],{},"下面是一个适合大多数 JSON API 的基本流程：",[50,3173,3176],{"className":3174,"code":3175,"language":2447,"meta":56},[2445],"接收请求\n→ 限制 body 大小\n→ 以 UTF-8 解码请求体\n→ 尝试解析 JSON\n→ 返回语法错误，或继续\n→ 用 Schema 校验数据结构\n→ 返回字段级错误，或继续\n→ 执行业务与权限校验\n→ 返回业务错误，或继续\n→ 执行业务操作并返回成功响应\n",[21,3177,3175],{"__ignoreMap":56},[17,3179,3180,3181,3183,3184,3187],{},"如果请求数据很复杂，可以先用 ",[63,3182,740],{"href":739}," 整理结构，再用 ",[63,3185,3186],{"href":2178},"JSONPath 测试工具"," 检查嵌套字段和数组层级。",[36,3189,3190],{"id":3190},"常见问题",[146,3192,3194,3196],{"id":3193},"jsonparse-能校验-json-schema-吗",[21,3195,1071],{}," 能校验 JSON Schema 吗？",[17,3198,3199,3200,3202],{},"不能。",[21,3201,1071],{}," 只将符合 JSON 语法的字符串转换为 JavaScript 值，不会验证必填字段、字段类型、允许值、数据范围或额外字段。",[146,3204,3206],{"id":3205},"合法-json-一定能被-api-接受吗","合法 JSON 一定能被 API 接受吗？",[17,3208,3209],{},"不一定。它可能语法正确，但缺少字段、类型不对、数值超范围、枚举值不允许，或者不符合权限、唯一性、库存和资源状态等业务规则。",[146,3211,3213,3215],{"id":3212},"format-email-一定会校验邮箱吗",[21,3214,1576],{}," 一定会校验邮箱吗？",[17,3217,3218,3219,3222,3223,3228],{},"不一定。是否强制校验取决于 JSON Schema validator 及其配置。以 ",[63,3220,1686],{"href":1684,"rel":3221},[67]," 为例，常见 formats 由 ",[63,3224,3226],{"href":1690,"rel":3225},[67],[21,3227,1694],{}," 提供，因此应确认项目已经正确注册对应插件。",[146,3230,3232],{"id":3231},"前端和后端都需要校验-json-吗","前端和后端都需要校验 JSON 吗？",[17,3234,3235],{},"建议两端都做，但职责不同。前端校验主要改善交互体验，帮助用户更早发现问题；后端校验负责安全和数据完整性，必须始终执行。",[146,3237,3239],{"id":3238},"json-schema-和-typescript-有什么区别","JSON Schema 和 TypeScript 有什么区别？",[17,3241,3242],{},"TypeScript 类型主要帮助开发阶段的静态检查，通常在编译后不会自动校验运行时传入的数据。JSON Schema 描述的是运行时数据应满足的结构与约束，可用于验证 HTTP 请求、Webhook、配置文件和第三方 API 数据。",[36,3244,3245],{"id":3245},"总结",[17,3247,3248],{},"JSON 校验不是单一的\"能否解析\"检查：",[156,3250,3251,3256,3262],{},[84,3252,3253,3255],{},[87,3254,2336],{},"：确认文本是否为合法 JSON；",[84,3257,3258,3261],{},[87,3259,3260],{},"Schema 校验","：确认字段、类型、约束和嵌套结构是否符合接口契约；",[84,3263,3264,3266],{},[87,3265,2348],{},"：确认数据在当前权限、资源和系统状态下是否可被接受。",[17,3268,3269,3271],{},[21,3270,1071],{}," 成功只是第一步。对于 API、Webhook、配置文件和第三方输入，应该将语法、Schema 和业务规则校验组合起来，并在后端重新执行关键校验。",[2361,3273,3274],{},[17,3275,3276,3277,3279,3280,2359],{},"想快速确认一段文本是否为合法 JSON，可以先使用 ",[63,3278,2368],{"href":767},"。如果错误发生在 API 响应解析阶段，查看 ",[63,3281,2358],{"href":780},[36,3283,3284],{"id":3284},"下一步",[81,3286,3287,3297,3306,3315],{},[84,3288,3289,3292,3293,3296],{},[87,3290,3291],{},"已有解析失败的 JSON？"," 先看",[63,3294,3295],{"href":780},"接口调试中的 10 个典型 JSON 错误","，找到并修复语法错误。",[84,3298,3299,3302,3303,3305],{},[87,3300,3301],{},"需要用 Schema 校验 JSON？"," 用 ",[63,3304,2368],{"href":767}," 把数据和 Schema 分别粘贴，查看校验结果。",[84,3307,3308,90,3311,3314],{},[87,3309,3310],{},"想查看复杂 JSON 的结构？",[63,3312,3313],{"href":2178},"用交互式树形视图浏览 JSON","，探索嵌套字段。",[84,3316,3317,3320,3321,3324],{},[87,3318,3319],{},"从零构建 API？"," 看我们的 ",[63,3322,3323],{"href":2189},"JSON 最佳实践"," 指南，涵盖错误处理、校验和响应设计。",[1162,3326],{},[17,3328,3329],{},[1167,3330,3331],{},"JSON Toolbox 的所有工具完全在浏览器中运行，数据不会离开你的设备。",{"title":56,"searchDepth":1171,"depth":1171,"links":3333},[3334,3335,3340,3345,3346,3350,3355,3365,3366,3375,3376],{"id":2372,"depth":1171,"text":2373},{"id":2455,"depth":1171,"text":2456,"children":3336},[3337,3338],{"id":2488,"depth":1177,"text":2489},{"id":2546,"depth":1177,"text":3339},"JSON.parse() 没有检查什么？",{"id":2612,"depth":1171,"text":2613,"children":3341},[3342,3343],{"id":2642,"depth":1177,"text":2642},{"id":2790,"depth":1177,"text":3344},"format: \"email\" 不一定总会强制校验",{"id":2857,"depth":1171,"text":2858},{"id":2912,"depth":1171,"text":2913,"children":3347},[3348,3349],{"id":2916,"depth":1177,"text":2917},{"id":2943,"depth":1177,"text":2944},{"id":2983,"depth":1171,"text":2984,"children":3351},[3352,3353,3354],{"id":2994,"depth":1177,"text":2995},{"id":3010,"depth":1177,"text":3011},{"id":3031,"depth":1177,"text":3031},{"id":3046,"depth":1171,"text":3047,"children":3356},[3357,3359,3361,3362,3363,3364],{"id":3050,"depth":1177,"text":3358},"误区 1：JSON.parse() 成功等于接口数据有效",{"id":3062,"depth":1177,"text":3360},"误区 2：只看 Content-Type",{"id":3082,"depth":1177,"text":3083},{"id":3098,"depth":1177,"text":3099},{"id":3119,"depth":1177,"text":3120},{"id":3143,"depth":1177,"text":3144},{"id":3167,"depth":1171,"text":3168},{"id":3190,"depth":1171,"text":3190,"children":3367},[3368,3370,3371,3373,3374],{"id":3193,"depth":1177,"text":3369},"JSON.parse() 能校验 JSON Schema 吗？",{"id":3205,"depth":1177,"text":3206},{"id":3212,"depth":1177,"text":3372},"format: \"email\" 一定会校验邮箱吗？",{"id":3231,"depth":1177,"text":3232},{"id":3238,"depth":1177,"text":3239},{"id":3245,"depth":1171,"text":3245},{"id":3284,"depth":1171,"text":3284},"了解 JSON 语法校验、JSON Schema 结构校验与业务规则校验的区别，并通过 JavaScript 示例构建更可靠的 API 数据校验流程。","\u002Fblog\u002Fcover\u002Fzh\u002Fjson-validation-syntax-vs-schema-cover.svg",[2250,1213],{},"\u002Fzh\u002Fblog\u002Fjson-validation-syntax-vs-schema",{"slug":2254,"text":3383,"btn":3384},"先检查 JSON 语法是否正确：","打开 JSON 校验工具",{"title":2267,"description":3377},"zh\u002Fblog\u002Fjson-validation-syntax-vs-schema",[214,3388,1476,2261,3389,3390],"JSON 校验","API 校验","数据校验","Xp9In5hPd63uHo5ihbSQBR6uwtqyava5GnL8TeMtZkQ",1791273862850]