Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Validating JSON with JSON Schema

Validating JSON with JSON Schema

My talk from Berlin PHP Usergroup, December 2013, about the benefits of using JSON schema for validating complex JSON data

Anne-Julia Seitz

December 03, 2013
Tweet

More Decks by Anne-Julia Seitz

Other Decks in Technology

Transcript

  1. About me → Anne-Julia Scheuermann → Creating Web-Applications since 2004

    → Developing information literacy solutions for
  2. Custom validation protected function isValidUnformatted(array $data) { if (empty($data['data'])) {

    return false; // no data sent } $data = $data['data']; $source = $data['source']; $style = empty($data['style']) ? null : $data['style']; $structure = $this->getStructure($source, $style); $allowedTopLevelFields = $this->getOtherValidFields(); $ignoredDataFields = $this->getIgnoredFields(); // source if (!empty($structure['source_data'])) { if (empty($data[$source])) { $this->errors[] = 'needed source data missing'; return false; } $notAllowed = array_diff_key($data[$source], array_flip($structure['source_data'])); // +300 lines of code more
  3. PHPMD warnings /!\ /** * @param array $data * *

    @Todo Fix suppressed warnings * @SuppressWarnings( * PHPMD.CyclomaticComplexity, * PHPMD.NPathComplexity * ) * @return bool */ protected function isValidUnformatted(array $data) { //...
  4. DTD for SGML <!DOCTYPE HTML PUBLIC ”-//W3C//DTD HTML 4.01//EN” ”http://www.w3.org/TR/html4/strict.dtd”>

    <!--=================== Generic Attributes ===============================--> <!ENTITY % coreattrs ”id ID #IMPLIED -- document-wide unique id -- class CDATA #IMPLIED -- space-separated list of classes -- style %StyleSheet; #IMPLIED -- associated style info -- title %Text; #IMPLIED -- advisory title --” >
  5. XSD for XML (XHTML) <?xml version=”1.0”?> <xs:schema xmlns:xs=”http://www.w3.org/2001/XMLSchema”> <xs:element name=”note”>

    <xs:complexType> <xs:sequence> <xs:element name=”to” type=”xs:string”/> <xs:element name=”from” type=”xs:string”/> <xs:element name=”body” type=”xs:string”/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
  6. number range 10 11 40 { ”type”: ”number”, “minimum”: 10,

    “maximum”: 40, “exclusiveMinimum”: true, “exclusiveMaximum”: false }
  7. array [1, 2, 3, 4, 5] [1, “2”, {“3”:”4 and

    5”}, [42]] {”type”: ”array”} {“this”: “is an object”}
  8. array items [] [1, 2, 3, 4, 5] [1, 2,

    3, 4, “5”] { ”type”: ”array”, “items”: {“type”: “number”} }
  9. {”author”: ”A. A. Milne”, ”year”: 1882} properties { ”type”: ”object”,

    ”properties”: { ”author”: {”type”: ”string”}, ”year”: {”type”: ”number”} } } {”year”: ”1882”} {”author”: ”A. A. Milne”} {}
  10. {”author”: ”A. A Milne”, ”title”: 1882} required properties { ”type”:

    ”object”, ”properties”: { ”author”: {”type”: ”string”}, ”title”: {”type”: ”string”}}, ”required”: [”title”] } {} {”author”: ”A. A Milne”, ”title”: ”Winni the Pooh”, ”year”: 1926} {”author”: “A. A Milne”}
  11. additional properties { ”type”: ”object”, ”properties”: { ”author”: {”type”: ”string”},

    ”title”: {”type”: ”string”} }, ”additionalProperties”: false } {”title”: []} {} {”author”: ”A. A. Milne”, ”title”: ”Winni the Pooh”, ”year”: 1926} {”author”: ”A. A. Milne”, ”title”: ”Winni the Pooh”}
  12. {”a”: ”aa”, “b”: “bb”} number of properties { ”type”: ”object”,

    ”minProperties”: 1, ”maxProperties”: 2 } {} {”a”: ”aa”} {”a”: ”aa”, “b”: “bb”, “c”: “cc”}
  13. {”name”: ”Alan”, “birthday”: “1882-01-18”} property dependencies { ”type”: ”object”, ”properties”:

    {“name”: {“type”: “string”}, “birthday”: {“type”: “string”}}, ”dependencies”: { “birthday”: [“name”]} } {”name”: ”Alan”} {“birthday”: “1882-01-18”}
  14. {”name”: ”Alan”, “birthday”: “1882-01-18”} schema dependencies { ”type”: ”object”, ”properties”:

    { “birthday”: {“type”: “string”}}, ”dependencies”: { “birthday”: { “properties”: {“name”: {“type”: “string”}}}} } {”name”: ”Alan”} {“birthday”: “1882-01-18”}
  15. {”PHPUnit”: ”testing”, “PHPCS”: “styling”} pattern properties { ”type”: ”object”, ”patternProperties”:

    { “^PHP”: {“type”: “string”}}, “additionalProperties”: {“type”: “integer”} } {”BeHat”: ”accepting”} {“PHPLOC”: 9001} {“LOC”: 9001}
  16. “one” “eleven” 1 -11 Combining with oneOf, anyOf, allOf {

    ”anyOf”: [ {“type”: “string”, “maxLength”: 5}, {“type”: “number”, “minimum”: 0} ] }
  17. title, description & default { ”title”: ”Expressive title”, ”description”: “Take

    time to explain”, ”default”: “Validators ignore this keyword” }
  18. definitions { “$schema”: “http://json-schema.org/draft-04/schema#”, “definitions”: { "address": { "type": "object",

    "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" } }, "required": ["street_address", "city", "state"] } } }
  19. $ref & definitions { “$schema”: “http://json-schema.org/draft-04/schema#”, “definitions”: { "address": {

    "type": "object", "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" } }, "required": ["street_address", "city", "state"] } } "type": "object", "properties": { "billing_address": { "$ref": "#/definitions/address" }, "shipping_address": { "$ref": "#/definitions/address" } } }
  20. $ref & definitions { “$schema”: “http://json-schema.org/draft-04/schema#”, “description”: “This schema defines

    an address”, "type": "object", "properties": { "city": { "type": "string" }, "state": { "type": "string" } }, "required": ["street_address", "city", "state"] } { “$schema”: “http://json-schema.org/draft-04/schema#”, “description”: “This schema describes an order”, "type": "object", "properties": { "billing_address": { "$ref": "address.json#" }, "shipping_address": { "$ref": "address.json#" } } } address.json order.json
  21. Validation Libraries geraintluff/jsv4-php 11 commits, 1 contributor hasbridge/php-json-schema 28 commits,

    2 contributors, not yet feature complete justinrainbow/json-schema 202 commits, 21 contributors
  22. Preparing validation with json-schema // Get the schema as object

    $retriever = new JsonSchema\Uri\UriRetriever; $schema = $retriever->retrieve('file://' . realpath('schema.json')); // Resolve references $refResolver = new JsonSchema\RefResolver($retriever); $refResolver->resolve($schema, 'file://' . __DIR__);
  23. Validation with json-schema /** * Validate json against schema *

    * @param string $data * @param string $schema * * @return bool */ public function isValid($data, $schema) { $data = json_decode($data); $this->validator->check($data, $schema); $this->errors = $this->validator->getErrors(); return $this->validator->isValid(); }
  24. Less code /** * Validate json against schema * *

    @param string $data * @param string $schema * * @return bool */ public function isValid($data, $schema) { $data = json_decode($data); $this->validator->check($data, $schema); $this->errors = $this->validator->getErrors(); return $this->validator->isValid(); }