User Tools

Site Tools


JSON schema generator

jschemgen.go
package main
 
import (
    "fmt"
    "reflect"
    "encoding/json"
)
 
type Func struct {
    Method      string          `json:"method"          descr:"Method name"`
    Params struct {
        Address     string  `json:"address"             descr:"Target address"`
        Count       string  `json:"count"               descr:"Count of retrains"`
        ReqNum      int             `json:"reqNum"`
    } `json:"params"`
} 
 
 
/* JSON Schema Generator */
func Reflector(value interface{}) map[string]interface{} {
 
    var reflector func(name string, descr string, value interface{}, depth int) map[string]interface{}
 
    reflector = func(name string, descr string, value interface{}, depth int) map[string]interface{} {
        sMap := make(map[string]interface{}) 
 
        rValue := reflect.ValueOf(value)
        rValue = reflect.Indirect(rValue)
        rType := rValue.Type()
 
        if depth == 0 {
            sMap["$schema"] = "http://json-schema.org/draft-04/schema#"
        }
        if len(descr) > 0 {
            sMap["description"] = descr
        }
        switch rType.Kind() {
            case reflect.String:
                sMap["type"] = "string"
            case reflect.Int, reflect.Int64:
                sMap["type"] = "integer"
            case reflect.Float32, reflect.Float64:
                sMap["type"] = "number"
            case reflect.Bool:
                sMap["type"] = "bool"
            case reflect.Struct:
                sMap["type"] = "object"
                req := make([]string, 0)
                newMap := make(map[string]interface{})
                for i := 0; i < rType.NumField(); i++ {
                    fieldValue  := rValue.Field(i)
                    fieldName   := rType.Field(i).Name
                    jsonTag, ok := rType.Field(i).Tag.Lookup("json")
                    if ok {
                        fieldName = jsonTag
                    }
                    req = append(req, fieldName)
                    descrTag, ok := rType.Field(i).Tag.Lookup("descr")
                    newMap[fieldName] = reflector(fieldName, descrTag, fieldValue.Interface(), depth + 1)
                }
                sMap["required"] = req
                sMap["properties"] = newMap
        }
        return sMap
    }
    return reflector("", "", value, 0)
}
 
type Descr struct {
    Type    string      `json:"type"`
    Name    string      `json:"name,omitempty"`
    Descr   string      `json:"description,omitempty"`
    Value   interface{}    `json:"value,omitempty"`
    Props   []Descr     `json:"fields,omitempty"`
}
 
 
 
func reflector2(name string, tDescr string, value interface{}, depth int) Descr {
    var descr Descr 
 
    rType := reflect.TypeOf(value)
    rValue := reflect.ValueOf(value)
    if depth == 0 {
    }
    if len(tDescr) > 0 {
        descr.Descr = tDescr
    }
    descr.Name = name
    switch rType.Kind() {
        case reflect.String:
            descr.Type = "string"
            descr.Value = rValue.String()
        case reflect.Int, reflect.Int64:
            descr.Type = "integer"
            descr.Value = rValue.Int()
        case reflect.Float32, reflect.Float64:
            descr.Type = "number"
        case reflect.Bool:
            descr.Type = "bool"
        case reflect.Struct:
            descr.Type = "object"
            //req := make([]string, 0)
            descr.Props = make([]Descr, 0)
            for i := 0; i < rType.NumField(); i++ {
                fieldValue  := rValue.Field(i)
                fieldName   := rType.Field(i).Name
                jsonTag, ok := rType.Field(i).Tag.Lookup("json")
                if ok {
                    fieldName = jsonTag
                }
                //req = append(req, fieldName)
                descrTag, ok := rType.Field(i).Tag.Lookup("descr")
                descr.Props = append(descr.Props, reflector2(fieldName, descrTag, fieldValue.Interface(), depth + 1))
            }
    }
    return descr
}
 
 
 
func main() {
    fu := Func{
        Method: "Add",
    }
    res := Reflector(&fu)
    //res := reflector2("","", fu, 0) //Reflector(fu)
 
    j, _ := json.MarshalIndent(res, "", "    ")
    fmt.Println(string(j))
}
# ./tagg2
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "properties": {
        "method": {
            "description": "Method name",
            "type": "string"
        },
        "params": {
            "properties": {
                "address": {
                    "description": "Target address",
                    "type": "string"
                },
                "count": {
                    "description": "Count of retrains",
                    "type": "string"
                },
                "reqNum": {
                    "type": "integer"
                }
            },
            "required": [
                "address",
                "count",
                "reqNum"
            ],
            "type": "object"
        }
    },
    "required": [
        "method",
        "params"
    ],
    "type": "object"
}