feat(api/v2): preserve Vikunja numeric error code in problem+json
translateDomainError discarded web.HTTPError.Code, so v2 error bodies always read code 0 — losing the v1 contract the error docs key off. Override huma.NewError with a VikunjaErrorModel that adds a code field, so both the generated OpenAPI schema and runtime responses carry it. Domain errors with a numeric code now surface it (e.g. 8002 for a missing label, matching v1); errors without one omit it.
This commit is contained in:
parent
e257823cef
commit
8532016a2d
|
|
@ -19,6 +19,7 @@ package apiv2
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/modules/auth"
|
||||
|
|
@ -57,7 +58,49 @@ func translateDomainError(err error) error {
|
|||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return huma.NewError(details.HTTPCode, msg)
|
||||
se := huma.NewError(details.HTTPCode, msg)
|
||||
// Preserve Vikunja's numeric domain error code (the value the
|
||||
// error docs key off) on the problem+json body. v1 exposes it as
|
||||
// `code`; without this v2 clients always read 0.
|
||||
if vm, ok := se.(*vikunjaErrorModel); ok {
|
||||
vm.Code = details.Code
|
||||
}
|
||||
return se
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// vikunjaErrorModel extends Huma's RFC 9457 body with Vikunja's numeric
|
||||
// domain error code, preserving the v1 error-code contract on v2. Wired in
|
||||
// as the global error type via the huma.NewError override in init().
|
||||
type vikunjaErrorModel struct {
|
||||
huma.ErrorModel
|
||||
Code int `json:"code,omitempty" doc:"Vikunja numeric error code; see https://vikunja.io/docs/errors/"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Replace Huma's default error constructor so both the generated
|
||||
// OpenAPI schema and runtime responses use vikunjaErrorModel. Huma
|
||||
// derives the error-response schema from NewError(0, "") at register
|
||||
// time and routes runtime errors through the same constructor, so the
|
||||
// `code` field stays consistent between spec and wire.
|
||||
huma.NewError = func(status int, msg string, errs ...error) huma.StatusError {
|
||||
details := make([]*huma.ErrorDetail, 0, len(errs))
|
||||
for _, e := range errs {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
if d, ok := e.(huma.ErrorDetailer); ok {
|
||||
details = append(details, d.ErrorDetail())
|
||||
} else {
|
||||
details = append(details, &huma.ErrorDetail{Message: e.Error()})
|
||||
}
|
||||
}
|
||||
return &vikunjaErrorModel{ErrorModel: huma.ErrorModel{
|
||||
Status: status,
|
||||
Title: http.StatusText(status),
|
||||
Detail: msg,
|
||||
Errors: details,
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue