| // Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // author xeipuuv |
| // author-github https://github.com/xeipuuv |
| // author-mail xeipuuv@gmail.com |
| // |
| // repository-name gojsonschema |
| // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. |
| // |
| // description Different strategies to load JSON files. |
| // Includes References (file and HTTP), JSON strings and Go types. |
| // |
| // created 01-02-2015 |
| |
| package gojsonschema |
| |
| import ( |
| "encoding/json" |
| "errors" |
| "fmt" |
| "github.com/xeipuuv/gojsonreference" |
| "io/ioutil" |
| "net/http" |
| "strings" |
| ) |
| |
| // JSON loader interface |
| |
| type jsonLoader interface { |
| jsonSource() interface{} |
| loadJSON() (interface{}, error) |
| loadSchema() (*Schema, error) |
| } |
| |
| // JSON Reference loader |
| // references are used to load JSONs from files and HTTP |
| |
| type jsonReferenceLoader struct { |
| source string |
| } |
| |
| func (l *jsonReferenceLoader) jsonSource() interface{} { |
| return l.source |
| } |
| |
| func NewReferenceLoader(source string) *jsonReferenceLoader { |
| return &jsonReferenceLoader{source: source} |
| } |
| |
| func (l *jsonReferenceLoader) loadJSON() (interface{}, error) { |
| |
| var err error |
| |
| reference, err := gojsonreference.NewJsonReference(l.jsonSource().(string)) |
| if err != nil { |
| return nil, err |
| } |
| |
| refToUrl := reference |
| refToUrl.GetUrl().Fragment = "" |
| |
| var document interface{} |
| |
| if reference.HasFileScheme { |
| |
| filename := strings.Replace(refToUrl.String(), "file://", "", -1) |
| document, err = l.loadFromFile(filename) |
| if err != nil { |
| return nil, err |
| } |
| |
| } else { |
| |
| document, err = l.loadFromHTTP(refToUrl.String()) |
| if err != nil { |
| return nil, err |
| } |
| |
| } |
| |
| return document, nil |
| |
| } |
| |
| func (l *jsonReferenceLoader) loadSchema() (*Schema, error) { |
| |
| var err error |
| |
| d := Schema{} |
| d.pool = newSchemaPool() |
| d.referencePool = newSchemaReferencePool() |
| |
| d.documentReference, err = gojsonreference.NewJsonReference(l.jsonSource().(string)) |
| if err != nil { |
| return nil, err |
| } |
| |
| spd, err := d.pool.GetDocument(d.documentReference) |
| if err != nil { |
| return nil, err |
| } |
| |
| err = d.parse(spd.Document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &d, nil |
| |
| } |
| |
| func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) { |
| |
| resp, err := http.Get(address) |
| if err != nil { |
| return nil, err |
| } |
| |
| // must return HTTP Status 200 OK |
| if resp.StatusCode != http.StatusOK { |
| return nil, errors.New(fmt.Sprintf(ERROR_MESSAGE_GET_HTTP_BAD_STATUS, resp.Status)) |
| } |
| |
| bodyBuff, err := ioutil.ReadAll(resp.Body) |
| if err != nil { |
| return nil, err |
| } |
| |
| var document interface{} |
| err = json.Unmarshal(bodyBuff, &document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return document, nil |
| } |
| |
| func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) { |
| |
| bodyBuff, err := ioutil.ReadFile(path) |
| if err != nil { |
| return nil, err |
| } |
| |
| var document interface{} |
| err = json.Unmarshal(bodyBuff, &document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return document, nil |
| } |
| |
| // JSON string loader |
| |
| type jsonStringLoader struct { |
| source string |
| } |
| |
| func (l *jsonStringLoader) jsonSource() interface{} { |
| return l.source |
| } |
| |
| func NewStringLoader(source string) *jsonStringLoader { |
| return &jsonStringLoader{source: source} |
| } |
| |
| func (l *jsonStringLoader) loadJSON() (interface{}, error) { |
| |
| var document interface{} |
| |
| err := json.Unmarshal([]byte(l.jsonSource().(string)), &document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return document, nil |
| |
| } |
| |
| func (l *jsonStringLoader) loadSchema() (*Schema, error) { |
| |
| var err error |
| |
| document, err := l.loadJSON() |
| if err != nil { |
| return nil, err |
| } |
| |
| d := Schema{} |
| d.pool = newSchemaPool() |
| d.referencePool = newSchemaReferencePool() |
| d.documentReference, err = gojsonreference.NewJsonReference("#") |
| d.pool.SetStandaloneDocument(document) |
| if err != nil { |
| return nil, err |
| } |
| |
| err = d.parse(document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &d, nil |
| |
| } |
| |
| // JSON Go (types) loader |
| // used to load JSONs from the code as maps, interface{}, structs ... |
| |
| type jsonGoLoader struct { |
| source interface{} |
| } |
| |
| func (l *jsonGoLoader) jsonSource() interface{} { |
| return l.source |
| } |
| |
| func NewGoLoader(source interface{}) *jsonGoLoader { |
| return &jsonGoLoader{source: source} |
| } |
| |
| func (l *jsonGoLoader) loadJSON() (interface{}, error) { |
| |
| // convert it to a compliant JSON first to avoid types "mismatches" |
| |
| jsonBytes, err := json.Marshal(l.jsonSource()) |
| if err != nil { |
| return nil, err |
| } |
| |
| var document interface{} |
| |
| err = json.Unmarshal(jsonBytes, &document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return document, nil |
| |
| } |
| |
| func (l *jsonGoLoader) loadSchema() (*Schema, error) { |
| |
| var err error |
| |
| document, err := l.loadJSON() |
| if err != nil { |
| return nil, err |
| } |
| |
| d := Schema{} |
| d.pool = newSchemaPool() |
| d.referencePool = newSchemaReferencePool() |
| d.documentReference, err = gojsonreference.NewJsonReference("#") |
| d.pool.SetStandaloneDocument(document) |
| if err != nil { |
| return nil, err |
| } |
| |
| err = d.parse(document) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &d, nil |
| |
| } |