Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use information from struct in schema generation #138

Open
jerbob92 opened this issue Feb 21, 2024 · 1 comment
Open

Can't use information from struct in schema generation #138

jerbob92 opened this issue Feb 21, 2024 · 1 comment

Comments

@jerbob92
Copy link

I have a use-case where I dynamically want to build JSON schema's from Go based on information from the database. I thought I would be able to do this with this library, but when implementing it I found out that the JSONSchema() and JSONSchemaExtend() interfaces do not give you access to the actual data of the struct. Any chance support for this could be added?

The main reason is because of the following 2 locations:

https://github.com/invopop/jsonschema/blob/main/reflect.go#L164 (directly drops the actual value)
https://github.com/invopop/jsonschema/blob/main/reflect.go#L360 (makes a new instance of the struct)

I think it could be relatively simple to store the original value (perhaps make it optional on the reflector?) and make it available in JSONSchema()/JSONSchemaExtend().

Example code:

package main

import (
	"encoding/json"
	"log"

	"github.com/invopop/jsonschema"
)

type PropertyMap struct {
	PropertyNames []string
	PropertyValues map[string]any
}

func (pm PropertyMap) MarshalJSON() ([]byte, error) {
	return json.Marshal(pm.PropertyValues)
}

func (pm PropertyMap) JSONSchema() *jsonschema.Schema {
	baseSchema := &jsonschema.Schema{
		Type: "object",
	}

	for i := range pm.PropertyNames {
		propertySchema := jsonschema.Reflect(pm.PropertyValues[pm.PropertyNames[i]])
		baseSchema.Properties.Set(pm.PropertyNames[i], propertySchema)
	}

	return baseSchema
}

func main() {
	newPropertyMap := &PropertyMap{
		PropertyNames: []string{"field1", "field2"},
		PropertyValues: map[string]any{
			"field1": "yes",
			"field2": "no",
		},
	}

	jsonSchema := jsonschema.Reflect(newPropertyMap)
	jsonSchemaData, err := jsonSchema.MarshalJSON()
	log.Println(string(jsonSchemaData))
}

Current output:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/PropertyMap",
    "$defs": {
        "PropertyMap": {
            "type": "object"
        }
    }
}

Expected output:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$ref": "#/$defs/PropertyMap",
    "$defs": {
        "PropertyMap": {
            "type": "object"
            "properties": {
                "field1": {
                    "type": "string"
                 },
                 "field2": {
                     "type": "boolean"
                 }
            }
        }
    }
}
@jerbob92
Copy link
Author

I have made the implementation here: klippa-app#1
It's currently in our fork because we also have other MR's open (#130 and #135).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant