...
1 package validation
2
3 import (
4 "fmt"
5 "strings"
6
7 "google.golang.org/genproto/googleapis/rpc/errdetails"
8 "google.golang.org/grpc/codes"
9 "google.golang.org/grpc/status"
10 )
11
12
13 type Error struct {
14 fieldViolations []*errdetails.BadRequest_FieldViolation
15 grpcStatus *status.Status
16 str string
17 }
18
19
20 func NewError(fieldViolations []*errdetails.BadRequest_FieldViolation) error {
21 if len(fieldViolations) == 0 {
22 panic("validation.NewError: must provide at least one field violation")
23 }
24 return &Error{
25 fieldViolations: fieldViolations,
26 }
27 }
28
29
30 func (e *Error) GRPCStatus() *status.Status {
31 if e.grpcStatus == nil {
32 var fields strings.Builder
33 for i, fieldViolation := range e.fieldViolations {
34 _, _ = fields.WriteString(fieldViolation.GetField())
35 if i < len(e.fieldViolations)-1 {
36 _, _ = fields.WriteString(", ")
37 }
38 }
39 withoutDetails := status.Newf(codes.InvalidArgument, "invalid fields: %s", fields.String())
40 if withDetails, err := withoutDetails.WithDetails(&errdetails.BadRequest{
41 FieldViolations: e.fieldViolations,
42 }); err != nil {
43 e.grpcStatus = withoutDetails
44 } else {
45 e.grpcStatus = withDetails
46 }
47 }
48 return e.grpcStatus
49 }
50
51
52 func (e *Error) Error() string {
53 if e.str == "" {
54 if len(e.fieldViolations) == 1 {
55 e.str = fmt.Sprintf(
56 "field violation on %s: %s",
57 e.fieldViolations[0].GetField(),
58 e.fieldViolations[0].GetDescription(),
59 )
60 } else {
61 var result strings.Builder
62 _, _ = result.WriteString("field violation on multiple fields:\n")
63 for i, fieldViolation := range e.fieldViolations {
64 _, _ = result.WriteString(fmt.Sprintf(" | %s: %s", fieldViolation.GetField(), fieldViolation.GetDescription()))
65 if i < len(e.fieldViolations)-1 {
66 _ = result.WriteByte('\n')
67 }
68 }
69 e.str = result.String()
70 }
71 }
72 return e.str
73 }
74
View as plain text