diff --git a/go.mod b/go.mod index 130af768351..c90909bb599 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/envoyproxy/protoc-gen-validate v1.0.4 github.com/fatih/color v1.15.0 github.com/fsnotify/fsnotify v1.7.0 + github.com/getkin/kin-openapi v0.126.0 github.com/go-git/go-git/v5 v5.12.0 github.com/go-jose/go-jose/v3 v3.0.1 github.com/go-logr/zapr v1.2.4 @@ -205,9 +206,9 @@ require ( github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect @@ -234,6 +235,7 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/yaml v0.3.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -274,6 +276,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/paulmach/orb v0.10.0 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pingcap/errors v0.11.5-0.20221009092201-b66cddb77c32 // indirect github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c // indirect @@ -303,6 +306,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/ugorji/go v1.1.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect diff --git a/go.sum b/go.sum index b5b2a80eaf6..7d15a0175ce 100644 --- a/go.sum +++ b/go.sum @@ -1150,6 +1150,8 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY= +github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -1206,22 +1208,22 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -1241,8 +1243,9 @@ github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA= @@ -1514,6 +1517,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= +github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= +github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -1868,6 +1873,8 @@ github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKf github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -2120,6 +2127,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= diff --git a/proto/gen/rill/runtime/v1/resources.pb.go b/proto/gen/rill/runtime/v1/resources.pb.go index d25c554b93a..f1928918efd 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.go +++ b/proto/gen/rill/runtime/v1/resources.pb.go @@ -4317,8 +4317,11 @@ type APISpec struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Resolver string `protobuf:"bytes,1,opt,name=resolver,proto3" json:"resolver,omitempty"` - ResolverProperties *structpb.Struct `protobuf:"bytes,2,opt,name=resolver_properties,json=resolverProperties,proto3" json:"resolver_properties,omitempty"` + Resolver string `protobuf:"bytes,1,opt,name=resolver,proto3" json:"resolver,omitempty"` + ResolverProperties *structpb.Struct `protobuf:"bytes,2,opt,name=resolver_properties,json=resolverProperties,proto3" json:"resolver_properties,omitempty"` + OpenapiSummary string `protobuf:"bytes,3,opt,name=openapi_summary,json=openapiSummary,proto3" json:"openapi_summary,omitempty"` + OpenapiParameters []*structpb.Struct `protobuf:"bytes,4,rep,name=openapi_parameters,json=openapiParameters,proto3" json:"openapi_parameters,omitempty"` + OpenapiResponseSchema *structpb.Struct `protobuf:"bytes,5,opt,name=openapi_response_schema,json=openapiResponseSchema,proto3" json:"openapi_response_schema,omitempty"` } func (x *APISpec) Reset() { @@ -4367,6 +4370,27 @@ func (x *APISpec) GetResolverProperties() *structpb.Struct { return nil } +func (x *APISpec) GetOpenapiSummary() string { + if x != nil { + return x.OpenapiSummary + } + return "" +} + +func (x *APISpec) GetOpenapiParameters() []*structpb.Struct { + if x != nil { + return x.OpenapiParameters + } + return nil +} + +func (x *APISpec) GetOpenapiResponseSchema() *structpb.Struct { + if x != nil { + return x.OpenapiResponseSchema + } + return nil +} + type APIState struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6283,114 +6307,126 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{ 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, - 0x6f, 0x0a, 0x07, 0x41, 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, + 0xb1, 0x02, 0x0a, 0x07, 0x41, 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x12, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, + 0x11, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x12, 0x4f, 0x0a, 0x17, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, - 0x22, 0x0a, 0x0a, 0x08, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x9b, 0x01, 0x0a, - 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x66, - 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, - 0x65, 0x66, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, - 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x0a, 0x50, - 0x61, 0x72, 0x73, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, - 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x22, 0x50, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, - 0x50, 0x61, 0x74, 0x68, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, - 0x63, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, - 0x79, 0x22, 0x2a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x22, 0x0a, - 0x0c, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e, - 0x65, 0x22, 0xfb, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, - 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0a, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x2e, - 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x77, 0x0a, 0x19, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x15, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x22, 0x0a, 0x0a, 0x08, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, + 0x9b, 0x01, 0x0a, 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x72, 0x65, 0x66, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x72, 0x65, 0x66, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0xa5, 0x01, + 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, + 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x50, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, + 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x79, 0x22, 0x2a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x22, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x6c, 0x69, 0x6e, 0x65, 0x22, 0xfb, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x4e, + 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, + 0x65, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x77, + 0x0a, 0x19, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x66, 0x72, 0x6f, + 0x6d, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x3b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, + 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x17, + 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x2d, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x65, 0x63, 0x48, 0x61, 0x73, + 0x68, 0x22, 0x78, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x32, + 0x12, 0x32, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x50, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, - 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x17, 0x70, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, - 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x2d, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x65, 0x63, 0x48, 0x61, 0x73, 0x68, 0x22, 0x78, - 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x32, 0x12, 0x32, 0x0a, - 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, - 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x8a, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x63, - 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, + 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, + 0x73, 0x70, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x8a, 0x01, 0x0a, 0x0f, + 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, + 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, + 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x2a, 0x85, 0x01, 0x0a, 0x0f, 0x41, 0x73, 0x73, + 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, + 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, - 0x0a, 0x15, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, - 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, - 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x55, 0x4e, 0x4e, - 0x49, 0x4e, 0x47, 0x10, 0x03, 0x2a, 0x85, 0x01, 0x0a, 0x0f, 0x41, 0x73, 0x73, 0x65, 0x72, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x53, 0x53, - 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x41, - 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x10, - 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x42, 0xc1, 0x01, - 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, - 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, - 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, - 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, - 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, - 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, - 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, - 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, + 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, + 0x42, 0xc1, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, + 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, + 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, + 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, + 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -6607,23 +6643,25 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 58, // 108: rill.runtime.v1.API.spec:type_name -> rill.runtime.v1.APISpec 59, // 109: rill.runtime.v1.API.state:type_name -> rill.runtime.v1.APIState 80, // 110: rill.runtime.v1.APISpec.resolver_properties:type_name -> google.protobuf.Struct - 65, // 111: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation - 77, // 112: rill.runtime.v1.ConnectorSpec.properties:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesEntry - 78, // 113: rill.runtime.v1.ConnectorSpec.properties_from_variables:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesFromVariablesEntry - 66, // 114: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec - 67, // 115: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState - 82, // 116: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain - 70, // 117: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 2, // 118: rill.runtime.v1.MetricsViewSpec.MeasureV2.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType - 71, // 119: rill.runtime.v1.MetricsViewSpec.MeasureV2.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow - 70, // 120: rill.runtime.v1.MetricsViewSpec.MeasureV2.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 70, // 121: rill.runtime.v1.MetricsViewSpec.MeasureV2.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 73, // 122: rill.runtime.v1.MetricsViewSpec.AvailableTimeRange.comparison_offsets:type_name -> rill.runtime.v1.MetricsViewSpec.AvailableComparisonOffset - 123, // [123:123] is the sub-list for method output_type - 123, // [123:123] is the sub-list for method input_type - 123, // [123:123] is the sub-list for extension type_name - 123, // [123:123] is the sub-list for extension extendee - 0, // [0:123] is the sub-list for field type_name + 80, // 111: rill.runtime.v1.APISpec.openapi_parameters:type_name -> google.protobuf.Struct + 80, // 112: rill.runtime.v1.APISpec.openapi_response_schema:type_name -> google.protobuf.Struct + 65, // 113: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation + 77, // 114: rill.runtime.v1.ConnectorSpec.properties:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesEntry + 78, // 115: rill.runtime.v1.ConnectorSpec.properties_from_variables:type_name -> rill.runtime.v1.ConnectorSpec.PropertiesFromVariablesEntry + 66, // 116: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec + 67, // 117: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState + 82, // 118: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain + 70, // 119: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 2, // 120: rill.runtime.v1.MetricsViewSpec.MeasureV2.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType + 71, // 121: rill.runtime.v1.MetricsViewSpec.MeasureV2.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow + 70, // 122: rill.runtime.v1.MetricsViewSpec.MeasureV2.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 70, // 123: rill.runtime.v1.MetricsViewSpec.MeasureV2.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 73, // 124: rill.runtime.v1.MetricsViewSpec.AvailableTimeRange.comparison_offsets:type_name -> rill.runtime.v1.MetricsViewSpec.AvailableComparisonOffset + 125, // [125:125] is the sub-list for method output_type + 125, // [125:125] is the sub-list for method input_type + 125, // [125:125] is the sub-list for extension type_name + 125, // [125:125] is the sub-list for extension extendee + 0, // [0:125] is the sub-list for field type_name } func init() { file_rill_runtime_v1_resources_proto_init() } diff --git a/proto/gen/rill/runtime/v1/resources.pb.validate.go b/proto/gen/rill/runtime/v1/resources.pb.validate.go index 101737d5254..aa458e17685 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.validate.go +++ b/proto/gen/rill/runtime/v1/resources.pb.validate.go @@ -8889,6 +8889,71 @@ func (m *APISpec) validate(all bool) error { } } + // no validation rules for OpenapiSummary + + for idx, item := range m.GetOpenapiParameters() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, APISpecValidationError{ + field: fmt.Sprintf("OpenapiParameters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, APISpecValidationError{ + field: fmt.Sprintf("OpenapiParameters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return APISpecValidationError{ + field: fmt.Sprintf("OpenapiParameters[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if all { + switch v := interface{}(m.GetOpenapiResponseSchema()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, APISpecValidationError{ + field: "OpenapiResponseSchema", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, APISpecValidationError{ + field: "OpenapiResponseSchema", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetOpenapiResponseSchema()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return APISpecValidationError{ + field: "OpenapiResponseSchema", + reason: "embedded message failed validation", + cause: err, + } + } + } + if len(errors) > 0 { return APISpecMultiError(errors) } diff --git a/proto/gen/rill/runtime/v1/runtime.swagger.yaml b/proto/gen/rill/runtime/v1/runtime.swagger.yaml index 062ecf6c2d5..ac3ec197a84 100644 --- a/proto/gen/rill/runtime/v1/runtime.swagger.yaml +++ b/proto/gen/rill/runtime/v1/runtime.swagger.yaml @@ -2952,6 +2952,14 @@ definitions: type: string resolverProperties: type: object + openapiSummary: + type: string + openapiParameters: + type: array + items: + type: object + openapiResponseSchema: + type: object v1APIState: type: object v1Alert: diff --git a/proto/rill/runtime/v1/resources.proto b/proto/rill/runtime/v1/resources.proto index 688671cca25..521b9dd7fca 100644 --- a/proto/rill/runtime/v1/resources.proto +++ b/proto/rill/runtime/v1/resources.proto @@ -503,6 +503,9 @@ message API { message APISpec { string resolver = 1; google.protobuf.Struct resolver_properties = 2; + string openapi_summary = 3; + repeated google.protobuf.Struct openapi_parameters = 4; + google.protobuf.Struct openapi_response_schema = 5; } message APIState {} diff --git a/runtime/compilers/rillv1/parse_api.go b/runtime/compilers/rillv1/parse_api.go index d2eb8985788..bd2b38627ae 100644 --- a/runtime/compilers/rillv1/parse_api.go +++ b/runtime/compilers/rillv1/parse_api.go @@ -3,12 +3,24 @@ package rillv1 import ( "fmt" + "github.com/rilldata/rill/runtime/pkg/openapiutil" "google.golang.org/protobuf/types/known/structpb" ) // APIYAML is the raw structure of a API resource defined in YAML (does not include common fields) type APIYAML struct { DataYAML `yaml:",inline" mapstructure:",squash"` + OpenAPI *OpenAPIYAML `yaml:"openapi"` +} + +type OpenAPIYAML struct { + Summary string `yaml:"summary"` + Request struct { + Parameters []map[string]any `yaml:"parameters"` + } `yaml:"request"` + Response struct { + Schema map[string]any `yaml:"schema"` + } `yaml:"response"` } // parseAPI parses an API definition and adds the resulting resource to p.Resources. @@ -20,6 +32,35 @@ func (p *Parser) parseAPI(node *Node) error { return err } + // Validate + var openapiSummary string + var openapiParams []*structpb.Struct + var openapiSchema *structpb.Struct + if tmp.OpenAPI != nil { + openapiSummary = tmp.OpenAPI.Summary + + _, err := openapiutil.MapToParameters(tmp.OpenAPI.Request.Parameters) + if err != nil { + return fmt.Errorf("encountered invalid parameter type: %w", err) + } + for _, param := range tmp.OpenAPI.Request.Parameters { + paramPB, err := structpb.NewStruct(param) + if err != nil { + return fmt.Errorf("encountered invalid parameter type: %w", err) + } + openapiParams = append(openapiParams, paramPB) + } + + _, err = openapiutil.MapToSchema(tmp.OpenAPI.Response.Schema) + if err != nil { + return fmt.Errorf("encountered invalid schema type: %w", err) + } + openapiSchema, err = structpb.NewStruct(tmp.OpenAPI.Response.Schema) + if err != nil { + return fmt.Errorf("encountered invalid schema type: %w", err) + } + } + // Map common node properties to DataYAML if !node.ConnectorInferred && node.Connector != "" { tmp.DataYAML.Connector = node.Connector @@ -43,6 +84,9 @@ func (p *Parser) parseAPI(node *Node) error { r.APISpec.Resolver = resolver r.APISpec.ResolverProperties = resolverProps + r.APISpec.OpenapiSummary = openapiSummary + r.APISpec.OpenapiParameters = openapiParams + r.APISpec.OpenapiResponseSchema = openapiSchema return nil } diff --git a/runtime/pkg/openapiutil/openapiutil.go b/runtime/pkg/openapiutil/openapiutil.go new file mode 100644 index 00000000000..2aa98357a4b --- /dev/null +++ b/runtime/pkg/openapiutil/openapiutil.go @@ -0,0 +1,39 @@ +package openapiutil + +import ( + "encoding/json" + + "github.com/getkin/kin-openapi/openapi3" +) + +func MapToParameters(params []map[string]any) (openapi3.Parameters, error) { + var parameters openapi3.Parameters + + jsonData, err := json.Marshal(params) + if err != nil { + return nil, err + } + + err = json.Unmarshal(jsonData, ¶meters) + if err != nil { + return nil, err + } + + return parameters, nil +} + +func MapToSchema(schema map[string]any) (*openapi3.Schema, error) { + specSchema := openapi3.Schema{} + + jsonData, err := json.Marshal(schema) + if err != nil { + return nil, err + } + + err = specSchema.UnmarshalJSON(jsonData) + if err != nil { + return nil, err + } + + return &specSchema, nil +} diff --git a/runtime/server/api.go b/runtime/server/api.go index b42883bb72b..8b53219c519 100644 --- a/runtime/server/api.go +++ b/runtime/server/api.go @@ -1,17 +1,24 @@ package server import ( + "context" "encoding/json" "errors" + "fmt" "io" "net/http" + "net/url" + "github.com/getkin/kin-openapi/openapi3" + runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime" "github.com/rilldata/rill/runtime/drivers" "github.com/rilldata/rill/runtime/pkg/httputil" "github.com/rilldata/rill/runtime/pkg/observability" + "github.com/rilldata/rill/runtime/pkg/openapiutil" "github.com/rilldata/rill/runtime/server/auth" "go.opentelemetry.io/otel/attribute" + "gopkg.in/yaml.v3" ) func (s *Server) apiHandler(w http.ResponseWriter, req *http.Request) error { @@ -80,3 +87,214 @@ func (s *Server) apiHandler(w http.ResponseWriter, req *http.Request) error { return nil } + +func (s *Server) combinedOpenAPISpec(w http.ResponseWriter, req *http.Request) error { + // Parse path parameters + ctx := req.Context() + instanceID := req.PathValue("instance_id") + + // Add observability attributes + observability.AddRequestAttributes(ctx) + s.addInstanceRequestAttributes(ctx, instanceID) + + // Only GET request is allowed + if req.Method != http.MethodGet { + return httputil.Error(http.StatusMethodNotAllowed, fmt.Errorf("GET only")) + } + + // Check if user has access to query for API data + if !auth.GetClaims(ctx).CanInstance(instanceID, auth.ReadAPI) { + return httputil.Errorf(http.StatusForbidden, "does not have access to custom APIs") + } + + apis := make(map[string]*runtimev1.API) + + // Get all built-in APIs + for name, api := range runtime.BuiltinAPIs { + apis[name] = api + } + + // Get all custom APIs + ctrl, err := s.runtime.Controller(ctx, instanceID) + if err != nil { + return httputil.Error(http.StatusBadRequest, err) + } + + list, err := ctrl.List(ctx, runtime.ResourceKindAPI, "", false) + if err != nil { + return err + } + + for _, res := range list { + apis[res.Meta.Name.Name] = res.GetApi() + } + + // Generate the OpenAPI spec + combinedAPISpec, err := s.generateOpenAPISpec(ctx, instanceID, apis) + if err != nil { + return httputil.Error(http.StatusInternalServerError, err) + } + + // Check accepted format of the OpenAPI spec: JSON or YAML + accept := req.Header.Get("Accept") + + // YAML + if accept == "application/yaml" || accept == "application/x-yaml" { + data, err := yaml.Marshal(combinedAPISpec) + if err != nil { + return httputil.Error(http.StatusInternalServerError, err) + } + + w.Header().Set("Content-Type", "application/yaml") + _, err = w.Write(data) + if err != nil { + return httputil.Error(http.StatusInternalServerError, err) + } + + return nil + } + + // JSON + data, err := combinedAPISpec.MarshalJSON() + if err != nil { + return httputil.Error(http.StatusInternalServerError, err) + } + + w.Header().Set("Content-Type", "application/json") + _, err = w.Write(data) + if err != nil { + return httputil.Error(http.StatusInternalServerError, err) + } + + return nil +} + +func (s *Server) generateOpenAPISpec(ctx context.Context, instanceID string, apis map[string]*runtimev1.API) (*openapi3.T, error) { + attributes := s.runtime.GetInstanceAttributes(ctx, instanceID) + var organization, project string + for _, attr := range attributes { + if attr.Key == "organization" { + organization = attr.Value.AsString() + } else if attr.Key == "project" { + project = attr.Value.AsString() + } + } + var title string + if organization != "" && project != "" { + title = fmt.Sprintf("Rill %s/%s project API", organization, project) + } else { + title = "Rill project API" + } + + spec := &openapi3.T{ + OpenAPI: "3.0.3", + Info: &openapi3.Info{ + Title: title, + Version: "1.0.0", + }, + Paths: &openapi3.Paths{}, + } + + var runtimeHost string + if s.opts.AuthAudienceURL != "" { + runtimeURL, err := url.Parse(s.opts.AuthAudienceURL) + if err != nil { + return nil, err + } + runtimeHost = runtimeURL.Host + } else { + runtimeHost = fmt.Sprintf("localhost:%d", s.opts.HTTPPort) + } + + spec.Servers = openapi3.Servers{ + &openapi3.Server{ + URL: fmt.Sprintf("http://%s/v1/instances/%s/api", runtimeHost, instanceID), + }, + } + + for name, api := range apis { + pathItem, err := s.generatePathItemSpec(name, api) + if err != nil { + return nil, err + } + + spec.Paths.Set(fmt.Sprintf("/%s", name), pathItem) + } + + return spec, nil +} + +func (s *Server) generatePathItemSpec(name string, api *runtimev1.API) (*openapi3.PathItem, error) { + summary := "" + if api.Spec.OpenapiSummary != "" { + summary = api.Spec.OpenapiSummary + } + if summary == "" { + summary = fmt.Sprintf("Query %s resolver", name) + } + + var parameters openapi3.Parameters + if api.Spec.OpenapiParameters != nil { + maps := make([]map[string]any, len(api.Spec.OpenapiParameters)) + for i, param := range api.Spec.OpenapiParameters { + maps[i] = param.AsMap() + } + var err error + parameters, err = openapiutil.MapToParameters(maps) + if err != nil { + return nil, err + } + } + + var schema *openapi3.Schema + if api.Spec.OpenapiResponseSchema != nil { + var err error + schema, err = openapiutil.MapToSchema(api.Spec.OpenapiResponseSchema.AsMap()) + if err != nil { + return nil, err + } + } else { + schema = &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + } + } + + pathItem := &openapi3.PathItem{ + Get: &openapi3.Operation{ + Summary: summary, + Parameters: parameters, + Responses: openapi3.NewResponses( + openapi3.WithStatus(200, &openapi3.ResponseRef{ + Value: openapi3.NewResponse().WithDescription( + fmt.Sprintf("Successful response of %s resolver", name), + ).WithContent( + openapi3.NewContentWithJSONSchema(&openapi3.Schema{ + Type: &openapi3.Types{"array"}, + Items: &openapi3.SchemaRef{ + Value: schema, + }, + }), + ), + }), + openapi3.WithStatus(400, &openapi3.ResponseRef{ + Value: openapi3.NewResponse().WithDescription( + "Bad request", + ).WithContent( + openapi3.NewContentWithJSONSchema(&openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Properties: map[string]*openapi3.SchemaRef{ + "error": { + Value: &openapi3.Schema{ + Type: &openapi3.Types{"string"}, + }, + }, + }, + }), + ), + }), + ), + }, + } + + return pathItem, nil +} diff --git a/runtime/server/server.go b/runtime/server/server.go index 069f0fdd692..df77993c05e 100644 --- a/runtime/server/server.go +++ b/runtime/server/server.go @@ -212,6 +212,9 @@ func (s *Server) HTTPHandler(ctx context.Context, registerAdditionalHandlers fun // Add handler for dynamic APIs, i.e. APIs backed by resolvers (such as custom APIs defined in YAML). observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/api/{name...}", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.apiHandler)))) + // Add handler for combined OpenAPI spec of custom APIs + observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/api/openapi", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.combinedOpenAPISpec)))) + // Add handler for resolving component data observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/components/{name}/data", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.componentDataHandler)))) // Serving static assets diff --git a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts index f7503b91dcc..658b820b8af 100644 --- a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts +++ b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts @@ -3637,6 +3637,21 @@ export class APISpec extends Message { */ resolverProperties?: Struct; + /** + * @generated from field: string openapi_summary = 3; + */ + openapiSummary = ""; + + /** + * @generated from field: repeated google.protobuf.Struct openapi_parameters = 4; + */ + openapiParameters: Struct[] = []; + + /** + * @generated from field: google.protobuf.Struct openapi_response_schema = 5; + */ + openapiResponseSchema?: Struct; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -3647,6 +3662,9 @@ export class APISpec extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "resolver", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "resolver_properties", kind: "message", T: Struct }, + { no: 3, name: "openapi_summary", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "openapi_parameters", kind: "message", T: Struct, repeated: true }, + { no: 5, name: "openapi_response_schema", kind: "message", T: Struct }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): APISpec { diff --git a/web-common/src/runtime-client/gen/index.schemas.ts b/web-common/src/runtime-client/gen/index.schemas.ts index d691079129a..0a677bb3eb2 100644 --- a/web-common/src/runtime-client/gen/index.schemas.ts +++ b/web-common/src/runtime-client/gen/index.schemas.ts @@ -534,6 +534,12 @@ export interface V1TimeSeriesValue { records?: V1TimeSeriesValueRecords; } +export interface V1TimeSeriesTimeRange { + start?: string; + end?: string; + interval?: V1TimeGrain; +} + export interface V1TimeSeriesResponse { results?: V1TimeSeriesValue[]; spark?: V1TimeSeriesValue[]; @@ -562,12 +568,6 @@ export const V1TimeGrain = { TIME_GRAIN_YEAR: "TIME_GRAIN_YEAR", } as const; -export interface V1TimeSeriesTimeRange { - start?: string; - end?: string; - interval?: V1TimeGrain; -} - export interface V1TimeRange { start?: string; end?: string; @@ -794,6 +794,13 @@ export interface V1Resource { connector?: V1ConnectorV2; } +export interface V1ReportState { + nextRunOn?: string; + currentExecution?: V1ReportExecution; + executionHistory?: V1ReportExecution[]; + executionCount?: number; +} + export type V1ReportSpecAnnotations = { [key: string]: string }; export interface V1ReportSpec { @@ -822,13 +829,6 @@ export interface V1ReportExecution { finishedOn?: string; } -export interface V1ReportState { - nextRunOn?: string; - currentExecution?: V1ReportExecution; - executionHistory?: V1ReportExecution[]; - executionCount?: number; -} - export interface V1Report { spec?: V1ReportSpec; state?: V1ReportState; @@ -862,6 +862,28 @@ export const V1ReconcileStatus = { RECONCILE_STATUS_RUNNING: "RECONCILE_STATUS_RUNNING", } as const; +export interface V1QueryResult { + metricsViewAggregationResponse?: V1MetricsViewAggregationResponse; + metricsViewToplistResponse?: V1MetricsViewToplistResponse; + metricsViewComparisonResponse?: V1MetricsViewComparisonResponse; + metricsViewTimeSeriesResponse?: V1MetricsViewTimeSeriesResponse; + metricsViewTotalsResponse?: V1MetricsViewTotalsResponse; + metricsViewRowsResponse?: V1MetricsViewRowsResponse; + columnRollupIntervalResponse?: V1ColumnRollupIntervalResponse; + columnTopKResponse?: V1ColumnTopKResponse; + columnNullCountResponse?: V1ColumnNullCountResponse; + columnDescriptiveStatisticsResponse?: V1ColumnDescriptiveStatisticsResponse; + columnTimeGrainResponse?: V1ColumnTimeGrainResponse; + columnNumericHistogramResponse?: V1ColumnNumericHistogramResponse; + columnRugHistogramResponse?: V1ColumnRugHistogramResponse; + columnTimeRangeResponse?: V1ColumnTimeRangeResponse; + columnCardinalityResponse?: V1ColumnCardinalityResponse; + columnTimeSeriesResponse?: V1ColumnTimeSeriesResponse; + tableCardinalityResponse?: V1TableCardinalityResponse; + tableColumnsResponse?: V1TableColumnsResponse; + tableRowsResponse?: V1TableRowsResponse; +} + export type V1QueryResponseDataItem = { [key: string]: any }; export interface V1QueryResponse { @@ -1278,6 +1300,25 @@ export interface V1MetricsViewComparisonMeasureAlias { alias?: string; } +export interface V1MetricsViewComparisonRequest { + instanceId?: string; + metricsViewName?: string; + dimension?: V1MetricsViewAggregationDimension; + measures?: V1MetricsViewAggregationMeasure[]; + comparisonMeasures?: string[]; + sort?: V1MetricsViewComparisonSort[]; + timeRange?: V1TimeRange; + comparisonTimeRange?: V1TimeRange; + where?: V1Expression; + having?: V1Expression; + aliases?: V1MetricsViewComparisonMeasureAlias[]; + limit?: string; + offset?: string; + priority?: number; + exact?: boolean; + filter?: V1MetricsViewFilter; +} + export interface V1MetricsViewColumn { name?: string; type?: string; @@ -1296,27 +1337,6 @@ export interface V1MetricsViewAggregationResponse { data?: V1MetricsViewAggregationResponseDataItem[]; } -export interface V1MetricsViewAggregationRequest { - instanceId?: string; - metricsView?: string; - dimensions?: V1MetricsViewAggregationDimension[]; - measures?: V1MetricsViewAggregationMeasure[]; - sort?: V1MetricsViewAggregationSort[]; - timeRange?: V1TimeRange; - comparisonTimeRange?: V1TimeRange; - timeStart?: string; - timeEnd?: string; - pivotOn?: string[]; - aliases?: V1MetricsViewComparisonMeasureAlias[]; - where?: V1Expression; - having?: V1Expression; - limit?: string; - offset?: string; - priority?: number; - filter?: V1MetricsViewFilter; - exact?: boolean; -} - export interface V1MetricsViewAggregationMeasureComputeCountDistinct { dimension?: string; } @@ -1356,23 +1376,25 @@ export interface V1MetricsViewAggregationDimension { alias?: string; } -export interface V1MetricsViewComparisonRequest { +export interface V1MetricsViewAggregationRequest { instanceId?: string; - metricsViewName?: string; - dimension?: V1MetricsViewAggregationDimension; + metricsView?: string; + dimensions?: V1MetricsViewAggregationDimension[]; measures?: V1MetricsViewAggregationMeasure[]; - comparisonMeasures?: string[]; - sort?: V1MetricsViewComparisonSort[]; + sort?: V1MetricsViewAggregationSort[]; timeRange?: V1TimeRange; comparisonTimeRange?: V1TimeRange; + timeStart?: string; + timeEnd?: string; + pivotOn?: string[]; + aliases?: V1MetricsViewComparisonMeasureAlias[]; where?: V1Expression; having?: V1Expression; - aliases?: V1MetricsViewComparisonMeasureAlias[]; limit?: string; offset?: string; priority?: number; - exact?: boolean; filter?: V1MetricsViewFilter; + exact?: boolean; } export interface V1MapType { @@ -1909,28 +1931,6 @@ export interface V1ColumnCardinalityResponse { categoricalSummary?: V1CategoricalSummary; } -export interface V1QueryResult { - metricsViewAggregationResponse?: V1MetricsViewAggregationResponse; - metricsViewToplistResponse?: V1MetricsViewToplistResponse; - metricsViewComparisonResponse?: V1MetricsViewComparisonResponse; - metricsViewTimeSeriesResponse?: V1MetricsViewTimeSeriesResponse; - metricsViewTotalsResponse?: V1MetricsViewTotalsResponse; - metricsViewRowsResponse?: V1MetricsViewRowsResponse; - columnRollupIntervalResponse?: V1ColumnRollupIntervalResponse; - columnTopKResponse?: V1ColumnTopKResponse; - columnNullCountResponse?: V1ColumnNullCountResponse; - columnDescriptiveStatisticsResponse?: V1ColumnDescriptiveStatisticsResponse; - columnTimeGrainResponse?: V1ColumnTimeGrainResponse; - columnNumericHistogramResponse?: V1ColumnNumericHistogramResponse; - columnRugHistogramResponse?: V1ColumnRugHistogramResponse; - columnTimeRangeResponse?: V1ColumnTimeRangeResponse; - columnCardinalityResponse?: V1ColumnCardinalityResponse; - columnTimeSeriesResponse?: V1ColumnTimeSeriesResponse; - tableCardinalityResponse?: V1TableCardinalityResponse; - tableColumnsResponse?: V1TableColumnsResponse; - tableRowsResponse?: V1TableRowsResponse; -} - export interface V1ColumnCardinalityRequest { instanceId?: string; connector?: string; @@ -2098,11 +2098,18 @@ export interface V1APIState { [key: string]: any; } +export type V1APISpecOpenapiResponseSchema = { [key: string]: any }; + +export type V1APISpecOpenapiParametersItem = { [key: string]: any }; + export type V1APISpecResolverProperties = { [key: string]: any }; export interface V1APISpec { resolver?: string; resolverProperties?: V1APISpecResolverProperties; + openapiSummary?: string; + openapiParameters?: V1APISpecOpenapiParametersItem[]; + openapiResponseSchema?: V1APISpecOpenapiResponseSchema; } /**