【问题标题】:Go structs to OpenAPI to JSONSchema generation automatically自动将结构转到 OpenAPI 到 JSONSchema 生成
【发布时间】:2018-03-17 10:54:01
【问题描述】:

我有一个 Go 结构,我想为其自动生成一个 OpenAPI 模式。一旦我有了该结构的 OpenAPI 定义,我就想生成它的 JSONSchema,这样我就可以验证传入的输入数据并将被解析到这些结构中。

结构如下所示:

// mySpec: io.myapp.MinimalPod
type MinimalPod struct {
    Name string `json:"name"`

    // k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec
    v1.PodSpec    
}

上述结构显然是 Kubernetes PodSpec 的扩充。

现在我使用的方法是将generate definition 部分用于我的结构MinimalPodPodSpec 的定义将来自Kubernetes 的upstream OpenAPI specPodSpecupstream OpenAPI spec中有一个键io.k8s.kubernetes.pkg.api.v1.PodSpec,这个定义就是injected from there in my Properties。现在,在我的解析上述结构的代码中,我有如果struct field is string 该怎么做的模板。

如果该字段有注释 starts with k8s: ... 下一部分是 Kubernetes 对象的 OpenAPI 定义键。在我们的例子中,OpenAPI 定义密钥io.k8s.kubernetes.pkg.api.v1.PodSpec。因此,我从上游 OpenAPI 定义中检索该字段的定义,并将其嵌入到我的结构的定义中。

一旦我为这个结构生成了一个 OpenAPI 定义,它被注入到 Kubernetes OpenAPI 模式的定义中,键为io.myapp.MinimalPod。现在我可以使用工具openapi2jsonschema 从中生成 JSONSchema。这会生成一个名为 MinimalPod.json 的 JSONSchema 文件。

现在jsonschema 工具和文件MinimalPod.json 可用于验证提供给我的工具解析器的输入,以查看是否所有字段都正确。

这是正确的做事方法,还是有一个工具/库,如果我向它提供 Go 结构,它会给我 OpenAPI 架构?如果它不识别从 Go 结构的自动解析中注入 Kubernetes OpenAPI 模式的位置并提供 OpenAPI 定义将不胜感激。


更新 1

按照@mehdy 的指示,这是我尝试过的:

我已使用此导入路径 github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 导入 PodSpec 定义而不是 k8s.io/api/core/v1,代码如下所示:

package foomodel

import "github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1"

// MinimalPod is a minimal pod.
// +k8s:openapi-gen=true
type MinimalPod struct {
        Name string `json:"name"`

        v1.PodSpec
}

现在,当我生成相同的标志时,-ik8s.io/api/core/v1 更改为 github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1

$ go run example/openapi-gen/main.go -i k8s.io/kube-openapi/example/model,github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 -h example/foomodel/header.txt -p k8s.io/kube-openapi/example/foomodel

这是生成的:

$ cat openapi_generated.go 
// +build !ignore_autogenerated

/*
======

Some random text


======
*/

// This file was autogenerated by openapi-gen. Do not edit it manually!

package foomodel

import (
        spec "github.com/go-openapi/spec"
        common "k8s.io/kube-openapi/pkg/common"
)

func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
        return map[string]common.OpenAPIDefinition{
                "k8s.io/kube-openapi/example/model.Container": {
                        Schema: spec.Schema{
                                SchemaProps: spec.SchemaProps{
                                        Description: "Container defines a single application container that you want to run within a pod.",
                                        Properties: map[string]spec.Schema{
                                                "health": {
                                                        SchemaProps: spec.SchemaProps{
                                                                Description: "One common definitions for 'livenessProbe' and 'readinessProbe' this allows to have only one place to define both probes (if they are the same) Periodic probe of container liveness and readiness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
                                                                Ref:         ref("k8s.io/client-go/pkg/api/v1.Probe"),
                                                        },
                                                },
                                                "Container": {
                                                        SchemaProps: spec.SchemaProps{
                                                                Ref: ref("k8s.io/client-go/pkg/api/v1.Container"),
                                                        },
                                                },
                                        },
                                        Required: []string{"Container"},
                                },
                        },
                        Dependencies: []string{
                                "k8s.io/client-go/pkg/api/v1.Container", "k8s.io/client-go/pkg/api/v1.Probe"},
                },
        }
}

我只得到了这么多生成的配置。当我切换回"k8s.io/api/core/v1" 时,我会自动生成超过 8k 行的配置代码。我在这里错过了什么?

这里缺少k8s.io/client-go/pkg/api/v1.Containerk8s.io/client-go/pkg/api/v1.Probe 的定义,而当我使用k8s.io/api/core/v1 作为导入时,所有内容都会生成。

注意:如需生成上述步骤,请在GOPATHgit clone https://github.com/kedgeproject/kedge

【问题讨论】:

标签: go kubernetes swagger jsonschema openapi


【解决方案1】:

您可以为此使用kube-openapi 包。我将向 repo 添加一个示例,但我已经测试了这个简单的模型:

// Car is a simple car model.
// +k8s:openapi-gen=true
type Car struct {
    Color    string
    Capacity int
    // +k8s:openapi-gen=false
    HiddenFeature string
}

如果您假设您在

中创建了此文件
go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model -p k8s.io/kube-openapi/example/model

(您还需要添加一个 header.txt 文件)。您应该会在 example/model 文件夹中看到一个名为 openapi_generated.go 的新文件。这是一个中间生成的文件,其中包含您的 OpenAPI 模型:

func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
    return map[string]common.OpenAPIDefinition{
        "k8s.io/kube-openapi/example/model.Car": {
            Schema: spec.Schema{
                SchemaProps: spec.SchemaProps{
                    Description: "Car is a simple car model.",
                    Properties: map[string]spec.Schema{
                        "Color": {
                            SchemaProps: spec.SchemaProps{
                                Type:   []string{"string"},
                                Format: "",
                            },
                        },
                        "Capacity": {
                            SchemaProps: spec.SchemaProps{
                                Type:   []string{"integer"},
                                Format: "int32",
                            },
                        },
                    },
                    Required: []string{"Color", "Capacity"},
                },
            },
            Dependencies: []string{},
        },
    }
}

从那里您应该能够调用生成的方法,获取您的类型的模型并获取其架构。

通过一些 go get magic 并稍微更改命令行,我能够为您的模型生成模型。以下是您应该在代码中更改的内容:

package model

import "k8s.io/api/core/v1"

// MinimalPod is a minimal pod.
// +k8s:openapi-gen=true
type MinimalPod struct {
    Name string `json:"name"`

    v1.PodSpec
}

然后稍微更改运行命令以在生成中包含 PodSpec:

go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model,k8s.io/api/core/v1 -p k8s.io/kube-openapi/example/model

这是我得到的:https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a

【讨论】:

  • 感谢您的详细回答,我已经尝试了您的建议,它对我有用,但请参阅问题中的更新 #1,它不适用于 PodSpec 的不同导入位置,感谢您的意见!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 2022-11-09
  • 1970-01-01
  • 2021-12-21
  • 2012-03-08
  • 2014-08-22
相关资源
最近更新 更多