refactor: introduce domain.ErrorWithPath interface
ci/woodpecker/push/govulncheck Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details

This commit is contained in:
Dawid Wysokiński 2024-03-01 07:46:42 +01:00
parent c173bcdba6
commit 0f4611962f
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
7 changed files with 89 additions and 81 deletions

View File

@ -1,5 +1,7 @@
package domain
import "strconv"
type ErrorType uint8
const (
@ -32,6 +34,33 @@ type ErrorWithParams interface {
Params() map[string]any
}
type ErrorPathSegment struct {
Model string
Field string
Index int // Index may be <0 and this means that it is unset
}
func (s ErrorPathSegment) String() string {
path := s.Model
if s.Field != "" {
if len(path) > 0 {
path += "."
}
path += s.Field
if s.Index > 0 {
path += "[" + strconv.Itoa(s.Index) + "]"
}
}
return path
}
type ErrorWithPath interface {
Error
Path() ErrorPathSegment
}
type simpleError struct {
msg string
typ ErrorType

View File

@ -3,7 +3,6 @@ package domain
import (
"errors"
"fmt"
"strconv"
)
type ValidationError struct {
@ -13,9 +12,10 @@ type ValidationError struct {
}
var _ ErrorWithParams = ValidationError{}
var _ ErrorWithPath = ValidationError{}
func (e ValidationError) Error() string {
prefix := e.Path()
prefix := e.Path().String()
if prefix != "" {
prefix += ": "
@ -24,17 +24,12 @@ func (e ValidationError) Error() string {
return prefix + e.Err.Error()
}
func (e ValidationError) Path() string {
path := e.Model
if e.Field != "" {
if len(path) > 0 {
path += "."
}
path += e.Field
func (e ValidationError) Path() ErrorPathSegment {
return ErrorPathSegment{
Model: e.Model,
Field: e.Field,
Index: -1,
}
return path
}
func (e ValidationError) Type() ErrorType {
@ -73,9 +68,10 @@ type SliceElementValidationError struct {
}
var _ ErrorWithParams = SliceElementValidationError{}
var _ ErrorWithPath = SliceElementValidationError{}
func (e SliceElementValidationError) Error() string {
prefix := e.Path()
prefix := e.Path().String()
if prefix != "" {
prefix += ": "
@ -84,17 +80,12 @@ func (e SliceElementValidationError) Error() string {
return prefix + e.Err.Error()
}
func (e SliceElementValidationError) Path() string {
path := e.Model
if e.Field != "" {
if len(path) > 0 {
path += "."
}
path += e.Field + "[" + strconv.Itoa(e.Index) + "]"
func (e SliceElementValidationError) Path() ErrorPathSegment {
return ErrorPathSegment{
Model: e.Model,
Field: e.Field,
Index: e.Index,
}
return path
}
func (e SliceElementValidationError) Type() ErrorType {

View File

@ -65,13 +65,7 @@ func (es apiErrors) toResponse() apimodel.ErrorResponse {
return resp
}
type errorPathSegment struct {
model string
field string
index int // index may be <0 and this means that it is unset
}
type errorPathFormatter func(segments []errorPathSegment) []string
type errorPathFormatter func(segments []domain.ErrorPathSegment) []string
type apiErrorRenderer struct {
// errorPathFormatter allows to override the default path formatter
@ -149,31 +143,25 @@ func (re apiErrorRenderer) invalidParamFormatErrorToAPIError(
func (re apiErrorRenderer) domainErrorToAPIError(domainErr domain.Error) apiError {
message := domainErr.Error()
var pathSegments []errorPathSegment
var pathSegments []domain.ErrorPathSegment
var err error = domainErr
for err != nil {
var validationErr domain.ValidationError
var sliceElementValidationErr domain.SliceElementValidationError
for {
var withPath domain.ErrorWithPath
switch {
case errors.As(err, &validationErr):
pathSegments = append(pathSegments, errorPathSegment{
model: validationErr.Model,
field: validationErr.Field,
index: -1,
})
err = validationErr.Unwrap()
if !errors.As(err, &withPath) {
break
}
pathSegments = append(pathSegments, withPath.Path())
u, ok := err.(interface {
Unwrap() error
})
if ok {
err = u.Unwrap()
message = err.Error()
case errors.As(err, &sliceElementValidationErr):
pathSegments = append(pathSegments, errorPathSegment{
model: sliceElementValidationErr.Model,
field: sliceElementValidationErr.Field,
index: sliceElementValidationErr.Index,
})
err = sliceElementValidationErr.Unwrap()
message = err.Error()
default:
} else {
err = nil
}
}

View File

@ -131,12 +131,12 @@ func playerFromContext(ctx context.Context) (domain.PlayerWithRelations, bool) {
return p, ok
}
func formatListPlayersErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListPlayersParams" {
func formatListPlayersErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListPlayersParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "cursor":
return []string{"$query", "cursor"}
case "limit":
@ -145,14 +145,14 @@ func formatListPlayersErrorPath(segments []errorPathSegment) []string {
return []string{"$query", "deleted"}
case "names":
path := []string{"$query", "name"}
if segments[0].index >= 0 {
path = append(path, strconv.Itoa(segments[0].index))
if segments[0].Index >= 0 {
path = append(path, strconv.Itoa(segments[0].Index))
}
return path
case "sort":
path := []string{"$query", "sort"}
if segments[0].index >= 0 {
path = append(path, strconv.Itoa(segments[0].index))
if segments[0].Index >= 0 {
path = append(path, strconv.Itoa(segments[0].Index))
}
return path
default:
@ -160,12 +160,12 @@ func formatListPlayersErrorPath(segments []errorPathSegment) []string {
}
}
func formatGetPlayerErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListPlayersParams" {
func formatGetPlayerErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListPlayersParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "ids":
return []string{"$path", "playerId"}
default:

View File

@ -138,12 +138,12 @@ func serverFromContext(ctx context.Context) (domain.Server, bool) {
return s, ok
}
func formatListServersErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListServersParams" {
func formatListServersErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListServersParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "cursor":
return []string{"$query", "cursor"}
case "limit":
@ -155,12 +155,12 @@ func formatListServersErrorPath(segments []errorPathSegment) []string {
}
}
func formatGetServerErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListServersParams" {
func formatGetServerErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListServersParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "keys":
return []string{"$path", "serverKey"}
default:

View File

@ -131,12 +131,12 @@ func tribeFromContext(ctx context.Context) (domain.Tribe, bool) {
return t, ok
}
func formatListTribesErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListTribesParams" {
func formatListTribesErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListTribesParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "cursor":
return []string{"$query", "cursor"}
case "limit":
@ -147,8 +147,8 @@ func formatListTribesErrorPath(segments []errorPathSegment) []string {
return []string{"$query", "tag"}
case "sort":
path := []string{"$query", "sort"}
if segments[0].index >= 0 {
path = append(path, strconv.Itoa(segments[0].index))
if segments[0].Index >= 0 {
path = append(path, strconv.Itoa(segments[0].Index))
}
return path
default:
@ -156,12 +156,12 @@ func formatListTribesErrorPath(segments []errorPathSegment) []string {
}
}
func formatGetTribeErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListTribesParams" {
func formatGetTribeErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListTribesParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "ids":
return []string{"$path", "tribeId"}
default:

View File

@ -73,12 +73,12 @@ func versionFromContext(ctx context.Context) (domain.Version, bool) {
return v, ok
}
func formatListVersionsErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListVersionsParams" {
func formatListVersionsErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListVersionsParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "cursor":
return []string{"$query", "cursor"}
case "limit":
@ -88,12 +88,12 @@ func formatListVersionsErrorPath(segments []errorPathSegment) []string {
}
}
func formatGetVersionErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListVersionsParams" {
func formatGetVersionErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListVersionsParams" {
return nil
}
switch segments[0].field {
switch segments[0].Field {
case "codes":
return []string{"$path", "versionCode"}
default: