bug/design: forwarding over `formatter` takes wrong type
- Dominant language
- Go
- Stars
- 6.1k
- Forks
- 583
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 15
Description
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 `Unwrap`s 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:
```go
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:
```go
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)
```
Contributor guide
Assessment
This issue has not been assessed yet.