【发布时间】:2018-08-22 22:27:29
【问题描述】:
我有一个自定义构建的 JSON 架构,它只有几个顶层。这里的问题是它不能 100% 验证所有内容。例如,它只检测到 4 个字段中的 2 个,并且所需字段根本不起作用,附加属性等也不起作用。我将 this library 用于我的 json 架构。
{
"users": {
"PUT": {
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"required": [
"DisplayName",
"Username",
"Email",
"Password"
],
"properties": {
"DisplayName": {
"$id": "#/properties/DisplayName",
"type": "string",
"title": "The Displayname Schema",
"default": "",
"examples": [
""
],
"minLength": 3,
"maxLength": 24,
"pattern": "^(.*)$"
},
"Username": {
"$id": "#/properties/Username",
"type": "string",
"title": "The Username Schema",
"default": "",
"examples": [
""
],
"minLength": 3,
"maxLength": 15,
"pattern": "^(.*)$"
},
"Email": {
"$id": "#/properties/Email",
"type": "string",
"title": "The Email Schema",
"default": "",
"examples": [
""
],
"minLength": 7,
"pattern": "^(.*)$",
"format": "email"
},
"Password": {
"$id": "#/properties/Password",
"type": "string",
"title": "The Password Schema",
"default": "",
"examples": [
""
],
"pattern": "^(.*)$"
}
},
"additionalProperties": false
}
}
}
我正在解析这样的所有内容:
func Validate(data interface{}, r *http.Request) (interface{}, error) {
// Convert the data struct to a readable JSON bytes
JSONparams, err := json.Marshal(data)
if err != nil {
return nil, err
}
// Split URL segments so we know what part of the API they are accessing
modules := strings.Split(r.URL.String(), "/")
modules = modules[(len(modules) - 1):]
// Read the schema file
fileSchema, _ := ioutil.ReadFile("config/schema/schema.json")
var object interface{}
// Unmarshal it so we can choose what schema we specifically want
err = json.Unmarshal(fileSchema, &object)
if err != nil {
log.Fatal(err)
}
// Choose the preferred schema
encodedJSON, err := json.Marshal(object.(map[string]interface{})[strings.Join(modules, "") + "s"].(map[string]interface{})[r.Method])
if err != nil {
log.Fatal(err)
}
// Load the JSON schema
schema := gojsonschema.NewStringLoader(string(encodedJSON))
// Load the JSON params
document := gojsonschema.NewStringLoader(string(JSONparams))
// Validate the document
result, err := gojsonschema.Validate(schema, document)
if err != nil {
return nil, err
}
if !result.Valid() {
// Map the errors into a new array
var errors = make(map[string]string)
for _, err := range result.Errors() {
errors[err.Field()] = err.Description()
}
// Convert the array to an interface that we can convert to JSON
resultMap := map[string]interface{}{
"success": false,
"result": map[string]interface{}{},
"errors": errors,
}
// Convert the interface to a JSON object
errorObject, err := json.Marshal(resultMap)
if err != nil {
return nil, err
}
return errorObject, nil
}
return nil, nil
}
type CreateParams struct {
DisplayName string
Username string
Email string
Password string
}
var (
response interface{}
status int = 0
)
func Create(w http.ResponseWriter, r *http.Request) {
status = 0
// Parse the request so we can access the query parameters
r.ParseForm()
// Assign them to the interface variables
data := &CreateParams{
DisplayName: r.Form.Get("DisplayName"),
Username: r.Form.Get("Username"),
Email: r.Form.Get("Email"),
Password: r.Form.Get("Password"),
}
// Validate the JSON data
errors, err := schema.Validate(data, r)
if err != nil {
responseJSON := map[string]interface{}{
"success": false,
"result": map[string]interface{}{},
}
log.Fatal(err.Error())
response, err = json.Marshal(responseJSON)
status = http.StatusInternalServerError
}
// Catch any errors generated by the validator and assign them to the response interface
if errors != nil {
response = errors
status = http.StatusBadRequest
}
// Status has not been set yet, so it's safe to assume that everything went fine
if status == 0 {
responseJSON := map[string]interface{}{
"success": true,
"result": map[string]interface{} {
"DisplayName": data.DisplayName,
"Username": data.Username,
"Email": data.Email,
"Password": nil,
},
}
response, err = json.Marshal(responseJSON)
status = http.StatusOK
}
// We are going to respond with JSON, so set the appropriate header
w.Header().Set("Content-Type", "application/json")
// Write the header and the response
w.WriteHeader(status)
w.Write(response.([]byte))
}
我这样做的原因是我正在构建一个 REST API,如果 api/auth/user 收到一个 PUT 请求,我希望能够为“用户”部分指定数据要求PUT 方法。
知道如何实现吗?
编辑: 我的 json 数据:
{
"DisplayName": "1234",
"Username": "1234",
"Email": "test@gmail.com",
"Password": "123456"
}
编辑 2: 该数据应该会因架构而失败。
{
"DisplayName": "1", // min length is 3
"Username": "", // this field is required but is empty here
"Email": "testgmail.com", // not following the email format
"Password": "123456111111111111111111111111111111111111111111111" // too long
}
【问题讨论】:
-
嗨!如果您提供您尝试验证的完整 JSON 架构和完整 JSON 实例数据,我将能够提供最好的帮助。我对 go 不熟悉,但我可以很容易地告诉你是否存在架构问题。
-
@Relequestual 我已经用完整的架构和我的 JSON 数据更新了帖子。谢谢。
-
我已经使用jsonschemavalidator.net 测试了您的架构和数据。您可以删除
pattern、default和examples,它们在这里没有做任何事情。此外,您不需要为每个字段指定$id。我可以让required按预期工作。我还可以使每个字段验证失败。我想你可能期望 JSON Schema 做一些它没有做的事情。您能否提供您希望验证失败的 JSON 数据示例? -
@Relequestual 已更新。我还想指出,在尝试您提供的模式验证器时,required 似乎不会覆盖参数的最小长度规则。
-
我不确定
required会如何覆盖min-length。必需只是意味着对象键必须存在,并且没有指定它的值。就您应该失败的示例而言:在您的架构中,“密码”没有设置最小长度。 “用户名”和“显示名称”按预期失败,未达到最小长度。对于“格式”,对这些的支持是可选的,并且取决于每个实现。
标签: go jsonschema