• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

testdata/H08-Jan-2019-11,21111,082

.gitignoreH A D08-Jan-201925 43

.travis.ymlH A D08-Jan-2019230 1312

README.mdH A D08-Jan-201915.1 KiB466346

draft.goH A D08-Jan-201910.1 KiB11988

errors.goH A D08-Jan-20197.1 KiB325240

format_checkers.goH A D08-Jan-20198.2 KiB344220

format_checkers_test.goH A D08-Jan-2019690 2417

glide.yamlH A D08-Jan-2019282 1410

internalLog.goH A D08-Jan-20191.1 KiB388

jsonContext.goH A D08-Jan-20192 KiB7334

jsonLoader.goH A D08-Jan-20198.6 KiB368237

jsonschema_test.goH A D08-Jan-20194.5 KiB187140

locales.goH A D08-Jan-20198.2 KiB314223

result.goH A D08-Jan-20195.3 KiB190120

schema.goH A D08-Jan-201928.3 KiB1,073917

schemaLoader.goH A D08-Jan-20194.3 KiB204140

schemaLoader_test.goH A D08-Jan-20194.7 KiB163116

schemaPool.goH A D08-Jan-20196.2 KiB216136

schemaReferencePool.goH A D08-Jan-20191.7 KiB6932

schemaType.goH A D08-Jan-20192.1 KiB8439

schema_test.goH A D08-Jan-20197.2 KiB332254

subSchema.goH A D08-Jan-20196.3 KiB257173

types.goH A D08-Jan-20191.4 KiB5929

utils.goH A D08-Jan-20194.8 KiB237142

utils_test.goH A D08-Jan-20193.1 KiB9250

validation.goH A D08-Jan-201923.6 KiB926700

README.md

