schema.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. // Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // author xeipuuv
  15. // author-github https://github.com/xeipuuv
  16. // author-mail [email protected]
  17. //
  18. // repository-name gojsonschema
  19. // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
  20. //
  21. // description Defines Schema, the main entry to every subSchema.
  22. // Contains the parsing logic and error checking.
  23. //
  24. // created 26-02-2013
  25. package gojsonschema
  26. import (
  27. // "encoding/json"
  28. "errors"
  29. "reflect"
  30. "regexp"
  31. "text/template"
  32. "github.com/xeipuuv/gojsonreference"
  33. )
  34. var (
  35. // Locale is the default locale to use
  36. // Library users can overwrite with their own implementation
  37. Locale locale = DefaultLocale{}
  38. // ErrorTemplateFuncs allows you to define custom template funcs for use in localization.
  39. ErrorTemplateFuncs template.FuncMap
  40. )
  41. func NewSchema(l JSONLoader) (*Schema, error) {
  42. ref, err := l.JsonReference()
  43. if err != nil {
  44. return nil, err
  45. }
  46. d := Schema{}
  47. d.pool = newSchemaPool(l.LoaderFactory())
  48. d.documentReference = ref
  49. d.referencePool = newSchemaReferencePool()
  50. var doc interface{}
  51. if ref.String() != "" {
  52. // Get document from schema pool
  53. spd, err := d.pool.GetDocument(d.documentReference)
  54. if err != nil {
  55. return nil, err
  56. }
  57. doc = spd.Document
  58. } else {
  59. // Load JSON directly
  60. doc, err = l.LoadJSON()
  61. if err != nil {
  62. return nil, err
  63. }
  64. d.pool.SetStandaloneDocument(doc)
  65. }
  66. err = d.parse(doc)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return &d, nil
  71. }
  72. type Schema struct {
  73. documentReference gojsonreference.JsonReference
  74. rootSchema *subSchema
  75. pool *schemaPool
  76. referencePool *schemaReferencePool
  77. }
  78. func (d *Schema) parse(document interface{}) error {
  79. d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY}
  80. return d.parseSchema(document, d.rootSchema)
  81. }
  82. func (d *Schema) SetRootSchemaName(name string) {
  83. d.rootSchema.property = name
  84. }
  85. // Parses a subSchema
  86. //
  87. // Pretty long function ( sorry :) )... but pretty straight forward, repetitive and boring
  88. // Not much magic involved here, most of the job is to validate the key names and their values,
  89. // then the values are copied into subSchema struct
  90. //
  91. func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error {
  92. if !isKind(documentNode, reflect.Map) {
  93. return errors.New(formatErrorDescription(
  94. Locale.ParseError(),
  95. ErrorDetails{
  96. "expected": STRING_SCHEMA,
  97. },
  98. ))
  99. }
  100. m := documentNode.(map[string]interface{})
  101. if currentSchema == d.rootSchema {
  102. currentSchema.ref = &d.documentReference
  103. }
  104. // $subSchema
  105. if existsMapKey(m, KEY_SCHEMA) {
  106. if !isKind(m[KEY_SCHEMA], reflect.String) {
  107. return errors.New(formatErrorDescription(
  108. Locale.InvalidType(),
  109. ErrorDetails{
  110. "expected": TYPE_STRING,
  111. "given": KEY_SCHEMA,
  112. },
  113. ))
  114. }
  115. schemaRef := m[KEY_SCHEMA].(string)
  116. schemaReference, err := gojsonreference.NewJsonReference(schemaRef)
  117. currentSchema.subSchema = &schemaReference
  118. if err != nil {
  119. return err
  120. }
  121. }
  122. // $ref
  123. if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) {
  124. return errors.New(formatErrorDescription(
  125. Locale.InvalidType(),
  126. ErrorDetails{
  127. "expected": TYPE_STRING,
  128. "given": KEY_REF,
  129. },
  130. ))
  131. }
  132. if k, ok := m[KEY_REF].(string); ok {
  133. jsonReference, err := gojsonreference.NewJsonReference(k)
  134. if err != nil {
  135. return err
  136. }
  137. if jsonReference.HasFullUrl {
  138. currentSchema.ref = &jsonReference
  139. } else {
  140. inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
  141. if err != nil {
  142. return err
  143. }
  144. currentSchema.ref = inheritedReference
  145. }
  146. if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok {
  147. currentSchema.refSchema = sch
  148. } else {
  149. err := d.parseReference(documentNode, currentSchema, k)
  150. if err != nil {
  151. return err
  152. }
  153. return nil
  154. }
  155. }
  156. // definitions
  157. if existsMapKey(m, KEY_DEFINITIONS) {
  158. if isKind(m[KEY_DEFINITIONS], reflect.Map) {
  159. currentSchema.definitions = make(map[string]*subSchema)
  160. for dk, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) {
  161. if isKind(dv, reflect.Map) {
  162. newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema, ref: currentSchema.ref}
  163. currentSchema.definitions[dk] = newSchema
  164. err := d.parseSchema(dv, newSchema)
  165. if err != nil {
  166. return errors.New(err.Error())
  167. }
  168. } else {
  169. return errors.New(formatErrorDescription(
  170. Locale.InvalidType(),
  171. ErrorDetails{
  172. "expected": STRING_ARRAY_OF_SCHEMAS,
  173. "given": KEY_DEFINITIONS,
  174. },
  175. ))
  176. }
  177. }
  178. } else {
  179. return errors.New(formatErrorDescription(
  180. Locale.InvalidType(),
  181. ErrorDetails{
  182. "expected": STRING_ARRAY_OF_SCHEMAS,
  183. "given": KEY_DEFINITIONS,
  184. },
  185. ))
  186. }
  187. }
  188. // id
  189. if existsMapKey(m, KEY_ID) && !isKind(m[KEY_ID], reflect.String) {
  190. return errors.New(formatErrorDescription(
  191. Locale.InvalidType(),
  192. ErrorDetails{
  193. "expected": TYPE_STRING,
  194. "given": KEY_ID,
  195. },
  196. ))
  197. }
  198. if k, ok := m[KEY_ID].(string); ok {
  199. currentSchema.id = &k
  200. }
  201. // title
  202. if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) {
  203. return errors.New(formatErrorDescription(
  204. Locale.InvalidType(),
  205. ErrorDetails{
  206. "expected": TYPE_STRING,
  207. "given": KEY_TITLE,
  208. },
  209. ))
  210. }
  211. if k, ok := m[KEY_TITLE].(string); ok {
  212. currentSchema.title = &k
  213. }
  214. // description
  215. if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) {
  216. return errors.New(formatErrorDescription(
  217. Locale.InvalidType(),
  218. ErrorDetails{
  219. "expected": TYPE_STRING,
  220. "given": KEY_DESCRIPTION,
  221. },
  222. ))
  223. }
  224. if k, ok := m[KEY_DESCRIPTION].(string); ok {
  225. currentSchema.description = &k
  226. }
  227. // type
  228. if existsMapKey(m, KEY_TYPE) {
  229. if isKind(m[KEY_TYPE], reflect.String) {
  230. if k, ok := m[KEY_TYPE].(string); ok {
  231. err := currentSchema.types.Add(k)
  232. if err != nil {
  233. return err
  234. }
  235. }
  236. } else {
  237. if isKind(m[KEY_TYPE], reflect.Slice) {
  238. arrayOfTypes := m[KEY_TYPE].([]interface{})
  239. for _, typeInArray := range arrayOfTypes {
  240. if reflect.ValueOf(typeInArray).Kind() != reflect.String {
  241. return errors.New(formatErrorDescription(
  242. Locale.InvalidType(),
  243. ErrorDetails{
  244. "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
  245. "given": KEY_TYPE,
  246. },
  247. ))
  248. } else {
  249. currentSchema.types.Add(typeInArray.(string))
  250. }
  251. }
  252. } else {
  253. return errors.New(formatErrorDescription(
  254. Locale.InvalidType(),
  255. ErrorDetails{
  256. "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
  257. "given": KEY_TYPE,
  258. },
  259. ))
  260. }
  261. }
  262. }
  263. // properties
  264. if existsMapKey(m, KEY_PROPERTIES) {
  265. err := d.parseProperties(m[KEY_PROPERTIES], currentSchema)
  266. if err != nil {
  267. return err
  268. }
  269. }
  270. // additionalProperties
  271. if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) {
  272. if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) {
  273. currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool)
  274. } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) {
  275. newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref}
  276. currentSchema.additionalProperties = newSchema
  277. err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema)
  278. if err != nil {
  279. return errors.New(err.Error())
  280. }
  281. } else {
  282. return errors.New(formatErrorDescription(
  283. Locale.InvalidType(),
  284. ErrorDetails{
  285. "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
  286. "given": KEY_ADDITIONAL_PROPERTIES,
  287. },
  288. ))
  289. }
  290. }
  291. // patternProperties
  292. if existsMapKey(m, KEY_PATTERN_PROPERTIES) {
  293. if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) {
  294. patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{})
  295. if len(patternPropertiesMap) > 0 {
  296. currentSchema.patternProperties = make(map[string]*subSchema)
  297. for k, v := range patternPropertiesMap {
  298. _, err := regexp.MatchString(k, "")
  299. if err != nil {
  300. return errors.New(formatErrorDescription(
  301. Locale.RegexPattern(),
  302. ErrorDetails{"pattern": k},
  303. ))
  304. }
  305. newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
  306. err = d.parseSchema(v, newSchema)
  307. if err != nil {
  308. return errors.New(err.Error())
  309. }
  310. currentSchema.patternProperties[k] = newSchema
  311. }
  312. }
  313. } else {
  314. return errors.New(formatErrorDescription(
  315. Locale.InvalidType(),
  316. ErrorDetails{
  317. "expected": STRING_SCHEMA,
  318. "given": KEY_PATTERN_PROPERTIES,
  319. },
  320. ))
  321. }
  322. }
  323. // dependencies
  324. if existsMapKey(m, KEY_DEPENDENCIES) {
  325. err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema)
  326. if err != nil {
  327. return err
  328. }
  329. }
  330. // items
  331. if existsMapKey(m, KEY_ITEMS) {
  332. if isKind(m[KEY_ITEMS], reflect.Slice) {
  333. for _, itemElement := range m[KEY_ITEMS].([]interface{}) {
  334. if isKind(itemElement, reflect.Map) {
  335. newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
  336. newSchema.ref = currentSchema.ref
  337. currentSchema.AddItemsChild(newSchema)
  338. err := d.parseSchema(itemElement, newSchema)
  339. if err != nil {
  340. return err
  341. }
  342. } else {
  343. return errors.New(formatErrorDescription(
  344. Locale.InvalidType(),
  345. ErrorDetails{
  346. "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
  347. "given": KEY_ITEMS,
  348. },
  349. ))
  350. }
  351. currentSchema.itemsChildrenIsSingleSchema = false
  352. }
  353. } else if isKind(m[KEY_ITEMS], reflect.Map) {
  354. newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
  355. newSchema.ref = currentSchema.ref
  356. currentSchema.AddItemsChild(newSchema)
  357. err := d.parseSchema(m[KEY_ITEMS], newSchema)
  358. if err != nil {
  359. return err
  360. }
  361. currentSchema.itemsChildrenIsSingleSchema = true
  362. } else {
  363. return errors.New(formatErrorDescription(
  364. Locale.InvalidType(),
  365. ErrorDetails{
  366. "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
  367. "given": KEY_ITEMS,
  368. },
  369. ))
  370. }
  371. }
  372. // additionalItems
  373. if existsMapKey(m, KEY_ADDITIONAL_ITEMS) {
  374. if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) {
  375. currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool)
  376. } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) {
  377. newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref}
  378. currentSchema.additionalItems = newSchema
  379. err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema)
  380. if err != nil {
  381. return errors.New(err.Error())
  382. }
  383. } else {
  384. return errors.New(formatErrorDescription(
  385. Locale.InvalidType(),
  386. ErrorDetails{
  387. "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
  388. "given": KEY_ADDITIONAL_ITEMS,
  389. },
  390. ))
  391. }
  392. }
  393. // validation : number / integer
  394. if existsMapKey(m, KEY_MULTIPLE_OF) {
  395. multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF])
  396. if multipleOfValue == nil {
  397. return errors.New(formatErrorDescription(
  398. Locale.InvalidType(),
  399. ErrorDetails{
  400. "expected": STRING_NUMBER,
  401. "given": KEY_MULTIPLE_OF,
  402. },
  403. ))
  404. }
  405. if *multipleOfValue <= 0 {
  406. return errors.New(formatErrorDescription(
  407. Locale.GreaterThanZero(),
  408. ErrorDetails{"number": KEY_MULTIPLE_OF},
  409. ))
  410. }
  411. currentSchema.multipleOf = multipleOfValue
  412. }
  413. if existsMapKey(m, KEY_MINIMUM) {
  414. minimumValue := mustBeNumber(m[KEY_MINIMUM])
  415. if minimumValue == nil {
  416. return errors.New(formatErrorDescription(
  417. Locale.MustBeOfA(),
  418. ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER},
  419. ))
  420. }
  421. currentSchema.minimum = minimumValue
  422. }
  423. if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) {
  424. if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) {
  425. if currentSchema.minimum == nil {
  426. return errors.New(formatErrorDescription(
  427. Locale.CannotBeUsedWithout(),
  428. ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM},
  429. ))
  430. }
  431. exclusiveMinimumValue := m[KEY_EXCLUSIVE_MINIMUM].(bool)
  432. currentSchema.exclusiveMinimum = exclusiveMinimumValue
  433. } else {
  434. return errors.New(formatErrorDescription(
  435. Locale.MustBeOfA(),
  436. ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": TYPE_BOOLEAN},
  437. ))
  438. }
  439. }
  440. if existsMapKey(m, KEY_MAXIMUM) {
  441. maximumValue := mustBeNumber(m[KEY_MAXIMUM])
  442. if maximumValue == nil {
  443. return errors.New(formatErrorDescription(
  444. Locale.MustBeOfA(),
  445. ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER},
  446. ))
  447. }
  448. currentSchema.maximum = maximumValue
  449. }
  450. if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) {
  451. if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) {
  452. if currentSchema.maximum == nil {
  453. return errors.New(formatErrorDescription(
  454. Locale.CannotBeUsedWithout(),
  455. ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM},
  456. ))
  457. }
  458. exclusiveMaximumValue := m[KEY_EXCLUSIVE_MAXIMUM].(bool)
  459. currentSchema.exclusiveMaximum = exclusiveMaximumValue
  460. } else {
  461. return errors.New(formatErrorDescription(
  462. Locale.MustBeOfA(),
  463. ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": STRING_NUMBER},
  464. ))
  465. }
  466. }
  467. if currentSchema.minimum != nil && currentSchema.maximum != nil {
  468. if *currentSchema.minimum > *currentSchema.maximum {
  469. return errors.New(formatErrorDescription(
  470. Locale.CannotBeGT(),
  471. ErrorDetails{"x": KEY_MINIMUM, "y": KEY_MAXIMUM},
  472. ))
  473. }
  474. }
  475. // validation : string
  476. if existsMapKey(m, KEY_MIN_LENGTH) {
  477. minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH])
  478. if minLengthIntegerValue == nil {
  479. return errors.New(formatErrorDescription(
  480. Locale.MustBeOfAn(),
  481. ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER},
  482. ))
  483. }
  484. if *minLengthIntegerValue < 0 {
  485. return errors.New(formatErrorDescription(
  486. Locale.MustBeGTEZero(),
  487. ErrorDetails{"key": KEY_MIN_LENGTH},
  488. ))
  489. }
  490. currentSchema.minLength = minLengthIntegerValue
  491. }
  492. if existsMapKey(m, KEY_MAX_LENGTH) {
  493. maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH])
  494. if maxLengthIntegerValue == nil {
  495. return errors.New(formatErrorDescription(
  496. Locale.MustBeOfAn(),
  497. ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER},
  498. ))
  499. }
  500. if *maxLengthIntegerValue < 0 {
  501. return errors.New(formatErrorDescription(
  502. Locale.MustBeGTEZero(),
  503. ErrorDetails{"key": KEY_MAX_LENGTH},
  504. ))
  505. }
  506. currentSchema.maxLength = maxLengthIntegerValue
  507. }
  508. if currentSchema.minLength != nil && currentSchema.maxLength != nil {
  509. if *currentSchema.minLength > *currentSchema.maxLength {
  510. return errors.New(formatErrorDescription(
  511. Locale.CannotBeGT(),
  512. ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH},
  513. ))
  514. }
  515. }
  516. if existsMapKey(m, KEY_PATTERN) {
  517. if isKind(m[KEY_PATTERN], reflect.String) {
  518. regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string))
  519. if err != nil {
  520. return errors.New(formatErrorDescription(
  521. Locale.MustBeValidRegex(),
  522. ErrorDetails{"key": KEY_PATTERN},
  523. ))
  524. }
  525. currentSchema.pattern = regexpObject
  526. } else {
  527. return errors.New(formatErrorDescription(
  528. Locale.MustBeOfA(),
  529. ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING},
  530. ))
  531. }
  532. }
  533. if existsMapKey(m, KEY_FORMAT) {
  534. formatString, ok := m[KEY_FORMAT].(string)
  535. if ok && FormatCheckers.Has(formatString) {
  536. currentSchema.format = formatString
  537. } else {
  538. return errors.New(formatErrorDescription(
  539. Locale.MustBeValidFormat(),
  540. ErrorDetails{"key": KEY_FORMAT, "given": m[KEY_FORMAT]},
  541. ))
  542. }
  543. }
  544. // validation : object
  545. if existsMapKey(m, KEY_MIN_PROPERTIES) {
  546. minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES])
  547. if minPropertiesIntegerValue == nil {
  548. return errors.New(formatErrorDescription(
  549. Locale.MustBeOfAn(),
  550. ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER},
  551. ))
  552. }
  553. if *minPropertiesIntegerValue < 0 {
  554. return errors.New(formatErrorDescription(
  555. Locale.MustBeGTEZero(),
  556. ErrorDetails{"key": KEY_MIN_PROPERTIES},
  557. ))
  558. }
  559. currentSchema.minProperties = minPropertiesIntegerValue
  560. }
  561. if existsMapKey(m, KEY_MAX_PROPERTIES) {
  562. maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES])
  563. if maxPropertiesIntegerValue == nil {
  564. return errors.New(formatErrorDescription(
  565. Locale.MustBeOfAn(),
  566. ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER},
  567. ))
  568. }
  569. if *maxPropertiesIntegerValue < 0 {
  570. return errors.New(formatErrorDescription(
  571. Locale.MustBeGTEZero(),
  572. ErrorDetails{"key": KEY_MAX_PROPERTIES},
  573. ))
  574. }
  575. currentSchema.maxProperties = maxPropertiesIntegerValue
  576. }
  577. if currentSchema.minProperties != nil && currentSchema.maxProperties != nil {
  578. if *currentSchema.minProperties > *currentSchema.maxProperties {
  579. return errors.New(formatErrorDescription(
  580. Locale.KeyCannotBeGreaterThan(),
  581. ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES},
  582. ))
  583. }
  584. }
  585. if existsMapKey(m, KEY_REQUIRED) {
  586. if isKind(m[KEY_REQUIRED], reflect.Slice) {
  587. requiredValues := m[KEY_REQUIRED].([]interface{})
  588. for _, requiredValue := range requiredValues {
  589. if isKind(requiredValue, reflect.String) {
  590. err := currentSchema.AddRequired(requiredValue.(string))
  591. if err != nil {
  592. return err
  593. }
  594. } else {
  595. return errors.New(formatErrorDescription(
  596. Locale.KeyItemsMustBeOfType(),
  597. ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING},
  598. ))
  599. }
  600. }
  601. } else {
  602. return errors.New(formatErrorDescription(
  603. Locale.MustBeOfAn(),
  604. ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY},
  605. ))
  606. }
  607. }
  608. // validation : array
  609. if existsMapKey(m, KEY_MIN_ITEMS) {
  610. minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS])
  611. if minItemsIntegerValue == nil {
  612. return errors.New(formatErrorDescription(
  613. Locale.MustBeOfAn(),
  614. ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER},
  615. ))
  616. }
  617. if *minItemsIntegerValue < 0 {
  618. return errors.New(formatErrorDescription(
  619. Locale.MustBeGTEZero(),
  620. ErrorDetails{"key": KEY_MIN_ITEMS},
  621. ))
  622. }
  623. currentSchema.minItems = minItemsIntegerValue
  624. }
  625. if existsMapKey(m, KEY_MAX_ITEMS) {
  626. maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS])
  627. if maxItemsIntegerValue == nil {
  628. return errors.New(formatErrorDescription(
  629. Locale.MustBeOfAn(),
  630. ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER},
  631. ))
  632. }
  633. if *maxItemsIntegerValue < 0 {
  634. return errors.New(formatErrorDescription(
  635. Locale.MustBeGTEZero(),
  636. ErrorDetails{"key": KEY_MAX_ITEMS},
  637. ))
  638. }
  639. currentSchema.maxItems = maxItemsIntegerValue
  640. }
  641. if existsMapKey(m, KEY_UNIQUE_ITEMS) {
  642. if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) {
  643. currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool)
  644. } else {
  645. return errors.New(formatErrorDescription(
  646. Locale.MustBeOfA(),
  647. ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN},
  648. ))
  649. }
  650. }
  651. // validation : all
  652. if existsMapKey(m, KEY_ENUM) {
  653. if isKind(m[KEY_ENUM], reflect.Slice) {
  654. for _, v := range m[KEY_ENUM].([]interface{}) {
  655. err := currentSchema.AddEnum(v)
  656. if err != nil {
  657. return err
  658. }
  659. }
  660. } else {
  661. return errors.New(formatErrorDescription(
  662. Locale.MustBeOfAn(),
  663. ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY},
  664. ))
  665. }
  666. }
  667. // validation : subSchema
  668. if existsMapKey(m, KEY_ONE_OF) {
  669. if isKind(m[KEY_ONE_OF], reflect.Slice) {
  670. for _, v := range m[KEY_ONE_OF].([]interface{}) {
  671. newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref}
  672. currentSchema.AddOneOf(newSchema)
  673. err := d.parseSchema(v, newSchema)
  674. if err != nil {
  675. return err
  676. }
  677. }
  678. } else {
  679. return errors.New(formatErrorDescription(
  680. Locale.MustBeOfAn(),
  681. ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY},
  682. ))
  683. }
  684. }
  685. if existsMapKey(m, KEY_ANY_OF) {
  686. if isKind(m[KEY_ANY_OF], reflect.Slice) {
  687. for _, v := range m[KEY_ANY_OF].([]interface{}) {
  688. newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref}
  689. currentSchema.AddAnyOf(newSchema)
  690. err := d.parseSchema(v, newSchema)
  691. if err != nil {
  692. return err
  693. }
  694. }
  695. } else {
  696. return errors.New(formatErrorDescription(
  697. Locale.MustBeOfAn(),
  698. ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
  699. ))
  700. }
  701. }
  702. if existsMapKey(m, KEY_ALL_OF) {
  703. if isKind(m[KEY_ALL_OF], reflect.Slice) {
  704. for _, v := range m[KEY_ALL_OF].([]interface{}) {
  705. newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref}
  706. currentSchema.AddAllOf(newSchema)
  707. err := d.parseSchema(v, newSchema)
  708. if err != nil {
  709. return err
  710. }
  711. }
  712. } else {
  713. return errors.New(formatErrorDescription(
  714. Locale.MustBeOfAn(),
  715. ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
  716. ))
  717. }
  718. }
  719. if existsMapKey(m, KEY_NOT) {
  720. if isKind(m[KEY_NOT], reflect.Map) {
  721. newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref}
  722. currentSchema.SetNot(newSchema)
  723. err := d.parseSchema(m[KEY_NOT], newSchema)
  724. if err != nil {
  725. return err
  726. }
  727. } else {
  728. return errors.New(formatErrorDescription(
  729. Locale.MustBeOfAn(),
  730. ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT},
  731. ))
  732. }
  733. }
  734. return nil
  735. }
  736. func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) error {
  737. var refdDocumentNode interface{}
  738. jsonPointer := currentSchema.ref.GetPointer()
  739. standaloneDocument := d.pool.GetStandaloneDocument()
  740. if standaloneDocument != nil {
  741. var err error
  742. refdDocumentNode, _, err = jsonPointer.Get(standaloneDocument)
  743. if err != nil {
  744. return err
  745. }
  746. } else {
  747. dsp, err := d.pool.GetDocument(*currentSchema.ref)
  748. if err != nil {
  749. return err
  750. }
  751. refdDocumentNode, _, err = jsonPointer.Get(dsp.Document)
  752. if err != nil {
  753. return err
  754. }
  755. }
  756. if !isKind(refdDocumentNode, reflect.Map) {
  757. return errors.New(formatErrorDescription(
  758. Locale.MustBeOfType(),
  759. ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT},
  760. ))
  761. }
  762. // returns the loaded referenced subSchema for the caller to update its current subSchema
  763. newSchemaDocument := refdDocumentNode.(map[string]interface{})
  764. newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref}
  765. d.referencePool.Add(currentSchema.ref.String()+reference, newSchema)
  766. err := d.parseSchema(newSchemaDocument, newSchema)
  767. if err != nil {
  768. return err
  769. }
  770. currentSchema.refSchema = newSchema
  771. return nil
  772. }
  773. func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error {
  774. if !isKind(documentNode, reflect.Map) {
  775. return errors.New(formatErrorDescription(
  776. Locale.MustBeOfType(),
  777. ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT},
  778. ))
  779. }
  780. m := documentNode.(map[string]interface{})
  781. for k := range m {
  782. schemaProperty := k
  783. newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref}
  784. currentSchema.AddPropertiesChild(newSchema)
  785. err := d.parseSchema(m[k], newSchema)
  786. if err != nil {
  787. return err
  788. }
  789. }
  790. return nil
  791. }
  792. func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error {
  793. if !isKind(documentNode, reflect.Map) {
  794. return errors.New(formatErrorDescription(
  795. Locale.MustBeOfType(),
  796. ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT},
  797. ))
  798. }
  799. m := documentNode.(map[string]interface{})
  800. currentSchema.dependencies = make(map[string]interface{})
  801. for k := range m {
  802. switch reflect.ValueOf(m[k]).Kind() {
  803. case reflect.Slice:
  804. values := m[k].([]interface{})
  805. var valuesToRegister []string
  806. for _, value := range values {
  807. if !isKind(value, reflect.String) {
  808. return errors.New(formatErrorDescription(
  809. Locale.MustBeOfType(),
  810. ErrorDetails{
  811. "key": STRING_DEPENDENCY,
  812. "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
  813. },
  814. ))
  815. } else {
  816. valuesToRegister = append(valuesToRegister, value.(string))
  817. }
  818. currentSchema.dependencies[k] = valuesToRegister
  819. }
  820. case reflect.Map:
  821. depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
  822. err := d.parseSchema(m[k], depSchema)
  823. if err != nil {
  824. return err
  825. }
  826. currentSchema.dependencies[k] = depSchema
  827. default:
  828. return errors.New(formatErrorDescription(
  829. Locale.MustBeOfType(),
  830. ErrorDetails{
  831. "key": STRING_DEPENDENCY,
  832. "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
  833. },
  834. ))
  835. }
  836. }
  837. return nil
  838. }