From d12860caf67e8be20bec1d0b57b82ffb83f4e140 Mon Sep 17 00:00:00 2001 From: Sergey Vilgelm Date: Mon, 19 Sep 2022 00:55:30 -0700 Subject: [PATCH] use %w to wrap the errors (#596) --- jsoninfo/unmarshal.go | 6 +++--- openapi3/components.go | 2 +- openapi3/header.go | 8 ++++---- openapi3/loader.go | 8 ++++---- openapi3/loader_test.go | 27 +++++++++++++++------------ openapi3/media_type.go | 4 ++-- openapi3/openapi3.go | 10 +++++----- openapi3/parameter.go | 12 ++++++------ openapi3/schema.go | 2 +- openapi3/schema_formats.go | 2 +- openapi3/security_scheme.go | 2 +- openapi3filter/req_resp_decoder.go | 12 ++++++------ routers/legacy/router.go | 2 +- 13 files changed, 50 insertions(+), 47 deletions(-) diff --git a/jsoninfo/unmarshal.go b/jsoninfo/unmarshal.go index eb6e758ac..16886ad83 100644 --- a/jsoninfo/unmarshal.go +++ b/jsoninfo/unmarshal.go @@ -25,7 +25,7 @@ type ObjectDecoder struct { func NewObjectDecoder(data []byte) (*ObjectDecoder, error) { var remainingFields map[string]json.RawMessage if err := json.Unmarshal(data, &remainingFields); err != nil { - return nil, fmt.Errorf("failed to unmarshal extension properties: %v (%s)", err, data) + return nil, fmt.Errorf("failed to unmarshal extension properties: %w (%s)", err, data) } return &ObjectDecoder{ Data: data, @@ -87,7 +87,7 @@ func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{}) continue } } - return fmt.Errorf("failed to unmarshal property %q (%s): %v", + return fmt.Errorf("failed to unmarshal property %q (%s): %w", field.JSONName, fieldValue.Type().String(), err) } if !isPtr { @@ -109,7 +109,7 @@ func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{}) continue } } - return fmt.Errorf("failed to unmarshal property %q (%s): %v", + return fmt.Errorf("failed to unmarshal property %q (%s): %w", field.JSONName, fieldPtr.Type().String(), err) } diff --git a/openapi3/components.go b/openapi3/components.go index e9af26911..ce7a86990 100644 --- a/openapi3/components.go +++ b/openapi3/components.go @@ -99,7 +99,7 @@ func (components *Components) Validate(ctx context.Context) (err error) { return } if err = v.Validate(ctx); err != nil { - return fmt.Errorf("%s: %s", k, err) + return fmt.Errorf("%s: %w", k, err) } } diff --git a/openapi3/header.go b/openapi3/header.go index 75e5dd1e2..c71d3f2a8 100644 --- a/openapi3/header.go +++ b/openapi3/header.go @@ -71,22 +71,22 @@ func (header *Header) Validate(ctx context.Context) error { sm.Style == SerializationSimple && !sm.Explode || sm.Style == SerializationSimple && sm.Explode; !smSupported { e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a header parameter", sm.Style, sm.Explode) - return fmt.Errorf("header schema is invalid: %v", e) + return fmt.Errorf("header schema is invalid: %w", e) } if (header.Schema == nil) == (header.Content == nil) { e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", header) - return fmt.Errorf("header schema is invalid: %v", e) + return fmt.Errorf("header schema is invalid: %w", e) } if schema := header.Schema; schema != nil { if err := schema.Validate(ctx); err != nil { - return fmt.Errorf("header schema is invalid: %v", err) + return fmt.Errorf("header schema is invalid: %w", err) } } if content := header.Content; content != nil { if err := content.Validate(ctx); err != nil { - return fmt.Errorf("header content is invalid: %v", err) + return fmt.Errorf("header content is invalid: %w", err) } } return nil diff --git a/openapi3/loader.go b/openapi3/loader.go index 87c9f8684..e9366dcb5 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -101,7 +101,7 @@ func (loader *Loader) loadSingleElementFromURI(ref string, rootPath *url.URL, el resolvedPath, err := resolvePath(rootPath, parsedURL) if err != nil { - return nil, fmt.Errorf("could not resolve path: %v", err) + return nil, fmt.Errorf("could not resolve path: %w", err) } data, err := loader.readURL(resolvedPath) @@ -285,7 +285,7 @@ func (loader *Loader) resolveComponent( if cursor, err = drillIntoField(cursor, pathPart); err != nil { e := failedToResolveRefFragmentPart(ref, pathPart) - return nil, fmt.Errorf("%s: %s", e.Error(), err.Error()) + return nil, fmt.Errorf("%s: %w", e, err) } if cursor == nil { return nil, failedToResolveRefFragmentPart(ref, pathPart) @@ -430,11 +430,11 @@ func (loader *Loader) resolveRef(doc *T, ref string, path *url.URL) (*T, string, var resolvedPath *url.URL if resolvedPath, err = resolvePath(path, parsedURL); err != nil { - return nil, "", nil, fmt.Errorf("error resolving path: %v", err) + return nil, "", nil, fmt.Errorf("error resolving path: %w", err) } if doc, err = loader.loadFromURIInternal(resolvedPath); err != nil { - return nil, "", nil, fmt.Errorf("error resolving reference %q: %v", ref, err) + return nil, "", nil, fmt.Errorf("error resolving reference %q: %w", ref, err) } return doc, "#" + fragment, resolvedPath, nil diff --git a/openapi3/loader_test.go b/openapi3/loader_test.go index e33b75d72..64a923c39 100644 --- a/openapi3/loader_test.go +++ b/openapi3/loader_test.go @@ -1,7 +1,6 @@ package openapi3 import ( - "errors" "fmt" "net" "net/http" @@ -524,23 +523,27 @@ paths: {} servers: - @@@ ` - for value, expected := range map[string]error{ - `{url: /}`: nil, - `{url: "http://{x}.{y}.example.com"}`: errors.New("invalid servers: server has undeclared variables"), - `{url: "http://{x}.y}.example.com"}`: errors.New("invalid servers: server URL has mismatched { and }"), - `{url: "http://{x.example.com"}`: errors.New("invalid servers: server URL has mismatched { and }"), - `{url: "http://{x}.example.com", variables: {x: {default: "www"}}}`: nil, - `{url: "http://{x}.example.com", variables: {x: {default: "www", enum: ["www"]}}}`: nil, - `{url: "http://{x}.example.com", variables: {x: {enum: ["www"]}}}`: errors.New(`invalid servers: field default is required in {"enum":["www"]}`), - `{url: "http://www.example.com", variables: {x: {enum: ["www"]}}}`: errors.New("invalid servers: server has undeclared variables"), - `{url: "http://{y}.example.com", variables: {x: {enum: ["www"]}}}`: errors.New("invalid servers: server has undeclared variables"), + for value, expected := range map[string]string{ + `{url: /}`: "", + `{url: "http://{x}.{y}.example.com"}`: "invalid servers: server has undeclared variables", + `{url: "http://{x}.y}.example.com"}`: "invalid servers: server URL has mismatched { and }", + `{url: "http://{x.example.com"}`: "invalid servers: server URL has mismatched { and }", + `{url: "http://{x}.example.com", variables: {x: {default: "www"}}}`: "", + `{url: "http://{x}.example.com", variables: {x: {default: "www", enum: ["www"]}}}`: "", + `{url: "http://{x}.example.com", variables: {x: {enum: ["www"]}}}`: `invalid servers: field default is required in {"enum":["www"]}`, + `{url: "http://www.example.com", variables: {x: {enum: ["www"]}}}`: "invalid servers: server has undeclared variables", + `{url: "http://{y}.example.com", variables: {x: {enum: ["www"]}}}`: "invalid servers: server has undeclared variables", } { t.Run(value, func(t *testing.T) { loader := NewLoader() doc, err := loader.LoadFromData([]byte(strings.Replace(spec, "@@@", value, 1))) require.NoError(t, err) err = doc.Validate(loader.Context) - require.Equal(t, expected, err) + if expected == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, expected) + } }) } } diff --git a/openapi3/media_type.go b/openapi3/media_type.go index 01df12ad0..b1a3417eb 100644 --- a/openapi3/media_type.go +++ b/openapi3/media_type.go @@ -95,10 +95,10 @@ func (mediaType *MediaType) Validate(ctx context.Context) error { } else if examples := mediaType.Examples; examples != nil { for k, v := range examples { if err := v.Validate(ctx); err != nil { - return fmt.Errorf("%s: %s", k, err) + return fmt.Errorf("%s: %w", k, err) } if err := validateExampleValue(v.Value.Value, schema.Value); err != nil { - return fmt.Errorf("%s: %s", k, err) + return fmt.Errorf("%s: %w", k, err) } } } diff --git a/openapi3/openapi3.go b/openapi3/openapi3.go index 20549c2b7..09b6c2c64 100644 --- a/openapi3/openapi3.go +++ b/openapi3/openapi3.go @@ -69,14 +69,14 @@ func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error { // NOTE: only mention info/components/paths/... key in this func's errors. { - wrap := func(e error) error { return fmt.Errorf("invalid components: %v", e) } + wrap := func(e error) error { return fmt.Errorf("invalid components: %w", e) } if err := doc.Components.Validate(ctx); err != nil { return wrap(err) } } { - wrap := func(e error) error { return fmt.Errorf("invalid info: %v", e) } + wrap := func(e error) error { return fmt.Errorf("invalid info: %w", e) } if v := doc.Info; v != nil { if err := v.Validate(ctx); err != nil { return wrap(err) @@ -87,7 +87,7 @@ func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error { } { - wrap := func(e error) error { return fmt.Errorf("invalid paths: %v", e) } + wrap := func(e error) error { return fmt.Errorf("invalid paths: %w", e) } if v := doc.Paths; v != nil { if err := v.Validate(ctx); err != nil { return wrap(err) @@ -98,7 +98,7 @@ func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error { } { - wrap := func(e error) error { return fmt.Errorf("invalid security: %v", e) } + wrap := func(e error) error { return fmt.Errorf("invalid security: %w", e) } if v := doc.Security; v != nil { if err := v.Validate(ctx); err != nil { return wrap(err) @@ -107,7 +107,7 @@ func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error { } { - wrap := func(e error) error { return fmt.Errorf("invalid servers: %v", e) } + wrap := func(e error) error { return fmt.Errorf("invalid servers: %w", e) } if v := doc.Servers; v != nil { if err := v.Validate(ctx); err != nil { return wrap(err) diff --git a/openapi3/parameter.go b/openapi3/parameter.go index f5d7d1f2f..64092538f 100644 --- a/openapi3/parameter.go +++ b/openapi3/parameter.go @@ -296,23 +296,23 @@ func (parameter *Parameter) Validate(ctx context.Context) error { } if !smSupported { e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a %s parameter", sm.Style, sm.Explode, in) - return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, e) + return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e) } if (parameter.Schema == nil) == (parameter.Content == nil) { e := errors.New("parameter must contain exactly one of content and schema") - return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, e) + return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e) } if content := parameter.Content; content != nil { if err := content.Validate(ctx); err != nil { - return fmt.Errorf("parameter %q content is invalid: %v", parameter.Name, err) + return fmt.Errorf("parameter %q content is invalid: %w", parameter.Name, err) } } if schema := parameter.Schema; schema != nil { if err := schema.Validate(ctx); err != nil { - return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, err) + return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, err) } if parameter.Example != nil && parameter.Examples != nil { return fmt.Errorf("parameter %q example and examples are mutually exclusive", parameter.Name) @@ -327,10 +327,10 @@ func (parameter *Parameter) Validate(ctx context.Context) error { } else if examples := parameter.Examples; examples != nil { for k, v := range examples { if err := v.Validate(ctx); err != nil { - return fmt.Errorf("%s: %s", k, err) + return fmt.Errorf("%s: %w", k, err) } if err := validateExampleValue(v.Value.Value, schema.Value); err != nil { - return fmt.Errorf("%s: %s", k, err) + return fmt.Errorf("%s: %w", k, err) } } } diff --git a/openapi3/schema.go b/openapi3/schema.go index c59070ee1..ded97f02a 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -755,7 +755,7 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error) if x := schema.Example; x != nil && !validationOpts.ExamplesValidationDisabled { if err := validateExampleValue(x, schema); err != nil { - return fmt.Errorf("invalid schema example: %s", err) + return fmt.Errorf("invalid schema example: %w", err) } } diff --git a/openapi3/schema_formats.go b/openapi3/schema_formats.go index 17b7564cf..51e245411 100644 --- a/openapi3/schema_formats.go +++ b/openapi3/schema_formats.go @@ -28,7 +28,7 @@ var SchemaStringFormats = make(map[string]Format, 4) func DefineStringFormat(name string, pattern string) { re, err := regexp.Compile(pattern) if err != nil { - err := fmt.Errorf("format %q has invalid pattern %q: %v", name, pattern, err) + err := fmt.Errorf("format %q has invalid pattern %q: %w", name, pattern, err) panic(err) } SchemaStringFormats[name] = Format{regexp: re} diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go index 52c3ef218..790b21a73 100644 --- a/openapi3/security_scheme.go +++ b/openapi3/security_scheme.go @@ -165,7 +165,7 @@ func (ss *SecurityScheme) Validate(ctx context.Context) error { return fmt.Errorf("security scheme of type %q should have 'flows'", ss.Type) } if err := flow.Validate(ctx); err != nil { - return fmt.Errorf("security scheme 'flow' is invalid: %v", err) + return fmt.Errorf("security scheme 'flow' is invalid: %w", err) } } else if ss.Flows != nil { return fmt.Errorf("security scheme of type %q can't have 'flows'", ss.Type) diff --git a/openapi3filter/req_resp_decoder.go b/openapi3filter/req_resp_decoder.go index a54b3bb47..73eb73e2b 100644 --- a/openapi3filter/req_resp_decoder.go +++ b/openapi3filter/req_resp_decoder.go @@ -654,7 +654,7 @@ func (d *cookieParamDecoder) DecodePrimitive(param string, sm *openapi3.Serializ return nil, found, nil } if err != nil { - return nil, found, fmt.Errorf("decoding param %q: %s", param, err) + return nil, found, fmt.Errorf("decoding param %q: %w", param, err) } val, err := parsePrimitive(cookie.Value, schema) @@ -673,7 +673,7 @@ func (d *cookieParamDecoder) DecodeArray(param string, sm *openapi3.Serializatio return nil, found, nil } if err != nil { - return nil, found, fmt.Errorf("decoding param %q: %s", param, err) + return nil, found, fmt.Errorf("decoding param %q: %w", param, err) } val, err := parseArray(strings.Split(cookie.Value, ","), schema) return val, found, err @@ -691,7 +691,7 @@ func (d *cookieParamDecoder) DecodeObject(param string, sm *openapi3.Serializati return nil, found, nil } if err != nil { - return nil, found, fmt.Errorf("decoding param %q: %s", param, err) + return nil, found, fmt.Errorf("decoding param %q: %w", param, err) } props, err := propsFromString(cookie.Value, ",", ",") if err != nil { @@ -753,7 +753,7 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string if v, ok := err.(*ParseError); ok { return nil, &ParseError{path: []interface{}{propName}, Cause: v} } - return nil, fmt.Errorf("property %q: %s", propName, err) + return nil, fmt.Errorf("property %q: %w", propName, err) } obj[propName] = value } @@ -771,7 +771,7 @@ func parseArray(raw []string, schemaRef *openapi3.SchemaRef) ([]interface{}, err if v, ok := err.(*ParseError); ok { return nil, &ParseError{path: []interface{}{i}, Cause: v} } - return nil, fmt.Errorf("item %d: %s", i, err) + return nil, fmt.Errorf("item %d: %w", i, err) } // If the items are nil, then the array is nil. There shouldn't be case where some values are actual primitive @@ -1044,7 +1044,7 @@ func multipartBodyDecoder(body io.Reader, header http.Header, schema *openapi3.S if v, ok := err.(*ParseError); ok { return nil, &ParseError{path: []interface{}{name}, Cause: v} } - return nil, fmt.Errorf("part %s: %s", name, err) + return nil, fmt.Errorf("part %s: %w", name, err) } values[name] = append(values[name], value) } diff --git a/routers/legacy/router.go b/routers/legacy/router.go index f1f47d9ed..fb8d4621e 100644 --- a/routers/legacy/router.go +++ b/routers/legacy/router.go @@ -60,7 +60,7 @@ type Router struct { // All operations of the document will be added to the router. func NewRouter(doc *openapi3.T) (routers.Router, error) { if err := doc.Validate(context.Background()); err != nil { - return nil, fmt.Errorf("validating OpenAPI failed: %v", err) + return nil, fmt.Errorf("validating OpenAPI failed: %w", err) } router := &Router{doc: doc} root := router.node()