diff --git a/.golangci.yml b/.golangci.yml
index 604c8c5..56f01a7 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -42,6 +42,10 @@ linters-settings:
# Default: 5
min-complexity: 10
+ gocritic:
+ disabled-checks:
+ - appendAssign
+
issues:
exclude-files:
- ".*_test\\.go$"
diff --git a/README.md b/README.md
index 7dbe61e..cdfe5b5 100644
--- a/README.md
+++ b/README.md
@@ -30,13 +30,18 @@ The connector can automatically transform OpenAPI 2.0 and 3.0 definitions to NDC
**Supported content types**
-- `application/json`
-- `application/x-www-form-urlencoded`
-- `application/octet-stream`
-- `multipart/form-data`
-- `application/x-ndjson`
-- `text/*`
-- Upload file content types, e.g.`image/*` from `base64` arguments.
+| Content Type | Supported |
+| --------------------------------- | --------- |
+| application/json | ✅ |
+| application/xml | ✅ |
+| application/x-www-form-urlencoded | ✅ |
+| multipart/form-data | ✅ |
+| application/octet-stream | ✅ (\*) |
+| text/\* | ✅ |
+| application/x-ndjson | ✅ |
+| image/\* | ✅ (\*) |
+
+\*: Upload file content types are converted to `base64` encoding.
## Quick start
@@ -83,9 +88,9 @@ HTTP connector supports both OpenAPI 2 and 3 specifications.
- `oas3`: OpenAPI 3.0/3.1.
- `oas2`: OpenAPI 2.0.
-#### HTTP schema
+#### HTTP Connector schema
-Enum: `http`
+Enum: `ndc`
HTTP schema is the native configuration schema which other specs will be converted to behind the scene. The schema extends the NDC Specification with HTTP configuration and can be converted from other specs by the [NDC HTTP schema CLI](./ndc-http-schema).
diff --git a/connector/connector.go b/connector/connector.go
index 3f73b28..764e7bf 100644
--- a/connector/connector.go
+++ b/connector/connector.go
@@ -19,7 +19,7 @@ type HTTPConnector struct {
capabilities *schema.RawCapabilitiesResponse
rawSchema *schema.RawSchemaResponse
schema *rest.NDCHttpSchema
- client *internal.HTTPClient
+ client internal.Doer
}
// NewHTTPConnector creates a HTTP connector instance
@@ -29,7 +29,7 @@ func NewHTTPConnector(opts ...Option) *HTTPConnector {
}
return &HTTPConnector{
- client: internal.NewHTTPClient(defaultOptions.client),
+ client: defaultOptions.client,
}
}
@@ -93,8 +93,6 @@ func (c *HTTPConnector) ParseConfiguration(ctx context.Context, configurationDir
// In addition, this function should register any
// connector-specific metrics with the metrics registry.
func (c *HTTPConnector) TryInitState(ctx context.Context, configuration *configuration.Configuration, metrics *connector.TelemetryState) (*State, error) {
- c.client.SetTracer(metrics.Tracer)
-
return &State{
Tracer: metrics.Tracer,
}, nil
diff --git a/connector/connector_test.go b/connector/connector_test.go
index 66fa22a..679de25 100644
--- a/connector/connector_test.go
+++ b/connector/connector_test.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"log"
+ "log/slog"
"net/http"
"net/http/httptest"
"os"
@@ -99,7 +100,7 @@ func TestHTTPConnector_emptyServer(t *testing.T) {
func TestHTTPConnector_authentication(t *testing.T) {
apiKey := "random_api_key"
bearerToken := "random_bearer_token"
- // slog.SetLogLoggerLevel(slog.LevelDebug)
+ slog.SetLogLoggerLevel(slog.LevelDebug)
server := createMockServer(t, apiKey, bearerToken)
defer server.Close()
@@ -166,6 +167,19 @@ func TestHTTPConnector_authentication(t *testing.T) {
"body": {
"name": "pet"
}
+ },
+ "fields": {
+ "type": "object",
+ "fields": {
+ "headers": {
+ "column": "headers",
+ "type": "column"
+ },
+ "response": {
+ "column": "response",
+ "type": "column"
+ }
+ }
}
}
],
@@ -287,19 +301,32 @@ func TestHTTPConnector_authentication(t *testing.T) {
},
"fields": {
"fields": {
- "fields": {
- "completed": {
- "column": "completed",
- "type": "column"
- },
- "status": {
- "column": "status",
- "type": "column"
- }
+ "headers": {
+ "column": "headers",
+ "type": "column"
},
- "type": "object"
+ "response": {
+ "column": "response",
+ "type": "column",
+ "fields": {
+ "type": "array",
+ "fields": {
+ "fields": {
+ "completed": {
+ "column": "completed",
+ "type": "column"
+ },
+ "status": {
+ "column": "status",
+ "type": "column"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
},
- "type": "array"
+ "type": "object"
}
}
],
@@ -321,6 +348,137 @@ func TestHTTPConnector_authentication(t *testing.T) {
})
})
+ t.Run("encoding-xml", func(t *testing.T) {
+ reqBody := []byte(`{
+ "operations": [
+ {
+ "type": "procedure",
+ "name": "putPetXml",
+ "arguments": {
+ "body": {
+ "id": 10,
+ "name": "doggie",
+ "category": {
+ "id": 1,
+ "name": "Dogs"
+ },
+ "photoUrls": ["string"],
+ "tags": [
+ {
+ "id": 0,
+ "name": "string"
+ }
+ ],
+ "status": "available"
+ }
+ },
+ "fields": {
+ "fields": {
+ "headers": {
+ "column": "headers",
+ "type": "column"
+ },
+ "response": {
+ "column": "response",
+ "fields": {
+ "fields": {
+ "category": {
+ "column": "category",
+ "fields": {
+ "fields": {
+ "id": {
+ "column": "id",
+ "type": "column"
+ },
+ "name": {
+ "column": "name",
+ "type": "column"
+ }
+ },
+ "type": "object"
+ },
+ "type": "column"
+ },
+ "field": {
+ "column": "field",
+ "type": "column"
+ },
+ "id": {
+ "column": "id",
+ "type": "column"
+ },
+ "name": {
+ "column": "name",
+ "type": "column"
+ },
+ "photoUrls": {
+ "column": "photoUrls",
+ "type": "column"
+ },
+ "status": {
+ "column": "status",
+ "type": "column"
+ },
+ "tags": {
+ "column": "tags",
+ "fields": {
+ "fields": {
+ "fields": {
+ "id": {
+ "column": "id",
+ "type": "column"
+ },
+ "name": {
+ "column": "name",
+ "type": "column"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "type": "column"
+ }
+ },
+ "type": "object"
+ },
+ "type": "column"
+ }
+ },
+ "type": "object"
+ }
+ }
+ ],
+ "collection_relationships": {}
+ }`)
+
+ res, err := http.Post(fmt.Sprintf("%s/mutation", testServer.URL), "application/json", bytes.NewBuffer(reqBody))
+ assert.NilError(t, err)
+ assertHTTPResponse(t, res, http.StatusOK, schema.MutationResponse{
+ OperationResults: []schema.MutationOperationResults{
+ schema.NewProcedureResult(map[string]any{
+ "headers": map[string]any{"Content-Type": string("application/xml")},
+ "response": map[string]any{
+ "id": float64(10),
+ "name": "doggie",
+ "category": map[string]any{
+ "id": float64(1),
+ "name": "Dogs",
+ },
+ "field": nil,
+ "photoUrls": []any{"string"},
+ "tags": []any{
+ map[string]any{
+ "id": float64(0),
+ "name": "string",
+ },
+ },
+ "status": "available",
+ },
+ }).Encode(),
+ },
+ })
+ })
}
func TestHTTPConnector_distribution(t *testing.T) {
@@ -670,6 +828,18 @@ func createMockServer(t *testing.T, apiKey string, bearerToken string) *httptest
}
})
+ mux.HandleFunc("/pet/xml", func(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodPut:
+ w.Header().Add("Content-Type", "application/xml")
+ w.WriteHeader(http.StatusOK)
+
+ _, _ = w.Write([]byte("\n1Dogs10doggiestringavailable0string"))
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ })
+
return httptest.NewServer(mux)
}
diff --git a/connector/internal/client.go b/connector/internal/client.go
index 6aca371..72f86d9 100644
--- a/connector/internal/client.go
+++ b/connector/internal/client.go
@@ -3,6 +3,7 @@ package internal
import (
"bytes"
"context"
+ "encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -17,6 +18,7 @@ import (
"sync"
"time"
+ "github.com/hasura/ndc-http/ndc-http-schema/configuration"
rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
"github.com/hasura/ndc-sdk-go/connector"
"github.com/hasura/ndc-sdk-go/schema"
@@ -36,16 +38,21 @@ type Doer interface {
// HTTPClient represents a http client wrapper with advanced methods
type HTTPClient struct {
- client Doer
- tracer *connector.Tracer
- propagator propagation.TextMapPropagator
+ client Doer
+ schema *rest.NDCHttpSchema
+ forwardHeaders configuration.ForwardHeadersSettings
+ tracer *connector.Tracer
+ propagator propagation.TextMapPropagator
}
// NewHTTPClient creates a http client wrapper
-func NewHTTPClient(client Doer) *HTTPClient {
+func NewHTTPClient(client Doer, httpSchema *rest.NDCHttpSchema, forwardHeaders configuration.ForwardHeadersSettings, tracer *connector.Tracer) *HTTPClient {
return &HTTPClient{
- client: client,
- propagator: otel.GetTextMapPropagator(),
+ client: client,
+ tracer: tracer,
+ schema: httpSchema,
+ forwardHeaders: forwardHeaders,
+ propagator: otel.GetTextMapPropagator(),
}
}
@@ -224,9 +231,21 @@ func (client *HTTPClient) sendSingle(ctx context.Context, request *RetryableRequ
contentType := parseContentType(resp.Header.Get(contentTypeHeader))
if resp.StatusCode >= 400 {
details := make(map[string]any)
- if contentType == rest.ContentTypeJSON && json.Valid(errorBytes) {
- details["error"] = json.RawMessage(errorBytes)
- } else {
+ switch contentType {
+ case rest.ContentTypeJSON:
+ if json.Valid(errorBytes) {
+ details["error"] = json.RawMessage(errorBytes)
+ } else {
+ details["error"] = string(errorBytes)
+ }
+ case rest.ContentTypeXML:
+ errData, err := decodeArbitraryXML(bytes.NewReader(errorBytes))
+ if err != nil {
+ details["error"] = string(errorBytes)
+ } else {
+ details["error"] = errData
+ }
+ default:
details["error"] = string(errorBytes)
}
@@ -235,7 +254,7 @@ func (client *HTTPClient) sendSingle(ctx context.Context, request *RetryableRequ
return nil, nil, schema.NewConnectorError(resp.StatusCode, resp.Status, details)
}
- result, headers, evalErr := evalHTTPResponse(ctx, span, resp, contentType, selection, resultType, logger)
+ result, headers, evalErr := client.evalHTTPResponse(ctx, span, resp, contentType, selection, resultType, logger)
if evalErr != nil {
span.SetStatus(codes.Error, "failed to decode the http response")
span.RecordError(evalErr)
@@ -317,7 +336,7 @@ func (client *HTTPClient) doRequest(ctx context.Context, request *RetryableReque
return resp, body, cancel, nil
}
-func evalHTTPResponse(ctx context.Context, span trace.Span, resp *http.Response, contentType string, selection schema.NestedField, resultType schema.Type, logger *slog.Logger) (any, http.Header, *schema.ConnectorError) {
+func (client *HTTPClient) evalHTTPResponse(ctx context.Context, span trace.Span, resp *http.Response, contentType string, selection schema.NestedField, resultType schema.Type, logger *slog.Logger) (any, http.Header, *schema.ConnectorError) {
if logger.Enabled(ctx, slog.LevelDebug) {
logAttrs := []any{
slog.Int("http_status", resp.StatusCode),
@@ -356,25 +375,26 @@ func evalHTTPResponse(ctx context.Context, span trace.Span, resp *http.Response,
return nil, resp.Header, nil
}
- switch contentType {
- case "":
+ var result any
+ switch {
+ case strings.HasPrefix(contentType, "text/"):
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, err.Error(), nil)
}
- if len(respBody) == 0 {
- return nil, resp.Header, nil
+
+ result = string(respBody)
+ case contentType == rest.ContentTypeXML:
+ field, err := client.extractResultType(resultType)
+ if err != nil {
+ return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, "failed to extract forwarded headers response: "+err.Error(), nil)
}
- return string(respBody), resp.Header, nil
- case "text/plain", "text/html":
- respBody, err := io.ReadAll(resp.Body)
+ result, err = NewXMLDecoder(client.schema).Decode(resp.Body, field)
if err != nil {
return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, err.Error(), nil)
}
-
- return string(respBody), resp.Header, nil
- case rest.ContentTypeJSON:
+ case contentType == rest.ContentTypeJSON:
if len(resultType) > 0 {
namedType, err := resultType.AsNamed()
if err == nil && namedType.Name == string(rest.ScalarString) {
@@ -391,26 +411,17 @@ func evalHTTPResponse(ctx context.Context, span trace.Span, resp *http.Response,
return string(respBytes), resp.Header, nil
}
- return strResult, resp.Header, nil
+ result = strResult
+
+ break
}
}
- var result any
err := json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, err.Error(), nil)
}
- if selection == nil || selection.IsNil() {
- return result, resp.Header, nil
- }
-
- result, err = utils.EvalNestedColumnFields(selection, result)
- if err != nil {
- return nil, nil, schema.InternalServerError(err.Error(), nil)
- }
-
- return result, resp.Header, nil
- case rest.ContentTypeNdJSON:
+ case contentType == rest.ContentTypeNdJSON:
var results []any
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
@@ -421,21 +432,90 @@ func evalHTTPResponse(ctx context.Context, span trace.Span, resp *http.Response,
}
results = append(results, r)
}
- if selection == nil || selection.IsNil() {
- return results, resp.Header, nil
- }
- result, err := utils.EvalNestedColumnFields(selection, any(results))
+ result = results
+ case strings.HasPrefix(contentType, "application/") || strings.HasPrefix(contentType, "image/") || strings.HasPrefix(contentType, "video/"):
+ rawBytes, err := io.ReadAll(resp.Body)
if err != nil {
- return nil, nil, schema.InternalServerError(err.Error(), nil)
+ return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, err.Error(), nil)
}
-
- return result, resp.Header, nil
+ result = base64.StdEncoding.EncodeToString(rawBytes)
default:
return nil, nil, schema.NewConnectorError(http.StatusInternalServerError, "failed to evaluate response", map[string]any{
"cause": "unsupported content type " + contentType,
})
}
+
+ result = client.createHeaderForwardingResponse(result, resp.Header)
+ if len(selection) == 0 {
+ return result, resp.Header, nil
+ }
+
+ result, err := utils.EvalNestedColumnFields(selection, result)
+ if err != nil {
+ return nil, nil, schema.InternalServerError(err.Error(), nil)
+ }
+
+ return result, resp.Header, nil
+}
+
+func (client *HTTPClient) extractResultType(resultType schema.Type) (schema.Type, error) {
+ if !client.forwardHeaders.Enabled || client.forwardHeaders.ResponseHeaders == nil || client.forwardHeaders.ResponseHeaders.ResultField == "" {
+ return resultType, nil
+ }
+
+ return client.extractForwardedHeadersResultType(resultType)
+}
+
+func (client *HTTPClient) extractForwardedHeadersResultType(resultType schema.Type) (schema.Type, error) {
+ rawType, err := resultType.InterfaceT()
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ return client.extractForwardedHeadersResultType(t.UnderlyingType)
+ case *schema.ArrayType:
+ return nil, errors.New("expected object type, got array")
+ case *schema.NamedType:
+ objectType, ok := client.schema.ObjectTypes[t.Name]
+ if !ok {
+ return nil, fmt.Errorf("%s: expected object type", t.Name)
+ }
+
+ if len(objectType.Fields) == 0 {
+ return nil, fmt.Errorf("%s: empty object field", t.Name)
+ }
+
+ resultField, ok := objectType.Fields[client.forwardHeaders.ResponseHeaders.ResultField]
+ if !ok {
+ return nil, fmt.Errorf("%s: result field %s does not exist", t.Name, client.forwardHeaders.ResponseHeaders.ResultField)
+ }
+
+ return resultField.Type, nil
+ case *schema.PredicateType:
+ return nil, errors.New("expected object type, got predicate type")
+ default:
+ return nil, err
+ }
+}
+
+func (client *HTTPClient) createHeaderForwardingResponse(result any, rawHeaders http.Header) any {
+ if !client.forwardHeaders.Enabled || client.forwardHeaders.ResponseHeaders == nil {
+ return result
+ }
+
+ headers := make(map[string]string)
+ for key, values := range rawHeaders {
+ if len(client.forwardHeaders.ResponseHeaders.ForwardHeaders) > 0 && !slices.Contains(client.forwardHeaders.ResponseHeaders.ForwardHeaders, key) {
+ continue
+ }
+ if len(values) > 0 && values[0] != "" {
+ headers[key] = values[0]
+ }
+ }
+
+ return map[string]any{
+ client.forwardHeaders.ResponseHeaders.HeadersField: headers,
+ client.forwardHeaders.ResponseHeaders.ResultField: result,
+ }
}
func parseContentType(input string) string {
diff --git a/connector/internal/multipart.go b/connector/internal/multipart.go
index 72144f0..a224d5f 100644
--- a/connector/internal/multipart.go
+++ b/connector/internal/multipart.go
@@ -49,7 +49,7 @@ func (w *MultipartWriter) WriteDataURI(name string, value any, headers http.Head
escapeQuotes(name), escapeQuotes(name)))
if dataURI.MediaType == "" {
- h.Set("Content-Type", "application/octet-stream")
+ h.Set("Content-Type", schema.ContentTypeOctetStream)
} else {
h.Set("Content-Type", dataURI.MediaType)
}
diff --git a/connector/internal/request_builder.go b/connector/internal/request_builder.go
index 808bc9c..4cfa6cd 100644
--- a/connector/internal/request_builder.go
+++ b/connector/internal/request_builder.go
@@ -84,8 +84,8 @@ func (c *RequestBuilder) buildRequestBody(request *RetryableRequest, rawRequest
return nil
}
- contentType := rawRequest.RequestBody.ContentType
- request.ContentType = contentType
+ contentType := parseContentType(rawRequest.RequestBody.ContentType)
+ request.ContentType = rawRequest.RequestBody.ContentType
bodyInfo, infoOk := c.Operation.Arguments[rest.BodyKey]
bodyData, ok := c.Arguments[rest.BodyKey]
@@ -142,6 +142,16 @@ func (c *RequestBuilder) buildRequestBody(request *RetryableRequest, rawRequest
request.ContentLength = int64(len(bodyBytes))
request.Body = bytes.NewReader(bodyBytes)
+ return nil
+ case contentType == rest.ContentTypeXML:
+ bodyBytes, err := NewXMLEncoder(c.Schema).Encode(&bodyInfo, bodyData)
+ if err != nil {
+ return err
+ }
+
+ request.ContentLength = int64(len(bodyBytes))
+ request.Body = bytes.NewReader(bodyBytes)
+
return nil
default:
return fmt.Errorf("unsupported content type %s", contentType)
@@ -434,7 +444,7 @@ func (c *RequestBuilder) getRequestUploadBody(rawRequest *rest.Request, bodyInfo
if rawRequest.RequestBody == nil || bodyInfo == nil {
return nil
}
- if rawRequest.RequestBody.ContentType == "application/octet-stream" {
+ if rawRequest.RequestBody.ContentType == rest.ContentTypeOctetStream {
return rawRequest.RequestBody
}
diff --git a/connector/internal/request_parameter.go b/connector/internal/request_parameter.go
index b4df690..4c566b0 100644
--- a/connector/internal/request_parameter.go
+++ b/connector/internal/request_parameter.go
@@ -287,25 +287,13 @@ func encodeParameterReflectionValues(reflectValue reflect.Value, fieldPaths []st
}
kind := reflectValue.Kind()
- switch kind {
- case reflect.Bool:
- return []ParameterItem{
- NewParameterItem([]Key{}, []string{strconv.FormatBool(reflectValue.Bool())}),
- }, nil
- case reflect.String:
- return []ParameterItem{NewParameterItem([]Key{}, []string{reflectValue.String()})}, nil
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return []ParameterItem{
- NewParameterItem([]Key{}, []string{strconv.FormatInt(reflectValue.Int(), 10)}),
- }, nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if result, err := stringifySimpleScalar(reflectValue, kind); err == nil {
return []ParameterItem{
- NewParameterItem([]Key{}, []string{strconv.FormatUint(reflectValue.Uint(), 10)}),
- }, nil
- case reflect.Float32, reflect.Float64:
- return []ParameterItem{
- NewParameterItem([]Key{}, []string{fmt.Sprintf("%f", reflectValue.Float())}),
+ NewParameterItem([]Key{}, []string{result}),
}, nil
+ }
+
+ switch kind {
case reflect.Slice, reflect.Array:
return encodeParameterReflectionSlice(reflectValue, fieldPaths)
case reflect.Map, reflect.Interface:
diff --git a/connector/internal/utils.go b/connector/internal/utils.go
index ca6039d..67428dd 100644
--- a/connector/internal/utils.go
+++ b/connector/internal/utils.go
@@ -4,8 +4,11 @@ import (
"fmt"
"net/http"
"net/url"
+ "reflect"
+ "strconv"
"strings"
+ rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
"github.com/hasura/ndc-sdk-go/schema"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
@@ -81,3 +84,80 @@ func cloneURL(input *url.URL) *url.URL {
RawFragment: input.RawFragment,
}
}
+
+func stringifySimpleScalar(val reflect.Value, kind reflect.Kind) (string, error) {
+ switch kind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(val.Int(), 10), nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return strconv.FormatUint(val.Uint(), 10), nil
+ case reflect.Float32, reflect.Float64:
+ return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil
+ case reflect.String:
+ return val.String(), nil
+ case reflect.Bool:
+ return strconv.FormatBool(val.Bool()), nil
+ case reflect.Interface:
+ return fmt.Sprint(val.Interface()), nil
+ default:
+ return "", fmt.Errorf("invalid value: %v", val.Interface())
+ }
+}
+
+func findXMLLeafObjectField(objectType rest.ObjectType) (*rest.ObjectField, string, bool) {
+ var f *rest.ObjectField
+ var fieldName string
+ for key, field := range objectType.Fields {
+ if field.HTTP == nil || field.HTTP.XML == nil {
+ return nil, "", false
+ }
+ if field.HTTP.XML.Text {
+ f = &field
+ fieldName = key
+ } else if !field.HTTP.XML.Attribute {
+ return nil, "", false
+ }
+ }
+
+ return f, fieldName, true
+}
+
+func getTypeSchemaXMLName(typeSchema *rest.TypeSchema, defaultName string) string {
+ if typeSchema != nil {
+ return getXMLName(typeSchema.XML, defaultName)
+ }
+
+ return defaultName
+}
+
+func getXMLName(xmlSchema *rest.XMLSchema, defaultName string) string {
+ if xmlSchema != nil {
+ if xmlSchema.Name != "" {
+ return xmlSchema.GetFullName()
+ }
+
+ if xmlSchema.Prefix != "" {
+ return xmlSchema.Prefix + ":" + defaultName
+ }
+ }
+
+ return defaultName
+}
+
+func getArrayOrNamedType(schemaType schema.Type) (*schema.ArrayType, *schema.NamedType, error) {
+ rawType, err := schemaType.InterfaceT()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ return getArrayOrNamedType(t.UnderlyingType)
+ case *schema.ArrayType:
+ return t, nil, nil
+ case *schema.NamedType:
+ return nil, t, nil
+ default:
+ return nil, nil, nil
+ }
+}
diff --git a/connector/internal/xml_decode.go b/connector/internal/xml_decode.go
new file mode 100644
index 0000000..5389930
--- /dev/null
+++ b/connector/internal/xml_decode.go
@@ -0,0 +1,462 @@
+package internal
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+
+ rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
+ "github.com/hasura/ndc-sdk-go/schema"
+)
+
+// XMLDecoder implements a dynamic XML decoder from the HTTP schema.
+type XMLDecoder struct {
+ schema *rest.NDCHttpSchema
+ decoder *xml.Decoder
+}
+
+// NewXMLDecoder creates a new XML encoder.
+func NewXMLDecoder(httpSchema *rest.NDCHttpSchema) *XMLDecoder {
+ return &XMLDecoder{
+ schema: httpSchema,
+ }
+}
+
+// Decode unmarshals xml bytes to a dynamic type.
+func (c *XMLDecoder) Decode(r io.Reader, resultType schema.Type) (any, error) {
+ c.decoder = xml.NewDecoder(r)
+
+ for {
+ token, err := c.decoder.Token()
+ if err != nil {
+ return nil, err
+ }
+ if token == nil {
+ break
+ }
+
+ if se, ok := token.(xml.StartElement); ok {
+ xmlTree := createXMLBlock(se)
+ if err := evalXMLTree(c.decoder, xmlTree); err != nil {
+ return nil, fmt.Errorf("failed to decode the xml result: %w", err)
+ }
+
+ result, err := c.evalXMLField(xmlTree, "", rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: resultType,
+ },
+ HTTP: &rest.TypeSchema{},
+ }, []string{})
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode the xml result: %w", err)
+ }
+
+ return result, nil
+ }
+ }
+
+ return nil, nil
+}
+
+func (c *XMLDecoder) evalXMLField(block *xmlBlock, fieldName string, field rest.ObjectField, fieldPaths []string) (any, error) {
+ rawType, err := field.Type.InterfaceT()
+ if err != nil {
+ return nil, err
+ }
+
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ return c.evalXMLField(block, fieldName, rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: t.UnderlyingType,
+ },
+ HTTP: field.HTTP,
+ }, fieldPaths)
+ case *schema.ArrayType:
+ return c.evalArrayField(block, fieldName, field, t, fieldPaths)
+ case *schema.NamedType:
+ return c.evalNamedField(block, t, fieldPaths)
+ default:
+ return nil, err
+ }
+}
+
+func (c *XMLDecoder) getArrayItemObjectField(field rest.ObjectField, t *schema.ArrayType) rest.ObjectField {
+ fieldItem := rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: t.ElementType,
+ },
+ }
+
+ if field.HTTP != nil && field.HTTP.Items != nil {
+ fieldItem.HTTP = field.HTTP.Items
+ }
+
+ return fieldItem
+}
+func (c *XMLDecoder) evalArrayField(block *xmlBlock, fieldName string, field rest.ObjectField, t *schema.ArrayType, fieldPaths []string) (any, error) {
+ if block.Fields == nil {
+ return nil, nil
+ }
+ if len(block.Fields) == 0 {
+ return []any{}, nil
+ }
+
+ var elements []xmlBlock
+ itemTokenName := fieldName
+ wrapped := len(fieldPaths) == 0
+ fieldItem := c.getArrayItemObjectField(field, t)
+
+ if field.HTTP != nil {
+ wrapped = wrapped || (field.HTTP.XML != nil && field.HTTP.XML.Wrapped)
+ if field.HTTP.Items != nil && field.HTTP.Items.XML != nil && field.HTTP.Items.XML.Name != "" {
+ itemTokenName = field.HTTP.Items.XML.Name
+ }
+ }
+
+ if wrapped {
+ for _, elems := range block.Fields {
+ if len(elems) > 0 {
+ elements = elems
+
+ break
+ }
+ }
+ } else if elems, ok := block.Fields[itemTokenName]; ok {
+ elements = elems
+ }
+
+ return c.evalArrayElements(elements, itemTokenName, fieldItem, fieldPaths)
+}
+
+func (c *XMLDecoder) evalArrayElements(elements []xmlBlock, itemTokenName string, fieldItem rest.ObjectField, fieldPaths []string) ([]any, error) {
+ if len(elements) == 0 {
+ return []any{}, nil
+ }
+
+ results := make([]any, len(elements))
+ for i, elem := range elements {
+ result, err := c.evalXMLField(&elem, itemTokenName, fieldItem, append(fieldPaths, strconv.Itoa(i)))
+ if err != nil {
+ return nil, err
+ }
+ results[i] = result
+ }
+
+ return results, nil
+}
+
+func (c *XMLDecoder) evalNamedField(block *xmlBlock, t *schema.NamedType, fieldPaths []string) (any, error) {
+ if scalarType, ok := c.schema.ScalarTypes[t.Name]; ok {
+ return c.decodeSimpleScalarValue(block, scalarType, fieldPaths)
+ }
+
+ objectType, ok := c.schema.ObjectTypes[t.Name]
+ if !ok {
+ return nil, fmt.Errorf("%s: invalid response type", strings.Join(fieldPaths, "."))
+ }
+
+ result := map[string]any{}
+
+ for _, attr := range block.Start.Attr {
+ for key, objectField := range objectType.Fields {
+ if objectField.HTTP == nil || objectField.HTTP.XML == nil || !objectField.HTTP.XML.Attribute {
+ continue
+ }
+
+ xmlKey := key
+ if objectField.HTTP.XML.Name != "" {
+ xmlKey = objectField.HTTP.XML.Name
+ }
+ if attr.Name.Local != xmlKey {
+ continue
+ }
+
+ attrValue, err := c.evalAttribute(objectField.Type, attr, append(fieldPaths, key))
+ if err != nil {
+ return nil, err
+ }
+
+ result[key] = attrValue
+
+ break
+ }
+ }
+
+ _, textFieldName, isLeaf := findXMLLeafObjectField(objectType)
+ if isLeaf {
+ textValue, err := c.decodeSimpleScalarValue(block, c.schema.ScalarTypes[string(rest.ScalarString)], fieldPaths)
+ if err != nil {
+ return nil, err
+ }
+
+ result[textFieldName] = textValue
+
+ return result, nil
+ }
+
+ for key, objectField := range objectType.Fields {
+ if objectField.HTTP == nil {
+ continue
+ }
+ xmlKey := key
+ if objectField.HTTP.XML != nil {
+ if objectField.HTTP.XML.Attribute {
+ continue
+ }
+
+ xmlKey = getXMLName(objectField.HTTP.XML, key)
+ }
+
+ fieldElems, ok := block.Fields[xmlKey]
+ if !ok || fieldElems == nil {
+ continue
+ }
+
+ switch len(fieldElems) {
+ case 0:
+ result[key] = []any{}
+ case 1:
+ propPaths := append(fieldPaths, key)
+ if objectField.HTTP.XML != nil && objectField.HTTP.XML.Wrapped {
+ // this can be a wrapped array
+ fieldResult, err := c.evalXMLField(&fieldElems[0], xmlKey, objectField, propPaths)
+ if err != nil {
+ return nil, err
+ }
+
+ result[key] = fieldResult
+
+ continue
+ }
+
+ at, nt, err := getArrayOrNamedType(objectField.Type)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", strings.Join(propPaths, "."), err)
+ }
+
+ if at != nil {
+ fieldItem := c.getArrayItemObjectField(objectField, at)
+ fieldResult, err := c.evalArrayElements(fieldElems, xmlKey, fieldItem, propPaths)
+ if err != nil {
+ return nil, err
+ }
+
+ result[key] = fieldResult
+ } else if nt != nil {
+ fieldResult, err := c.evalNamedField(&fieldElems[0], nt, propPaths)
+ if err != nil {
+ return nil, err
+ }
+
+ result[key] = fieldResult
+ }
+ default:
+ fieldResult, err := c.evalXMLField(&xmlBlock{
+ Start: fieldElems[0].Start,
+ Fields: map[string][]xmlBlock{
+ xmlKey: fieldElems,
+ },
+ }, xmlKey, objectField, append(fieldPaths, key))
+ if err != nil {
+ return nil, err
+ }
+
+ result[key] = fieldResult
+ }
+ }
+
+ return result, nil
+}
+
+func (c *XMLDecoder) evalAttribute(schemaType schema.Type, attr xml.Attr, fieldPaths []string) (any, error) {
+ rawType, err := schemaType.InterfaceT()
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ return c.evalAttribute(t.UnderlyingType, attr, fieldPaths)
+ case *schema.ArrayType:
+ var result any
+ if err := json.Unmarshal([]byte(attr.Value), &result); err != nil {
+ return nil, fmt.Errorf("%s: failed to decode xml attribute, %w", strings.Join(fieldPaths, ","), err)
+ }
+
+ return result, nil
+ case *schema.NamedType:
+ if scalarType, ok := c.schema.ScalarTypes[t.Name]; ok {
+ return c.decodeSimpleScalarValue(&xmlBlock{
+ Data: attr.Value,
+ }, scalarType, fieldPaths)
+ }
+
+ var result any
+ if err := json.Unmarshal([]byte(attr.Value), &result); err != nil {
+ return nil, fmt.Errorf("%s: failed to decode xml attribute, %w", strings.Join(fieldPaths, ","), err)
+ }
+
+ return result, nil
+ default:
+ return nil, err
+ }
+}
+
+func (c *XMLDecoder) decodeSimpleScalarValue(block *xmlBlock, scalarType schema.ScalarType, fieldPaths []string) (any, error) {
+ respType, err := scalarType.Representation.InterfaceT()
+
+ var result any = nil
+ switch respType.(type) {
+ case *schema.TypeRepresentationString:
+ result = block.Data
+ case *schema.TypeRepresentationDate, *schema.TypeRepresentationTimestamp, *schema.TypeRepresentationTimestampTZ, *schema.TypeRepresentationUUID, *schema.TypeRepresentationEnum:
+ if len(block.Data) > 0 {
+ result = block.Data
+ }
+ case *schema.TypeRepresentationBytes:
+ result = block.Data
+ case *schema.TypeRepresentationBoolean:
+ if len(block.Data) == 0 {
+ break
+ }
+
+ result, err = strconv.ParseBool(block.Data)
+ case *schema.TypeRepresentationBigDecimal, *schema.TypeRepresentationBigInteger:
+ if len(block.Data) == 0 {
+ break
+ }
+
+ result = block.Data
+ case *schema.TypeRepresentationInteger, *schema.TypeRepresentationInt8, *schema.TypeRepresentationInt16, *schema.TypeRepresentationInt32, *schema.TypeRepresentationInt64: //nolint:all
+ if len(block.Data) == 0 {
+ break
+ }
+
+ result, err = strconv.ParseInt(block.Data, 10, 64)
+ case *schema.TypeRepresentationNumber, *schema.TypeRepresentationFloat32, *schema.TypeRepresentationFloat64: //nolint:all
+ if len(block.Data) == 0 {
+ break
+ }
+
+ result, err = strconv.ParseFloat(block.Data, 64)
+ case *schema.TypeRepresentationGeography, *schema.TypeRepresentationGeometry, *schema.TypeRepresentationJSON:
+ result = decodeArbitraryXMLBlock(block)
+ }
+
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ return result, nil
+}
+
+func decodeArbitraryXMLBlock(block *xmlBlock) any {
+ if len(block.Start.Attr) == 0 && len(block.Fields) == 0 {
+ return block.Data
+ }
+
+ result := make(map[string]any)
+ if len(block.Start.Attr) > 0 {
+ attributes := make(map[string]string)
+ for _, attr := range block.Start.Attr {
+ attributes[attr.Name.Local] = attr.Value
+ }
+ result["attributes"] = attributes
+ }
+
+ if len(block.Fields) == 0 {
+ result["content"] = block.Data
+
+ return result
+ }
+
+ for key, field := range block.Fields {
+ switch len(field) {
+ case 0:
+ case 1:
+ // limitation: we can't know if the array is wrapped
+ result[key] = decodeArbitraryXMLBlock(&field[0])
+ default:
+ items := make([]any, len(field))
+ for i, f := range field {
+ items[i] = decodeArbitraryXMLBlock(&f)
+ }
+ result[key] = items
+ }
+ }
+
+ return result
+}
+
+type xmlBlock struct {
+ Start xml.StartElement
+ Data string
+ Fields map[string][]xmlBlock
+}
+
+func createXMLBlock(start xml.StartElement) *xmlBlock {
+ return &xmlBlock{
+ Start: start,
+ Fields: map[string][]xmlBlock{},
+ }
+}
+
+func evalXMLTree(decoder *xml.Decoder, block *xmlBlock) error {
+L:
+ for {
+ nextToken, err := decoder.Token()
+ if err != nil {
+ return err
+ }
+
+ if nextToken == nil {
+ return nil
+ }
+
+ switch tok := nextToken.(type) {
+ case xml.StartElement:
+ childBlock := createXMLBlock(tok)
+ if err := evalXMLTree(decoder, childBlock); err != nil {
+ return err
+ }
+ block.Fields[tok.Name.Local] = append(block.Fields[tok.Name.Local], *childBlock)
+ case xml.CharData:
+ block.Data = string(tok)
+ case xml.EndElement:
+ break L
+ }
+ }
+
+ return nil
+}
+
+func decodeArbitraryXML(r io.Reader) (any, error) {
+ decoder := xml.NewDecoder(r)
+
+ for {
+ token, err := decoder.Token()
+ if err != nil {
+ return nil, err
+ }
+ if token == nil {
+ break
+ }
+
+ if se, ok := token.(xml.StartElement); ok {
+ xmlTree := createXMLBlock(se)
+ if err := evalXMLTree(decoder, xmlTree); err != nil {
+ return nil, fmt.Errorf("failed to decode the xml result: %w", err)
+ }
+
+ result := decodeArbitraryXMLBlock(xmlTree)
+
+ return result, nil
+ }
+ }
+
+ return nil, nil
+}
diff --git a/connector/internal/xml_decode_test.go b/connector/internal/xml_decode_test.go
new file mode 100644
index 0000000..a2a21fd
--- /dev/null
+++ b/connector/internal/xml_decode_test.go
@@ -0,0 +1,70 @@
+package internal
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/hasura/ndc-sdk-go/schema"
+ "gotest.tools/v3/assert"
+)
+
+func TestDecodeXML(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Body string
+ Type schema.Type
+ Expected map[string]any
+ }{
+ {
+ Name: "getSearchXml",
+ Type: schema.NewNamedType("JSON").Encode(),
+ Body: `x86_64x86_64Standard OBS instance at build.opensuse.orgThis instance delivers the default build targets for OBS.https://api.opensuse.org/public`,
+ Expected: map[string]any{
+ "project": []any{
+ map[string]any{
+ "attributes": map[string]string{"name": "home:Admin"},
+ "description": string(""),
+ "person": map[string]any{
+ "attributes": map[string]string{"role": "maintainer", "userid": "Admin"},
+ "content": string(""),
+ },
+ "repository": []any{
+ map[string]any{
+ "arch": string("x86_64"),
+ "attributes": map[string]string{"name": "openSUSE_Tumbleweed"},
+ "path": map[string]any{
+ "attributes": map[string]string{"project": "openSUSE.org:openSUSE:Factory", "repository": "snapshot"},
+ "content": string(""),
+ },
+ },
+ map[string]any{
+ "arch": string("x86_64"),
+ "attributes": map[string]string{"name": "15.3"},
+ "path": map[string]any{
+ "attributes": map[string]string{"project": "openSUSE.org:openSUSE:Leap:15.3", "repository": "standard"},
+ "content": string(""),
+ },
+ },
+ },
+ "title": string(""),
+ },
+ map[string]any{
+ "attributes": map[string]string{"name": "openSUSE.org"},
+ "description": string("This instance delivers the default build targets for OBS."),
+ "remoteurl": string("https://api.opensuse.org/public"),
+ "title": string("Standard OBS instance at build.opensuse.org"),
+ },
+ },
+ },
+ },
+ }
+
+ ndcSchema := createMockSchema(t)
+ for _, tc := range testCases {
+ t.Run(tc.Name, func(t *testing.T) {
+ result, err := NewXMLDecoder(ndcSchema).Decode(strings.NewReader(tc.Body), tc.Type)
+ assert.NilError(t, err)
+ assert.DeepEqual(t, tc.Expected, result)
+ })
+ }
+}
diff --git a/connector/internal/xml_encode.go b/connector/internal/xml_encode.go
new file mode 100644
index 0000000..14dc64e
--- /dev/null
+++ b/connector/internal/xml_encode.go
@@ -0,0 +1,325 @@
+package internal
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
+ "github.com/hasura/ndc-sdk-go/schema"
+ "github.com/hasura/ndc-sdk-go/utils"
+)
+
+// XMLEncoder implements a dynamic XML encoder from the HTTP schema.
+type XMLEncoder struct {
+ schema *rest.NDCHttpSchema
+}
+
+// NewXMLEncoder creates a new XML encoder.
+func NewXMLEncoder(httpSchema *rest.NDCHttpSchema) *XMLEncoder {
+ return &XMLEncoder{
+ schema: httpSchema,
+ }
+}
+
+// Encode marshals the body to xml bytes.
+func (c *XMLEncoder) Encode(bodyInfo *rest.ArgumentInfo, bodyData any) ([]byte, error) {
+ var buf bytes.Buffer
+ enc := xml.NewEncoder(&buf)
+
+ err := c.evalXMLField(enc, "", rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: bodyInfo.Type,
+ },
+ HTTP: bodyInfo.HTTP.Schema,
+ }, bodyData, []string{})
+
+ if err != nil {
+ return nil, err
+ }
+
+ if err := enc.Flush(); err != nil {
+ return nil, err
+ }
+
+ return append([]byte(xml.Header), buf.Bytes()...), nil
+}
+
+func (c *XMLEncoder) evalXMLField(enc *xml.Encoder, name string, field rest.ObjectField, value any, fieldPaths []string) error {
+ rawType, err := field.Type.InterfaceT()
+ var innerValue reflect.Value
+ var notNull bool
+
+ if value != nil {
+ innerValue, notNull = utils.UnwrapPointerFromAnyToReflectValue(value)
+ }
+
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ if !notNull {
+ return nil
+ }
+
+ return c.evalXMLField(enc, name, rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: t.UnderlyingType,
+ },
+ HTTP: field.HTTP,
+ }, innerValue.Interface(), fieldPaths)
+ case *schema.ArrayType:
+ if !notNull {
+ return fmt.Errorf("%s: expect an array, got null", strings.Join(fieldPaths, "."))
+ }
+
+ vi := innerValue.Interface()
+ values, ok := vi.([]any)
+ if !ok {
+ return fmt.Errorf("%s: expect an array, got %v", strings.Join(fieldPaths, "."), vi)
+ }
+
+ var wrapped bool
+ xmlName := name
+ if field.HTTP.XML != nil {
+ wrapped = field.HTTP.XML.Wrapped
+ if field.HTTP.XML.Name != "" {
+ xmlName = field.HTTP.XML.Name
+ }
+ }
+
+ if wrapped {
+ err := enc.EncodeToken(xml.StartElement{
+ Name: xml.Name{Space: "", Local: xmlName},
+ })
+ if err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+ }
+
+ for i, v := range values {
+ err := c.evalXMLField(enc, name, rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Type: t.ElementType,
+ },
+ HTTP: field.HTTP.Items,
+ }, v, append(fieldPaths, strconv.FormatInt(int64(i), 10)))
+
+ if err != nil {
+ return err
+ }
+ }
+
+ if wrapped {
+ err := enc.EncodeToken(xml.EndElement{
+ Name: xml.Name{Space: "", Local: xmlName},
+ })
+ if err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+ }
+
+ return nil
+ case *schema.NamedType:
+ if !notNull {
+ return fmt.Errorf("%s: expect a non-null type, got null", strings.Join(fieldPaths, "."))
+ }
+
+ xmlName := getTypeSchemaXMLName(field.HTTP, name)
+ var attributes []xml.Attr
+ if field.HTTP != nil && field.HTTP.XML != nil && field.HTTP.XML.Namespace != "" {
+ attributes = append(attributes, field.HTTP.XML.GetNamespaceAttribute())
+ }
+
+ if _, ok := c.schema.ScalarTypes[t.Name]; ok {
+ if err := c.encodeSimpleScalar(enc, xmlName, reflect.ValueOf(value), attributes); err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ return nil
+ }
+
+ objectType, ok := c.schema.ObjectTypes[t.Name]
+ if !ok {
+ return fmt.Errorf("%s: invalid type %s", strings.Join(fieldPaths, "."), t.Name)
+ }
+
+ iv := innerValue.Interface()
+ values, ok := iv.(map[string]any)
+ if !ok {
+ return fmt.Errorf("%s: expected a map, got %s", strings.Join(fieldPaths, "."), innerValue.Kind())
+ }
+
+ attributes, fieldKeys, err := c.evalAttributes(objectType, utils.GetSortedKeys(objectType.Fields), values, fieldPaths)
+ if err != nil {
+ return err
+ }
+
+ xmlName = getXMLName(objectType.XML, name)
+ if objectType.XML != nil && objectType.XML.Namespace != "" {
+ attributes = append(attributes, objectType.XML.GetNamespaceAttribute())
+ }
+
+ err = enc.EncodeToken(xml.StartElement{
+ Name: xml.Name{Space: "", Local: xmlName},
+ Attr: attributes,
+ })
+ if err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ if len(fieldKeys) == 1 && objectType.Fields[fieldKeys[0]].HTTP != nil && objectType.Fields[fieldKeys[0]].HTTP.XML != nil && objectType.Fields[fieldKeys[0]].HTTP.XML.Text {
+ objectField := objectType.Fields[fieldKeys[0]]
+ fieldValue, ok := values[fieldKeys[0]]
+ if ok && fieldValue != nil {
+ textValue, err := c.encodeXMLText(objectField.Type, reflect.ValueOf(fieldValue), fieldPaths)
+ if err != nil {
+ return err
+ }
+
+ if textValue != nil {
+ err = enc.EncodeToken(xml.CharData(*textValue))
+ if err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+ }
+ }
+ } else {
+ for _, key := range fieldKeys {
+ objectField := objectType.Fields[key]
+ fieldValue := values[key]
+ if err := c.evalXMLField(enc, key, objectField, fieldValue, append(fieldPaths, key)); err != nil {
+ return err
+ }
+ }
+ }
+
+ err = enc.EncodeToken(xml.EndElement{
+ Name: xml.Name{Space: "", Local: xmlName},
+ })
+ if err != nil {
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ return nil
+ default:
+ return fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+}
+
+func (c *XMLEncoder) evalAttributes(objectType rest.ObjectType, keys []string, values map[string]any, fieldPaths []string) ([]xml.Attr, []string, error) {
+ var attrs []xml.Attr
+ remainKeys := make([]string, 0)
+ for _, key := range keys {
+ objectField := objectType.Fields[key]
+ isNullXML := objectField.HTTP == nil || objectField.HTTP.XML == nil
+ if isNullXML || !objectField.HTTP.XML.Attribute {
+ remainKeys = append(remainKeys, key)
+
+ continue
+ }
+
+ value, ok := values[key]
+ if !ok || value == nil {
+ continue
+ }
+
+ // the attribute value is usually a primitive scalar,
+ // otherwise just encode the value as json string
+ str, err := c.encodeXMLText(objectField.Type, reflect.ValueOf(value), append(fieldPaths, key))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if str == nil {
+ continue
+ }
+
+ attrs = append(attrs, xml.Attr{
+ Name: xml.Name{Local: getTypeSchemaXMLName(objectField.HTTP, key)},
+ Value: *str,
+ })
+ }
+
+ return attrs, remainKeys, nil
+}
+
+func (c *XMLEncoder) encodeXMLText(schemaType schema.Type, value reflect.Value, fieldPaths []string) (*string, error) {
+ rawType, err := schemaType.InterfaceT()
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ innerValue, notNull := utils.UnwrapPointerFromReflectValue(value)
+
+ switch t := rawType.(type) {
+ case *schema.NullableType:
+ if !notNull {
+ return nil, nil
+ }
+
+ return c.encodeXMLText(t.UnderlyingType, value, fieldPaths)
+ case *schema.ArrayType:
+ if !notNull {
+ return nil, fmt.Errorf("%s: field it required", strings.Join(fieldPaths, "."))
+ }
+
+ resultBytes, err := json.Marshal(innerValue.Interface())
+ if err != nil {
+ return nil, fmt.Errorf("%s: failed to encode xml attribute, %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ result := string(resultBytes)
+
+ return &result, nil
+ case *schema.NamedType:
+ if !notNull {
+ return nil, fmt.Errorf("%s, field it required", strings.Join(fieldPaths, "."))
+ }
+
+ if _, ok := c.schema.ScalarTypes[t.Name]; ok {
+ str, err := stringifySimpleScalar(value, value.Kind())
+ if err != nil {
+ return nil, err
+ }
+
+ return &str, nil
+ }
+
+ resultBytes, err := json.Marshal(innerValue.Interface())
+ if err != nil {
+ return nil, fmt.Errorf("%s: failed to encode xml attribute, %w", strings.Join(fieldPaths, "."), err)
+ }
+
+ result := string(resultBytes)
+
+ return &result, nil
+ default:
+ return nil, fmt.Errorf("%s: failed to encode xml attribute, unsupported schema type", strings.Join(fieldPaths, "."))
+ }
+}
+
+func (c *XMLEncoder) encodeSimpleScalar(enc *xml.Encoder, name string, value reflect.Value, attributes []xml.Attr) error {
+ str, err := stringifySimpleScalar(value, value.Kind())
+ if err != nil {
+ return err
+ }
+
+ err = enc.EncodeToken(xml.StartElement{
+ Name: xml.Name{Space: "", Local: name},
+ Attr: attributes,
+ })
+ if err != nil {
+ return err
+ }
+
+ if err := enc.EncodeToken(xml.CharData(str)); err != nil {
+ return err
+ }
+
+ return enc.EncodeToken(xml.EndElement{
+ Name: xml.Name{Space: "", Local: name},
+ })
+}
diff --git a/connector/internal/xml_encode_test.go b/connector/internal/xml_encode_test.go
new file mode 100644
index 0000000..783c38d
--- /dev/null
+++ b/connector/internal/xml_encode_test.go
@@ -0,0 +1,123 @@
+package internal
+
+import (
+ "bytes"
+ "testing"
+
+ rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
+ "gotest.tools/v3/assert"
+)
+
+func TestCreateXMLForm(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Body map[string]any
+
+ Expected string
+ }{
+ {
+ Name: "putPetXml",
+ Body: map[string]any{
+ "id": int64(10),
+ "name": "doggie",
+ "category": map[string]any{
+ "id": int64(1),
+ "name": "Dogs",
+ },
+ "photoUrls": []any{"string"},
+ "tags": []any{
+ map[string]any{
+ "id": int64(0),
+ "name": "string",
+ },
+ },
+ "status": "available",
+ },
+ Expected: "\n1Dogs10doggiestringavailable0string",
+ },
+ {
+ Name: "putCommentXml",
+ Body: map[string]any{
+ "user": "Iggy",
+ "comment_count": int64(6),
+ "comment": []any{
+ map[string]any{
+ "who": "Iggy",
+ "when": "2021-10-15 13:28:22 UTC",
+ "id": int64(1),
+ "bsrequest": int64(115),
+ "xmlValue": "This is a pretty cool request!",
+ },
+ map[string]any{
+ "who": "Iggy",
+ "when": "2021-10-15 13:49:39 UTC",
+ "id": int64(2),
+ "project": "home:Admin",
+ "xmlValue": "This is a pretty cool project!",
+ },
+ map[string]any{
+ "who": "Iggy",
+ "when": "2021-10-15 13:54:38 UTC",
+ "id": int64(3),
+ "project": "home:Admin",
+ "package": "0ad",
+ "xmlValue": "This is a pretty cool package!",
+ },
+ },
+ },
+ Expected: `
+This is a pretty cool request!This is a pretty cool project!This is a pretty cool package!`,
+ },
+ {
+ Name: "putBookXml",
+ Body: map[string]any{
+ "id": int64(0),
+ "title": "string",
+ "author": "Author",
+ "attr": "foo",
+ },
+ Expected: `
+Author0string`,
+ },
+ {
+ Name: "putCommentXml",
+ Body: map[string]any{
+ "project": "home:Admin",
+ "package": "0ad",
+ "comment": []any{
+ map[string]any{
+ "who": "Iggy",
+ "when": "2021-10-15 13:28:22 UTC",
+ "id": int64(1),
+ "xmlValue": "This is a pretty cool comment!",
+ },
+ },
+ },
+ Expected: "\nThis is a pretty cool comment!",
+ },
+ }
+
+ ndcSchema := createMockSchema(t)
+ for _, tc := range testCases {
+ t.Run(tc.Name, func(t *testing.T) {
+ var info *rest.OperationInfo
+ for key, f := range ndcSchema.Procedures {
+ if key == tc.Name {
+ info = &f
+ break
+ }
+ }
+ assert.Assert(t, info != nil)
+ argumentInfo := info.Arguments["body"]
+ result, err := NewXMLEncoder(ndcSchema).Encode(&argumentInfo, tc.Body)
+ assert.NilError(t, err)
+ assert.Equal(t, tc.Expected, string(result))
+
+ dec := NewXMLDecoder(ndcSchema)
+ parsedResult, err := dec.Decode(bytes.NewBuffer([]byte(tc.Expected)), info.ResultType)
+ assert.NilError(t, err)
+
+ assert.DeepEqual(t, tc.Body, parsedResult)
+ })
+ }
+}
diff --git a/connector/mutation.go b/connector/mutation.go
index 0fe8f94..65e8034 100644
--- a/connector/mutation.go
+++ b/connector/mutation.go
@@ -32,7 +32,7 @@ func (c *HTTPConnector) MutationExplain(ctx context.Context, configuration *conf
operation := request.Operations[0]
switch operation.Type {
case schema.MutationOperationProcedure:
- httpRequest, _, httpOptions, err := c.explainProcedure(&operation)
+ httpRequest, _, _, httpOptions, err := c.explainProcedure(&operation)
if err != nil {
return nil, err
}
@@ -43,16 +43,16 @@ func (c *HTTPConnector) MutationExplain(ctx context.Context, configuration *conf
}
}
-func (c *HTTPConnector) explainProcedure(operation *schema.MutationOperation) (*internal.RetryableRequest, *rest.OperationInfo, *internal.HTTPOptions, error) {
+func (c *HTTPConnector) explainProcedure(operation *schema.MutationOperation) (*internal.RetryableRequest, *rest.OperationInfo, *configuration.NDCHttpRuntimeSchema, *internal.HTTPOptions, error) {
procedure, metadata, err := c.metadata.GetProcedure(operation.Name)
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// 1. resolve arguments, evaluate URL and query parameters
var rawArgs map[string]any
if err := json.Unmarshal(operation.Arguments, &rawArgs); err != nil {
- return nil, nil, nil, schema.BadRequestError("failed to decode arguments", map[string]any{
+ return nil, nil, nil, nil, schema.BadRequestError("failed to decode arguments", map[string]any{
"cause": err.Error(),
})
}
@@ -61,25 +61,25 @@ func (c *HTTPConnector) explainProcedure(operation *schema.MutationOperation) (*
builder := internal.NewRequestBuilder(c.schema, procedure, rawArgs, metadata.Runtime)
httpRequest, err := builder.Build()
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
if err := c.evalForwardedHeaders(httpRequest, rawArgs); err != nil {
- return nil, nil, nil, schema.UnprocessableContentError("invalid forwarded headers", map[string]any{
+ return nil, nil, nil, nil, schema.UnprocessableContentError("invalid forwarded headers", map[string]any{
"cause": err.Error(),
})
}
httpOptions, err := c.parseHTTPOptionsFromArguments(procedure.Arguments, rawArgs)
if err != nil {
- return nil, nil, nil, schema.UnprocessableContentError("invalid http options", map[string]any{
+ return nil, nil, nil, nil, schema.UnprocessableContentError("invalid http options", map[string]any{
"cause": err.Error(),
})
}
httpOptions.Settings = metadata.Settings
- return httpRequest, procedure, httpOptions, nil
+ return httpRequest, procedure, &metadata, httpOptions, nil
}
func (c *HTTPConnector) execMutationSync(ctx context.Context, state *State, request *schema.MutationRequest) (*schema.MutationResponse, error) {
@@ -130,7 +130,7 @@ func (c *HTTPConnector) execMutationOperation(parentCtx context.Context, state *
ctx, span := state.Tracer.Start(parentCtx, fmt.Sprintf("Execute Operation %d", index))
defer span.End()
- httpRequest, procedure, httpOptions, err := c.explainProcedure(&operation)
+ httpRequest, procedure, metadata, httpOptions, err := c.explainProcedure(&operation)
if err != nil {
span.SetStatus(codes.Error, "failed to explain mutation")
span.RecordError(err)
@@ -139,7 +139,8 @@ func (c *HTTPConnector) execMutationOperation(parentCtx context.Context, state *
}
httpOptions.Concurrency = c.config.Concurrency.HTTP
- result, headers, err := c.client.Send(ctx, httpRequest, operation.Fields, procedure.ResultType, httpOptions)
+ client := internal.NewHTTPClient(c.client, metadata.NDCHttpSchema, c.config.ForwardHeaders, state.Tracer)
+ result, _, err := client.Send(ctx, httpRequest, operation.Fields, procedure.ResultType, httpOptions)
if err != nil {
span.SetStatus(codes.Error, "failed to execute mutation")
span.RecordError(err)
@@ -147,5 +148,5 @@ func (c *HTTPConnector) execMutationOperation(parentCtx context.Context, state *
return nil, err
}
- return schema.NewProcedureResult(c.createHeaderForwardingResponse(result, headers)).Encode(), nil
+ return schema.NewProcedureResult(result).Encode(), nil
}
diff --git a/connector/query.go b/connector/query.go
index b0347dc..1c6bbe1 100644
--- a/connector/query.go
+++ b/connector/query.go
@@ -40,7 +40,7 @@ func (c *HTTPConnector) QueryExplain(ctx context.Context, configuration *configu
requestVars = []schema.QueryRequestVariablesElem{make(schema.QueryRequestVariablesElem)}
}
- httpRequest, _, httpOptions, err := c.explainQuery(request, requestVars[0])
+ httpRequest, _, _, httpOptions, err := c.explainQuery(request, requestVars[0])
if err != nil {
return nil, err
}
@@ -48,16 +48,16 @@ func (c *HTTPConnector) QueryExplain(ctx context.Context, configuration *configu
return serializeExplainResponse(httpRequest, httpOptions)
}
-func (c *HTTPConnector) explainQuery(request *schema.QueryRequest, variables map[string]any) (*internal.RetryableRequest, *rest.OperationInfo, *internal.HTTPOptions, error) {
+func (c *HTTPConnector) explainQuery(request *schema.QueryRequest, variables map[string]any) (*internal.RetryableRequest, *rest.OperationInfo, *configuration.NDCHttpRuntimeSchema, *internal.HTTPOptions, error) {
function, metadata, err := c.metadata.GetFunction(request.Collection)
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// 1. resolve arguments, evaluate URL and query parameters
rawArgs, err := utils.ResolveArgumentVariables(request.Arguments, variables)
if err != nil {
- return nil, nil, nil, schema.UnprocessableContentError("failed to resolve argument variables", map[string]any{
+ return nil, nil, nil, nil, schema.UnprocessableContentError("failed to resolve argument variables", map[string]any{
"cause": err.Error(),
})
}
@@ -65,25 +65,25 @@ func (c *HTTPConnector) explainQuery(request *schema.QueryRequest, variables map
// 2. build the request
req, err := internal.NewRequestBuilder(c.schema, function, rawArgs, metadata.Runtime).Build()
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
if err := c.evalForwardedHeaders(req, rawArgs); err != nil {
- return nil, nil, nil, schema.UnprocessableContentError("invalid forwarded headers", map[string]any{
+ return nil, nil, nil, nil, schema.UnprocessableContentError("invalid forwarded headers", map[string]any{
"cause": err.Error(),
})
}
httpOptions, err := c.parseHTTPOptionsFromArguments(function.Arguments, rawArgs)
if err != nil {
- return nil, nil, nil, schema.UnprocessableContentError("invalid http options", map[string]any{
+ return nil, nil, nil, nil, schema.UnprocessableContentError("invalid http options", map[string]any{
"cause": err.Error(),
})
}
httpOptions.Settings = metadata.Settings
- return req, function, httpOptions, err
+ return req, function, &metadata, httpOptions, err
}
func (c *HTTPConnector) execQuerySync(ctx context.Context, state *State, request *schema.QueryRequest, valueField schema.NestedField, requestVars []schema.QueryRequestVariablesElem) ([]schema.RowSet, error) {
@@ -145,7 +145,7 @@ func (c *HTTPConnector) execQuery(ctx context.Context, state *State, request *sc
ctx, span := state.Tracer.Start(ctx, fmt.Sprintf("Execute Query %d", index))
defer span.End()
- httpRequest, function, httpOptions, err := c.explainQuery(request, variables)
+ httpRequest, function, metadata, httpOptions, err := c.explainQuery(request, variables)
if err != nil {
span.SetStatus(codes.Error, "failed to explain query")
span.RecordError(err)
@@ -154,7 +154,8 @@ func (c *HTTPConnector) execQuery(ctx context.Context, state *State, request *sc
}
httpOptions.Concurrency = c.config.Concurrency.HTTP
- result, headers, err := c.client.Send(ctx, httpRequest, queryFields, function.ResultType, httpOptions)
+ client := internal.NewHTTPClient(c.client, metadata.NDCHttpSchema, c.config.ForwardHeaders, state.Tracer)
+ result, _, err := client.Send(ctx, httpRequest, queryFields, function.ResultType, httpOptions)
if err != nil {
span.SetStatus(codes.Error, "failed to execute the http request")
span.RecordError(err)
@@ -162,7 +163,7 @@ func (c *HTTPConnector) execQuery(ctx context.Context, state *State, request *sc
return nil, err
}
- return c.createHeaderForwardingResponse(result, headers), nil
+ return result, nil
}
func serializeExplainResponse(httpRequest *internal.RetryableRequest, httpOptions *internal.HTTPOptions) (*schema.ExplainResponse, error) {
diff --git a/connector/schema.go b/connector/schema.go
index 30c6100..3a5553e 100644
--- a/connector/schema.go
+++ b/connector/schema.go
@@ -5,8 +5,6 @@ import (
"encoding/json"
"fmt"
"log/slog"
- "net/http"
- "slices"
"github.com/go-viper/mapstructure/v2"
"github.com/hasura/ndc-http/connector/internal"
@@ -90,24 +88,3 @@ func (c *HTTPConnector) evalForwardedHeaders(req *internal.RetryableRequest, raw
return nil
}
-
-func (c *HTTPConnector) createHeaderForwardingResponse(result any, rawHeaders http.Header) any {
- if !c.config.ForwardHeaders.Enabled || c.config.ForwardHeaders.ResponseHeaders == nil {
- return result
- }
-
- headers := make(map[string]string)
- for key, values := range rawHeaders {
- if len(c.config.ForwardHeaders.ResponseHeaders.ForwardHeaders) > 0 && !slices.Contains(c.config.ForwardHeaders.ResponseHeaders.ForwardHeaders, key) {
- continue
- }
- if len(values) > 0 && values[0] != "" {
- headers[key] = values[0]
- }
- }
-
- return map[string]any{
- c.config.ForwardHeaders.ResponseHeaders.HeadersField: headers,
- c.config.ForwardHeaders.ResponseHeaders.ResultField: result,
- }
-}
diff --git a/connector/testdata/auth/schema.yaml b/connector/testdata/auth/schema.yaml
index 099301a..9e68d9d 100644
--- a/connector/testdata/auth/schema.yaml
+++ b/connector/testdata/auth/schema.yaml
@@ -139,6 +139,27 @@ procedures:
name: ProgressResponse
type: named
type: array
+ putPetXml:
+ request:
+ url: "/pet/xml"
+ method: put
+ security: []
+ requestBody:
+ contentType: application/xml
+ response:
+ contentType: application/xml
+ arguments:
+ body:
+ description: Request body of PUT /pet/xml
+ type:
+ name: PetXml
+ type: named
+ http:
+ in: body
+ description: Update an existing pet
+ result_type:
+ name: PetXml
+ type: named
object_types:
Pet:
fields:
@@ -152,6 +173,136 @@ object_types:
type:
name: String
type: named
+ PetXml:
+ fields:
+ category:
+ type:
+ type: nullable
+ underlying_type:
+ name: Category
+ type: named
+ http:
+ type:
+ - object
+ xml:
+ name: category
+ field:
+ description:
+ This empty field is returned instead of the list of scopes if the
+ user making the call doesn't have the authorization required.
+ type:
+ type: nullable
+ underlying_type:
+ name: JSON
+ type: named
+ http:
+ type:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ photoUrls:
+ type:
+ element_type:
+ name: String
+ type: named
+ type: array
+ http:
+ type:
+ - array
+ items:
+ type:
+ - string
+ xml:
+ name: photoUrl
+ xml:
+ name: ""
+ wrapped: true
+ status:
+ description: pet status in the store
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ tags:
+ type:
+ type: nullable
+ underlying_type:
+ element_type:
+ name: Tag
+ type: named
+ type: array
+ http:
+ type:
+ - array
+ xml:
+ name: ""
+ wrapped: true
+ xml:
+ name: pet
+ Tag:
+ fields:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ xml:
+ name: tag
+ Category:
+ fields:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ xml:
+ name: category
CreateModelRequest:
fields:
model:
@@ -181,12 +332,30 @@ scalar_types:
Boolean:
aggregate_functions: {}
comparison_operators: {}
+ representation:
+ type: boolean
Int:
aggregate_functions: {}
comparison_operators: {}
+ representation:
+ type: int32
+ Int32:
+ aggregate_functions: {}
+ comparison_operators: {}
+ representation:
+ type: int32
+ Int64:
+ aggregate_functions: {}
+ comparison_operators: {}
+ representation:
+ type: int64
JSON:
aggregate_functions: {}
comparison_operators: {}
+ representation:
+ type: json
String:
aggregate_functions: {}
comparison_operators: {}
+ representation:
+ type: string
diff --git a/connector/types.go b/connector/types.go
index 2e07c46..fc50f61 100644
--- a/connector/types.go
+++ b/connector/types.go
@@ -5,7 +5,7 @@ import (
"net/http"
"github.com/hasura/ndc-http/connector/internal"
- "go.opentelemetry.io/otel/trace"
+ "github.com/hasura/ndc-sdk-go/connector"
)
var (
@@ -15,7 +15,7 @@ var (
// State is the global state which is shared for every connector request.
type State struct {
- Tracer trace.Tracer
+ Tracer *connector.Tracer
}
type options struct {
diff --git a/ndc-http-schema/command/convert.go b/ndc-http-schema/command/convert.go
index a2126d8..5193b51 100644
--- a/ndc-http-schema/command/convert.go
+++ b/ndc-http-schema/command/convert.go
@@ -17,23 +17,6 @@ import (
// ConvertToNDCSchema converts to NDC HTTP schema from file
func CommandConvertToNDCSchema(args *configuration.ConvertCommandArguments, logger *slog.Logger) error {
start := time.Now()
- logger.Debug(
- "converting the document to NDC HTTP schema",
- slog.String("file", args.File),
- slog.String("config", args.Config),
- slog.String("output", args.Output),
- slog.String("spec", args.Spec),
- slog.String("format", args.Format),
- slog.String("prefix", args.Prefix),
- slog.String("trim_prefix", args.TrimPrefix),
- slog.String("env_prefix", args.EnvPrefix),
- slog.Any("patch_before", args.PatchBefore),
- slog.Any("patch_after", args.PatchAfter),
- slog.Any("allowed_content_types", args.AllowedContentTypes),
- slog.Bool("strict", args.Strict),
- slog.Bool("pure", args.Pure),
- )
-
if args.File == "" && args.Config == "" {
err := errors.New("--config or --file argument is required")
logger.Error(err.Error())
@@ -65,6 +48,24 @@ func CommandConvertToNDCSchema(args *configuration.ConvertCommandArguments, logg
}
configuration.ResolveConvertConfigArguments(&config, configDir, args)
+ logger.Debug(
+ "converting the document to NDC HTTP schema",
+ slog.String("file", config.File),
+ slog.String("config", config.File),
+ slog.String("output", config.Output),
+ slog.String("spec", string(config.Spec)),
+ slog.String("format", args.Format),
+ slog.String("prefix", config.Prefix),
+ slog.String("trim_prefix", config.TrimPrefix),
+ slog.String("env_prefix", config.EnvPrefix),
+ slog.Any("patch_before", config.PatchBefore),
+ slog.Any("patch_after", config.PatchAfter),
+ slog.Any("allowed_content_types", config.AllowedContentTypes),
+ slog.Bool("strict", config.Strict),
+ slog.Bool("pure", config.Pure),
+ slog.Bool("no_deprecation", config.NoDeprecation),
+ )
+
result, err := configuration.ConvertToNDCSchema(&config, logger)
if err != nil {
diff --git a/ndc-http-schema/command/testdata/auth/expected.json b/ndc-http-schema/command/testdata/auth/expected.json
index a1753a0..c33923b 100644
--- a/ndc-http-schema/command/testdata/auth/expected.json
+++ b/ndc-http-schema/command/testdata/auth/expected.json
@@ -10,19 +10,29 @@
"securitySchemes": {
"api_key": {
"type": "apiKey",
+ "in": "header",
+ "name": "api_key",
"value": {
"env": "PET_STORE_API_KEY"
+ }
+ },
+ "basic": {
+ "type": "basic",
+ "header": "Authorization",
+ "username": {
+ "value": "user"
},
- "in": "header",
- "name": "api_key"
+ "password": {
+ "value": "password"
+ }
},
"bearer": {
"type": "http",
+ "header": "",
+ "scheme": "bearer",
"value": {
"env": "PET_STORE_BEARER_TOKEN"
- },
- "header": "",
- "scheme": "bearer"
+ }
},
"petstore_auth": {
"type": "oauth2",
@@ -47,19 +57,29 @@
"securitySchemes": {
"api_key": {
"type": "apiKey",
+ "in": "header",
+ "name": "api_key",
"value": {
"env": "PET_STORE_API_KEY"
+ }
+ },
+ "basic": {
+ "type": "basic",
+ "header": "Authorization",
+ "username": {
+ "value": "user"
},
- "in": "header",
- "name": "api_key"
+ "password": {
+ "value": "password"
+ }
},
"bearer": {
"type": "http",
+ "header": "",
+ "scheme": "bearer",
"value": {
"env": "PET_STORE_BEARER_TOKEN"
- },
- "header": "",
- "scheme": "bearer"
+ }
},
"petstore_auth": {
"type": "oauth2",
@@ -86,7 +106,6 @@
"request": {
"url": "/pet",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -105,7 +124,6 @@
"request": {
"url": "/pet/findByStatus",
"method": "get",
- "type": "http",
"security": [
{
"bearer": []
@@ -146,7 +164,6 @@
"request": {
"url": "/pet/retry",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -162,6 +179,38 @@
}
},
"object_types": {
+ "Category": {
+ "fields": {
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["string"]
+ }
+ }
+ },
+ "xml": {
+ "name": "category"
+ }
+ },
"CreateModelRequest": {
"fields": {
"model": {
@@ -195,6 +244,115 @@
}
}
},
+ "PetXml": {
+ "fields": {
+ "category": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Category",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["object"],
+ "xml": {
+ "name": "category"
+ }
+ }
+ },
+ "field": {
+ "description": "This empty field is returned instead of the list of scopes if the user making the call doesn't have the authorization required.",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": null
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": ["string"]
+ }
+ },
+ "photoUrls": {
+ "type": {
+ "element_type": {
+ "name": "String",
+ "type": "named"
+ },
+ "type": "array"
+ },
+ "http": {
+ "type": ["array"],
+ "items": {
+ "type": ["string"],
+ "xml": {
+ "name": "photoUrl"
+ }
+ },
+ "xml": {
+ "wrapped": true
+ }
+ }
+ },
+ "status": {
+ "description": "pet status in the store",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["string"]
+ }
+ },
+ "tags": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "Tag",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ },
+ "http": {
+ "type": ["array"],
+ "xml": {
+ "wrapped": true
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "pet"
+ }
+ },
"ProgressResponse": {
"fields": {
"completed": {
@@ -218,6 +376,38 @@
}
}
}
+ },
+ "Tag": {
+ "fields": {
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["string"]
+ }
+ }
+ },
+ "xml": {
+ "name": "tag"
+ }
}
},
"procedures": {
@@ -225,7 +415,6 @@
"request": {
"url": "/pet",
"method": "post",
- "type": "http",
"headers": {
"Content-Type": {
"value": "application/json"
@@ -265,7 +454,11 @@
"request": {
"url": "/model",
"method": "post",
- "type": "http",
+ "security": [
+ {
+ "basic": []
+ }
+ ],
"requestBody": {
"contentType": "application/json"
},
@@ -289,6 +482,35 @@
},
"type": "array"
}
+ },
+ "putPetXml": {
+ "request": {
+ "url": "/pet/xml",
+ "method": "put",
+ "requestBody": {
+ "contentType": "application/xml"
+ },
+ "response": {
+ "contentType": "application/xml"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /pet/xml",
+ "type": {
+ "name": "PetXml",
+ "type": "named"
+ },
+ "http": {
+ "in": "body"
+ }
+ }
+ },
+ "description": "Update an existing pet",
+ "result_type": {
+ "name": "PetXml",
+ "type": "named"
+ }
}
},
"scalar_types": {
@@ -306,6 +528,27 @@
"type": "int32"
}
},
+ "Int32": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "type": "int32"
+ }
+ },
+ "Int64": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "type": "int64"
+ }
+ },
+ "JSON": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "type": "json"
+ }
+ },
"String": {
"aggregate_functions": {},
"comparison_operators": {},
diff --git a/ndc-http-schema/command/testdata/auth/schema.yaml b/ndc-http-schema/command/testdata/auth/schema.yaml
index ed5faa1..9e68d9d 100644
--- a/ndc-http-schema/command/testdata/auth/schema.yaml
+++ b/ndc-http-schema/command/testdata/auth/schema.yaml
@@ -15,6 +15,14 @@ settings:
value:
env: PET_STORE_BEARER_TOKEN
scheme: bearer
+ basic:
+ type: basic
+ header: Authorization
+ username:
+ value: user
+ password:
+ value: password
+ scheme: bearer
petstore_auth:
type: oauth2
flows:
@@ -113,6 +121,8 @@ procedures:
request:
url: /model
method: post
+ security:
+ - basic: []
requestBody:
contentType: application/json
response:
@@ -129,6 +139,27 @@ procedures:
name: ProgressResponse
type: named
type: array
+ putPetXml:
+ request:
+ url: "/pet/xml"
+ method: put
+ security: []
+ requestBody:
+ contentType: application/xml
+ response:
+ contentType: application/xml
+ arguments:
+ body:
+ description: Request body of PUT /pet/xml
+ type:
+ name: PetXml
+ type: named
+ http:
+ in: body
+ description: Update an existing pet
+ result_type:
+ name: PetXml
+ type: named
object_types:
Pet:
fields:
@@ -142,6 +173,136 @@ object_types:
type:
name: String
type: named
+ PetXml:
+ fields:
+ category:
+ type:
+ type: nullable
+ underlying_type:
+ name: Category
+ type: named
+ http:
+ type:
+ - object
+ xml:
+ name: category
+ field:
+ description:
+ This empty field is returned instead of the list of scopes if the
+ user making the call doesn't have the authorization required.
+ type:
+ type: nullable
+ underlying_type:
+ name: JSON
+ type: named
+ http:
+ type:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ photoUrls:
+ type:
+ element_type:
+ name: String
+ type: named
+ type: array
+ http:
+ type:
+ - array
+ items:
+ type:
+ - string
+ xml:
+ name: photoUrl
+ xml:
+ name: ""
+ wrapped: true
+ status:
+ description: pet status in the store
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ tags:
+ type:
+ type: nullable
+ underlying_type:
+ element_type:
+ name: Tag
+ type: named
+ type: array
+ http:
+ type:
+ - array
+ xml:
+ name: ""
+ wrapped: true
+ xml:
+ name: pet
+ Tag:
+ fields:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ xml:
+ name: tag
+ Category:
+ fields:
+ id:
+ type:
+ type: nullable
+ underlying_type:
+ name: Int64
+ type: named
+ http:
+ type:
+ - integer
+ format: int64
+ name:
+ type:
+ type: nullable
+ underlying_type:
+ name: String
+ type: named
+ http:
+ type:
+ - string
+ xml:
+ name: category
CreateModelRequest:
fields:
model:
@@ -178,6 +339,21 @@ scalar_types:
comparison_operators: {}
representation:
type: int32
+ Int32:
+ aggregate_functions: {}
+ comparison_operators: {}
+ representation:
+ type: int32
+ Int64:
+ aggregate_functions: {}
+ comparison_operators: {}
+ representation:
+ type: int64
+ JSON:
+ aggregate_functions: {}
+ comparison_operators: {}
+ representation:
+ type: json
String:
aggregate_functions: {}
comparison_operators: {}
diff --git a/ndc-http-schema/command/testdata/patch/expected.json b/ndc-http-schema/command/testdata/patch/expected.json
index 4eb3fe8..becd002 100644
--- a/ndc-http-schema/command/testdata/patch/expected.json
+++ b/ndc-http-schema/command/testdata/patch/expected.json
@@ -11,19 +11,29 @@
"securitySchemes": {
"api_key": {
"type": "apiKey",
+ "in": "header",
+ "name": "api_key",
"value": {
"value": "dog-secret"
+ }
+ },
+ "basic": {
+ "type": "basic",
+ "header": "Authorization",
+ "username": {
+ "value": "user"
},
- "in": "header",
- "name": "api_key"
+ "password": {
+ "value": "password"
+ }
},
"bearer": {
"type": "http",
+ "header": "",
+ "scheme": "bearer",
"value": {
"env": "PET_STORE_BEARER_TOKEN"
- },
- "header": "",
- "scheme": "bearer"
+ }
}
},
"security": [
@@ -40,19 +50,29 @@
"securitySchemes": {
"api_key": {
"type": "apiKey",
+ "in": "header",
+ "name": "api_key",
"value": {
"value": "cat-secret"
+ }
+ },
+ "basic": {
+ "type": "basic",
+ "header": "Authorization",
+ "username": {
+ "value": "user"
},
- "in": "header",
- "name": "api_key"
+ "password": {
+ "value": "password"
+ }
},
"bearer": {
"type": "http",
+ "header": "",
+ "scheme": "bearer",
"value": {
"env": "PET_STORE_BEARER_TOKEN"
- },
- "header": "",
- "scheme": "bearer"
+ }
}
},
"security": [
@@ -65,19 +85,29 @@
"securitySchemes": {
"api_key": {
"type": "apiKey",
+ "in": "header",
+ "name": "api_key",
"value": {
"env": "PET_STORE_API_KEY"
+ }
+ },
+ "basic": {
+ "type": "basic",
+ "header": "Authorization",
+ "username": {
+ "value": "user"
},
- "in": "header",
- "name": "api_key"
+ "password": {
+ "value": "password"
+ }
},
"bearer": {
"type": "http",
+ "header": "",
+ "scheme": "bearer",
"value": {
"env": "PET_STORE_BEARER_TOKEN"
- },
- "header": "",
- "scheme": "bearer"
+ }
}
},
"security": [
@@ -92,7 +122,6 @@
"request": {
"url": "/pet",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -129,7 +158,6 @@
"request": {
"url": "/pet/findByStatus",
"method": "get",
- "type": "http",
"security": [
{
"bearer": []
@@ -187,7 +215,6 @@
"request": {
"url": "/pet/findByStatus",
"method": "get",
- "type": "http",
"security": [
{
"bearer": []
@@ -245,7 +272,6 @@
"request": {
"url": "/pet",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -282,7 +308,6 @@
"request": {
"url": "/pet/retry",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -318,7 +343,6 @@
"request": {
"url": "/pet/retry",
"method": "get",
- "type": "http",
"response": {
"contentType": ""
}
@@ -434,6 +458,38 @@
}
}
},
+ "Category": {
+ "fields": {
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["string"]
+ }
+ }
+ },
+ "xml": {
+ "name": "category"
+ }
+ },
"CreateModelDistributedHeadersResponse": {
"fields": {
"headers": {
@@ -744,6 +800,52 @@
}
}
},
+ "HttpDistributedOptions": {
+ "description": "Distributed execution options for HTTP requests to multiple servers",
+ "fields": {
+ "parallel": {
+ "description": "Execute requests to remote servers in parallel",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Boolean",
+ "type": "named"
+ }
+ }
+ },
+ "servers": {
+ "description": "Specify remote servers to receive the request",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "HttpServerId",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ }
+ }
+ },
+ "HttpSingleOptions": {
+ "description": "Execution options for HTTP requests to a single server",
+ "fields": {
+ "servers": {
+ "description": "Specify remote servers to receive the request. If there are many server IDs the server is selected randomly",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "HttpServerId",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ }
+ }
+ },
"Pet": {
"fields": {
"id": {
@@ -851,6 +953,115 @@
}
}
},
+ "PetXml": {
+ "fields": {
+ "category": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Category",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["object"],
+ "xml": {
+ "name": "category"
+ }
+ }
+ },
+ "field": {
+ "description": "This empty field is returned instead of the list of scopes if the user making the call doesn't have the authorization required.",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": null
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": ["string"]
+ }
+ },
+ "photoUrls": {
+ "type": {
+ "element_type": {
+ "name": "String",
+ "type": "named"
+ },
+ "type": "array"
+ },
+ "http": {
+ "type": ["array"],
+ "items": {
+ "type": ["string"],
+ "xml": {
+ "name": "photoUrl"
+ }
+ },
+ "xml": {
+ "wrapped": true
+ }
+ }
+ },
+ "status": {
+ "description": "pet status in the store",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["string"]
+ }
+ },
+ "tags": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "Tag",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ },
+ "http": {
+ "type": ["array"],
+ "xml": {
+ "wrapped": true
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "pet"
+ }
+ },
"ProgressResponse": {
"fields": {
"completed": {
@@ -875,50 +1086,118 @@
}
}
},
- "HttpDistributedOptions": {
- "description": "Distributed execution options for HTTP requests to multiple servers",
+ "PutPetXmlDistributedHeadersResponse": {
"fields": {
- "parallel": {
- "description": "Execute requests to remote servers in parallel",
+ "headers": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Boolean",
+ "name": "JSON",
"type": "named"
}
}
},
- "servers": {
- "description": "Specify remote servers to receive the request",
+ "response": {
+ "type": {
+ "name": "PutPetXmlDistributedResult",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "PutPetXmlDistributedResult": {
+ "description": "Distributed responses of putPetXmlDistributed",
+ "fields": {
+ "errors": {
+ "description": "Error responses of putPetXmlDistributed",
+ "type": {
+ "element_type": {
+ "name": "DistributedError",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ },
+ "results": {
+ "description": "Results of putPetXmlDistributed",
+ "type": {
+ "element_type": {
+ "name": "PutPetXmlDistributedResultData",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ }
+ },
+ "PutPetXmlDistributedResultData": {
+ "description": "Distributed response data of putPetXmlDistributed",
+ "fields": {
+ "data": {
+ "description": "A result of putPetXmlDistributed",
+ "type": {
+ "name": "PetXml",
+ "type": "named"
+ }
+ },
+ "server": {
+ "description": "Identity of the remote server",
+ "type": {
+ "name": "HttpServerId",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "PutPetXmlHeadersResponse": {
+ "fields": {
+ "headers": {
"type": {
"type": "nullable",
"underlying_type": {
- "element_type": {
- "name": "HttpServerId",
- "type": "named"
- },
- "type": "array"
+ "name": "JSON",
+ "type": "named"
}
}
+ },
+ "response": {
+ "type": {
+ "name": "PetXml",
+ "type": "named"
+ }
}
}
},
- "HttpSingleOptions": {
- "description": "Execution options for HTTP requests to a single server",
+ "Tag": {
"fields": {
- "servers": {
- "description": "Specify remote servers to receive the request. If there are many server IDs the server is selected randomly",
+ "id": {
"type": {
"type": "nullable",
"underlying_type": {
- "element_type": {
- "name": "HttpServerId",
- "type": "named"
- },
- "type": "array"
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": ["integer"],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
}
+ },
+ "http": {
+ "type": ["string"]
}
}
+ },
+ "xml": {
+ "name": "tag"
}
}
},
@@ -927,7 +1206,6 @@
"request": {
"url": "/pet",
"method": "post",
- "type": "http",
"headers": {
"Content-Type": {
"value": "application/json"
@@ -987,7 +1265,6 @@
"request": {
"url": "/pet",
"method": "post",
- "type": "http",
"headers": {
"Content-Type": {
"value": "application/json"
@@ -1047,7 +1324,11 @@
"request": {
"url": "/model",
"method": "post",
- "type": "http",
+ "security": [
+ {
+ "basic": []
+ }
+ ],
"requestBody": {
"contentType": "application/json"
},
@@ -1093,7 +1374,11 @@
"request": {
"url": "/model",
"method": "post",
- "type": "http",
+ "security": [
+ {
+ "basic": []
+ }
+ ],
"requestBody": {
"contentType": "application/json"
},
@@ -1134,6 +1419,104 @@
"name": "CreateModelDistributedHeadersResponse",
"type": "named"
}
+ },
+ "putPetXml": {
+ "request": {
+ "url": "/pet/xml",
+ "method": "put",
+ "requestBody": {
+ "contentType": "application/xml"
+ },
+ "response": {
+ "contentType": "application/xml"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /pet/xml",
+ "type": {
+ "name": "PetXml",
+ "type": "named"
+ },
+ "http": {
+ "in": "body"
+ }
+ },
+ "headers": {
+ "description": "Headers forwarded from the Hasura engine",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ }
+ },
+ "httpOptions": {
+ "description": "Execution options for HTTP requests to a single server",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "HttpSingleOptions",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "description": "Update an existing pet",
+ "result_type": {
+ "name": "PutPetXmlHeadersResponse",
+ "type": "named"
+ }
+ },
+ "putPetXmlDistributed": {
+ "request": {
+ "url": "/pet/xml",
+ "method": "put",
+ "requestBody": {
+ "contentType": "application/xml"
+ },
+ "response": {
+ "contentType": "application/xml"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /pet/xml",
+ "type": {
+ "name": "PetXml",
+ "type": "named"
+ },
+ "http": {
+ "in": "body"
+ }
+ },
+ "headers": {
+ "description": "Headers forwarded from the Hasura engine",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ }
+ },
+ "httpOptions": {
+ "description": "Distributed execution options for HTTP requests to multiple servers",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "HttpDistributedOptions",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "description": "Update an existing pet",
+ "result_type": {
+ "name": "PutPetXmlDistributedHeadersResponse",
+ "type": "named"
+ }
}
},
"scalar_types": {
@@ -1144,6 +1527,14 @@
"type": "boolean"
}
},
+ "HttpServerId": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "one_of": ["dog", "cat"],
+ "type": "enum"
+ }
+ },
"Int": {
"aggregate_functions": {},
"comparison_operators": {},
@@ -1151,19 +1542,25 @@
"type": "int32"
}
},
- "JSON": {
+ "Int32": {
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "type": "json"
+ "type": "int32"
}
},
- "HttpServerId": {
+ "Int64": {
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["dog", "cat"],
- "type": "enum"
+ "type": "int64"
+ }
+ },
+ "JSON": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "type": "json"
}
},
"String": {
diff --git a/ndc-http-schema/configuration/convert.go b/ndc-http-schema/configuration/convert.go
index afc7804..df619d0 100644
--- a/ndc-http-schema/configuration/convert.go
+++ b/ndc-http-schema/configuration/convert.go
@@ -32,6 +32,7 @@ func ConvertToNDCSchema(config *ConvertConfig, logger *slog.Logger) (*schema.NDC
EnvPrefix: config.EnvPrefix,
AllowedContentTypes: config.AllowedContentTypes,
Strict: config.Strict,
+ NoDeprecation: config.NoDeprecation,
Logger: logger,
}
rawContent = utils.RemoveYAMLSpecialCharacters(rawContent)
@@ -82,6 +83,9 @@ func ResolveConvertConfigArguments(config *ConvertConfig, configDir string, args
if args.Strict {
config.Strict = args.Strict
}
+ if args.NoDeprecation {
+ config.NoDeprecation = args.NoDeprecation
+ }
if len(args.AllowedContentTypes) > 0 {
config.AllowedContentTypes = args.AllowedContentTypes
}
diff --git a/ndc-http-schema/configuration/types.go b/ndc-http-schema/configuration/types.go
index 6c6f36c..80bbe59 100644
--- a/ndc-http-schema/configuration/types.go
+++ b/ndc-http-schema/configuration/types.go
@@ -214,6 +214,8 @@ type ConvertConfig struct {
Pure bool `json:"pure,omitempty" yaml:"pure"`
// Require strict validation
Strict bool `json:"strict,omitempty" yaml:"strict"`
+ // Ignore deprecated fields.
+ NoDeprecation bool `json:"noDeprecation,omitempty" yaml:"noDeprecation"`
// Patch files to be applied into the input file before converting
PatchBefore []restUtils.PatchConfig `json:"patchBefore,omitempty" yaml:"patchBefore"`
// Patch files to be applied into the input file after converting
@@ -239,6 +241,7 @@ type ConvertCommandArguments struct {
Spec string `help:"The API specification of the file, is one of oas3 (openapi3), oas2 (openapi2)"`
Format string `default:"json" help:"The output format, is one of json, yaml. If the output is set, automatically detect the format in the output file extension"`
Strict bool `default:"false" help:"Require strict validation"`
+ NoDeprecation bool `default:"false" help:"Ignore deprecated fields"`
Pure bool `default:"false" help:"Return the pure NDC schema only"`
Prefix string `help:"Add a prefix to the function and procedure names"`
TrimPrefix string `help:"Trim the prefix in URL, e.g. /v1"`
diff --git a/ndc-http-schema/openapi/internal/ndc.go b/ndc-http-schema/openapi/internal/ndc.go
index df1e221..8def99a 100644
--- a/ndc-http-schema/openapi/internal/ndc.go
+++ b/ndc-http-schema/openapi/internal/ndc.go
@@ -148,6 +148,7 @@ func (nsc *NDCBuilder) validateType(schemaType schema.Type) (schema.TypeEncoder,
newObjectType := rest.ObjectType{
Description: objectType.Description,
+ XML: objectType.XML,
Fields: make(map[string]rest.ObjectField),
}
diff --git a/ndc-http-schema/openapi/internal/oas2.go b/ndc-http-schema/openapi/internal/oas2.go
index 805a4b7..287f6b6 100644
--- a/ndc-http-schema/openapi/internal/oas2.go
+++ b/ndc-http-schema/openapi/internal/oas2.go
@@ -59,12 +59,6 @@ func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.
})
}
- for iterPath := docModel.Model.Paths.PathItems.First(); iterPath != nil; iterPath = iterPath.Next() {
- if err := oc.pathToNDCOperations(iterPath); err != nil {
- return nil, err
- }
- }
-
if docModel.Model.Definitions != nil {
for cSchema := docModel.Model.Definitions.Definitions.First(); cSchema != nil; cSchema = cSchema.Next() {
if err := oc.convertComponentSchemas(cSchema); err != nil {
@@ -73,6 +67,12 @@ func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.
}
}
+ for iterPath := docModel.Model.Paths.PathItems.First(); iterPath != nil; iterPath = iterPath.Next() {
+ if err := oc.pathToNDCOperations(iterPath); err != nil {
+ return nil, err
+ }
+ }
+
if docModel.Model.SecurityDefinitions != nil && docModel.Model.SecurityDefinitions.Definitions != nil {
oc.schema.Settings.SecuritySchemes = make(map[string]rest.SecurityScheme)
for scheme := docModel.Model.SecurityDefinitions.Definitions.First(); scheme != nil; scheme = scheme.Next() {
@@ -149,7 +149,7 @@ func (oc *OAS2Builder) pathToNDCOperations(pathItem orderedmap.Pair[string, *v2.
pathKey := pathItem.Key()
pathValue := pathItem.Value()
- funcGet, funcName, err := newOAS2OperationBuilder(oc).BuildFunction(pathKey, pathValue.Get, pathValue.Parameters)
+ funcGet, funcName, err := newOAS2OperationBuilder(oc, pathKey, "get").BuildFunction(pathValue.Get, pathValue.Parameters)
if err != nil {
return err
}
@@ -157,7 +157,7 @@ func (oc *OAS2Builder) pathToNDCOperations(pathItem orderedmap.Pair[string, *v2.
oc.schema.Functions[funcName] = *funcGet
}
- procPost, procPostName, err := newOAS2OperationBuilder(oc).BuildProcedure(pathKey, "post", pathValue.Post, pathValue.Parameters)
+ procPost, procPostName, err := newOAS2OperationBuilder(oc, pathKey, "post").BuildProcedure(pathValue.Post, pathValue.Parameters)
if err != nil {
return err
}
@@ -165,7 +165,7 @@ func (oc *OAS2Builder) pathToNDCOperations(pathItem orderedmap.Pair[string, *v2.
oc.schema.Procedures[procPostName] = *procPost
}
- procPut, procPutName, err := newOAS2OperationBuilder(oc).BuildProcedure(pathKey, "put", pathValue.Put, pathValue.Parameters)
+ procPut, procPutName, err := newOAS2OperationBuilder(oc, pathKey, "put").BuildProcedure(pathValue.Put, pathValue.Parameters)
if err != nil {
return err
}
@@ -173,7 +173,7 @@ func (oc *OAS2Builder) pathToNDCOperations(pathItem orderedmap.Pair[string, *v2.
oc.schema.Procedures[procPutName] = *procPut
}
- procPatch, procPatchName, err := newOAS2OperationBuilder(oc).BuildProcedure(pathKey, "patch", pathValue.Patch, pathValue.Parameters)
+ procPatch, procPatchName, err := newOAS2OperationBuilder(oc, pathKey, "patch").BuildProcedure(pathValue.Patch, pathValue.Parameters)
if err != nil {
return err
}
@@ -181,7 +181,7 @@ func (oc *OAS2Builder) pathToNDCOperations(pathItem orderedmap.Pair[string, *v2.
oc.schema.Procedures[procPatchName] = *procPatch
}
- procDelete, procDeleteName, err := newOAS2OperationBuilder(oc).BuildProcedure(pathKey, "delete", pathValue.Delete, pathValue.Parameters)
+ procDelete, procDeleteName, err := newOAS2OperationBuilder(oc, pathKey, "delete").BuildProcedure(pathValue.Delete, pathValue.Parameters)
if err != nil {
return err
}
@@ -207,6 +207,7 @@ func (oc *OAS2Builder) convertComponentSchemas(schemaItem orderedmap.Pair[string
if typeEncoder != nil {
typeName = getNamedType(typeEncoder, true, "")
}
+
cacheKey := "#/definitions/" + typeKey
// treat no-property objects as a Arbitrary JSON scalar
if typeEncoder == nil || typeName == string(rest.ScalarJSON) {
diff --git a/ndc-http-schema/openapi/internal/oas2_operation.go b/ndc-http-schema/openapi/internal/oas2_operation.go
index 9492226..ff2446c 100644
--- a/ndc-http-schema/openapi/internal/oas2_operation.go
+++ b/ndc-http-schema/openapi/internal/oas2_operation.go
@@ -15,65 +15,52 @@ import (
type oas2OperationBuilder struct {
builder *OAS2Builder
+ pathKey string
+ method string
Arguments map[string]rest.ArgumentInfo
}
-func newOAS2OperationBuilder(builder *OAS2Builder) *oas2OperationBuilder {
+func newOAS2OperationBuilder(builder *OAS2Builder, pathKey string, method string) *oas2OperationBuilder {
return &oas2OperationBuilder{
builder: builder,
+ pathKey: pathKey,
+ method: method,
Arguments: make(map[string]rest.ArgumentInfo),
}
}
// BuildFunction build a HTTP NDC function information from OpenAPI v2 operation
-func (oc *oas2OperationBuilder) BuildFunction(pathKey string, operation *v2.Operation, commonParams []*v2.Parameter) (*rest.OperationInfo, string, error) {
+func (oc *oas2OperationBuilder) BuildFunction(operation *v2.Operation, commonParams []*v2.Parameter) (*rest.OperationInfo, string, error) {
if operation == nil {
return nil, "", nil
}
- funcName := formatOperationName(operation.OperationId)
- if funcName == "" {
- funcName = buildPathMethodName(pathKey, "get", oc.builder.ConvertOptions)
- }
+
+ funcName := buildUniqueOperationName(oc.builder.schema, operation.OperationId, oc.pathKey, oc.method, oc.builder.ConvertOptions)
oc.builder.Logger.Info("function",
slog.String("name", funcName),
- slog.String("path", pathKey),
+ slog.String("path", oc.pathKey),
)
- responseContentType := oc.getResponseContentTypeV2(operation.Produces)
- if responseContentType == "" {
- oc.builder.Logger.Info("supported response content type",
- slog.String("name", funcName),
- slog.String("path", pathKey),
- slog.String("method", "get"),
- slog.Any("produces", operation.Produces),
- slog.Any("consumes", operation.Consumes),
- )
-
- return nil, "", nil
- }
-
- resultType, err := oc.convertResponse(operation.Responses, pathKey, []string{funcName, "Result"})
+ resultType, response, err := oc.convertResponse(operation, []string{funcName, "Result"})
if err != nil {
- return nil, "", fmt.Errorf("%s: %w", pathKey, err)
+ return nil, "", fmt.Errorf("%s: %w", oc.pathKey, err)
}
if resultType == nil {
return nil, "", nil
}
- reqBody, err := oc.convertParameters(operation, pathKey, commonParams, []string{funcName})
+ reqBody, err := oc.convertParameters(operation, commonParams, []string{funcName})
if err != nil {
return nil, "", fmt.Errorf("%s: %w", funcName, err)
}
- description := oc.getOperationDescription(pathKey, "get", operation)
+ description := oc.getOperationDescription(operation)
function := rest.OperationInfo{
Request: &rest.Request{
- URL: pathKey,
+ URL: oc.pathKey,
Method: "get",
RequestBody: reqBody,
- Response: rest.Response{
- ContentType: responseContentType,
- },
- Security: convertSecurities(operation.Security),
+ Response: *response,
+ Security: convertSecurities(operation.Security),
},
Description: &description,
Arguments: oc.Arguments,
@@ -84,59 +71,41 @@ func (oc *oas2OperationBuilder) BuildFunction(pathKey string, operation *v2.Oper
}
// BuildProcedure build a HTTP NDC function information from OpenAPI v2 operation
-func (oc *oas2OperationBuilder) BuildProcedure(pathKey string, method string, operation *v2.Operation, commonParams []*v2.Parameter) (*rest.OperationInfo, string, error) {
+func (oc *oas2OperationBuilder) BuildProcedure(operation *v2.Operation, commonParams []*v2.Parameter) (*rest.OperationInfo, string, error) {
if operation == nil {
return nil, "", nil
}
- procName := formatOperationName(operation.OperationId)
- if procName == "" {
- procName = buildPathMethodName(pathKey, method, oc.builder.ConvertOptions)
- }
+ procName := buildUniqueOperationName(oc.builder.schema, operation.OperationId, oc.pathKey, oc.method, oc.builder.ConvertOptions)
oc.builder.Logger.Info("procedure",
slog.String("name", procName),
- slog.String("path", pathKey),
- slog.String("method", method),
+ slog.String("path", oc.pathKey),
+ slog.String("method", oc.method),
)
- responseContentType := oc.getResponseContentTypeV2(operation.Produces)
- if responseContentType == "" {
- oc.builder.Logger.Info("supported response content type",
- slog.String("name", procName),
- slog.String("path", pathKey),
- slog.String("method", method),
- slog.Any("produces", operation.Produces),
- slog.Any("consumes", operation.Consumes),
- )
-
- return nil, "", nil
- }
-
- resultType, err := oc.convertResponse(operation.Responses, pathKey, []string{procName, "Result"})
+ resultType, response, err := oc.convertResponse(operation, []string{procName, "Result"})
if err != nil {
- return nil, "", fmt.Errorf("%s: %w", pathKey, err)
+ return nil, "", fmt.Errorf("%s: %w", oc.pathKey, err)
}
if resultType == nil {
return nil, "", nil
}
- reqBody, err := oc.convertParameters(operation, pathKey, commonParams, []string{procName})
+ reqBody, err := oc.convertParameters(operation, commonParams, []string{procName})
if err != nil {
- return nil, "", fmt.Errorf("%s: %w", pathKey, err)
+ return nil, "", fmt.Errorf("%s: %w", oc.pathKey, err)
}
- description := oc.getOperationDescription(pathKey, method, operation)
+ description := oc.getOperationDescription(operation)
procedure := rest.OperationInfo{
Request: &rest.Request{
- URL: pathKey,
- Method: method,
+ URL: oc.pathKey,
+ Method: oc.method,
RequestBody: reqBody,
Security: convertSecurities(operation.Security),
- Response: rest.Response{
- ContentType: responseContentType,
- },
+ Response: *response,
},
Description: &description,
Arguments: oc.Arguments,
@@ -146,14 +115,14 @@ func (oc *oas2OperationBuilder) BuildProcedure(pathKey string, method string, op
return &procedure, procName, nil
}
-func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, apiPath string, commonParams []*v2.Parameter, fieldPaths []string) (*rest.RequestBody, error) {
+func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, commonParams []*v2.Parameter, fieldPaths []string) (*rest.RequestBody, error) {
if operation == nil || (len(operation.Parameters) == 0 && len(commonParams) == 0) {
return nil, nil
}
- contentType := rest.ContentTypeJSON
- if len(operation.Consumes) > 0 && !slices.Contains(operation.Consumes, rest.ContentTypeJSON) {
- contentType = operation.Consumes[0]
+ contentType := oc.getContentTypeV2(operation.Consumes)
+ if contentType == "" {
+ contentType = rest.ContentTypeJSON
}
var requestBody *rest.RequestBody
@@ -183,7 +152,7 @@ func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, apiPa
switch {
case param.Type != "":
- typeEncoder, err = newOAS2SchemaBuilder(oc.builder, apiPath, rest.ParameterLocation(param.In)).getSchemaTypeFromParameter(param, fieldPaths)
+ typeEncoder, err = newOAS2SchemaBuilder(oc.builder, oc.pathKey, rest.ParameterLocation(param.In)).getSchemaTypeFromParameter(param, fieldPaths)
if err != nil {
return nil, err
}
@@ -208,7 +177,7 @@ func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, apiPa
typeSchema.MinLength = &minLength
}
case param.Schema != nil:
- typeEncoder, typeSchema, err = newOAS2SchemaBuilder(oc.builder, apiPath, rest.ParameterLocation(param.In)).
+ typeEncoder, typeSchema, err = newOAS2SchemaBuilder(oc.builder, oc.pathKey, rest.ParameterLocation(param.In)).
getSchemaTypeFromProxy(param.Schema, !paramRequired, fieldPaths)
if err != nil {
return nil, err
@@ -279,7 +248,7 @@ func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, apiPa
bodyName := utils.StringSliceToPascalCase(fieldPaths) + "Body"
oc.builder.schema.ObjectTypes[bodyName] = formDataObject
- desc := "Form data of " + apiPath
+ desc := "Form data of " + oc.pathKey
oc.Arguments["body"] = rest.ArgumentInfo{
ArgumentInfo: schema.ArgumentInfo{
Type: schema.NewNamedType(bodyName).Encode(),
@@ -298,59 +267,84 @@ func (oc *oas2OperationBuilder) convertParameters(operation *v2.Operation, apiPa
return requestBody, nil
}
-func (oc *oas2OperationBuilder) convertResponse(responses *v2.Responses, apiPath string, fieldPaths []string) (schema.TypeEncoder, error) {
- if responses == nil || responses.Codes == nil || responses.Codes.IsZero() {
- return nil, nil
+func (oc *oas2OperationBuilder) convertResponse(operation *v2.Operation, fieldPaths []string) (schema.TypeEncoder, *rest.Response, error) {
+ if operation.Responses == nil || operation.Responses.Codes == nil || operation.Responses.Codes.IsZero() {
+ return nil, nil, nil
+ }
+
+ contentType := oc.getContentTypeV2(operation.Produces)
+ if contentType == "" {
+ oc.builder.Logger.Info("empty content type in response",
+ slog.String("path", oc.pathKey),
+ slog.String("method", oc.method),
+ slog.Any("produces", operation.Produces),
+ slog.Any("consumes", operation.Consumes),
+ )
+
+ return nil, nil, nil
}
var resp *v2.Response
- if responses.Codes == nil || responses.Codes.IsZero() {
+ var statusCode int64
+ if operation.Responses.Codes == nil || operation.Responses.Codes.IsZero() {
// the response is always successful
- resp = responses.Default
+ resp = operation.Responses.Default
} else {
- for r := responses.Codes.First(); r != nil; r = r.Next() {
+ for r := operation.Responses.Codes.First(); r != nil; r = r.Next() {
if r.Key() == "" {
continue
}
+
code, err := strconv.ParseInt(r.Key(), 10, 32)
if err != nil {
continue
}
if isUnsupportedResponseCodes(code) {
- return nil, nil
+ return nil, nil, nil
} else if code >= 200 && code < 300 {
resp = r.Value()
+ statusCode = code
break
}
}
}
+ response := &rest.Response{
+ ContentType: contentType,
+ }
+
// return nullable boolean type if the response content is null
- if resp == nil || resp.Schema == nil {
+ if resp == nil || (resp.Schema == nil && statusCode == 204) {
scalarName := string(rest.ScalarBoolean)
if _, ok := oc.builder.schema.ScalarTypes[scalarName]; !ok {
oc.builder.schema.ScalarTypes[scalarName] = *defaultScalarTypes[rest.ScalarBoolean]
}
- return schema.NewNullableNamedType(scalarName), nil
+ return schema.NewNullableNamedType(scalarName), response, nil
}
- schemaType, _, err := newOAS2SchemaBuilder(oc.builder, apiPath, rest.InBody).
+ if resp.Schema == nil {
+ return getResultTypeFromContentType(oc.builder.schema, contentType), response, nil
+ }
+
+ schemaType, _, err := newOAS2SchemaBuilder(oc.builder, oc.pathKey, rest.InBody).
getSchemaTypeFromProxy(resp.Schema, false, fieldPaths)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- return schemaType, nil
+ return schemaType, response, nil
}
-func (oc *oas2OperationBuilder) getResponseContentTypeV2(contentTypes []string) string {
- contentType := rest.ContentTypeJSON
- if len(contentTypes) == 0 || slices.Contains(contentTypes, contentType) {
- return contentType
+func (oc *oas2OperationBuilder) getContentTypeV2(contentTypes []string) string {
+ for _, contentType := range preferredContentTypes {
+ if len(contentTypes) == 0 || slices.Contains(contentTypes, contentType) {
+ return contentType
+ }
}
+
if len(oc.builder.ConvertOptions.AllowedContentTypes) == 0 {
return contentTypes[0]
}
@@ -364,7 +358,7 @@ func (oc *oas2OperationBuilder) getResponseContentTypeV2(contentTypes []string)
return ""
}
-func (oc *oas2OperationBuilder) getOperationDescription(pathKey string, method string, operation *v2.Operation) string {
+func (oc *oas2OperationBuilder) getOperationDescription(operation *v2.Operation) string {
if operation.Summary != "" {
return utils.StripHTMLTags(operation.Summary)
}
@@ -372,5 +366,5 @@ func (oc *oas2OperationBuilder) getOperationDescription(pathKey string, method s
return utils.StripHTMLTags(operation.Description)
}
- return strings.ToUpper(method) + " " + pathKey
+ return strings.ToUpper(oc.method) + " " + oc.pathKey
}
diff --git a/ndc-http-schema/openapi/internal/oas2_schema.go b/ndc-http-schema/openapi/internal/oas2_schema.go
index 5bb57a0..5f5d084 100644
--- a/ndc-http-schema/openapi/internal/oas2_schema.go
+++ b/ndc-http-schema/openapi/internal/oas2_schema.go
@@ -1,7 +1,6 @@
package internal
import (
- "errors"
"fmt"
"slices"
"strconv"
@@ -36,12 +35,13 @@ func (oc *oas2SchemaBuilder) getSchemaTypeFromParameter(param *v2.Parameter, fie
switch param.Type {
case "object":
- return nil, errors.New("unsupported object parameter")
+ return nil, fmt.Errorf("%s: unsupported object parameter", strings.Join(fieldPaths, "."))
case "array":
if param.Items == nil || param.Items.Type == "" {
if oc.builder.Strict {
- return nil, errors.New("array item is empty")
+ return nil, fmt.Errorf("%s: array item is empty", strings.Join(fieldPaths, "."))
}
+
typeEncoder = schema.NewArrayType(oc.builder.buildScalarJSON())
} else {
itemName, isNull := getScalarFromType(oc.builder.schema, []string{param.Items.Type}, param.Format, param.Enum, oc.trimPathPrefix(oc.apiPath), fieldPaths)
@@ -50,7 +50,7 @@ func (oc *oas2SchemaBuilder) getSchemaTypeFromParameter(param *v2.Parameter, fie
}
default:
if !isPrimitiveScalar([]string{param.Type}) {
- return nil, fmt.Errorf("unsupported schema type %s", param.Type)
+ return nil, fmt.Errorf("%s: unsupported schema type %s", strings.Join(fieldPaths, "."), param.Type)
}
scalarName, isNull := getScalarFromType(oc.builder.schema, []string{param.Type}, param.Format, param.Enum, oc.trimPathPrefix(oc.apiPath), fieldPaths)
@@ -136,8 +136,17 @@ func (oc *oas2SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
// treat no-property objects as a JSON scalar
oc.builder.schema.ScalarTypes[refName] = *defaultScalarTypes[rest.ScalarJSON]
} else {
+ xmlSchema := typeResult.XML
+ if xmlSchema == nil {
+ xmlSchema = &rest.XMLSchema{}
+ }
+
+ if xmlSchema.Name == "" {
+ xmlSchema.Name = fieldPaths[0]
+ }
object := rest.ObjectType{
Fields: make(map[string]rest.ObjectField),
+ XML: xmlSchema,
}
if description != "" {
object.Description = &description
@@ -163,13 +172,16 @@ func (oc *oas2SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
object.Fields[propName] = objField
}
+ if isXMLLeafObject(object) {
+ object.Fields[xmlValueFieldName] = xmlValueField
+ }
oc.builder.schema.ObjectTypes[refName] = object
}
result = schema.NewNamedType(refName)
case "array":
if typeSchema.Items == nil || typeSchema.Items.A == nil {
if oc.builder.ConvertOptions.Strict {
- return nil, nil, errors.New("array item is empty")
+ return nil, nil, fmt.Errorf("%s: array item is empty", strings.Join(fieldPaths, "."))
}
result = schema.NewArrayType(oc.builder.buildScalarJSON())
} else {
diff --git a/ndc-http-schema/openapi/internal/oas3.go b/ndc-http-schema/openapi/internal/oas3.go
index 429b531..7050793 100644
--- a/ndc-http-schema/openapi/internal/oas3.go
+++ b/ndc-http-schema/openapi/internal/oas3.go
@@ -262,6 +262,14 @@ func (oc *OAS3Builder) convertComponentSchemas(schemaItem orderedmap.Pair[string
if typeEncoder != nil {
typeName = getNamedType(typeEncoder, true, "")
}
+
+ if schemaResult.XML == nil {
+ schemaResult.XML = &rest.XMLSchema{}
+ }
+ if schemaResult.XML.Name == "" {
+ schemaResult.XML.Name = typeKey
+ }
+
cacheKey := "#/components/schemas/" + typeKey
// treat no-property objects as a Arbitrary JSON scalar
if typeEncoder == nil || typeName == string(rest.ScalarJSON) {
@@ -296,9 +304,7 @@ func (oc *OAS3Builder) trimPathPrefix(input string) string {
// build a named type for JSON scalar
func (oc *OAS3Builder) buildScalarJSON() *schema.NamedType {
scalarName := string(rest.ScalarJSON)
- if _, ok := oc.schema.ScalarTypes[scalarName]; !ok {
- oc.schema.ScalarTypes[scalarName] = *defaultScalarTypes[rest.ScalarJSON]
- }
+ oc.schema.AddScalar(scalarName, *defaultScalarTypes[rest.ScalarJSON])
return schema.NewNamedType(scalarName)
}
@@ -361,6 +367,7 @@ func (oc *OAS3Builder) populateWriteSchemaType(schemaType schema.Type) (schema.T
}
writeObject := rest.ObjectType{
Description: objectType.Description,
+ XML: objectType.XML,
Fields: make(map[string]rest.ObjectField),
}
var hasWriteField bool
diff --git a/ndc-http-schema/openapi/internal/oas3_operation.go b/ndc-http-schema/openapi/internal/oas3_operation.go
index 360c391..c33ce04 100644
--- a/ndc-http-schema/openapi/internal/oas3_operation.go
+++ b/ndc-http-schema/openapi/internal/oas3_operation.go
@@ -3,6 +3,7 @@ package internal
import (
"fmt"
"log/slog"
+ "slices"
"strconv"
"strings"
"time"
@@ -11,6 +12,7 @@ import (
"github.com/hasura/ndc-http/ndc-http-schema/utils"
"github.com/hasura/ndc-sdk-go/schema"
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
+ "github.com/pb33f/libopenapi/orderedmap"
)
type oas3OperationBuilder struct {
@@ -34,12 +36,13 @@ func newOAS3OperationBuilder(builder *OAS3Builder, pathKey string, method string
// BuildFunction build a HTTP NDC function information from OpenAPI v3 operation
func (oc *oas3OperationBuilder) BuildFunction(itemGet *v3.Operation) (*rest.OperationInfo, string, error) {
- start := time.Now()
- funcName := formatOperationName(itemGet.OperationId)
- if funcName == "" {
- funcName = buildPathMethodName(oc.pathKey, "get", oc.builder.ConvertOptions)
+ if oc.builder.ConvertOptions.NoDeprecation && itemGet.Deprecated != nil && *itemGet.Deprecated {
+ return nil, "", nil
}
+ start := time.Now()
+ funcName := buildUniqueOperationName(oc.builder.schema, itemGet.OperationId, oc.pathKey, oc.method, oc.builder.ConvertOptions)
+
defer func() {
oc.builder.Logger.Info("function",
slog.String("name", funcName),
@@ -53,6 +56,7 @@ func (oc *oas3OperationBuilder) BuildFunction(itemGet *v3.Operation) (*rest.Oper
if err != nil {
return nil, "", fmt.Errorf("%s: %w", oc.pathKey, err)
}
+
if resultType == nil {
return nil, "", nil
}
@@ -80,14 +84,12 @@ func (oc *oas3OperationBuilder) BuildFunction(itemGet *v3.Operation) (*rest.Oper
}
func (oc *oas3OperationBuilder) BuildProcedure(operation *v3.Operation) (*rest.OperationInfo, string, error) {
- if operation == nil {
+ if operation == nil || (oc.builder.ConvertOptions.NoDeprecation && operation.Deprecated != nil && *operation.Deprecated) {
return nil, "", nil
}
+
start := time.Now()
- procName := formatOperationName(operation.OperationId)
- if procName == "" {
- procName = buildPathMethodName(oc.pathKey, oc.method, oc.builder.ConvertOptions)
- }
+ procName := buildUniqueOperationName(oc.builder.schema, operation.OperationId, oc.pathKey, oc.method, oc.builder.ConvertOptions)
defer func() {
oc.builder.Logger.Info("procedure",
@@ -158,7 +160,7 @@ func (oc *oas3OperationBuilder) convertParameters(params []*v3.Parameter, apiPat
}
for _, param := range append(params, oc.commonParams...) {
- if param == nil {
+ if param == nil || (param.Deprecated && oc.builder.ConvertOptions.NoDeprecation) {
continue
}
paramName := param.Name
@@ -214,18 +216,33 @@ func (oc *oas3OperationBuilder) convertParameters(params []*v3.Parameter, apiPat
return nil
}
+func (oc *oas3OperationBuilder) getContentType(contents *orderedmap.Map[string, *v3.MediaType]) (string, *v3.MediaType) {
+ var contentType string
+ var media *v3.MediaType
+ for _, ct := range preferredContentTypes {
+ for iter := contents.First(); iter != nil; iter = iter.Next() {
+ key := iter.Key()
+ value := iter.Value()
+ if strings.HasPrefix(key, ct) && value != nil {
+ return key, value
+ }
+
+ if media == nil && value != nil && (len(oc.builder.AllowedContentTypes) == 0 || slices.Contains(oc.builder.AllowedContentTypes, key)) {
+ contentType = key
+ media = value
+ }
+ }
+ }
+
+ return contentType, media
+}
+
func (oc *oas3OperationBuilder) convertRequestBody(reqBody *v3.RequestBody, apiPath string, fieldPaths []string) (*rest.RequestBody, schema.TypeEncoder, error) {
if reqBody == nil || reqBody.Content == nil {
return nil, nil, nil
}
- contentType := rest.ContentTypeJSON
- content, ok := reqBody.Content.Get(contentType)
- if !ok {
- contentPair := reqBody.Content.First()
- contentType = contentPair.Key()
- content = contentPair.Value()
- }
+ contentType, content := oc.getContentType(reqBody.Content)
bodyRequired := false
if reqBody.Required != nil && *reqBody.Required {
@@ -335,6 +352,7 @@ func (oc *oas3OperationBuilder) convertResponse(responses *v3.Responses, apiPath
}
var resp *v3.Response
+ var statusCode int64
if responses.Codes != nil && !responses.Codes.IsZero() {
for r := responses.Codes.First(); r != nil; r = r.Next() {
if r.Key() == "" {
@@ -349,6 +367,7 @@ func (oc *oas3OperationBuilder) convertResponse(responses *v3.Responses, apiPath
return nil, nil, nil
} else if code >= 200 && code < 300 {
resp = r.Value()
+ statusCode = code
break
}
@@ -358,48 +377,40 @@ func (oc *oas3OperationBuilder) convertResponse(responses *v3.Responses, apiPath
// return nullable boolean type if the response content is null
if resp == nil || resp.Content == nil {
scalarName := string(rest.ScalarBoolean)
- if _, ok := oc.builder.schema.ScalarTypes[scalarName]; !ok {
- oc.builder.schema.ScalarTypes[scalarName] = *defaultScalarTypes[rest.ScalarBoolean]
- }
+ oc.builder.schema.AddScalar(scalarName, *defaultScalarTypes[rest.ScalarBoolean])
return schema.NewNullableNamedType(scalarName), &rest.Response{
ContentType: rest.ContentTypeJSON,
}, nil
}
- contentType := rest.ContentTypeJSON
- bodyContent, present := resp.Content.Get(contentType)
- if !present {
- if len(oc.builder.AllowedContentTypes) == 0 {
- firstContent := resp.Content.First()
- bodyContent = firstContent.Value()
- contentType = firstContent.Key()
- present = true
- } else {
- for _, ct := range oc.builder.AllowedContentTypes {
- bodyContent, present = resp.Content.Get(ct)
- if present {
- contentType = ct
-
- break
- }
- }
+ contentType, bodyContent := oc.getContentType(resp.Content)
+ if bodyContent == nil {
+ if statusCode == 204 {
+ scalarName := string(rest.ScalarBoolean)
+ oc.builder.schema.AddScalar(scalarName, *defaultScalarTypes[rest.ScalarBoolean])
+
+ return schema.NewNullableNamedType(scalarName), &rest.Response{
+ ContentType: rest.ContentTypeJSON,
+ }, nil
}
- }
- if !present {
return nil, nil, nil
}
+ schemaResponse := &rest.Response{
+ ContentType: contentType,
+ }
+ if bodyContent.Schema == nil {
+ return getResultTypeFromContentType(oc.builder.schema, contentType), schemaResponse, nil
+ }
+
schemaType, _, err := newOAS3SchemaBuilder(oc.builder, apiPath, rest.InBody, false).
getSchemaTypeFromProxy(bodyContent.Schema, false, fieldPaths)
if err != nil {
return nil, nil, err
}
- schemaResponse := &rest.Response{
- ContentType: contentType,
- }
switch contentType {
case rest.ContentTypeNdJSON:
// Newline Delimited JSON (ndjson) format represents a stream of structured objects
diff --git a/ndc-http-schema/openapi/internal/oas3_schema.go b/ndc-http-schema/openapi/internal/oas3_schema.go
index 562dcb4..321ac24 100644
--- a/ndc-http-schema/openapi/internal/oas3_schema.go
+++ b/ndc-http-schema/openapi/internal/oas3_schema.go
@@ -1,7 +1,6 @@
package internal
import (
- "errors"
"fmt"
"log/slog"
"slices"
@@ -35,6 +34,7 @@ func (oc *oas3SchemaBuilder) getSchemaTypeFromProxy(schemaProxy *base.SchemaProx
if schemaProxy == nil {
return nil, nil, errParameterSchemaEmpty(fieldPaths)
}
+
innerSchema := schemaProxy.Schema()
if innerSchema == nil {
return nil, nil, fmt.Errorf("cannot get schema of $.%s from proxy: %s", strings.Join(fieldPaths, "."), schemaProxy.GetReference())
@@ -101,6 +101,10 @@ func (oc *oas3SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
return nil, nil, errParameterSchemaEmpty(fieldPaths)
}
+ if oc.builder.ConvertOptions.NoDeprecation && typeSchema.Deprecated != nil && *typeSchema.Deprecated {
+ return nil, nil, nil
+ }
+
description := utils.StripHTMLTags(typeSchema.Description)
nullable := typeSchema.Nullable != nil && *typeSchema.Nullable
if len(typeSchema.AllOf) > 0 {
@@ -179,12 +183,15 @@ func (oc *oas3SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
object := rest.ObjectType{
Fields: make(map[string]rest.ObjectField),
+ XML: typeResult.XML,
}
readObject := rest.ObjectType{
Fields: make(map[string]rest.ObjectField),
+ XML: typeResult.XML,
}
writeObject := rest.ObjectType{
Fields: make(map[string]rest.ObjectField),
+ XML: typeResult.XML,
}
if description != "" {
@@ -237,6 +244,10 @@ func (oc *oas3SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
}
if len(readObject.Fields) == 0 && len(writeObject.Fields) == 0 {
+ if len(object.Fields) > 0 && isXMLLeafObject(object) {
+ object.Fields[xmlValueFieldName] = xmlValueField
+ }
+
oc.builder.schema.ObjectTypes[refName] = object
result = schema.NewNamedType(refName)
} else {
@@ -244,6 +255,15 @@ func (oc *oas3SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
readObject.Fields[key] = field
writeObject.Fields[key] = field
}
+
+ if len(readObject.Fields) > 0 && isXMLLeafObject(readObject) {
+ readObject.Fields[xmlValueFieldName] = xmlValueField
+ }
+
+ if len(writeObject.Fields) > 0 && isXMLLeafObject(writeObject) {
+ writeObject.Fields[xmlValueFieldName] = xmlValueField
+ }
+
writeRefName := formatWriteObjectName(refName)
oc.builder.schema.ObjectTypes[refName] = readObject
oc.builder.schema.ObjectTypes[writeRefName] = writeObject
@@ -255,7 +275,11 @@ func (oc *oas3SchemaBuilder) getSchemaType(typeSchema *base.Schema, fieldPaths [
}
case "array":
if typeSchema.Items == nil || typeSchema.Items.A == nil {
- return nil, nil, errors.New("array item is empty")
+ if oc.builder.Strict {
+ return nil, nil, fmt.Errorf("%s: array item is empty", strings.Join(fieldPaths, "."))
+ }
+
+ return oc.builder.buildScalarJSON(), typeResult, nil
}
itemName := getSchemaRefTypeNameV3(typeSchema.Items.A.GetReference())
diff --git a/ndc-http-schema/openapi/internal/types.go b/ndc-http-schema/openapi/internal/types.go
index f1eea24..dac31fa 100644
--- a/ndc-http-schema/openapi/internal/types.go
+++ b/ndc-http-schema/openapi/internal/types.go
@@ -7,6 +7,7 @@ import (
rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
"github.com/hasura/ndc-sdk-go/schema"
+ "github.com/hasura/ndc-sdk-go/utils"
)
var (
@@ -19,6 +20,8 @@ var (
errParameterNameRequired = errors.New("parameter name is empty")
)
+var preferredContentTypes = []string{rest.ContentTypeJSON, rest.ContentTypeXML}
+
var defaultScalarTypes = map[rest.ScalarName]*schema.ScalarType{
rest.ScalarBoolean: {
AggregateFunctions: schema.ScalarTypeAggregateFunctions{},
@@ -113,6 +116,21 @@ var defaultScalarTypes = map[rest.ScalarName]*schema.ScalarType{
},
}
+const xmlValueFieldName string = "xmlValue"
+
+var xmlValueField = rest.ObjectField{
+ ObjectField: schema.ObjectField{
+ Description: utils.ToPtr("Value of the xml field"),
+ Type: schema.NewNamedType(string(rest.ScalarString)).Encode(),
+ },
+ HTTP: &rest.TypeSchema{
+ Type: []string{"string"},
+ XML: &rest.XMLSchema{
+ Text: true,
+ },
+ },
+}
+
// ConvertOptions represent the common convert options for both OpenAPI v2 and v3
type ConvertOptions struct {
MethodAlias map[string]string
@@ -121,5 +139,6 @@ type ConvertOptions struct {
TrimPrefix string
EnvPrefix string
Strict bool
+ NoDeprecation bool
Logger *slog.Logger
}
diff --git a/ndc-http-schema/openapi/internal/utils.go b/ndc-http-schema/openapi/internal/utils.go
index bd49861..3e0a69d 100644
--- a/ndc-http-schema/openapi/internal/utils.go
+++ b/ndc-http-schema/openapi/internal/utils.go
@@ -239,6 +239,16 @@ func createSchemaFromOpenAPISchema(input *base.Schema) *rest.TypeSchema {
ps.ReadOnly = input.ReadOnly != nil && *input.ReadOnly
ps.WriteOnly = input.WriteOnly != nil && *input.WriteOnly
+ if input.XML != nil {
+ ps.XML = &rest.XMLSchema{
+ Name: input.XML.Name,
+ Prefix: input.XML.Prefix,
+ Namespace: input.XML.Namespace,
+ Wrapped: input.XML.Wrapped,
+ Attribute: input.XML.Attribute,
+ }
+ }
+
return ps
}
@@ -407,3 +417,48 @@ func formatOperationName(input string) string {
return sb.String()
}
+
+func buildUniqueOperationName(httpSchema *rest.NDCHttpSchema, operationId, pathKey, method string, options *ConvertOptions) string {
+ opName := formatOperationName(operationId)
+ exists := opName == ""
+ if !exists {
+ _, exists = httpSchema.Functions[opName]
+ if !exists {
+ _, exists = httpSchema.Procedures[opName]
+ }
+ }
+
+ if exists {
+ opName = buildPathMethodName(pathKey, method, options)
+ }
+
+ return opName
+}
+
+// guess the result type from content type
+func getResultTypeFromContentType(httpSchema *rest.NDCHttpSchema, contentType string) schema.TypeEncoder {
+ var scalarName rest.ScalarName
+ switch {
+ case strings.HasPrefix(contentType, "text/"):
+ scalarName = rest.ScalarString
+ case contentType == rest.ContentTypeOctetStream || strings.HasPrefix(contentType, "image/") || strings.HasPrefix(contentType, "video/"):
+ scalarName = rest.ScalarBinary
+ default:
+ scalarName = rest.ScalarJSON
+ }
+
+ httpSchema.AddScalar(string(scalarName), *defaultScalarTypes[scalarName])
+
+ return schema.NewNamedType(string(scalarName))
+}
+
+// check if the XML object doesn't have any child element.
+func isXMLLeafObject(objectType rest.ObjectType) bool {
+ for _, field := range objectType.Fields {
+ if field.HTTP == nil || field.HTTP.XML == nil || !field.HTTP.XML.Attribute {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/ndc-http-schema/openapi/oas3_test.go b/ndc-http-schema/openapi/oas3_test.go
index 35bc6c4..43a0e30 100644
--- a/ndc-http-schema/openapi/oas3_test.go
+++ b/ndc-http-schema/openapi/oas3_test.go
@@ -33,14 +33,16 @@ func TestOpenAPIv3ToRESTSchema(t *testing.T) {
EnvPrefix: "PET_STORE",
},
},
- // go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/onesignal/source.json -o ./ndc-http-schema/openapi/testdata/onesignal/expected.json --spec openapi3
- // go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/onesignal/source.json -o ./ndc-http-schema/openapi/testdata/onesignal/schema.json --pure --spec openapi3
+ // go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/onesignal/source.json -o ./ndc-http-schema/openapi/testdata/onesignal/expected.json --spec openapi3 --no-deprecation
+ // go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/onesignal/source.json -o ./ndc-http-schema/openapi/testdata/onesignal/schema.json --pure --spec openapi3 --no-deprecation
{
Name: "onesignal",
Source: "testdata/onesignal/source.json",
Expected: "testdata/onesignal/expected.json",
Schema: "testdata/onesignal/schema.json",
- Options: ConvertOptions{},
+ Options: ConvertOptions{
+ NoDeprecation: true,
+ },
},
// go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/openai/source.json -o ./ndc-http-schema/openapi/testdata/openai/expected.json --spec openapi3
// go run ./ndc-http-schema convert -f ./ndc-http-schema/openapi/testdata/openai/source.json -o ./ndc-http-schema/openapi/testdata/openai/schema.json --pure --spec openapi3
diff --git a/ndc-http-schema/openapi/testdata/jsonplaceholder/expected.json b/ndc-http-schema/openapi/testdata/jsonplaceholder/expected.json
index 3e6c6f9..af06af1 100644
--- a/ndc-http-schema/openapi/testdata/jsonplaceholder/expected.json
+++ b/ndc-http-schema/openapi/testdata/jsonplaceholder/expected.json
@@ -679,6 +679,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Album"
}
},
"Comment": {
@@ -756,6 +759,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Comment"
}
},
"Photo": {
@@ -834,6 +840,9 @@
"format": "uri"
}
}
+ },
+ "xml": {
+ "name": "Photo"
}
},
"Post": {
@@ -896,6 +905,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Post"
}
},
"Todo": {
@@ -958,6 +970,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Todo"
}
},
"User": {
@@ -1076,6 +1091,9 @@
]
}
}
+ },
+ "xml": {
+ "name": "User"
}
},
"UserAddress": {
@@ -1150,6 +1168,9 @@
]
}
}
+ },
+ "xml": {
+ "name": "User"
}
},
"UserAddressGeo": {
@@ -1182,6 +1203,9 @@
]
}
}
+ },
+ "xml": {
+ "name": "User"
}
},
"UserCompany": {
@@ -1228,6 +1252,9 @@
]
}
}
+ },
+ "xml": {
+ "name": "User"
}
}
},
diff --git a/ndc-http-schema/openapi/testdata/onesignal/expected.json b/ndc-http-schema/openapi/testdata/onesignal/expected.json
index be9e4a4..998cece 100644
--- a/ndc-http-schema/openapi/testdata/onesignal/expected.json
+++ b/ndc-http-schema/openapi/testdata/onesignal/expected.json
@@ -798,28 +798,6 @@
]
}
},
- "include_player_ids": {
- "type": {
- "type": "nullable",
- "underlying_type": {
- "element_type": {
- "name": "String",
- "type": "named"
- },
- "type": "array"
- }
- },
- "http": {
- "type": [
- "array"
- ],
- "items": {
- "type": [
- "string"
- ]
- }
- }
- },
"included_segments": {
"type": {
"type": "nullable",
diff --git a/ndc-http-schema/openapi/testdata/onesignal/schema.json b/ndc-http-schema/openapi/testdata/onesignal/schema.json
index 7e98fc7..2909135 100644
--- a/ndc-http-schema/openapi/testdata/onesignal/schema.json
+++ b/ndc-http-schema/openapi/testdata/onesignal/schema.json
@@ -488,18 +488,6 @@
}
}
},
- "include_player_ids": {
- "type": {
- "type": "nullable",
- "underlying_type": {
- "element_type": {
- "name": "String",
- "type": "named"
- },
- "type": "array"
- }
- }
- },
"included_segments": {
"type": {
"type": "nullable",
diff --git a/ndc-http-schema/openapi/testdata/petstore2/expected.json b/ndc-http-schema/openapi/testdata/petstore2/expected.json
index cfb8e31..0884050 100644
--- a/ndc-http-schema/openapi/testdata/petstore2/expected.json
+++ b/ndc-http-schema/openapi/testdata/petstore2/expected.json
@@ -71,7 +71,9 @@
"name": "aggregated_by",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -88,7 +90,9 @@
"name": "browsers",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -105,7 +109,9 @@
"name": "end_date",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -122,7 +128,9 @@
"name": "limit",
"in": "query",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -139,7 +147,9 @@
"name": "offset",
"in": "query",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -155,7 +165,9 @@
"name": "on-behalf-of",
"in": "header",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -169,7 +181,9 @@
"name": "start_date",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -207,7 +221,9 @@
"name": "list_id",
"in": "path",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -223,7 +239,9 @@
"name": "on-behalf-of",
"in": "header",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -260,7 +278,9 @@
"name": "on-behalf-of",
"in": "header",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -298,7 +318,9 @@
"name": "username",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -315,7 +337,10 @@
"method": "get",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -336,7 +361,9 @@
"name": "status",
"in": "query",
"schema": {
- "type": ["array"]
+ "type": [
+ "array"
+ ]
}
}
}
@@ -356,7 +383,10 @@
"method": "get",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -377,7 +407,9 @@
"name": "tags",
"in": "query",
"schema": {
- "type": ["array"]
+ "type": [
+ "array"
+ ]
}
}
}
@@ -430,7 +462,9 @@
"name": "orderId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"maximum": 10,
"minimum": 1
}
@@ -467,7 +501,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -512,7 +548,9 @@
"name": "username",
"in": "path",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -545,7 +583,9 @@
"name": "client_name",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -562,7 +602,9 @@
"name": "limit",
"in": "query",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -579,7 +621,9 @@
"name": "offset",
"in": "query",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -596,7 +640,9 @@
"name": "owner",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -646,7 +692,9 @@
"name": "password",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -660,7 +708,9 @@
"name": "username",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -686,7 +736,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"unique_clicks": {
@@ -699,9 +751,14 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
+ },
+ "xml": {
+ "name": "advanced_stats_clicks"
}
},
"AdvancedStatsClicksOpens": {
@@ -717,7 +774,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"opens": {
@@ -730,7 +789,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"unique_clicks": {
@@ -743,7 +804,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"unique_opens": {
@@ -756,7 +819,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -772,7 +837,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -785,7 +852,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -797,9 +866,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "ApiResponse"
}
},
"Category": {
@@ -813,7 +887,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -826,9 +902,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "Category"
}
},
"ContactdbCustomFieldWithIdValue": {
@@ -843,7 +924,9 @@
}
},
"http": {
- "type": ["number"]
+ "type": [
+ "number"
+ ]
}
},
"name": {
@@ -856,7 +939,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -869,7 +954,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"value": {
@@ -882,7 +969,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -901,12 +990,19 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
+ },
+ "xml": {
+ "name": "contactdb_recipient"
}
},
"ContactdbRecipientRecipients": {
@@ -924,7 +1020,9 @@
}
},
"http": {
- "type": ["array"]
+ "type": [
+ "array"
+ ]
}
},
"first_name": {
@@ -937,9 +1035,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "contactdb_recipient"
}
},
"DomainAuthenticationDomainSpf": {
@@ -951,7 +1054,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"custom_spf": {
@@ -961,7 +1066,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"default": {
@@ -971,7 +1078,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"dns": {
@@ -981,7 +1090,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"domain": {
@@ -991,7 +1102,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"id": {
@@ -1001,7 +1114,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"ips": {
@@ -1014,7 +1129,9 @@
"type": "array"
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
"type": null
}
@@ -1027,7 +1144,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"subdomain": {
@@ -1040,7 +1159,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"user_id": {
@@ -1050,7 +1171,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"username": {
@@ -1060,7 +1183,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"valid": {
@@ -1070,9 +1195,14 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"DomainAuthenticationDomainSpfDns": {
@@ -1085,7 +1215,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"domain_spf": {
@@ -1095,7 +1227,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"mail_server": {
@@ -1105,7 +1239,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"subdomain_spf": {
@@ -1115,9 +1251,14 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"DomainAuthenticationDomainSpfDnsDkim": {
@@ -1130,7 +1271,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"host": {
@@ -1140,7 +1283,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1150,7 +1295,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"valid": {
@@ -1160,9 +1307,14 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"DomainAuthenticationDomainSpfDnsDomainSpf": {
@@ -1175,7 +1327,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"host": {
@@ -1185,7 +1339,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1195,7 +1351,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"valid": {
@@ -1205,9 +1363,14 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"DomainAuthenticationDomainSpfDnsMailServer": {
@@ -1220,7 +1383,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"host": {
@@ -1230,7 +1395,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1240,7 +1407,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"valid": {
@@ -1250,9 +1419,14 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"DomainAuthenticationDomainSpfDnsSubdomainSpf": {
@@ -1265,7 +1439,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"host": {
@@ -1275,7 +1451,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1285,7 +1463,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"valid": {
@@ -1295,9 +1475,14 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
+ },
+ "xml": {
+ "name": "domain_authentication:domain_spf"
}
},
"GETBrowsersStatsResult": {
@@ -1312,7 +1497,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"stats": {
@@ -1328,12 +1515,19 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
+ },
+ "xml": {
+ "name": "GET_browsers_stats"
}
},
"GETBrowsersStatsResultStats": {
@@ -1348,7 +1542,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"name": {
@@ -1361,7 +1557,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1374,9 +1572,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "GET_browsers_stats"
}
},
"GETContactdbListsListIdRecipientsResult": {
@@ -1393,9 +1596,14 @@
}
},
"http": {
- "type": ["array"]
+ "type": [
+ "array"
+ ]
}
}
+ },
+ "xml": {
+ "name": "GET_contactdb_lists_list_id_recipients"
}
},
"GETGeoStatsResult": {
@@ -1410,7 +1618,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"stats": {
@@ -1426,12 +1636,19 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
+ },
+ "xml": {
+ "name": "GET_geo_stats"
}
},
"GETGeoStatsResultStats": {
@@ -1446,7 +1663,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"name": {
@@ -1459,7 +1678,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1472,9 +1693,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "GET_geo_stats"
}
},
"OAuth2Client": {
@@ -1489,7 +1715,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"client_name": {
@@ -1502,7 +1730,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"client_secret": {
@@ -1515,7 +1745,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"client_secret_expires_at": {
@@ -1528,7 +1760,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1542,9 +1776,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "oAuth2Client"
}
},
"Order": {
@@ -1558,7 +1797,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"id": {
@@ -1570,7 +1811,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1583,7 +1826,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1596,7 +1841,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -1609,7 +1856,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "date-time"
}
},
@@ -1623,9 +1872,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "Order"
}
},
"Pet": {
@@ -1639,7 +1893,12 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "Category"
+ }
}
},
"field": {
@@ -1664,7 +1923,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1674,7 +1935,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"photoUrls": {
@@ -1686,9 +1949,20 @@
"type": "array"
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "name": "photoUrl"
+ }
+ },
+ "xml": {
+ "name": "",
+ "wrapped": true
}
}
},
@@ -1702,7 +1976,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"tags": {
@@ -1717,9 +1993,18 @@
}
},
"http": {
- "type": ["array"]
+ "type": [
+ "array"
+ ],
+ "xml": {
+ "name": "",
+ "wrapped": true
+ }
}
}
+ },
+ "xml": {
+ "name": "Pet"
}
},
"SnakeObject": {
@@ -1745,7 +2030,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1758,9 +2045,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "User"
}
},
"Tag": {
@@ -1774,7 +2066,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1787,9 +2081,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "Tag"
}
},
"UpdatePetWithFormBody": {
@@ -1804,7 +2103,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"status": {
@@ -1817,7 +2118,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1834,7 +2137,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"file": {
@@ -1847,7 +2152,9 @@
}
},
"http": {
- "type": ["file"]
+ "type": [
+ "file"
+ ]
}
}
}
@@ -1863,7 +2170,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"firstName": {
@@ -1875,7 +2184,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"id": {
@@ -1887,7 +2198,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -1900,7 +2213,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"password": {
@@ -1912,7 +2227,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"phone": {
@@ -1924,7 +2241,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"userStatus": {
@@ -1937,7 +2256,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -1950,9 +2271,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "User"
}
}
},
@@ -1963,7 +2289,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -1983,7 +2312,12 @@
"http": {
"in": "body",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "Pet"
+ }
}
}
}
@@ -2031,7 +2365,9 @@
"name": "orderId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"minimum": 1
}
}
@@ -2052,7 +2388,10 @@
"method": "delete",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -2072,7 +2411,9 @@
"name": "api_key",
"in": "header",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -2086,7 +2427,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -2119,7 +2462,9 @@
"name": "username",
"in": "path",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2153,7 +2498,9 @@
"http": {
"in": "body",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -2185,7 +2532,12 @@
"http": {
"in": "body",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "Order"
+ }
}
}
}
@@ -2196,13 +2548,64 @@
"type": "named"
}
},
+ "putPetXml": {
+ "request": {
+ "url": "/pet/xml",
+ "method": "put",
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ],
+ "requestBody": {
+ "contentType": "application/xml"
+ },
+ "response": {
+ "contentType": "application/xml"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Pet object that needs to be added to the store",
+ "type": {
+ "name": "Pet",
+ "type": "named"
+ },
+ "http": {
+ "in": "body",
+ "schema": {
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "Pet"
+ }
+ }
+ }
+ }
+ },
+ "description": "PUT /pet/xml",
+ "result_type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Boolean",
+ "type": "named"
+ }
+ }
+ },
"updatePet": {
"request": {
"url": "/pet",
"method": "put",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -2222,7 +2625,12 @@
"http": {
"in": "body",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "Pet"
+ }
}
}
}
@@ -2242,7 +2650,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -2262,7 +2673,9 @@
"http": {
"in": "formData",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -2276,7 +2689,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -2311,7 +2726,12 @@
"http": {
"in": "body",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "User"
+ }
}
}
},
@@ -2325,7 +2745,9 @@
"name": "username",
"in": "path",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2345,7 +2767,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -2365,7 +2790,9 @@
"http": {
"in": "formData",
"schema": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -2379,7 +2806,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -2410,7 +2839,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["day", "week", "month"],
+ "one_of": [
+ "day",
+ "week",
+ "month"
+ ],
"type": "enum"
}
},
@@ -2418,7 +2851,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["date", "text", "number"],
+ "one_of": [
+ "date",
+ "text",
+ "number"
+ ],
"type": "enum"
}
},
@@ -2461,7 +2898,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["placed", "approved", "delivered"],
+ "one_of": [
+ "placed",
+ "approved",
+ "delivered"
+ ],
"type": "enum"
}
},
@@ -2469,7 +2910,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["available", "pending", "sold"],
+ "one_of": [
+ "available",
+ "pending",
+ "sold"
+ ],
"type": "enum"
}
},
diff --git a/ndc-http-schema/openapi/testdata/petstore2/schema.json b/ndc-http-schema/openapi/testdata/petstore2/schema.json
index 88ff895..a660857 100644
--- a/ndc-http-schema/openapi/testdata/petstore2/schema.json
+++ b/ndc-http-schema/openapi/testdata/petstore2/schema.json
@@ -1449,6 +1449,26 @@
"type": "named"
}
},
+ {
+ "arguments": {
+ "body": {
+ "description": "Pet object that needs to be added to the store",
+ "type": {
+ "name": "Pet",
+ "type": "named"
+ }
+ }
+ },
+ "description": "PUT /pet/xml",
+ "name": "putPetXml",
+ "result_type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Boolean",
+ "type": "named"
+ }
+ }
+ },
{
"arguments": {
"body": {
diff --git a/ndc-http-schema/openapi/testdata/petstore2/swagger.json b/ndc-http-schema/openapi/testdata/petstore2/swagger.json
index 0e0e09d..4ae38ad 100644
--- a/ndc-http-schema/openapi/testdata/petstore2/swagger.json
+++ b/ndc-http-schema/openapi/testdata/petstore2/swagger.json
@@ -119,6 +119,29 @@
"security": [{ "petstore_auth": ["write:pets", "read:pets"] }]
}
},
+
+ "/pet/xml": {
+ "put": {
+ "operationId": "updatePet",
+ "consumes": ["application/xml"],
+ "produces": ["application/xml"],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "body",
+ "description": "Pet object that needs to be added to the store",
+ "required": true,
+ "schema": { "$ref": "#/definitions/Pet" }
+ }
+ ],
+ "responses": {
+ "400": { "description": "Invalid ID supplied" },
+ "404": { "description": "Pet not found" },
+ "405": { "description": "Validation exception" }
+ },
+ "security": [{ "petstore_auth": ["write:pets", "read:pets"] }]
+ }
+ },
"/pet/findByStatus": {
"get": {
"tags": ["pet"],
diff --git a/ndc-http-schema/openapi/testdata/petstore3/expected.json b/ndc-http-schema/openapi/testdata/petstore3/expected.json
index 4ae617e..2e69209 100644
--- a/ndc-http-schema/openapi/testdata/petstore3/expected.json
+++ b/ndc-http-schema/openapi/testdata/petstore3/expected.json
@@ -50,7 +50,10 @@
"security": [
{},
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"version": "1.0.19"
@@ -79,7 +82,9 @@
"name": "collection_method",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -116,7 +121,9 @@
"name": "customer",
"in": "query",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -153,7 +160,9 @@
"name": "ending_before",
"in": "query",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -176,9 +185,13 @@
"name": "expand",
"in": "query",
"schema": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -198,7 +211,9 @@
"name": "limit",
"in": "query",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
},
@@ -216,7 +231,9 @@
"name": "starting_after",
"in": "query",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -235,7 +252,9 @@
"name": "status",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -253,7 +272,9 @@
"name": "subscription",
"in": "query",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -271,7 +292,10 @@
"method": "get",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -292,7 +316,9 @@
"name": "start_date",
"in": "query",
"schema": {
- "type": ["number"]
+ "type": [
+ "number"
+ ]
}
}
},
@@ -310,7 +336,9 @@
"name": "status",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -330,7 +358,10 @@
"method": "get",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -355,9 +386,13 @@
"name": "tags",
"in": "query",
"schema": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -372,6 +407,69 @@
"type": "array"
}
},
+ "getArchitectures": {
+ "request": {
+ "url": "/architectures",
+ "method": "get",
+ "response": {
+ "contentType": "application/xml; charset=utf-8"
+ }
+ },
+ "arguments": {},
+ "description": "List all known architectures.",
+ "result_type": {
+ "name": "GetArchitecturesResult",
+ "type": "named"
+ }
+ },
+ "getBuildProjectNameRepositoryNameBuildconfig": {
+ "request": {
+ "url": "/build/{project_name}/{repository_name}/_buildconfig",
+ "method": "get",
+ "response": {
+ "contentType": "text/plain"
+ }
+ },
+ "arguments": {
+ "project_name": {
+ "description": "Project name",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "name": "project_name",
+ "in": "path",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ },
+ "repository_name": {
+ "description": "Repository name",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "name": "repository_name",
+ "in": "path",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ "description": "Show the build configuration for the specified repository.",
+ "result_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
"getInventory": {
"request": {
"url": "/store/inventory",
@@ -411,7 +509,9 @@
"name": "orderId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -432,7 +532,10 @@
"api_key": []
},
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -450,7 +553,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -462,6 +567,92 @@
"type": "named"
}
},
+ "getSearchXml": {
+ "request": {
+ "url": "/search/xml",
+ "method": "get",
+ "response": {
+ "contentType": "application/xml; charset=utf-8"
+ }
+ },
+ "arguments": {
+ "in": {
+ "description": "Where to search and apply a XPath expression: either the list of projects or the list of packages. Example of a result when `projects` is selected: ``` x86_64 x86_64 Standard OBS instance at build.opensuse.org This instance delivers the default build targets for OBS. https://api.opensuse.org/public ``` Example of a result when `packages` is selected: ``` ```",
+ "type": {
+ "name": "SearchIn",
+ "type": "named"
+ },
+ "http": {
+ "name": "in",
+ "in": "query",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ },
+ "match": {
+ "description": "XPath expression used to filter the results.",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "name": "match",
+ "in": "query",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ },
+ "return": {
+ "description": "XPath expression that defines which values will be returned. Instead of returning a collection of projects or packages, the result will be a collection of: - contents of elements, when that XPath expression match elements, or, - values of atttributes, when that XPath expression match atttributes. Example of result, for a query string like `?in=projects\u0026match=repository/arch='x86_64'\u0026return=repository/name`: ``` openSUSE_Tumbleweed 15.3 ```",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "name": "return",
+ "in": "query",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ },
+ "values": {
+ "description": "When set to `1`, return a list of values, instead of returning a list of projects or packages. The result will be a collection of: - contents of elements, when the expression defined in the `match` query parameter match elements. For example: `match=repository/arch`. - values of atttributes, when the expression defined in the `match` query parameter match atttributes. For example: `match=repository/name`. Example of result, for a query string like `?in=projects\u0026match=repository/path/project\u0026values=1`: ``` openSUSE.org:openSUSE:Factory openSUSE.org:openSUSE:Leap:15.3 ```",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "name": "values",
+ "in": "query",
+ "schema": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ "description": "Search in projects or in packages.",
+ "result_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ },
"getSnake": {
"request": {
"url": "/snake",
@@ -496,7 +687,9 @@
"name": "username",
"in": "path",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -529,7 +722,9 @@
"name": "password",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -546,7 +741,9 @@
"name": "username",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -570,7 +767,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"state": {
@@ -582,7 +781,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"street": {
@@ -594,7 +795,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"zip": {
@@ -606,9 +809,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "address"
}
},
"ApiResponse": {
@@ -622,7 +830,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -635,7 +845,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -647,27 +859,37 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "##default"
}
},
- "Category": {
+ "Book": {
"fields": {
- "id": {
+ "attr": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Int64",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["integer"],
- "format": "int64"
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "prefix": "smp",
+ "attribute": true
+ }
}
},
- "name": {
+ "author": {
"type": {
"type": "nullable",
"underlying_type": {
@@ -676,14 +898,26 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
- }
- }
- },
- "CreateFineTuningJobRequest": {
- "fields": {
- "model": {
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ]
+ }
+ },
+ "title": {
"type": {
"type": "nullable",
"underlying_type": {
@@ -692,220 +926,532 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "book",
+ "prefix": "smp",
+ "namespace": "http://example.com/schema"
}
},
- "GetInvoicesResult": {
+ "Category": {
"fields": {
- "has_more": {
- "description": "True if this list has another page of items after this one that can be fetched.",
+ "id": {
"type": {
- "name": "Boolean",
- "type": "named"
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "integer"
+ ],
+ "format": "int64"
}
},
- "object": {
- "description": "String representing the object's type. Objects of the same type share the same value. Always has the value `list`.",
+ "name": {
"type": {
- "name": "InvoicesObject",
- "type": "named"
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
- },
- "url": {
- "description": "The URL where this list can be accessed.",
+ }
+ },
+ "xml": {
+ "name": "category"
+ }
+ },
+ "CreateFineTuningJobRequest": {
+ "fields": {
+ "model": {
"type": {
- "name": "String",
- "type": "named"
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
},
"http": {
- "type": ["string"],
- "pattern": "^/v1/invoices",
- "maxLength": 5000
+ "type": [
+ "string"
+ ]
}
}
}
},
- "Order": {
+ "GetArchitecturesResult": {
"fields": {
- "complete": {
+ "count": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Boolean",
+ "name": "Int32",
"type": "named"
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "id": {
+ "entry": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Int64",
- "type": "named"
+ "element_type": {
+ "name": "GetArchitecturesResultEntry",
+ "type": "named"
+ },
+ "type": "array"
}
},
"http": {
- "type": ["integer"],
- "format": "int64"
+ "type": [
+ "array"
+ ],
+ "items": {
+ "type": [
+ "object"
+ ]
+ }
}
},
- "petId": {
+ "name": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Int64",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["integer"],
- "format": "int64"
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "quantity": {
+ "rev": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Int32",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["integer"],
- "format": "int32"
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "shipDate": {
+ "srcmd5": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "TimestampTZ",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["string"],
- "format": "date-time"
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "status": {
- "description": "Order Status",
+ "vrev": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "OrderStatus",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
}
+ },
+ "xml": {
+ "name": "directory"
}
},
- "Pet": {
+ "GetArchitecturesResultEntry": {
"fields": {
- "category": {
+ "md5": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Category",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "field": {
- "description": "This empty field is returned instead of the list of scopes if the user making the call doesn't have the authorization required.",
+ "mtime": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "JSON",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": null
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "id": {
+ "name": {
"type": {
"type": "nullable",
"underlying_type": {
- "name": "Int64",
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["integer"],
- "format": "int64"
- }
- },
- "name": {
- "type": {
- "name": "String",
- "type": "named"
- },
- "http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
}
},
- "photoUrls": {
+ "size": {
"type": {
- "element_type": {
+ "type": "nullable",
+ "underlying_type": {
"name": "String",
"type": "named"
- },
- "type": "array"
+ }
},
"http": {
- "type": ["array"],
- "items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
}
}
},
- "status": {
- "description": "pet status in the store",
+ "xmlValue": {
+ "description": "Value of the xml field",
"type": {
- "type": "nullable",
- "underlying_type": {
- "name": "PetStatus",
- "type": "named"
- }
+ "name": "String",
+ "type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "text": true
+ }
}
- },
- "tags": {
- "type": {
- "type": "nullable",
- "underlying_type": {
- "element_type": {
- "name": "Tag",
+ }
+ }
+ },
+ "GetInvoicesResult": {
+ "fields": {
+ "has_more": {
+ "description": "True if this list has another page of items after this one that can be fetched.",
+ "type": {
+ "name": "Boolean",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "boolean"
+ ]
+ }
+ },
+ "object": {
+ "description": "String representing the object's type. Objects of the same type share the same value. Always has the value `list`.",
+ "type": {
+ "name": "InvoicesObject",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "string"
+ ]
+ }
+ },
+ "url": {
+ "description": "The URL where this list can be accessed.",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "pattern": "^/v1/invoices",
+ "maxLength": 5000
+ }
+ }
+ }
+ },
+ "Order": {
+ "fields": {
+ "complete": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Boolean",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "boolean"
+ ]
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "format": "int64"
+ }
+ },
+ "petId": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "format": "int64"
+ }
+ },
+ "quantity": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "format": "int32"
+ }
+ },
+ "shipDate": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "TimestampTZ",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "format": "date-time"
+ }
+ },
+ "status": {
+ "description": "Order Status",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "OrderStatus",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ },
+ "xml": {
+ "name": "order"
+ }
+ },
+ "Pet": {
+ "fields": {
+ "category": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Category",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "category"
+ }
+ }
+ },
+ "field": {
+ "description": "This empty field is returned instead of the list of scopes if the user making the call doesn't have the authorization required.",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": null
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int64",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "format": "int64"
+ }
+ },
+ "name": {
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "string"
+ ]
+ }
+ },
+ "photoUrls": {
+ "type": {
+ "element_type": {
+ "name": "String",
+ "type": "named"
+ },
+ "type": "array"
+ },
+ "http": {
+ "type": [
+ "array"
+ ],
+ "items": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "name": "photoUrl"
+ }
+ },
+ "xml": {
+ "wrapped": true
+ }
+ }
+ },
+ "status": {
+ "description": "pet status in the store",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "PetStatus",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ]
+ }
+ },
+ "tags": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "Tag",
"type": "named"
},
"type": "array"
}
},
"http": {
- "type": ["array"]
+ "type": [
+ "array"
+ ],
+ "xml": {
+ "wrapped": true
+ }
}
}
+ },
+ "xml": {
+ "name": "pet"
}
},
"PostCheckoutSessionsBody": {
@@ -920,7 +1466,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"allow_promotion_codes": {
@@ -933,7 +1481,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"automatic_tax": {
@@ -946,7 +1496,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"billing_address_collection": {
@@ -959,7 +1511,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"cancel_url": {
@@ -972,7 +1526,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -986,7 +1542,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 200
}
},
@@ -1000,7 +1558,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"currency": {
@@ -1013,7 +1573,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"custom_fields": {
@@ -1029,9 +1591,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -1045,7 +1611,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"customer": {
@@ -1058,7 +1626,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -1072,7 +1642,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"customer_email": {
@@ -1085,7 +1657,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"customer_update": {
@@ -1098,7 +1672,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"discounts": {
@@ -1114,9 +1690,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -1133,9 +1713,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -1150,7 +1734,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -1164,7 +1750,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"line_items": {
@@ -1180,9 +1768,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -1196,7 +1788,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"metadata": {
@@ -1209,7 +1803,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"mode": {
@@ -1222,7 +1818,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"payment_intent_data": {
@@ -1235,7 +1833,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"payment_method_collection": {
@@ -1248,7 +1848,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"payment_method_configuration": {
@@ -1261,7 +1863,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 100
}
},
@@ -1275,7 +1879,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"payment_method_types": {
@@ -1291,9 +1897,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -1307,7 +1917,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"redirect_on_completion": {
@@ -1320,7 +1932,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"return_url": {
@@ -1333,7 +1947,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -1347,7 +1963,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"shipping_address_collection": {
@@ -1360,7 +1978,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"shipping_options": {
@@ -1376,9 +1996,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -1392,7 +2016,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"subscription_data": {
@@ -1405,7 +2031,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"success_url": {
@@ -1418,7 +2046,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -1432,7 +2062,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"ui_mode": {
@@ -1445,7 +2077,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1462,7 +2096,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -1478,7 +2114,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"enabled": {
@@ -1487,7 +2125,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
}
@@ -1501,7 +2141,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"liability": {
@@ -1513,7 +2155,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -1529,7 +2173,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -1538,7 +2184,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1555,7 +2203,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"promotions": {
@@ -1567,7 +2217,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"terms_of_service": {
@@ -1579,7 +2231,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1592,7 +2246,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1608,7 +2264,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"key": {
@@ -1617,7 +2275,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 200
}
},
@@ -1627,7 +2287,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"numeric": {
@@ -1639,7 +2301,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"optional": {
@@ -1651,7 +2315,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"text": {
@@ -1663,7 +2329,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"type": {
@@ -1672,7 +2340,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1688,9 +2358,13 @@
"type": "array"
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -1704,7 +2378,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 100
}
},
@@ -1714,7 +2390,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 100
}
}
@@ -1728,7 +2406,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 50
}
},
@@ -1738,7 +2418,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1754,7 +2436,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"minimum_length": {
@@ -1766,7 +2450,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -1782,7 +2468,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"minimum_length": {
@@ -1794,7 +2482,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -1811,7 +2501,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"shipping_address": {
@@ -1823,7 +2515,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"submit": {
@@ -1835,7 +2529,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"terms_of_service_acceptance": {
@@ -1847,7 +2543,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -1860,7 +2558,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1200
}
}
@@ -1874,7 +2574,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1200
}
}
@@ -1888,7 +2590,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1200
}
}
@@ -1902,7 +2606,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1200
}
}
@@ -1920,7 +2626,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"name": {
@@ -1932,7 +2640,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"shipping": {
@@ -1944,7 +2654,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -1960,7 +2672,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -1973,7 +2687,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -1988,7 +2704,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"invoice_data": {
@@ -2000,7 +2718,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -2019,9 +2739,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2038,9 +2762,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
},
@@ -2053,7 +2781,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1500
}
},
@@ -2066,7 +2796,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2079,7 +2811,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"metadata": {
@@ -2091,7 +2825,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"rendering_options": {
@@ -2103,7 +2839,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -2116,7 +2854,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 40
}
},
@@ -2126,7 +2866,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 140
}
}
@@ -2143,7 +2885,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -2152,7 +2896,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2168,7 +2914,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2184,7 +2932,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"dynamic_tax_rates": {
@@ -2199,9 +2949,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2215,7 +2969,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2228,7 +2984,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"quantity": {
@@ -2240,7 +2998,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"tax_rates": {
@@ -2255,9 +3015,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2272,7 +3036,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"maximum": {
@@ -2284,7 +3050,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"minimum": {
@@ -2296,7 +3064,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -2309,7 +3079,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"product": {
@@ -2321,7 +3093,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2334,7 +3108,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"recurring": {
@@ -2346,7 +3122,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"tax_behavior": {
@@ -2358,7 +3136,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"unit_amount": {
@@ -2370,7 +3150,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"unit_amount_decimal": {
@@ -2382,7 +3164,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "decimal"
}
}
@@ -2399,7 +3183,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 40000
}
},
@@ -2415,9 +3201,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -2430,7 +3220,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"name": {
@@ -2439,7 +3231,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2452,7 +3246,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2466,7 +3262,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"interval_count": {
@@ -2478,7 +3276,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -2495,7 +3295,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"capture_method": {
@@ -2507,7 +3309,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"description": {
@@ -2519,7 +3323,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1000
}
},
@@ -2532,7 +3338,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"on_behalf_of": {
@@ -2544,7 +3352,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"receipt_email": {
@@ -2556,7 +3366,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"setup_future_usage": {
@@ -2568,7 +3380,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"shipping": {
@@ -2580,7 +3394,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"statement_descriptor": {
@@ -2592,7 +3408,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 22
}
},
@@ -2605,7 +3423,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 22
}
},
@@ -2618,7 +3438,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"transfer_group": {
@@ -2630,7 +3452,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2643,7 +3467,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"carrier": {
@@ -2655,7 +3481,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2665,7 +3493,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2678,7 +3508,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2691,7 +3523,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2708,7 +3542,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2721,7 +3557,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2731,7 +3569,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2744,7 +3584,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2757,7 +3599,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -2770,7 +3614,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -2787,7 +3633,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"destination": {
@@ -2796,7 +3644,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -2813,7 +3663,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"affirm": {
@@ -2825,7 +3677,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"afterpay_clearpay": {
@@ -2837,7 +3691,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"alipay": {
@@ -2849,7 +3705,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"au_becs_debit": {
@@ -2861,7 +3719,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"bacs_debit": {
@@ -2873,7 +3733,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"bancontact": {
@@ -2885,7 +3747,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"boleto": {
@@ -2897,7 +3761,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"card": {
@@ -2909,7 +3775,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"cashapp": {
@@ -2921,7 +3789,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"customer_balance": {
@@ -2933,7 +3803,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"eps": {
@@ -2945,7 +3817,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"fpx": {
@@ -2957,7 +3831,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"giropay": {
@@ -2969,7 +3845,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"grabpay": {
@@ -2981,7 +3859,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"ideal": {
@@ -2993,7 +3873,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"klarna": {
@@ -3005,7 +3887,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"konbini": {
@@ -3017,7 +3901,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"link": {
@@ -3029,7 +3915,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"oxxo": {
@@ -3041,7 +3929,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"p24": {
@@ -3053,7 +3943,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"paynow": {
@@ -3065,7 +3957,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"paypal": {
@@ -3077,7 +3971,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"pix": {
@@ -3089,7 +3985,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"revolut_pay": {
@@ -3101,7 +3999,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"sepa_debit": {
@@ -3113,7 +4013,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"sofort": {
@@ -3125,7 +4027,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"swish": {
@@ -3137,7 +4041,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"us_bank_account": {
@@ -3149,7 +4055,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"wechat_pay": {
@@ -3161,7 +4069,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -3177,7 +4087,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"currency": {
@@ -3189,7 +4101,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"mandate_options": {
@@ -3201,7 +4115,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"setup_future_usage": {
@@ -3213,7 +4129,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"verification_method": {
@@ -3225,7 +4143,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3241,7 +4161,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"default_for": {
@@ -3256,9 +4178,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -3271,7 +4197,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 500
}
},
@@ -3284,7 +4212,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"transaction_type": {
@@ -3296,7 +4226,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3312,7 +4244,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3328,7 +4262,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3344,7 +4280,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3360,7 +4298,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3376,7 +4316,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3392,7 +4334,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3408,7 +4352,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"setup_future_usage": {
@@ -3420,7 +4366,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3436,7 +4384,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"request_three_d_secure": {
@@ -3448,7 +4398,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"setup_future_usage": {
@@ -3460,7 +4412,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"statement_descriptor_suffix_kana": {
@@ -3472,7 +4426,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 22
}
},
@@ -3485,7 +4441,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 17
}
}
@@ -3502,7 +4460,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
}
@@ -3518,7 +4478,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3534,7 +4496,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"funding_type": {
@@ -3546,7 +4510,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"setup_future_usage": {
@@ -3558,7 +4524,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3574,7 +4542,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"requested_address_types": {
@@ -3589,9 +4559,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -3601,7 +4575,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3614,7 +4590,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -3631,7 +4609,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3647,7 +4627,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3663,7 +4645,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3679,7 +4663,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3695,7 +4681,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3711,7 +4699,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3727,7 +4717,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"setup_future_usage": {
@@ -3739,7 +4731,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3755,7 +4749,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3771,7 +4767,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"setup_future_usage": {
@@ -3783,7 +4781,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3799,7 +4799,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"tos_shown_and_accepted": {
@@ -3811,7 +4813,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
}
@@ -3827,7 +4831,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3843,7 +4849,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"preferred_locale": {
@@ -3855,7 +4863,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"reference": {
@@ -3867,7 +4877,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 127
}
},
@@ -3880,7 +4892,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 32
}
},
@@ -3893,7 +4907,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3909,7 +4925,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -3925,7 +4943,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3941,7 +4961,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3957,7 +4979,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -3973,7 +4997,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -3990,7 +5016,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"setup_future_usage": {
@@ -4002,7 +5030,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"verification_method": {
@@ -4014,7 +5044,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4033,9 +5065,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -4052,9 +5088,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4071,7 +5111,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -4081,7 +5123,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"setup_future_usage": {
@@ -4093,7 +5137,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4107,7 +5153,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
}
@@ -4124,7 +5172,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 1000
}
},
@@ -4137,7 +5187,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"on_behalf_of": {
@@ -4149,7 +5201,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4166,9 +5220,13 @@
"type": "array"
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4185,7 +5243,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -4198,7 +5258,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4214,7 +5276,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"display_name": {
@@ -4223,7 +5287,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 100
}
},
@@ -4236,7 +5302,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"metadata": {
@@ -4248,7 +5316,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"tax_behavior": {
@@ -4260,7 +5330,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"tax_code": {
@@ -4272,7 +5344,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -4284,7 +5358,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4300,7 +5376,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"minimum": {
@@ -4312,7 +5390,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4325,7 +5405,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"value": {
@@ -4334,7 +5416,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -4347,7 +5431,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"value": {
@@ -4356,7 +5442,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -4369,7 +5457,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"currency": {
@@ -4378,7 +5468,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"currency_options": {
@@ -4390,7 +5482,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4407,7 +5501,9 @@
}
},
"http": {
- "type": ["number"]
+ "type": [
+ "number"
+ ]
}
},
"billing_cycle_anchor": {
@@ -4419,7 +5515,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -4435,9 +5533,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -4451,7 +5553,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 500
}
},
@@ -4464,7 +5568,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"metadata": {
@@ -4476,7 +5582,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"on_behalf_of": {
@@ -4488,7 +5596,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"proration_behavior": {
@@ -4500,7 +5610,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"transfer_data": {
@@ -4512,7 +5624,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"trial_end": {
@@ -4524,7 +5638,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -4537,7 +5653,9 @@
}
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"trial_settings": {
@@ -4549,7 +5667,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4565,7 +5685,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4581,7 +5703,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"type": {
@@ -4590,7 +5714,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4606,7 +5732,9 @@
}
},
"http": {
- "type": ["number"]
+ "type": [
+ "number"
+ ]
}
},
"destination": {
@@ -4615,7 +5743,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4628,7 +5758,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4641,7 +5773,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4655,7 +5789,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
}
}
@@ -4675,9 +5811,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -4694,9 +5834,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -4708,7 +5852,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "binary"
}
},
@@ -4722,7 +5868,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"purpose": {
@@ -4732,7 +5880,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -4746,7 +5896,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"expires_at": {
@@ -4758,7 +5910,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -4791,9 +5945,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -4808,7 +5966,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
}
}
@@ -4820,12 +5980,520 @@
"type": {
"type": "nullable",
"underlying_type": {
- "name": "TestHelpersCode",
+ "name": "TestHelpersCode",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ "PutCommentXmlBody": {
+ "fields": {
+ "comment": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "PutCommentXmlBodyComment",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ },
+ "http": {
+ "type": [
+ "array"
+ ],
+ "items": {
+ "type": [
+ "object"
+ ]
+ }
+ }
+ },
+ "comment_count": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "name": "comment",
+ "attribute": true
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "request": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "user": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "comments"
+ }
+ },
+ "PutCommentXmlBodyComment": {
+ "fields": {
+ "bsrequest": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "parent": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "when": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "who": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "xmlValue": {
+ "description": "Value of the xml field",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "text": true
+ }
+ }
+ }
+ }
+ },
+ "PutCommentXmlResult": {
+ "fields": {
+ "comment": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "PutCommentXmlResultComment",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ },
+ "http": {
+ "type": [
+ "array"
+ ],
+ "items": {
+ "type": [
+ "object"
+ ]
+ }
+ }
+ },
+ "comment_count": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "name": "comment",
+ "attribute": true
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "request": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "user": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "comments"
+ }
+ },
+ "PutCommentXmlResultComment": {
+ "fields": {
+ "bsrequest": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "parent": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "integer"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "when": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "who": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
"type": "named"
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "xmlValue": {
+ "description": "Value of the xml field",
+ "type": {
+ "name": "String",
+ "type": "named"
+ },
+ "http": {
+ "type": [
+ "string"
+ ],
+ "xml": {
+ "text": true
+ }
}
}
}
@@ -4841,7 +6509,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"id": {
@@ -4853,7 +6523,12 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ],
+ "xml": {
+ "name": "order"
+ }
}
}
}
@@ -4869,7 +6544,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"id": {
@@ -4881,7 +6558,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -4894,7 +6573,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -4907,7 +6588,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -4920,7 +6603,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "date-time"
}
},
@@ -4934,9 +6619,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "order"
}
},
"Tag": {
@@ -4950,7 +6640,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -4963,9 +6655,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "tag"
}
},
"TreasuryInboundTransfer": {
@@ -4978,7 +6675,9 @@
"type": "named"
},
"http": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
},
"cancelable": {
@@ -4988,7 +6687,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"context": {
@@ -5010,7 +6711,9 @@
"type": "named"
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -5021,7 +6724,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"description": {
@@ -5034,7 +6739,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5048,7 +6755,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"financial_account": {
@@ -5058,7 +6767,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5072,7 +6783,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5083,7 +6796,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5094,7 +6809,9 @@
"type": "named"
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"metadata": {
@@ -5104,7 +6821,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"object": {
@@ -5114,7 +6833,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"origin_payment_method": {
@@ -5124,7 +6845,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5138,7 +6861,9 @@
}
},
"http": {
- "type": ["boolean"]
+ "type": [
+ "boolean"
+ ]
}
},
"statement_descriptor": {
@@ -5148,7 +6873,9 @@
"type": "named"
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
},
@@ -5159,7 +6886,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"status_transitions": {
@@ -5168,7 +6897,9 @@
"type": "named"
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"transaction": {
@@ -5195,7 +6926,9 @@
"type": "named"
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -5212,7 +6945,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -5226,7 +6961,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
},
@@ -5240,7 +6977,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "unix-time"
}
}
@@ -5257,7 +6996,9 @@
}
},
"http": {
- "type": ["object"]
+ "type": [
+ "object"
+ ]
}
},
"addresses": {
@@ -5272,7 +7013,9 @@
}
},
"http": {
- "type": ["array"]
+ "type": [
+ "array"
+ ]
}
},
"children": {
@@ -5287,9 +7030,13 @@
}
},
"http": {
- "type": ["array"],
+ "type": [
+ "array"
+ ],
"items": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -5302,7 +7049,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "uuid"
}
},
@@ -5315,7 +7064,9 @@
}
},
"http": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"format": "binary"
}
}
@@ -5332,7 +7083,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"firstName": {
@@ -5344,7 +7097,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"id": {
@@ -5356,7 +7111,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
},
@@ -5369,7 +7126,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"password": {
@@ -5381,7 +7140,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"phone": {
@@ -5393,7 +7154,9 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
},
"userStatus": {
@@ -5406,7 +7169,9 @@
}
},
"http": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int32"
}
},
@@ -5419,9 +7184,14 @@
}
},
"http": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
+ },
+ "xml": {
+ "name": "user"
}
}
},
@@ -5445,7 +7215,9 @@
"name": "account",
"in": "path",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -5591,7 +7363,9 @@
"explode": true
},
"expand_json": {
- "contentType": ["application/json"]
+ "contentType": [
+ "application/json"
+ ]
},
"file": {
"headers": {
@@ -5599,7 +7373,9 @@
"explode": false,
"argumentName": "headerXRateLimitLimit",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -5634,7 +7410,9 @@
"explode": false,
"argumentName": "headerXRateLimitLimit",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -5690,7 +7468,9 @@
"name": "id",
"in": "path",
"schema": {
- "type": ["string"],
+ "type": [
+ "string"
+ ],
"maxLength": 5000
}
}
@@ -5708,7 +7488,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -5834,7 +7617,9 @@
"name": "orderId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -5855,7 +7640,10 @@
"method": "delete",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -5875,7 +7663,9 @@
"name": "api_key",
"in": "header",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -5889,7 +7679,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -5923,7 +7715,9 @@
"name": "username",
"in": "path",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -5969,13 +7763,117 @@
"type": "named"
}
},
+ "putBookXml": {
+ "request": {
+ "url": "/book/xml",
+ "method": "put",
+ "requestBody": {
+ "contentType": "application/xml; charset=utf-8"
+ },
+ "response": {
+ "contentType": "application/xml; charset=utf-8"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /book/xml",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Book",
+ "type": "named"
+ }
+ },
+ "http": {
+ "in": "body"
+ }
+ }
+ },
+ "description": "PUT /book/xml",
+ "result_type": {
+ "name": "Book",
+ "type": "named"
+ }
+ },
+ "putCommentXml": {
+ "request": {
+ "url": "/comment/xml",
+ "method": "put",
+ "requestBody": {
+ "contentType": "application/xml; charset=utf-8"
+ },
+ "response": {
+ "contentType": "application/xml; charset=utf-8"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /comment/xml",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "PutCommentXmlBody",
+ "type": "named"
+ }
+ },
+ "http": {
+ "in": "body"
+ }
+ }
+ },
+ "description": "PUT /comment/xml",
+ "result_type": {
+ "name": "PutCommentXmlResult",
+ "type": "named"
+ }
+ },
+ "putPetXml": {
+ "request": {
+ "url": "/pet/xml",
+ "method": "put",
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ],
+ "requestBody": {
+ "contentType": "application/xml"
+ },
+ "response": {
+ "contentType": "application/xml"
+ }
+ },
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /pet/xml",
+ "type": {
+ "name": "Pet",
+ "type": "named"
+ },
+ "http": {
+ "in": "body"
+ }
+ }
+ },
+ "description": "Update an existing pet",
+ "result_type": {
+ "name": "Pet",
+ "type": "named"
+ }
+ },
"updatePet": {
"request": {
"url": "/pet",
"method": "put",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -6009,7 +7907,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"response": {
@@ -6030,7 +7931,9 @@
"name": "name",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -6044,7 +7947,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -6062,7 +7967,9 @@
"name": "status",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
}
@@ -6082,7 +7989,10 @@
"method": "post",
"security": [
{
- "petstore_auth": ["write:pets", "read:pets"]
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
}
],
"requestBody": {
@@ -6106,7 +8016,9 @@
"name": "additionalMetadata",
"in": "query",
"schema": {
- "type": ["string"]
+ "type": [
+ "string"
+ ]
}
}
},
@@ -6133,7 +8045,9 @@
"name": "petId",
"in": "path",
"schema": {
- "type": ["integer"],
+ "type": [
+ "integer"
+ ],
"format": "int64"
}
}
@@ -6153,13 +8067,18 @@
"contentType": "multipart/form-data",
"encoding": {
"profileImage": {
- "contentType": ["image/png", "image/jpeg"],
+ "contentType": [
+ "image/png",
+ "image/jpeg"
+ ],
"headers": {
"X-Rate-Limit-Limit": {
"explode": false,
"argumentName": "headerXRateLimitLimit",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -6194,7 +8113,9 @@
"explode": false,
"argumentName": "headerXRateLimitLimit",
"schema": {
- "type": ["integer"]
+ "type": [
+ "integer"
+ ]
}
}
}
@@ -6225,7 +8146,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "never"],
+ "one_of": [
+ "auto",
+ "never"
+ ],
"type": "enum"
}
},
@@ -6233,7 +8157,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["AC", "AD"],
+ "one_of": [
+ "AC",
+ "AD"
+ ],
"type": "enum"
}
},
@@ -6241,7 +8168,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["", "exclude_tax", "include_inclusive_tax"],
+ "one_of": [
+ "",
+ "exclude_tax",
+ "include_inclusive_tax"
+ ],
"type": "enum"
}
},
@@ -6249,7 +8180,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "required"],
+ "one_of": [
+ "auto",
+ "required"
+ ],
"type": "enum"
}
},
@@ -6257,7 +8191,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["automatic", "automatic_async", "manual"],
+ "one_of": [
+ "automatic",
+ "automatic_async",
+ "manual"
+ ],
"type": "enum"
}
},
@@ -6265,7 +8203,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["android", "ios", "web"],
+ "one_of": [
+ "android",
+ "ios",
+ "web"
+ ],
"type": "enum"
}
},
@@ -6273,7 +8215,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["cad", "usd"],
+ "one_of": [
+ "cad",
+ "usd"
+ ],
"type": "enum"
}
},
@@ -6281,7 +8226,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["always", "if_required"],
+ "one_of": [
+ "always",
+ "if_required"
+ ],
"type": "enum"
}
},
@@ -6289,7 +8237,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["invoice", "subscription"],
+ "one_of": [
+ "invoice",
+ "subscription"
+ ],
"type": "enum"
}
},
@@ -6297,7 +8248,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["bank_transfer"],
+ "one_of": [
+ "bank_transfer"
+ ],
"type": "enum"
}
},
@@ -6305,7 +8258,12 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["day", "month", "week", "year"],
+ "one_of": [
+ "day",
+ "month",
+ "week",
+ "year"
+ ],
"type": "enum"
}
},
@@ -6313,7 +8271,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "bg", "cs"],
+ "one_of": [
+ "auto",
+ "bg",
+ "cs"
+ ],
"type": "enum"
}
},
@@ -6321,7 +8283,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["cancel", "create_invoice", "pause"],
+ "one_of": [
+ "cancel",
+ "create_invoice",
+ "pause"
+ ],
"type": "enum"
}
},
@@ -6329,7 +8295,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["payment", "setup", "subscription"],
+ "one_of": [
+ "payment",
+ "setup",
+ "subscription"
+ ],
"type": "enum"
}
},
@@ -6337,7 +8307,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "never"],
+ "one_of": [
+ "auto",
+ "never"
+ ],
"type": "enum"
}
},
@@ -6345,7 +8318,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["always", "if_required"],
+ "one_of": [
+ "always",
+ "if_required"
+ ],
"type": "enum"
}
},
@@ -6353,7 +8329,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["acss_debit", "affirm"],
+ "one_of": [
+ "acss_debit",
+ "affirm"
+ ],
"type": "enum"
}
},
@@ -6361,7 +8340,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["combined", "interval", "sporadic"],
+ "one_of": [
+ "combined",
+ "interval",
+ "sporadic"
+ ],
"type": "enum"
}
},
@@ -6369,7 +8352,12 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["balances", "ownership", "payment_method", "transactions"],
+ "one_of": [
+ "balances",
+ "ownership",
+ "payment_method",
+ "transactions"
+ ],
"type": "enum"
}
},
@@ -6377,7 +8365,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "hidden"],
+ "one_of": [
+ "auto",
+ "hidden"
+ ],
"type": "enum"
}
},
@@ -6385,7 +8376,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["cs-CZ", "da-DK"],
+ "one_of": [
+ "cs-CZ",
+ "da-DK"
+ ],
"type": "enum"
}
},
@@ -6393,7 +8387,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["balances", "transactions"],
+ "one_of": [
+ "balances",
+ "transactions"
+ ],
"type": "enum"
}
},
@@ -6401,7 +8398,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "none"],
+ "one_of": [
+ "auto",
+ "none"
+ ],
"type": "enum"
}
},
@@ -6409,7 +8409,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["create_prorations", "none"],
+ "one_of": [
+ "create_prorations",
+ "none"
+ ],
"type": "enum"
}
},
@@ -6417,7 +8420,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["always", "if_required", "never"],
+ "one_of": [
+ "always",
+ "if_required",
+ "never"
+ ],
"type": "enum"
}
},
@@ -6425,7 +8432,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["any", "automatic", "challenge"],
+ "one_of": [
+ "any",
+ "automatic",
+ "challenge"
+ ],
"type": "enum"
}
},
@@ -6433,7 +8444,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["aba", "iban"],
+ "one_of": [
+ "aba",
+ "iban"
+ ],
"type": "enum"
}
},
@@ -6441,7 +8455,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["off_session", "on_session"],
+ "one_of": [
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6449,7 +8466,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "never"],
+ "one_of": [
+ "auto",
+ "never"
+ ],
"type": "enum"
}
},
@@ -6457,7 +8477,12 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["auto", "book", "donate", "pay"],
+ "one_of": [
+ "auto",
+ "book",
+ "donate",
+ "pay"
+ ],
"type": "enum"
}
},
@@ -6465,7 +8490,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["exclusive", "inclusive", "unspecified"],
+ "one_of": [
+ "exclusive",
+ "inclusive",
+ "unspecified"
+ ],
"type": "enum"
}
},
@@ -6473,7 +8502,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "required"],
+ "one_of": [
+ "none",
+ "required"
+ ],
"type": "enum"
}
},
@@ -6481,7 +8513,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["business", "personal"],
+ "one_of": [
+ "business",
+ "personal"
+ ],
"type": "enum"
}
},
@@ -6489,7 +8524,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["account", "self"],
+ "one_of": [
+ "account",
+ "self"
+ ],
"type": "enum"
}
},
@@ -6497,7 +8535,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["embedded", "hosted"],
+ "one_of": [
+ "embedded",
+ "hosted"
+ ],
"type": "enum"
}
},
@@ -6505,7 +8546,13 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["business_day", "day", "hour", "month", "week"],
+ "one_of": [
+ "business_day",
+ "day",
+ "hour",
+ "month",
+ "week"
+ ],
"type": "enum"
}
},
@@ -6513,7 +8560,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["automatic", "instant", "microdeposits"],
+ "one_of": [
+ "automatic",
+ "instant",
+ "microdeposits"
+ ],
"type": "enum"
}
},
@@ -6562,7 +8613,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["charge_automatically", "send_invoice"],
+ "one_of": [
+ "charge_automatically",
+ "send_invoice"
+ ],
"type": "enum"
}
},
@@ -6570,7 +8624,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["list"],
+ "one_of": [
+ "list"
+ ],
"type": "enum"
}
},
@@ -6578,7 +8634,13 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["draft", "open", "paid", "uncollectible", "void"],
+ "one_of": [
+ "draft",
+ "open",
+ "paid",
+ "uncollectible",
+ "void"
+ ],
"type": "enum"
}
},
@@ -6593,7 +8655,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["placed", "approved", "delivered"],
+ "one_of": [
+ "placed",
+ "approved",
+ "delivered"
+ ],
"type": "enum"
}
},
@@ -6608,7 +8674,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["available", "pending", "sold"],
+ "one_of": [
+ "available",
+ "pending",
+ "sold"
+ ],
"type": "enum"
}
},
@@ -6616,7 +8686,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["custom"],
+ "one_of": [
+ "custom"
+ ],
"type": "enum"
}
},
@@ -6624,7 +8696,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["dropdown", "numeric", "text"],
+ "one_of": [
+ "dropdown",
+ "numeric",
+ "text"
+ ],
"type": "enum"
}
},
@@ -6632,7 +8708,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6640,7 +8720,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6648,7 +8730,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6656,7 +8740,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6664,7 +8750,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6672,7 +8760,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6680,7 +8772,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6688,7 +8782,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6696,7 +8794,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6704,7 +8806,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["eu_bank_transfer", "gb_bank_transfer"],
+ "one_of": [
+ "eu_bank_transfer",
+ "gb_bank_transfer"
+ ],
"type": "enum"
}
},
@@ -6712,7 +8817,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6720,7 +8827,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6728,7 +8837,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6736,7 +8847,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6744,7 +8857,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6752,7 +8867,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6760,7 +8877,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6768,7 +8887,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6776,7 +8897,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session"],
+ "one_of": [
+ "none",
+ "off_session"
+ ],
"type": "enum"
}
},
@@ -6784,7 +8908,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6792,7 +8918,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6800,7 +8928,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6808,7 +8938,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["", "manual"],
+ "one_of": [
+ "",
+ "manual"
+ ],
"type": "enum"
}
},
@@ -6816,7 +8949,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["", "none", "off_session"],
+ "one_of": [
+ "",
+ "none",
+ "off_session"
+ ],
"type": "enum"
}
},
@@ -6824,7 +8961,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session"],
+ "one_of": [
+ "none",
+ "off_session"
+ ],
"type": "enum"
}
},
@@ -6832,7 +8972,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6840,7 +8984,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6848,7 +8994,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none", "off_session", "on_session"],
+ "one_of": [
+ "none",
+ "off_session",
+ "on_session"
+ ],
"type": "enum"
}
},
@@ -6856,7 +9006,10 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["automatic", "instant"],
+ "one_of": [
+ "automatic",
+ "instant"
+ ],
"type": "enum"
}
},
@@ -6864,7 +9017,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["none"],
+ "one_of": [
+ "none"
+ ],
"type": "enum"
}
},
@@ -6872,7 +9027,20 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["fixed_amount"],
+ "one_of": [
+ "fixed_amount"
+ ],
+ "type": "enum"
+ }
+ },
+ "SearchIn": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "one_of": [
+ "projects",
+ "packages"
+ ],
"type": "enum"
}
},
@@ -6880,7 +9048,11 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["placed", "approved", "delivered"],
+ "one_of": [
+ "placed",
+ "approved",
+ "delivered"
+ ],
"type": "enum"
}
},
@@ -6924,7 +9096,9 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["treasury.inbound_transfer"],
+ "one_of": [
+ "treasury.inbound_transfer"
+ ],
"type": "enum"
}
},
@@ -6932,7 +9106,12 @@
"aggregate_functions": {},
"comparison_operators": {},
"representation": {
- "one_of": ["canceled", "failed", "processing", "succeeded"],
+ "one_of": [
+ "canceled",
+ "failed",
+ "processing",
+ "succeeded"
+ ],
"type": "enum"
}
},
diff --git a/ndc-http-schema/openapi/testdata/petstore3/schema.json b/ndc-http-schema/openapi/testdata/petstore3/schema.json
index ec0d6f6..b0ab1c1 100644
--- a/ndc-http-schema/openapi/testdata/petstore3/schema.json
+++ b/ndc-http-schema/openapi/testdata/petstore3/schema.json
@@ -172,6 +172,39 @@
"type": "array"
}
},
+ {
+ "arguments": {},
+ "description": "List all known architectures.",
+ "name": "getArchitectures",
+ "result_type": {
+ "name": "GetArchitecturesResult",
+ "type": "named"
+ }
+ },
+ {
+ "arguments": {
+ "project_name": {
+ "description": "Project name",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "repository_name": {
+ "description": "Repository name",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "description": "Show the build configuration for the specified repository.",
+ "name": "getBuildProjectNameRepositoryNameBuildconfig",
+ "result_type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
{
"arguments": {},
"description": "Returns pet inventories by status",
@@ -215,6 +248,50 @@
"type": "named"
}
},
+ {
+ "arguments": {
+ "in": {
+ "description": "Where to search and apply a XPath expression: either the list of projects or the list of packages. Example of a result when `projects` is selected: ``` x86_64 x86_64 Standard OBS instance at build.opensuse.org This instance delivers the default build targets for OBS. https://api.opensuse.org/public ``` Example of a result when `packages` is selected: ``` ```",
+ "type": {
+ "name": "SearchIn",
+ "type": "named"
+ }
+ },
+ "match": {
+ "description": "XPath expression used to filter the results.",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ },
+ "return": {
+ "description": "XPath expression that defines which values will be returned. Instead of returning a collection of projects or packages, the result will be a collection of: - contents of elements, when that XPath expression match elements, or, - values of atttributes, when that XPath expression match atttributes. Example of result, for a query string like `?in=projects\u0026match=repository/arch='x86_64'\u0026return=repository/name`: ``` openSUSE_Tumbleweed 15.3 ```",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "values": {
+ "description": "When set to `1`, return a list of values, instead of returning a list of projects or packages. The result will be a collection of: - contents of elements, when the expression defined in the `match` query parameter match elements. For example: `match=repository/arch`. - values of atttributes, when the expression defined in the `match` query parameter match atttributes. For example: `match=repository/name`. Example of result, for a query string like `?in=projects\u0026match=repository/path/project\u0026values=1`: ``` openSUSE.org:openSUSE:Factory openSUSE.org:openSUSE:Leap:15.3 ```",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "description": "Search in projects or in packages.",
+ "name": "getSearchXml",
+ "result_type": {
+ "name": "JSON",
+ "type": "named"
+ }
+ },
{
"arguments": {},
"description": "Get snake object",
@@ -344,6 +421,46 @@
}
}
},
+ "Book": {
+ "fields": {
+ "attr": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "author": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "title": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ }
+ },
"Category": {
"fields": {
"id": {
@@ -379,6 +496,114 @@
}
}
},
+ "GetArchitecturesResult": {
+ "fields": {
+ "count": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "entry": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "GetArchitecturesResultEntry",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "rev": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "srcmd5": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "vrev": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ }
+ },
+ "GetArchitecturesResultEntry": {
+ "fields": {
+ "md5": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "mtime": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "name": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "size": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "xmlValue": {
+ "description": "Value of the xml field",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ },
"GetInvoicesResult": {
"fields": {
"has_more": {
@@ -3462,6 +3687,276 @@
}
}
},
+ "PutCommentXmlBody": {
+ "fields": {
+ "comment": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "PutCommentXmlBodyComment",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "comment_count": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "request": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "user": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ }
+ },
+ "PutCommentXmlBodyComment": {
+ "fields": {
+ "bsrequest": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "parent": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "when": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "who": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "xmlValue": {
+ "description": "Value of the xml field",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "PutCommentXmlResult": {
+ "fields": {
+ "comment": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "element_type": {
+ "name": "PutCommentXmlResultComment",
+ "type": "named"
+ },
+ "type": "array"
+ }
+ }
+ },
+ "comment_count": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "request": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "user": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ }
+ },
+ "PutCommentXmlResultComment": {
+ "fields": {
+ "bsrequest": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "id": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "package": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "parent": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Int32",
+ "type": "named"
+ }
+ }
+ },
+ "project": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "when": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "who": {
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ },
+ "xmlValue": {
+ "description": "Value of the xml field",
+ "type": {
+ "name": "String",
+ "type": "named"
+ }
+ }
+ }
+ },
"SnakeObject": {
"fields": {
"features": {
@@ -4138,6 +4633,63 @@
"type": "named"
}
},
+ {
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /book/xml",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "Book",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "description": "PUT /book/xml",
+ "name": "putBookXml",
+ "result_type": {
+ "name": "Book",
+ "type": "named"
+ }
+ },
+ {
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /comment/xml",
+ "type": {
+ "type": "nullable",
+ "underlying_type": {
+ "name": "PutCommentXmlBody",
+ "type": "named"
+ }
+ }
+ }
+ },
+ "description": "PUT /comment/xml",
+ "name": "putCommentXml",
+ "result_type": {
+ "name": "PutCommentXmlResult",
+ "type": "named"
+ }
+ },
+ {
+ "arguments": {
+ "body": {
+ "description": "Request body of PUT /pet/xml",
+ "type": {
+ "name": "Pet",
+ "type": "named"
+ }
+ }
+ },
+ "description": "Update an existing pet",
+ "name": "putPetXml",
+ "result_type": {
+ "name": "Pet",
+ "type": "named"
+ }
+ },
{
"arguments": {
"body": {
@@ -5166,6 +5718,17 @@
"type": "enum"
}
},
+ "SearchIn": {
+ "aggregate_functions": {},
+ "comparison_operators": {},
+ "representation": {
+ "one_of": [
+ "projects",
+ "packages"
+ ],
+ "type": "enum"
+ }
+ },
"SnakeObjectIdStatus": {
"aggregate_functions": {},
"comparison_operators": {},
diff --git a/ndc-http-schema/openapi/testdata/petstore3/source.json b/ndc-http-schema/openapi/testdata/petstore3/source.json
index a0998a5..4bad2dd 100644
--- a/ndc-http-schema/openapi/testdata/petstore3/source.json
+++ b/ndc-http-schema/openapi/testdata/petstore3/source.json
@@ -160,6 +160,51 @@
]
}
},
+ "/pet/xml": {
+ "put": {
+ "tags": ["pet"],
+ "summary": "Update an existing pet",
+ "description": "Update an existing pet by Id",
+ "operationId": "updatePet",
+ "requestBody": {
+ "description": "Update an existent pet in the store",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ },
+ "405": {
+ "description": "Validation exception"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": ["write:pets", "read:pets"]
+ }
+ ]
+ }
+ },
"/pet/findByStatus": {
"get": {
"tags": ["pet"],
@@ -3135,6 +3180,503 @@
"summary": "Initialize Browser-Based Logout User Flow",
"tags": ["public"]
}
+ },
+ "/build/{project_name}/{repository_name}/_buildconfig": {
+ "get": {
+ "summary": "Show the build configuration for the specified repository.",
+ "description": "Show the build configuration for the specified repository. Includes all base package\nrequirements, mappings and macros.\n",
+ "security": [],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "project_name",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "description": "Project name",
+ "example": "home:Admin"
+ },
+ {
+ "in": "path",
+ "name": "repository_name",
+ "schema": {
+ "type": "string"
+ },
+ "required": true,
+ "description": "Repository name",
+ "example": "openSUSE_Tumbleweed"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "text/plain": {}
+ }
+ }
+ }
+ }
+ },
+ "/architectures": {
+ "get": {
+ "summary": "List all known architectures.",
+ "description": "Get a list of all known architectures known to OBS in general.\nThis is not the list of architectures provided by this instance. Check the\nschedulers element from the `/configuration` route for this.\n",
+ "responses": {
+ "200": {
+ "description": "OK. The request has succeeded.",
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "name": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "rev": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "vrev": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "srcmd5": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "entry": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "md5": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "size": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "mtime": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "directory"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/comment/xml": {
+ "put": {
+ "security": [],
+ "parameters": [],
+ "requestBody": {
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "comment_count": {
+ "type": "integer",
+ "xml": {
+ "attribute": true,
+ "name": "comment"
+ }
+ },
+ "comment": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "who": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "when": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "parent": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "bsrequest": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "package": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ }
+ },
+ "request": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "package": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "user": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "xml": {
+ "name": "comments"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "comment_count": {
+ "type": "integer",
+ "xml": {
+ "attribute": true,
+ "name": "comment"
+ }
+ },
+ "comment": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "who": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "when": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "parent": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "bsrequest": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "package": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ }
+ },
+ "request": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "package": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "user": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ },
+ "xml": {
+ "name": "comments"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/book/xml": {
+ "put": {
+ "security": [],
+ "parameters": [],
+ "requestBody": {
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "$ref": "#/components/schemas/book"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "$ref": "#/components/schemas/book"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/search/xml": {
+ "get": {
+ "summary": "Search in projects or in packages.",
+ "description": "Get a list of projects or a list of packages that match a XPath expression, passed in the query parameter `match`.",
+ "security": [],
+ "parameters": [
+ {
+ "in": "query",
+ "name": "in",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": ["projects", "packages"],
+ "example": "projects"
+ },
+ "description": "Where to search and apply a XPath expression: either the list of projects or the list of packages.\n\nExample of a result when `projects` is selected:\n```\n\n \n \n \n \n \n \n x86_64\n \n \n \n x86_64\n \n \n \n Standard OBS instance at build.opensuse.org\n This instance delivers the default build targets for OBS.\n https://api.opensuse.org/public\n \n\n```\n\nExample of a result when `packages` is selected:\n```\n\n \n \n \n \n\n```\n"
+ },
+ {
+ "in": "query",
+ "name": "match",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "description": "XPath expression used to filter the results."
+ },
+ {
+ "in": "query",
+ "name": "return",
+ "schema": {
+ "type": "string",
+ "example": "repository/name"
+ },
+ "description": "XPath expression that defines which values will be returned.\n\nInstead of returning a collection of projects or packages, the result will be a collection of:\n - contents of elements, when that XPath expression match elements, or,\n - values of atttributes, when that XPath expression match atttributes.\n\nExample of result, for a query string like `?in=projects&match=repository/arch='x86_64'&return=repository/name`:\n```\n\n openSUSE_Tumbleweed\n 15.3\n\n```\n"
+ },
+ {
+ "in": "query",
+ "name": "values",
+ "schema": {
+ "type": "string",
+ "example": 1
+ },
+ "description": "When set to `1`, return a list of values, instead of returning a list of projects or packages.\n\nThe result will be a collection of:\n - contents of elements, when the expression defined in the `match` query parameter match elements.\n For example: `match=repository/arch`.\n - values of atttributes, when the expression defined in the `match` query parameter match atttributes.\n For example: `match=repository/name`.\n\nExample of result, for a query string like `?in=projects&match=repository/path/project&values=1`:\n```\n\n openSUSE.org:openSUSE:Factory\n openSUSE.org:openSUSE:Leap:15.3\n\n```\n"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK. The request has succeeded.",
+ "content": {
+ "application/xml; charset=utf-8": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "matches": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "person": {
+ "type": "object",
+ "properties": {
+ "userid": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "role": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "collection"
+ }
+ },
+ {
+ "type": "object",
+ "properties": {
+ "matches": {
+ "type": "integer",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "package": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "project": {
+ "type": "string",
+ "xml": {
+ "attribute": true
+ }
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "xml": {
+ "name": "collection"
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
}
},
"components": {
@@ -3631,6 +4173,31 @@
]
}
}
+ },
+ "book": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "title": {
+ "type": "string"
+ },
+ "author": {
+ "type": "string"
+ },
+ "attr": {
+ "type": "string",
+ "xml": {
+ "prefix": "smp",
+ "attribute": true
+ }
+ }
+ },
+ "xml": {
+ "prefix": "smp",
+ "namespace": "http://example.com/schema"
+ }
}
},
"requestBodies": {
diff --git a/ndc-http-schema/openapi/testdata/prefix2/expected_multi_words.json b/ndc-http-schema/openapi/testdata/prefix2/expected_multi_words.json
index fcc8888..2b88659 100644
--- a/ndc-http-schema/openapi/testdata/prefix2/expected_multi_words.json
+++ b/ndc-http-schema/openapi/testdata/prefix2/expected_multi_words.json
@@ -131,6 +131,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Post"
}
}
},
diff --git a/ndc-http-schema/openapi/testdata/prefix2/expected_single_word.json b/ndc-http-schema/openapi/testdata/prefix2/expected_single_word.json
index a0c0a45..ce17ec9 100644
--- a/ndc-http-schema/openapi/testdata/prefix2/expected_single_word.json
+++ b/ndc-http-schema/openapi/testdata/prefix2/expected_single_word.json
@@ -131,6 +131,9 @@
"format": "int64"
}
}
+ },
+ "xml": {
+ "name": "Post"
}
}
},
diff --git a/ndc-http-schema/schema/enum.go b/ndc-http-schema/schema/enum.go
index fbb1ced..6828be4 100644
--- a/ndc-http-schema/schema/enum.go
+++ b/ndc-http-schema/schema/enum.go
@@ -224,6 +224,7 @@ const (
ContentTypeMultipartFormData = "multipart/form-data"
ContentTypeTextPlain = "text/plain"
ContentTypeTextHTML = "text/html"
+ ContentTypeOctetStream = "application/octet-stream"
)
// ParameterEncodingStyle represents the encoding style of the parameter.
diff --git a/ndc-http-schema/schema/schema.go b/ndc-http-schema/schema/schema.go
index ea437be..e3f096e 100644
--- a/ndc-http-schema/schema/schema.go
+++ b/ndc-http-schema/schema/schema.go
@@ -2,6 +2,7 @@ package schema
import (
"encoding/json"
+ "encoding/xml"
"errors"
"fmt"
@@ -91,6 +92,14 @@ func (rm NDCHttpSchema) GetProcedure(name string) *OperationInfo {
return &fn
}
+// AddScalar adds a new scalar if not exist.
+func (rm *NDCHttpSchema) AddScalar(name string, scalar schema.ScalarType) {
+ _, ok := rm.ScalarTypes[name]
+ if !ok {
+ rm.ScalarTypes[name] = scalar
+ }
+}
+
type Response struct {
ContentType string `json:"contentType" mapstructure:"contentType" yaml:"contentType"`
}
@@ -148,6 +157,7 @@ type TypeSchema struct {
MaxLength *int64 `json:"maxLength,omitempty" mapstructure:"maxLength" yaml:"maxLength,omitempty"`
MinLength *int64 `json:"minLength,omitempty" mapstructure:"minLength" yaml:"minLength,omitempty"`
Items *TypeSchema `json:"items,omitempty" mapstructure:"items" yaml:"items,omitempty"`
+ XML *XMLSchema `json:"xml,omitempty" mapstructure:"xml" yaml:"xml,omitempty"`
Description string `json:"-" yaml:"-"`
ReadOnly bool `json:"-" yaml:"-"`
WriteOnly bool `json:"-" yaml:"-"`
@@ -309,6 +319,8 @@ type ObjectType struct {
Description *string `json:"description,omitempty" mapstructure:"description,omitempty" yaml:"description,omitempty"`
// Fields defined on this object type
Fields map[string]ObjectField `json:"fields" mapstructure:"fields" yaml:"fields"`
+ // XML schema
+ XML *XMLSchema `json:"xml,omitempty" mapstructure:"xml" yaml:"xml,omitempty"`
}
// Schema returns schema the object field
@@ -421,6 +433,48 @@ func (j *ArgumentInfo) UnmarshalJSON(b []byte) error {
return nil
}
+// XMLSchema represents a XML schema that adds additional metadata to describe the XML representation of this property.
+type XMLSchema struct {
+ // Replaces the name of the element/attribute used for the described schema property.
+ // When defined within items, it will affect the name of the individual XML elements within the list.
+ // When defined alongside type being array (outside the items), it will affect the wrapping element and only if wrapped is true.
+ // If wrapped is false, it will be ignored.
+ Name string `json:"name,omitempty" mapstructure:"name" yaml:"name,omitempty"`
+ // The prefix to be used for the name.
+ Prefix string `json:"prefix,omitempty" mapstructure:"prefix" yaml:"prefix,omitempty"`
+ // The URI of the namespace definition. This MUST be in the form of an absolute URI.
+ Namespace string `json:"namespace,omitempty" mapstructure:"namespace" yaml:"namespace,omitempty"`
+ // Used only for an array definition. Signifies whether the array is wrapped (for example, ) or unwrapped ().
+ Wrapped bool `json:"wrapped,omitempty" mapstructure:"wrapped" yaml:"wrapped,omitempty"`
+ // Declares whether the property definition translates to an attribute instead of an element.
+ Attribute bool `json:"attribute,omitempty" mapstructure:"attribute" yaml:"attribute,omitempty"`
+ // Represents a text value of the xml element.
+ Text bool `json:"text,omitempty" mapstructure:"text" yaml:"text,omitempty"`
+}
+
+// GetFullName gets the full name with prefix.
+func (xs XMLSchema) GetFullName() string {
+ if xs.Prefix == "" {
+ return xs.Name
+ }
+
+ return xs.Prefix + ":" + xs.Name
+}
+
+// GetNamespaceAttribute gets the namespace attribute
+func (xs XMLSchema) GetNamespaceAttribute() xml.Attr {
+ // xmlns:smp="http://example.com/schema"
+ name := "xmlns"
+ if xs.Prefix != "" {
+ name += ":" + xs.Prefix
+ }
+
+ return xml.Attr{
+ Name: xml.Name{Local: name},
+ Value: xs.Namespace,
+ }
+}
+
func toAnySlice[T any](values []T) []any {
results := make([]any, len(values))
for i, v := range values {
diff --git a/ndc-http-schema/utils/file.go b/ndc-http-schema/utils/file.go
index aa8db40..82b50a3 100644
--- a/ndc-http-schema/utils/file.go
+++ b/ndc-http-schema/utils/file.go
@@ -55,6 +55,13 @@ func WriteSchemaFile(outputPath string, content any) error {
return err
}
+ basePath := filepath.Dir(outputPath)
+ if basePath != "." {
+ if err := os.MkdirAll(basePath, 0664); err != nil {
+ return err
+ }
+ }
+
return os.WriteFile(outputPath, rawBytes, 0664)
}