1[![GoDoc](https://godoc.org/github.com/xeipuuv/gojsonschema?status.svg)](https://godoc.org/github.com/xeipuuv/gojsonschema)
2[![Build Status](https://travis-ci.org/xeipuuv/gojsonschema.svg)](https://travis-ci.org/xeipuuv/gojsonschema)
3
4# gojsonschema
5
6## Description
7
8An implementation of JSON Schema for the Go  programming language. Supports draft-04, draft-06 and draft-07.
9
10References :
11
12* http://json-schema.org
13* http://json-schema.org/latest/json-schema-core.html
14* http://json-schema.org/latest/json-schema-validation.html
15
16## Installation
17
18```
19go get github.com/xeipuuv/gojsonschema
20```
21
22Dependencies :
23* [github.com/xeipuuv/gojsonpointer](https://github.com/xeipuuv/gojsonpointer)
24* [github.com/xeipuuv/gojsonreference](https://github.com/xeipuuv/gojsonreference)
25* [github.com/stretchr/testify/assert](https://github.com/stretchr/testify#assert-package)
26
27## Usage
28
29### Example
30
31```go
32
33package main
34
35import (
36    "fmt"
37    "github.com/xeipuuv/gojsonschema"
38)
39
40func main() {
41
42    schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
43    documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json")
44
45    result, err := gojsonschema.Validate(schemaLoader, documentLoader)
46    if err != nil {
47        panic(err.Error())
48    }
49
50    if result.Valid() {
51        fmt.Printf("The document is valid\n")
52    } else {
53        fmt.Printf("The document is not valid. see errors :\n")
54        for _, desc := range result.Errors() {
55            fmt.Printf("- %s\n", desc)
56        }
57    }
58}
59
60
61```
62
63#### Loaders
64
65There are various ways to load your JSON data.
66In order to load your schemas and documents,
67first declare an appropriate loader :
68
69* Web / HTTP, using a reference :
70
71```go
72loader := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json")
73```
74
75* Local file, using a reference :
76
77```go
78loader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
79```
80
81References use the URI scheme, the prefix (file://) and a full path to the file are required.
82
83* JSON strings :
84
85```go
86loader := gojsonschema.NewStringLoader(`{"type": "string"}`)
87```
88
89* Custom Go types :
90
91```go
92m := map[string]interface{}{"type": "string"}
93loader := gojsonschema.NewGoLoader(m)
94```
95
96And
97
98```go
99type Root struct {
100	Users []User `json:"users"`
101}
102
103type User struct {
104	Name string `json:"name"`
105}
106
107...
108
109data := Root{}
110data.Users = append(data.Users, User{"John"})
111data.Users = append(data.Users, User{"Sophia"})
112data.Users = append(data.Users, User{"Bill"})
113
114loader := gojsonschema.NewGoLoader(data)
115```
116
117#### Validation
118
119Once the loaders are set, validation is easy :
120
121```go
122result, err := gojsonschema.Validate(schemaLoader, documentLoader)
123```
124
125Alternatively, you might want to load a schema only once and process to multiple validations :
126
127```go
128schema, err := gojsonschema.NewSchema(schemaLoader)
129...
130result1, err := schema.Validate(documentLoader1)
131...
132result2, err := schema.Validate(documentLoader2)
133...
134// etc ...
135```
136
137To check the result :
138
139```go
140    if result.Valid() {
141    	fmt.Printf("The document is valid\n")
142    } else {
143        fmt.Printf("The document is not valid. see errors :\n")
144        for _, err := range result.Errors() {
145        	// Err implements the ResultError interface
146            fmt.Printf("- %s\n", err)
147        }
148    }
149```
150
151
152## Loading local schemas
153
154By default `file` and `http(s)` references to external schemas are loaded automatically via the file system or via http(s). An external schema can also be loaded using a `SchemaLoader`.
155
156```go
157	sl := gojsonschema.NewSchemaLoader()
158	loader1 := gojsonschema.NewStringLoader(`{ "type" : "string" }`)
159	err := sl.AddSchema("http://some_host.com/string.json", loader1)
160```
161
162Alternatively if your schema already has an `$id` you can use the `AddSchemas` function
163```go
164	loader2 := gojsonschema.NewStringLoader(`{
165			"$id" : "http://some_host.com/maxlength.json",
166			"maxLength" : 5
167		}`)
168	err = sl.AddSchemas(loader2)
169```
170
171The main schema should be passed to the `Compile` function. This main schema can then directly reference the added schemas without needing to download them.
172```go
173	loader3 := gojsonschema.NewStringLoader(`{
174		"$id" : "http://some_host.com/main.json",
175		"allOf" : [
176			{ "$ref" : "http://some_host.com/string.json" },
177			{ "$ref" : "http://some_host.com/maxlength.json" }
178		]
179	}`)
180
181	schema, err := sl.Compile(loader3)
182
183	documentLoader := gojsonschema.NewStringLoader(`"hello world"`)
184
185	result, err := schema.Validate(documentLoader)
186```
187
188It's also possible to pass a `ReferenceLoader` to the `Compile` function that references a loaded schema.
189
190```go
191err = sl.AddSchemas(loader3)
192schema, err := sl.Compile(gojsonschema.NewReferenceLoader("http://some_host.com/main.json"))
193```
194
195Schemas added by `AddSchema` and `AddSchemas` are only validated when the entire schema is compiled, unless meta-schema validation is used.
196
197## Using a specific draft
198By default `gojsonschema` will try to detect the draft of a schema by using the `$schema` keyword and parse it in a strict draft-04, draft-06 or draft-07 mode. If `$schema` is missing, or the draft version is not explicitely set, a hybrid mode is used which merges together functionality of all drafts into one mode.
199
200Autodectection can be turned off with the `AutoDetect` property. Specific draft versions can be specified with the `Draft` property.
201
202```go
203sl := gojsonschema.NewSchemaLoader()
204sl.Draft = gojsonschema.Draft7
205sl.AutoDetect = false
206```
207
208If autodetection is on (default), a draft-07 schema can savely reference draft-04 schemas and vice-versa, as long as `$schema` is specified in all schemas.
209
210## Meta-schema validation
211Schemas that are added using the `AddSchema`, `AddSchemas` and `Compile` can be validated against their meta-schema by setting the `Validate` property.
212
213The following example will produce an error as `multipleOf` must be a number. If `Validate` is off (default), this error is only returned at the `Compile` step.
214
215```go
216sl := gojsonschema.NewSchemaLoader()
217sl.Validate = true
218err := sl.AddSchemas(gojsonschema.NewStringLoader(`{
219     $id" : "http://some_host.com/invalid.json",
220    "$schema": "http://json-schema.org/draft-07/schema#",
221    "multipleOf" : true
222}`))
223 ```
224```
225 ```
226
227Errors returned by meta-schema validation are more readable and contain more information, which helps significantly if you are developing a schema.
228
229Meta-schema validation also works with a custom `$schema`. In case `$schema` is missing, or `AutoDetect` is set to `false`, the meta-schema of the used draft is used.
230
231
232## Working with Errors
233
234The library handles string error codes which you can customize by creating your own gojsonschema.locale and setting it
235```go
236gojsonschema.Locale = YourCustomLocale{}
237```
238
239However, each error contains additional contextual information.
240
241Newer versions of `gojsonschema` may have new additional errors, so code that uses a custom locale will need to be updated when this happens.
242
243**err.Type()**: *string* Returns the "type" of error that occurred. Note you can also type check. See below
244
245Note: An error of RequiredType has an err.Type() return value of "required"
246
247    "required": RequiredError
248    "invalid_type": InvalidTypeError
249    "number_any_of": NumberAnyOfError
250    "number_one_of": NumberOneOfError
251    "number_all_of": NumberAllOfError
252    "number_not": NumberNotError
253    "missing_dependency": MissingDependencyError
254    "internal": InternalError
255    "const": ConstEror
256    "enum": EnumError
257    "array_no_additional_items": ArrayNoAdditionalItemsError
258    "array_min_items": ArrayMinItemsError
259    "array_max_items": ArrayMaxItemsError
260    "unique": ItemsMustBeUniqueError
261    "contains" : ArrayContainsError
262    "array_min_properties": ArrayMinPropertiesError
263    "array_max_properties": ArrayMaxPropertiesError
264    "additional_property_not_allowed": AdditionalPropertyNotAllowedError
265    "invalid_property_pattern": InvalidPropertyPatternError
266    "invalid_property_name":  InvalidPropertyNameError
267    "string_gte": StringLengthGTEError
268    "string_lte": StringLengthLTEError
269    "pattern": DoesNotMatchPatternError
270    "multiple_of": MultipleOfError
271    "number_gte": NumberGTEError
272    "number_gt": NumberGTError
273    "number_lte": NumberLTEError
274    "number_lt": NumberLTError
275    "condition_then" : ConditionThenError
276    "condition_else" : ConditionElseError
277
278**err.Value()**: *interface{}* Returns the value given
279
280**err.Context()**: *gojsonschema.JsonContext* Returns the context. This has a String() method that will print something like this: (root).firstName
281
282**err.Field()**: *string* Returns the fieldname in the format firstName, or for embedded properties, person.firstName. This returns the same as the String() method on *err.Context()* but removes the (root). prefix.
283
284**err.Description()**: *string* The error description. This is based on the locale you are using. See the beginning of this section for overwriting the locale with a custom implementation.
285
286**err.DescriptionFormat()**: *string* The error description format. This is relevant if you are adding custom validation errors afterwards to the result.
287
288**err.Details()**: *gojsonschema.ErrorDetails* Returns a map[string]interface{} of additional error details specific to the error. For example, GTE errors will have a "min" value, LTE will have a "max" value. See errors.go for a full description of all the error details. Every error always contains a "field" key that holds the value of *err.Field()*
289
290Note in most cases, the err.Details() will be used to generate replacement strings in your locales, and not used directly. These strings follow the text/template format i.e.
291```
292{{.field}} must be greater than or equal to {{.min}}
293```
294
295The library allows you to specify custom template functions, should you require more complex error message handling.
296```go
297gojsonschema.ErrorTemplateFuncs = map[string]interface{}{
298	"allcaps": func(s string) string {
299		return strings.ToUpper(s)
300	},
301}
302```
303
304Given the above definition, you can use the custom function `"allcaps"` in your localization templates:
305```
306{{allcaps .field}} must be greater than or equal to {{.min}}
307```
308
309The above error message would then be rendered with the `field` value in capital letters. For example:
310```
311"PASSWORD must be greater than or equal to 8"
312```
313
314Learn more about what types of template functions you can use in `ErrorTemplateFuncs` by referring to Go's [text/template FuncMap](https://golang.org/pkg/text/template/#FuncMap) type.
315
316## Formats
317JSON Schema allows for optional "format" property to validate instances against well-known formats. gojsonschema ships with all of the formats defined in the spec that you can use like this:
318
319````json
320{"type": "string", "format": "email"}
321````
322
323Not all formats defined in draft-07 are available. Implemented formats are:
324
325* `date`
326* `time`
327* `date-time`
328* `hostname`. Subdomains that start with a number are also supported, but this means that it doesn't strictly follow [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5) and has the implication that ipv4 addresses are also recognized as valid hostnames.
329* `email`. Go's email parser deviates slightly from [RFC5322](https://tools.ietf.org/html/rfc5322). Includes unicode support.
330* `idn-email`. Same caveat as `email`.
331* `ipv4`
332* `ipv6`
333* `uri`. Includes unicode support.
334* `uri-reference`. Includes unicode support.
335* `iri`
336* `iri-reference`
337* `uri-template`
338* `uuid`
339* `regex`. Go uses the [RE2](https://github.com/google/re2/wiki/Syntax) engine and is not [ECMA262](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) compatible.
340* `json-pointer`
341* `relative-json-pointer`
342
343`email`, `uri` and `uri-reference` use the same validation code as their unicode counterparts `idn-email`, `iri` and `iri-reference`. If you rely on unicode support you should use the specific
344unicode enabled formats for the sake of interoperability as other implementations might not support unicode in the regular formats.
345
346The validation code for `uri`, `idn-email` and their relatives use mostly standard library code. Go 1.5 and 1.6 contain some minor bugs with handling URIs and unicode. You are encouraged to use Go 1.7+ if you rely on these formats.
347
348For repetitive or more complex formats, you can create custom format checkers and add them to gojsonschema like this:
349
350```go
351// Define the format checker
352type RoleFormatChecker struct {}
353
354// Ensure it meets the gojsonschema.FormatChecker interface
355func (f RoleFormatChecker) IsFormat(input interface{}) bool {
356
357    asString, ok := input.(string)
358    if ok == false {
359        return false
360    }
361
362    return strings.HasPrefix("ROLE_", asString)
363}
364
365// Add it to the library
366gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{})
367````
368
369Now to use in your json schema:
370````json
371{"type": "string", "format": "role"}
372````
373
374Another example would be to check if the provided integer matches an id on database:
375
376JSON schema:
377```json
378{"type": "integer", "format": "ValidUserId"}
379```
380
381```go
382// Define the format checker
383type ValidUserIdFormatChecker struct {}
384
385// Ensure it meets the gojsonschema.FormatChecker interface
386func (f ValidUserIdFormatChecker) IsFormat(input interface{}) bool {
387
388    asFloat64, ok := input.(float64) // Numbers are always float64 here
389    if ok == false {
390        return false
391    }
392
393    // XXX
394    // do the magic on the database looking for the int(asFloat64)
395
396    return true
397}
398
399// Add it to the library
400gojsonschema.FormatCheckers.Add("ValidUserId", ValidUserIdFormatChecker{})
401````
402
403Formats can also be removed, for example if you want to override one of the formats that is defined by default.
404
405```go
406gojsonschema.FormatCheckers.Remove("hostname")
407```
408
409
410## Additional custom validation
411After the validation has run and you have the results, you may add additional
412errors using `Result.AddError`. This is useful to maintain the same format within the resultset instead
413of having to add special exceptions for your own errors. Below is an example.
414
415```go
416type AnswerInvalidError struct {
417    gojsonschema.ResultErrorFields
418}
419
420func newAnswerInvalidError(context *gojsonschema.JsonContext, value interface{}, details gojsonschema.ErrorDetails) *AnswerInvalidError {
421    err := AnswerInvalidError{}
422    err.SetContext(context)
423    err.SetType("custom_invalid_error")
424    // it is important to use SetDescriptionFormat() as this is used to call SetDescription() after it has been parsed
425    // using the description of err will be overridden by this.
426    err.SetDescriptionFormat("Answer to the Ultimate Question of Life, the Universe, and Everything is {{.answer}}")
427    err.SetValue(value)
428    err.SetDetails(details)
429
430    return &err
431}
432
433func main() {
434    // ...
435    schema, err := gojsonschema.NewSchema(schemaLoader)
436    result, err := gojsonschema.Validate(schemaLoader, documentLoader)
437
438    if true { // some validation
439        jsonContext := gojsonschema.NewJsonContext("question", nil)
440        errDetail := gojsonschema.ErrorDetails{
441            "answer": 42,
442        }
443        result.AddError(
444            newAnswerInvalidError(
445                gojsonschema.NewJsonContext("answer", jsonContext),
446                52,
447                errDetail,
448            ),
449            errDetail,
450        )
451    }
452
453    return result, err
454
455}
456```
457
458This is especially useful if you want to add validation beyond what the
459json schema drafts can provide such business specific logic.
460
461## Uses
462
463gojsonschema uses the following test suite :
464
465https://github.com/json-schema/JSON-Schema-Test-Suite
466