<p>I have a Go struct for which I want to generate an OpenAPI schema automatically. Once I have an OpenAPI definition of that struct I wanna generate JSONSchema of it, so that I can validate the input data that comes and is gonna be parsed into those structs.</p>

<p>The struct looks like the following:</p>

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

    // k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec
    v1.PodSpec    
}
</code></pre>

<p>Above struct is clearly an augmentation of what Kubernetes <code>PodSpec</code> is.</p>

<p>Now the approach that I have used is to <a href="https://github.com/kedgeproject/json-schema-generator/blob/30c91750ee456480c7021ff1c30df455a22856ae/main.go#L32" rel="nofollow noreferrer">generate <code>definition</code></a> part for my struct <code>MinimalPod</code>, the definition for <code>PodSpec</code> will come from <a href="https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json" rel="nofollow noreferrer">upstream OpenAPI spec</a> of Kubernetes. <code>PodSpec</code> has a key <code>io.k8s.kubernetes.pkg.api.v1.PodSpec</code> in the <a href="https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json" rel="nofollow noreferrer">upstream OpenAPI spec</a>, this definition is <a href="https://github.com/kedgeproject/json-schema-generator/blob/30c91750ee456480c7021ff1c30df455a22856ae/parsego.go#L152" rel="nofollow noreferrer">injected from there in my Properties</a>. Now in my code that parses above struct I have templates of what to do if <a href="https://github.com/kedgeproject/json-schema-generator/blob/30c91750ee456480c7021ff1c30df455a22856ae/parsego.go#L289" rel="nofollow noreferrer">struct field is <code>string</code></a>. </p>

<p>If the field has a comment that <a href="https://github.com/kedgeproject/json-schema-generator/blob/30c91750ee456480c7021ff1c30df455a22856ae/parsego.go#L405" rel="nofollow noreferrer">starts with <code>k8s: ...</code></a> the next part is Kubernetes object's <em>OpenAPI definition key</em>. In our case the <em>OpenAPI definition key</em> is <code>io.k8s.kubernetes.pkg.api.v1.PodSpec</code>. So I retrieve that field's definition from the upstream OpenAPI definition and embed it into the definition of my struct.</p>

<p>Once I have generated an OpenAPI definition for this struct which is injected in Kubernetes OpenAPI schema's definition with key being <code>io.myapp.MinimalPod</code>. Now I can use the tool <a href="https://github.com/garethr/openapi2jsonschema" rel="nofollow noreferrer"><code>openapi2jsonschema</code></a> to generate JSONSchema out of this one. Which generates a JSONSchema file named <code>MinimalPod.json</code>.</p>

<p>Now <code>jsonschema</code> tool and the file <code>MinimalPod.json</code> can be used for validating input given to my tool parser to see if all fields were given right.</p>

<p>Is this the right approach of doing things, or is there a tool/library and if I feed Go structs to it, it gives me OpenAPI schema? It would be fine if it does not identify where to inject Kubernetes OpenAPI schema from even automatic parsing of Go structs and giving OpenAPI definition would be much appreciated.</p>

<hr>

<h2>Update 1</h2>

<p>After following @mehdy 's instructions, this is what I have tried:</p>

<p>I have used this import path <code>github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1</code> to import the <code>PodSpec</code> definition instead of <code>k8s.io/api/core/v1</code> and code looks like this:</p>

<pre><code>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
}
</code></pre>

<p>Now when I generate the same with flag <code>-i</code> changed from <code>k8s.io/api/core/v1</code> to <code>github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1</code></p>

<pre><code>$ 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
</code></pre>

<p>This is what is generated:</p>

<pre><code>$ 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"},
                },
        }
}
</code></pre>

<p>I get only this much of the configuration generated. While when I switch back to <code>"k8s.io/api/core/v1"</code> I get config code auto generated which is more than 8k lines. What am I missing here?</p>

<p>Here definition of <code>k8s.io/client-go/pkg/api/v1.Container</code> and <code>k8s.io/client-go/pkg/api/v1.Probe</code> is missing while when I use <code>k8s.io/api/core/v1</code> as import everything is generated.</p>

<p><strong>Note</strong>: To generate above steps, please <code>git clone https://github.com/kedgeproject/kedge</code> in <code>GOPATH</code>.</p>

<p>You can use <a href="https://github.com/kubernetes/kube-openapi" rel="nofollow noreferrer">kube-openapi</a> package for this. I am going to add a sample to the repo but I've tested this simple model:</p>

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

<p>If you assume you created this file in </p>

<pre><code>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
</code></pre>

<p>(you also need to add a header.txt file). You should see a new file created in example/model folder called openapi_generated.go. This is an intermediate generated file that has your OpenAPI model in it:</p>

<pre><code>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{},
        },
    }
}
</code></pre>

<p>From there you should be able to call the generated method, get the model for your Type and get its Schema.</p>

<p>With some go get magic and changing the command line a little, I was able to generate the model for your model. Here is what you should change in your code:</p>

<pre><code>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
}
</code></pre>

<p>and then change the run command a little to include PodSpec in the generation:</p>

<pre><code>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
</code></pre>

<p>Here is what I got: <a href="https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a" rel="nofollow noreferrer">https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a</a></p>
