schema.go 24 KB

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