代码之家  ›  专栏  ›  技术社区  ›  Matt Welke

当我还没有发布JSON模式,因为它还没有经过测试时,我如何为它的$id提供一个绝对的URL?

  •  0
  • Matt Welke  · 技术社区  · 4 年前

    我正在组合JSON模式,我想使用$ref来DRY我的模式。我将有许多模式,每个模式都将使用公共子模式。我想在发布模式之前对其进行单元测试,方法是编写单元测试,断言在给定特定输入的情况下,输入被视为有效或无效,使用我相信是正确的JSON模式库(这样我只是在测试我的模式,而不是库)。

    我感到困惑的是,为了在发布模式之前加载它们(我希望在本地运行测试和CI/CD期间这样做),我需要使用这样的相对本地路径:

    "pet": { "$ref": "file://./schemas/components/pet.schema.json" }
    

    这是因为宠物模式还没有发布到URL。它还没有通过自动化测试验证它是正确的。这对于运行测试来说足够好了,对于在Docker映像中打包也很好,这样在应用程序启动时就可以从磁盘加载模式。

    但是,如果我在将一个顶级模式发布到一个绝对URL后,将其提供给某人(利用$ref),它就不会加载到他们的程序中,因为我使用的路径只适用于我的单元测试。

    我发现我必须使用绝对URL来发布我的模式,以便在使用程序时使用它们。我最终发布了架构 https://mattwelke.github.io/go-jsonschema-ref-docker-example/schemas/person.1-0-0.schema.json 和 https://mattwelke.github.io/go-jsonschema-ref-docker-example/schemas/components/pet.1-0-0.schema.json 那样。我通过编写程序测试了它们在消耗程序中的良好工作:

    package main
    
    import (
        "fmt"
    
        "github.com/xeipuuv/gojsonschema"
    )
    
    func main() {
        schemaLoader := gojsonschema.NewReferenceLoader("https://mattwelke.github.io/go-jsonschema-ref-docker-example/schemas/person.1-0-0.schema.json")
    
        jsonStr := `
        {
            "name": "Matt",
            "pet": {
                "name": "Shady"
            }
        }
        `
    
        documentLoader := gojsonschema.NewStringLoader(jsonStr)
    
        result, err := gojsonschema.Validate(schemaLoader, documentLoader)
        if err != nil {
            panic(fmt.Errorf("could not validate: %w", err))
        }
    
        if result.Valid() {
            fmt.Printf("The document is valid.\n")
        } else {
            fmt.Printf("The document is not valid. See errors:\n")
            for _, desc := range result.Errors() {
                fmt.Printf("- %s\n", desc)
            }
        }
    }
    

    这产生了以下预期产出:

    The document is valid.
    

    所以我对这种“鸡和蛋”的情况感到困惑。

    我能够发布可以使用的模式,只要我在发布它们之前没有对它们进行单元测试。

    我能够对模式进行单元测试,只要:

    • 我不想以单元测试验证为正确的形式发布它们。
    • 我可以在应用程序启动时通过HTTPS加载它们,而不是从磁盘加载。我对此感到担忧,因为我不希望网络服务器成为我的应用程序启动的故障点。

    我希望能深入了解如何实现这两个目标。

    0 回复  |  直到 4 年前
        1
  •  3
  •   Ether    4 年前

    我感到困惑的是,为了在发布模式之前加载它们(我希望在本地运行测试和CI/CD期间这样做),我需要使用相对的本地路径

    你最初的假设是错误的。中使用的URI $id 关键字可以是任意的标识符——它们不需要通过指定位置的网络或磁盘来解析。事实上,JSON模式实现假设在指定的位置找到模式文档是错误的:它们必须支持本地加载文档并将其与指定的标识符关联:

    关键字“$id”用其规范URI标识模式资源。

    请注意,这个URI是一个标识符,不一定是一个网络定位器。在网络可寻址URL的情况下,模式不需要从其规范URI下载。

    source

    如果模式是网络可寻址的URL,则不需要从该地址下载该模式,并且实现不应该假设它们在遇到网络可寻址URI时应该执行网络操作。

    source

    因此,您可以为您的模式文档提供任何您喜欢的标识符,例如您在最终发布供公众使用的模式时预期使用的URI,并使用该标识符执行本地测试。

    任何不支持这样做的实现都违反了规范,应该将其作为bug报告给维护人员。