Skip to content

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

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions