User Tools

Site Tools


,

JSON Schema Generator

json-schema-gem.go
/*
 * Copyright 2020 Oleg Borodin  <borodin@unix7.org>
 */
 
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 main() {
    fu := Func{
        Method: "Add",
    }
    res := Reflector(&fu)
 
    j, _ := json.MarshalIndent(res, "", "    ")
    fmt.Println(string(j))
}

Output

$ go run tagg2.go
{
    "$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"
}