草庐IT

go - 自定义构建的 JSON 模式未正确验证

coder 2024-07-09 原文

我有一个自定义构建的 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
}

最佳答案

如果我使用 gojsonschema 手动加载模式和数据,它会按预期工作。我怀疑由于您以某种复杂的方式加载模式,因此您放入的模式最终会与您期望的有所不同,但由于您的代码示例都是基于 HTTP 的,所以我自己无法真正测试它.

关于go - 自定义构建的 JSON 模式未正确验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51976000/

有关go - 自定义构建的 JSON 模式未正确验证的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  4. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  6. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  9. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  10. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

随机推荐