| package oasmiddleware |
|
|
| import ( |
| "errors" |
| "fmt" |
| "strings" |
|
|
| "github.com/getkin/kin-openapi/openapi3" |
| "github.com/getkin/kin-openapi/openapi3filter" |
|
|
| "github.com/openmeterio/openmeter/api/v3/apierrors" |
| ) |
|
|
| var oasRuleToAip = map[string]string{ |
| "minLength": "min_length", |
| "maxLength": "max_length", |
| "minItems": "min_items", |
| "maxItems": "max_items", |
| } |
|
|
| func ToAipError(me openapi3.MultiError) []apierrors.InvalidParameter { |
| return aipMapper(me, nil) |
| } |
|
|
| func aipMapper(me openapi3.MultiError, parent *apierrors.InvalidParameter) []apierrors.InvalidParameter { |
| var ipErrs []apierrors.InvalidParameter |
| for _, err := range me { |
| var i *apierrors.InvalidParameter |
| if parent != nil { |
| i = parent |
| } else { |
| i = &apierrors.InvalidParameter{} |
| } |
| switch err := err.(type) { |
| case *openapi3.SchemaError: |
| i.Reason = err.Reason |
| ipErrs = append(ipErrs, invalidParamFromSchemaError(err, i)) |
| case *openapi3filter.RequestError: |
| if err.Parameter != nil { |
| if err.Parameter.Name != "" { |
| i.Field = err.Parameter.Name |
| } |
| if err.Parameter.In != "" { |
| i.Source = apierrors.ToInvalid(err.Parameter.In) |
| } |
| if err.Parameter.Required { |
| i.Rule = "required" |
| } |
| } |
| i.Reason = err.Reason |
| if err.Reason == "" || err.RequestBody != nil { |
| i.Reason = err.Error() |
| } |
|
|
| if err, ok := err.Err.(openapi3.MultiError); ok { |
| ipErrs = append(ipErrs, aipMapper(err, i)...) |
| continue |
| } |
|
|
| if err, ok := err.Err.(*openapi3.SchemaError); ok { |
| i.Choices = make([]string, 0) |
| if err.SchemaField == "enum" { |
| i.Rule = "enum" |
| for _, v := range err.Schema.Enum { |
| i.Choices = append(i.Choices, fmt.Sprintf("%v", v)) |
| } |
| i.Reason = fmt.Sprintf("must be one of: [%s]", strings.Join(i.Choices, ",")) |
| } else if err.SchemaField == "oneOf" { |
| ipErrs = append(ipErrs, collectFromSchemaError(err)...) |
| continue |
| } |
| } |
| ipErrs = append(ipErrs, *i) |
| } |
| } |
| return ipErrs |
| } |
|
|
| |
| |
| |
| func collectFromSchemaError(se *openapi3.SchemaError) []apierrors.InvalidParameter { |
| childParams := unwrapOriginError(se) |
| if len(childParams) == 0 { |
| return []apierrors.InvalidParameter{ |
| invalidParamFromSchemaError(se, nil), |
| } |
| } |
| return childParams |
| } |
|
|
| |
| |
| func unwrapOriginError(schemaErr *openapi3.SchemaError) []apierrors.InvalidParameter { |
| if schemaErr == nil || schemaErr.Origin == nil { |
| return nil |
| } |
|
|
| |
| var me openapi3.MultiError |
| if errors.As(schemaErr.Origin, &me) { |
| var result []apierrors.InvalidParameter |
| for _, subErr := range me { |
| var subSE *openapi3.SchemaError |
| if errors.As(subErr, &subSE) { |
| result = append(result, collectFromSchemaError(subSE)...) |
| } |
| } |
| return result |
| } |
|
|
| |
| var innerSE *openapi3.SchemaError |
| if errors.As(schemaErr.Origin, &innerSE) { |
| return collectFromSchemaError(innerSE) |
| } |
|
|
| |
| return nil |
| } |
|
|
| func invalidParamFromSchemaError( |
| schemaErr *openapi3.SchemaError, |
| parent *apierrors.InvalidParameter, |
| ) apierrors.InvalidParameter { |
| var ip *apierrors.InvalidParameter |
| if parent != nil { |
| ip = parent |
| } else { |
| ip = &apierrors.InvalidParameter{ |
| Reason: schemaErr.Reason, |
| } |
| } |
| if rule, ok := oasRuleToAip[schemaErr.SchemaField]; ok { |
| ip.Rule = rule |
| } else { |
| ip.Rule = schemaErr.SchemaField |
| } |
| if path := schemaErr.JSONPointer(); len(path) > 0 { |
| ip.Field = strings.Join(path, ".") |
| } |
| return *ip |
| } |
|
|