Skip to content

bug/design: forwarding over formatter takes wrong type #3718

@gabyx

Description

@gabyx

I suspect there is an error in generation of the Encode/Decode...Error functions. See the example below.

When I look at the generated code, I see that formatter(ctx, res) gets the casted type res (cm.CustodianError) (our error type on the method).

  • This is problematic when you return a wrapped error from the endpoint: i.e. wrapping cm.CustodianError to be able to do custom stuff in a custom formatter (e.g. v is an error which Unwraps to cm.CustodianError etc).

  • IMO: it should receive v, before Unwrap in As(v, &res) such that the formatter has a chance to actually read a wrapped type.

  • From a design perspective I dont understand yet why body = formatter(ctx, res) returns a goahttp.Statuser because
    the returned interface goahttp.Statuser is not used as the status is forcefully set (see below):
    Maybe formatter needs to be extended to be something like:

    type ErrorFormatter interface {
        MarshalToStatuser(ctx context.Context, v any) goahttp.Statuser
        Marshal(ctx context.Context, v any) any
    }
  • Also problematic is that errors.As(v, &res) is not checked and just panics (should be a debug assert).

Encode/Decode Generated:

func EncodeGetContractError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(ctx context.Context, err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
	encodeError := goahttp.ErrorEncoder(encoder, formatter)
	return func(ctx context.Context, w http.ResponseWriter, v error) error {
		var en goa.GoaErrorNamer
		if !errors.As(v, &en) {
			return encodeError(ctx, w, v)
		}
		switch en.GoaErrorName() {
		case "cm#not-found":
			var res *cm.CustodianError
			errors.As(v, &res)
			enc := encoder(ctx, w)
			var body any
			if formatter != nil {
				body = formatter(ctx, res)
			} else {
				body = NewGetContractCmNotFoundResponseBody(res)
			}
			w.Header().Set("goa-error", res.GoaErrorName())
			w.WriteHeader(http.StatusNotFound)
			return enc.Encode(body)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions