王學仁(學仁大大)
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
資料驗證好幫手 - JSON Schema Validator === 文件大綱: * [JSON schema 簡介及作用](#intro) - 告訴你什麼是JSON Schema * [JSON schema 詳細介紹](#instruction) - 有完整的文件告訴你JSON Schema中每個propety的作用 * [JSON Schema範例](#sample) - 就像看例句學英文一樣,看範例或許比看文件更好懂 * [JSON Schema Validator](#validator) - [Ajv套件](#ajv) * [Jquery-Validation](#jquery-validation) - 直得參考的的套件 ## <a id="intro">JSON schema 簡介及作用</a> 直接先看一下JSON schema的範例,暖個身 ```json { "title":"產品資訊", "description":"產品包含商品標號、商品名稱及價錢", "type":"object", "properties":{ "pid":{ "description":"產品的id,是product id的縮寫", "type":"integer" }, "name":{ "description":"產品名稱", "type":"string", "maxLength": 10 }, "price":{ "type":"number", "exclusiveMinimum":0 } }, "required":[ "pid", "name", "price" ] } ``` JSON Schema就是JSON資料結構的規範,規定一個JSON資料該有哪些資料,包含規定型態、大小範圍等。JSON Schema有官方規範,可以在[http://json-schema.org](http://json-schema.org)上查看,目前已出到draft-07。 這份文件要介紹的 [Ajv (Another JSON Schema Validator)](https://github.com/epoberezkin/ajv) 套件會支援 draft-04/06/07 這幾個版本。 JSON Schema 功用如下: * 用於構建人機可讀的文件: - JSON Schema 可以讓系統讀取,同時也是一個讓人一目瞭然的文件檔,一舉兩得。 * 用於生成模擬資料: - 有了JSON Schema,可以自動生成符合規定的資料讓測試程式使用。 * 用於資料驗證: - 不需要再寫程式來判斷資料長度跟內容了,所有的邏輯都可以移植到JSON Schema中維護,最後我們會使用ajv這個工具來使用JSON schema進行驗證。 --- ## <a id="instruction">JSON schema 詳細介紹</a> 網路上已經有文件把9成的功能介紹完了,廢話不多說直接看[JSON Schema 辭典](http://xaber.co/2015/10/20/JSON-schema-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B%E6%96%87%E6%A1%A3/)吧! 其他教學文件: * [JSON Schema 基本概念教學](http://taobaofed.org/blog/2016/01/25/jsonschema/) * [JSON Schema 參考書](http://imweb.io/topic/57b5f69373ac222929653f23) * [ajv的keyword列表](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md) --- ## <a id="sample">JSON Schema範例</a> 比起看文件,大家更愛範例,所以在這邊提供幾個範例,剩下的可以去上面的文件看。 資料是數字(在這邊成為n), 3 <= n < 9 且 n要是3的倍數 ```json= { "type": "number", "minimum": 3, "exclusiveMaximum": 9, "multipleOf": 3 } ``` * `exclusiveMinimum`與`exclusiveMaximum`在draft-04以前是boolean,但在draft-06以後則變成數字。 --- 字串長度為5~10 ```json= { "type": "string", "minLength": 5, "maxLength": 10, } ``` --- 符合正規表示式的字串,輸入的字串必須符合身分證字號的格式 ```json= { "title": "ID card number", "type": "string", "pattern": "^[A-Z]{1}[0-9]{9}$" } ``` --- 符合ipv4的的字串,還有`email`跟`date-time`等format ```json= { "type": "string", "format":"ipv4" } ``` --- 陣列長度2~5,而且必須都是數字,並不得有重複的數字 ```json= { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 5, "uniqueItems": true } ``` --- 陣列內只能有指定的[ `整數` , `DC或Marvel` ],不可以有其他東西 ```json= { "type": "array", "items": [ { "description": "粉絲的年紀", "type": "integer" }, { "type": "string", "enum": ["DC", "Marvel"] } ], "additionalItems": false } ``` * 在沒有additionalItems的情況下,[ `整數` , `DC或Marvel` , `這邊要放多少東西都可以` ],additionalItems可以指定type等相關資訊,代表多出來的陣列內容必須符合additionalItems的限制。 --- Object物件中,最多只能有5個property,一定要有`nickname`,當有`carMileage`時,就一定要有`carBrand`,反之則不需要,`carBrand`只能填bmw或benz,除了原本定義的property之外,其他的property都得是string型態。 ```json= { "type":"object", "maxProperties":5, "properties":{ "nickname":{ "type": "string" }, "carBrand":{ "enum": ["benz", "bmw"] }, "carMileage":{ "type":"number" } }, "required": ["nickname"], "dependencies":{ "carMileage": ["carBrand"] }, "additionalProperties":{ "type":"string" } } ``` `oneOf`代表 **只能** 符合其中一項,也就是這個數字必須是5或3的倍數,但不能是15的倍數,另外還有`anyOf`跟`allOf`以及`not`可以使用 ```json= { "type": "number", "oneOf": [ { "multipleOf": 5 }, { "multipleOf": 3 } ] } ``` --- 使用refs引用定義好的definitions,先定義好正整數後直接引用 ```json= { "type": "array", "items": { "$ref": "#/definitions/positiveInteger" }, "definitions": { "positiveInteger": { "type": "integer", "exclusiveMinimum": 0 } } } ``` definitions相當於引用自己建立的變數的感覺,厲害的是$refs可以引用外部檔案的schema,像是json-schema.org提供的官方範例[geo.json](http://json-schema.org/example/geo.json#) ```json= { "$ref": "http://json-schema.org/geo.json#" } ``` --- [draft-04更新到draft-06時多出的功能](http://json-schema.org/draft-06/json-schema-release-notes.html): * [contains](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#contains) - `{ "contains": { "type": "integer" } }` means that any array with at least one integer, any non-array is matched * [propertyNames](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#propertynames) - property名稱必須符合規範 * [const](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#const) - 比對不同property的值是否相同 [draft-06更新到draft-07時多出的功能](http://json-schema.org/draft-07/json-schema-release-notes.html): * [if/then/else](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#ifthenelse) if-else的範例 ```json= { "type": "integer", "minimum": 1, "maximum": 1000, "if": { "minimum": 100 }, "then": { "multipleOf": 100 }, "else": { "if": { "minimum": 10 }, "then": { "multipleOf": 10 } } } ``` 符合規定的資料: 1, 5, 10, 20, 50, 100, 200, 500, 1000 不符合規定的資料: * -1, 0 (<1) * 2000 (>1000) * 11, 57, 123 (any number with more than one non-zero digit) * non-integers --- ### \$schema與\$id到底是什麼? The "\$schema" keyword * [$schema](https://spacetelescope.github.io/understanding-json-schema/reference/schema.html)代表你寫的JSON Schema文件遵循的規範是哪一個版本。最新版的draft的schema是`http://json-schema.org/schema#`,目前如果你打開來看的話會是draft-07,如果想指定成draft-06版的話可以寫成`http://json-schema.org/draft-06/schema#` The "\$id" keyword - schemaId * 官方文件提到的[schemaId](https://github.com/epoberezkin/ajv#referenced-schema-options) * \$id 是拿來定義這個schema的獨立編號,必須是uri。 [http://json-schema.org/example/geo.json#](http://json-schema.org/example/geo.json#)中的\$id就是`"http://json-schema.org/geo"`,別人使用$ref想遠端過來取用這個schema就是對應這個\$id,object中的property也可以有\$id,有如path的概念 * 來看以下範例,如果想取用內部的定義則用`#/definitions/B`,取用外部的話則用`http://example.com/other.json`,詳細教學看[這邊](https://tools.ietf.org/html/draft-wright-json-schema-01#section-9.2) ```json= { "$id": "http://example.com/root.json", "definitions": { "A": { "$id": "#foo" }, "B": { "$id": "other.json", "definitions": { "X": { "$id": "#bar" }, "Y": { "$id": "t/inner.json" } } }, "C": { "$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f" } } } ``` * [其他\$id參考文件](https://spacetelescope.github.io/understanding-json-schema/structuring.html#the-id-property) --- ## <a id="validator">JSON Schema Validator</a> JSON Schema Validator就是專門來驗證JSON的工具,將要比對的資料拿去跟schema比對,馬上就知道資料符不符合規定,並且能夠得知是哪個資料的哪個環節不符合規定,相當方便,目前星星數最多,而且還有在維護的就屬[Ajv(Another JSON Schema Validator)](https://github.com/epoberezkin/ajv)莫屬了,以前我用過的JSON Schema Validator是[tv4](https://github.com/geraintluff/tv4)。 另外有一個[react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form),只要在`<form>`物件中放入schema跟data,它就能自動生成Bootstrap表單,它的介紹語是這樣寫的"A simple React component capable of building HTML forms out of a JSON schema and using Bootstrap semantics by default." react-jsonschema-form 程式範例 ```jsx= import React, { Component } from "react"; import { render } from "react-dom"; import Form from "react-jsonschema-form"; const schema = { title: "Todo", type: "object", required: ["title"], properties: { title: {type: "string", title: "Title", default: "A new task"}, done: {type: "boolean", title: "Done?", default: false} } }; const log = (type) => console.log.bind(console, type); render(( <Form schema={schema} onChange={log("changed")} onSubmit={log("submitted")} onError={log("errors")} /> ), document.getElementById("app")); ``` 但因為綁定Bootstrap有一點死,所以這邊還是選用比較有彈性的ajv。 --- ## <a id="ajv">Ajv: Another JSON Schema Validator</a> 注意:完整的文件可以直接去[github](https://github.com/epoberezkin/ajv)上看,這邊會提到比較常用到的內容,或是我有用過的內容。[[npm ajv 連結](https://www.npmjs.com/package/ajv)] 這邊有模擬在Nodejs上面執行ajv的[連結](https://npm.runkit.com/ajv),可以進去試用看看。 我們已經學會了JSON Schema了,現在直接使用Ajv來比對schema跟data就能驗證資料了,看看下面的範例吧!符合條件的話ajv.validate就會回傳true,反之則false ```javascript= var ajv = Ajv(); var schema = { "type": "number", "oneOf": [ { "multipleOf": 5 }, { "multipleOf": 3 } ] }; var data10 = 10; var data15 = 15; console.log(ajv.validate(schema, data10)); // true console.log(ajv.validate(schema, data15)); // false ``` --- 如果想知道錯在哪裡,我們就輸出`ajv.errors`,也是直接看下面範例。 我們在字串長度應該是5的schema中輸入長度是4的字串 ```javascript= var ajv = Ajv(); var schema = { "type": "string", "minLength": 5 }; var data = "four"; var valid = ajv.validate(schema, data); if (!valid) console.log(ajv.errors); ``` 資料長度不符合規定時Ajv回傳的錯誤訊息格式如下,大致上看得懂,我們去看下個範例後再解說這些參數是幹嘛的。 ```json= [ { "keyword":"minLength", "dataPath":"", "schemaPath":"#/minLength", "params":{ "limit":5 }, "message":"should NOT be shorter than 5 characters" } ] ``` --- 這次的範例有兩個錯誤,分別是`2016-12-99`不符合`date`格式,以及`fruit`欄位應該要是字串卻填入了數字,如果要顯示超過一個以上的error就必須在[Options](https://github.com/epoberezkin/ajv#options)欄位加上`{ allErrors: true }`,否則它只會回傳第一個error。 ```javascript= var ajv = new Ajv({ allErrors: true }); var schema = { "type": "object", "properties": { "purchaseDate": { "format": "date" }, "foods": { "type": "object", "properties": { "fruit": { "type": "string" } }, }, } }; var data = { "purchaseDate": "2016-12-99", "foods": { "fruit": 5566 } }; var valid = ajv.validate(schema, data); if (!valid) console.log(ajv.errors); ``` 回傳了兩個錯誤 ```json= [ { "keyword":"format", "dataPath":".purchaseDate", "schemaPath":"#/properties/purchaseDate/format", "params":{ "format":"date" }, "message":"should match format 'date'" }, { "keyword":"type", "dataPath":".foods.fruit", "schemaPath":"#/properties/foods/properties/fruit/type", "params":{ "type":"string" }, "message":"should be string" } ] ``` 想要知道error object的架構,可以看[Validation errors](https://github.com/epoberezkin/ajv#validation-errors),我把裡面的部分內容節錄在下方。 * `keyword`: validation keyword. * `dataPath`: the path to the part of the data that was validated. By default dataPath uses JavaScript property access notation (e.g., ".prop[1].subProp"). When the option jsonPointers is true (see Options) dataPath will be set using JSON pointer standard (e.g., "/prop/1/subProp"). * `schemaPath`: the path (JSON-pointer as a URI fragment) to the schema of the keyword that failed validation. * `params`: the object with the additional information about error that can be used to create custom error messages. [[params文件](https://github.com/epoberezkin/ajv#error-parameters)] * `message`: the standard error message (can be excluded with option messages set to false). --- [API列表](https://github.com/epoberezkin/ajv#api) - 接在ajv後面的api都寫在這。 **`.compile(Object schema)`** validating function and cache the compiled schema for future use,比起每次都用`ajv.validate()`的執行速度還快,官方文件也說這是`The fastest validation call` --- **`.errorsText([Array<Object> errors [, Object options]])`** `ajv.errorsText(ajv.errors)`這樣的寫法可以把error object轉換成一個錯誤訊息字串, remote schemas have to be added with addSchema or compiled to be available --- **`.addFormat(String name, String|RegExp|Function|Object format)`** 使用`addFormat`定義客製化的format,可以參考下面的範例 ```javascript= var ajv = new Ajv().addFormat('cellphone', '^09[0-9]{2}-[0-9]{3}-[0-9]{3}$'); var schema = { "format": "cellphone" }; var data = '0912-345-678'; // format have to be 09XX-XXX-XXX var validate = ajv.compile(schema); console.log(validate(data)); // true ``` --- **`.addKeyword(String keyword, Object definition)`** 自訂keyword ```javascript= ajv.addKeyword('range', { type: 'number', compile: function (sch, parentSchema) { var min = sch[0]; var max = sch[1]; return parentSchema.exclusiveRange === true ? function (data) { return data > min && data < max; } : function (data) { return data >= min && data <= max; } } }); var schema = { "range": [2, 4], "exclusiveRange": true }; var validate = ajv.compile(schema); console.log(validate(2.01)); // true console.log(validate(3.99)); // true console.log(validate(2)); // false console.log(validate(4)); // false ``` --- **`.addSchema(Array<Object>|Object schema [, String key])`** `compile`跟`addSchema`非常像,其實我也分不太出來為啥要分兩個, [addSchema vs schemas](https://github.com/epoberezkin/ajv#combining-schemas-with-ref) 直接傳schema ```javascript var validate = jv.addSchema(schema) ``` 傳schema並給予一個key值 ```javascript var valid = ajv.addSchema(schema, 'mySchema').validate('mySchema', data); ``` 除了`addSchema`的話,也可以在宣告`Ajv`時直接assign`schemas` ```javascript var ajv = new Ajv({schemas: [schema1, schema2]}); ``` schemas: an array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them --- **`.addMetaSchema(Array<Object>|Object schema [, String key])`** * 這裡有官方對於[Meta Schema](http://json-schema.org/specification.html)的介紹,meta-schema是就是JSON Schema的範本,目前最新的meta-schema是draft-07。 至於為何要addMetaSchema我還不是非常清楚 --- **`.getSchema(String key)`** 只透過uri來取得Schema ```javascript ajv.getSchema('http://example.com/schemas/schema.json') ``` --- ## <a id="jquery-validation">Jquery-Validation - 直得參考的的套件</a> 我認為JSON-validator必須要有良好的message回傳機制才實用,所以我找到了一個我個人認為設計蠻好的套件[jquery-validation](https://github.com/jquery-validation/jquery-validation),因為是jquery所以不太適合套用到reactjs專案,但是可以試著引用它的設計模式來打造一個適合自己專案的validator。可以看看Youtube上的[jQuery Validation Plugin 播放清單]( https://www.youtube.com/watch?v=xNSQ3i-BWMo&list=PL5ze0DjYv5DaAm5eC2chbTK1Y6uoTUtZ9)來了解如何使用。 基本上它就是將驗證的rule與要回傳的message分成兩個property互相對應

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully