From 4c3e40c6a61cae5e2fdb2972cba70f6af22aca93 Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Tue, 29 Aug 2023 11:02:35 +1000 Subject: [PATCH] feat: generate a basic JSON-schema from FTL schema data types (#333) This is currently restricted to a single data type, as our initial use case is for the request editor in the Console. Future work could/should include: - Using the JSON schema to validate ingress requests. - Exporting the schema so users can codegen clients. --------- Co-authored-by: github-actions[bot] --- .golangci.yml | 1 + backend/schema/encoding.go | 4 +- backend/schema/jsonschema.go | 126 ++++++++++++++++++++++++++++++ backend/schema/jsonschema_test.go | 98 +++++++++++++++++++++++ examples/go.mod | 2 + examples/go.sum | 18 +++++ examples/online-boutique/go.mod | 2 + examples/online-boutique/go.sum | 18 +++++ go.mod | 2 + go.sum | 18 +++++ 10 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 backend/schema/jsonschema.go create mode 100644 backend/schema/jsonschema_test.go diff --git a/.golangci.yml b/.golangci.yml index bf1432ec1..d86af1713 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -123,3 +123,4 @@ issues: - "parameter testing.TB should have name tb" - "blank-imports" - 'should have comment \(or a comment on this block\) or be unexported' + - caseOrder diff --git a/backend/schema/encoding.go b/backend/schema/encoding.go index 8afe0885f..93362ce38 100644 --- a/backend/schema/encoding.go +++ b/backend/schema/encoding.go @@ -65,7 +65,7 @@ var _ Type = (*DataRef)(nil) func (*DataRef) schemaChildren() []Node { return nil } func (*DataRef) schemaType() {} -func (s *DataRef) String() string { return s.Name } +func (s DataRef) String() string { return makeRef(s.Module, s.Name) } var _ Decl = (*Data)(nil) @@ -97,7 +97,7 @@ var _ Type = (*VerbRef)(nil) func (*VerbRef) schemaChildren() []Node { return nil } func (*VerbRef) schemaType() {} -func (v *VerbRef) String() string { return makeRef(v.Module, v.Name) } +func (v VerbRef) String() string { return makeRef(v.Module, v.Name) } var _ Decl = (*Verb)(nil) diff --git a/backend/schema/jsonschema.go b/backend/schema/jsonschema.go new file mode 100644 index 000000000..f2e45f22d --- /dev/null +++ b/backend/schema/jsonschema.go @@ -0,0 +1,126 @@ +package schema + +import ( + "fmt" + "strings" + + "github.com/alecthomas/errors" + js "github.com/swaggest/jsonschema-go" +) + +// DataToJSONSchema converts the schema for a Data object to a JSON Schema. +// +// It takes in the full schema in order to resolve and define references. +func DataToJSONSchema(schema *Schema, dataRef DataRef) (*js.Schema, error) { + // Collect all data types. + dataTypes := map[DataRef]*Data{} + for _, module := range schema.Modules { + for _, decl := range module.Decls { + if data, ok := decl.(*Data); ok { + dataTypes[DataRef{Module: module.Name, Name: data.Name}] = data + } + } + } + + // Find the root data type. + rootData, ok := dataTypes[dataRef] + if !ok { + return nil, errors.Errorf("unknown data type %s", dataRef) + } + + // Encode root, and collect all data types reachable from the root. + dataRefs := map[DataRef]bool{} + root := nodeToJSSchema(rootData, dataRefs) + if len(dataRefs) == 0 { + return root, nil + } + // Resolve and encode all data types reachable from the root. + root.Definitions = map[string]js.SchemaOrBool{} + for dataRef := range dataRefs { + data, ok := dataTypes[dataRef] + if !ok { + return nil, errors.Errorf("unknown data type %s", dataRef) + } + root.Definitions[dataRef.String()] = js.SchemaOrBool{TypeObject: nodeToJSSchema(data, dataRefs)} + } + return root, nil +} + +func nodeToJSSchema(node Node, dataRefs map[DataRef]bool) *js.Schema { + switch node := node.(type) { + case *Data: + st := js.Object + schema := &js.Schema{ + Description: jsComments(node.Comments), + Type: &js.Type{SimpleTypes: &st}, + Properties: map[string]js.SchemaOrBool{}, + AdditionalProperties: jsBool(false), + } + for _, field := range node.Fields { + jsField := nodeToJSSchema(field.Type, dataRefs) + jsField.Description = jsComments(field.Comments) + schema.Properties[field.Name] = js.SchemaOrBool{TypeObject: jsField} + } + return schema + + case *Int: + st := js.Integer + return &js.Schema{Type: &js.Type{SimpleTypes: &st}} + + case *Float: + st := js.Number + return &js.Schema{Type: &js.Type{SimpleTypes: &st}} + + case *String: + st := js.String + return &js.Schema{Type: &js.Type{SimpleTypes: &st}} + + case *Bool: + st := js.Boolean + return &js.Schema{Type: &js.Type{SimpleTypes: &st}} + + case *Time: + st := js.String + dt := "date-time" + return &js.Schema{Type: &js.Type{SimpleTypes: &st}, Format: &dt} + + case *Array: + st := js.Array + return &js.Schema{ + Type: &js.Type{SimpleTypes: &st}, + Items: &js.Items{SchemaOrBool: &js.SchemaOrBool{TypeObject: nodeToJSSchema(node.Element, dataRefs)}}, + } + + case *Map: + st := js.Object + // JSON schema generic map of key type to value type + return &js.Schema{ + Type: &js.Type{SimpleTypes: &st}, + AdditionalProperties: &js.SchemaOrBool{TypeObject: nodeToJSSchema(node.Value, dataRefs)}, + PropertyNames: &js.SchemaOrBool{TypeObject: nodeToJSSchema(node.Key, dataRefs)}, + } + + case *DataRef: + ref := fmt.Sprintf("#/definitions/%s", node.String()) + dataRefs[*node] = true + return &js.Schema{Ref: &ref} + + case Decl, *Field, Metadata, *MetadataCalls, *MetadataIngress, *Module, *Schema, Type, *Verb, *VerbRef: + panic(fmt.Sprintf("unsupported node type %T", node)) + + default: + panic(fmt.Sprintf("unsupported node type %T", node)) + } +} + +func jsBool(ok bool) *js.SchemaOrBool { + return &js.SchemaOrBool{TypeBoolean: &ok} +} + +func jsComments(comments []string) *string { + if len(comments) == 0 { + return nil + } + out := strings.Join(comments, "\n") + return &out +} diff --git a/backend/schema/jsonschema_test.go b/backend/schema/jsonschema_test.go new file mode 100644 index 000000000..eea979f91 --- /dev/null +++ b/backend/schema/jsonschema_test.go @@ -0,0 +1,98 @@ +package schema + +import ( + "encoding/json" + "testing" + + "github.com/alecthomas/assert/v2" +) + +func TestDataToJSONSchema(t *testing.T) { + schema, err := DataToJSONSchema(&Schema{ + Modules: []*Module{ + {Name: "foo", Decls: []Decl{&Data{ + Name: "Foo", + Comments: []string{"Data comment"}, + Fields: []*Field{ + {Name: "string", Type: &String{}, Comments: []string{"Field comment"}}, + {Name: "int", Type: &Int{}}, + {Name: "float", Type: &Float{}}, + {Name: "bool", Type: &Bool{}}, + {Name: "time", Type: &Time{}}, + {Name: "array", Type: &Array{Element: &String{}}}, + {Name: "arrayOfArray", Type: &Array{Element: &Array{Element: &String{}}}}, + {Name: "map", Type: &Map{Key: &String{}, Value: &Int{}}}, + {Name: "ref", Type: &DataRef{Module: "bar", Name: "Bar"}}, + }}}}, + {Name: "bar", Decls: []Decl{ + &Data{Name: "Bar", Fields: []*Field{{Name: "bar", Type: &String{}}}}, + }}, + }, + }, DataRef{Module: "foo", Name: "Foo"}) + assert.NoError(t, err) + actual, err := json.MarshalIndent(schema, "", " ") + assert.NoError(t, err) + expected := `{ + "description": "Data comment", + "additionalProperties": false, + "definitions": { + "bar.Bar": { + "additionalProperties": false, + "properties": { + "bar": { + "type": "string" + } + }, + "type": "object" + } + }, + "properties": { + "array": { + "items": { + "type": "string" + }, + "type": "array" + }, + "arrayOfArray": { + "items": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "bool": { + "type": "boolean" + }, + "float": { + "type": "number" + }, + "int": { + "type": "integer" + }, + "map": { + "additionalProperties": { + "type": "integer" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "ref": { + "$ref": "#/definitions/bar.Bar" + }, + "string": { + "description": "Field comment", + "type": "string" + }, + "time": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" +}` + assert.Equal(t, expected, string(actual)) +} diff --git a/examples/go.mod b/examples/go.mod index f30980709..e6946b0a1 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,6 +22,8 @@ require ( github.com/mattn/go-isatty v0.0.17 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/rs/cors v1.9.0 // indirect + github.com/swaggest/jsonschema-go v0.3.59 // indirect + github.com/swaggest/refl v1.2.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 516c00c6f..723de06c1 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -10,6 +10,10 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= +github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= +github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/bufbuild/connect-grpcreflect-go v1.1.0 h1:T0FKu1y9zZW4cjHuF+Q7jIN6ek8HTpCxOP8ZsORZICg= @@ -33,6 +37,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -50,8 +56,20 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.59 h1:BoPhtNvWbZRo1Wl6xvR3g6WL01COJTOAs6vMUnZgocM= +github.com/swaggest/jsonschema-go v0.3.59/go.mod h1:5WFFGBBte5JAWAV8gDpNRJ/tlQnb1AHDdf/ghgsVUik= +github.com/swaggest/refl v1.2.0 h1:Qqqhfwi7REXF6/4cwJmj3gQMzl0Q0cYquxTYdD0kvi0= +github.com/swaggest/refl v1.2.0/go.mod h1:CkC6g7h1PW33KprTuYRSw8UUOslRUt4lF3oe7tTIgNU= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= diff --git a/examples/online-boutique/go.mod b/examples/online-boutique/go.mod index 86c178a2b..a5ccd1766 100644 --- a/examples/online-boutique/go.mod +++ b/examples/online-boutique/go.mod @@ -26,6 +26,8 @@ require ( github.com/mattn/go-isatty v0.0.17 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/rs/cors v1.9.0 // indirect + github.com/swaggest/jsonschema-go v0.3.59 // indirect + github.com/swaggest/refl v1.2.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect diff --git a/examples/online-boutique/go.sum b/examples/online-boutique/go.sum index 85b9a06b1..b76bb29f9 100644 --- a/examples/online-boutique/go.sum +++ b/examples/online-boutique/go.sum @@ -10,6 +10,10 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= +github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= +github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/bufbuild/connect-grpcreflect-go v1.1.0 h1:T0FKu1y9zZW4cjHuF+Q7jIN6ek8HTpCxOP8ZsORZICg= @@ -35,6 +39,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvH github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -52,8 +58,20 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.59 h1:BoPhtNvWbZRo1Wl6xvR3g6WL01COJTOAs6vMUnZgocM= +github.com/swaggest/jsonschema-go v0.3.59/go.mod h1:5WFFGBBte5JAWAV8gDpNRJ/tlQnb1AHDdf/ghgsVUik= +github.com/swaggest/refl v1.2.0 h1:Qqqhfwi7REXF6/4cwJmj3gQMzl0Q0cYquxTYdD0kvi0= +github.com/swaggest/refl v1.2.0/go.mod h1:CkC6g7h1PW33KprTuYRSw8UUOslRUt4lF3oe7tTIgNU= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= diff --git a/go.mod b/go.mod index 239f7e647..19e12deec 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/otiai10/copy v1.12.0 github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.9.0 + github.com/swaggest/jsonschema-go v0.3.59 github.com/titanous/json5 v1.0.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 @@ -37,6 +38,7 @@ require ( github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/swaggest/refl v1.2.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect diff --git a/go.sum b/go.sum index 985b8b6cd..c128ac64d 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,10 @@ github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW5 github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= +github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/bufbuild/connect-grpcreflect-go v1.1.0 h1:T0FKu1y9zZW4cjHuF+Q7jIN6ek8HTpCxOP8ZsORZICg= @@ -167,6 +171,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -224,6 +230,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -232,8 +240,18 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.59 h1:BoPhtNvWbZRo1Wl6xvR3g6WL01COJTOAs6vMUnZgocM= +github.com/swaggest/jsonschema-go v0.3.59/go.mod h1:5WFFGBBte5JAWAV8gDpNRJ/tlQnb1AHDdf/ghgsVUik= +github.com/swaggest/refl v1.2.0 h1:Qqqhfwi7REXF6/4cwJmj3gQMzl0Q0cYquxTYdD0kvi0= +github.com/swaggest/refl v1.2.0/go.mod h1:CkC6g7h1PW33KprTuYRSw8UUOslRUt4lF3oe7tTIgNU= github.com/titanous/json5 v1.0.0 h1:hJf8Su1d9NuI/ffpxgxQfxh/UiBFZX7bMPid0rIL/7s= github.com/titanous/json5 v1.0.0/go.mod h1:7JH1M8/LHKc6cyP5o5g3CSaRj+mBrIimTxzpvmckH8c= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=