-
Notifications
You must be signed in to change notification settings - Fork 0
/
grpc.go
118 lines (94 loc) · 2.76 KB
/
grpc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package ginerrors
import (
"fmt"
"net/http"
"github.com/go-playground/validator/v10"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type GRPCValidationError struct {
Violations []*errdetails.BadRequest_FieldViolation
}
var (
httpToGRPCCodes = map[int]codes.Code{
http.StatusNotFound: codes.NotFound,
http.StatusMethodNotAllowed: codes.Unavailable,
http.StatusInternalServerError: codes.Internal,
http.StatusBadRequest: codes.InvalidArgument,
}
grpcToHTTPCodes = map[codes.Code]int{
codes.NotFound: http.StatusNotFound,
codes.Unavailable: http.StatusMethodNotAllowed,
codes.Internal: http.StatusInternalServerError,
codes.InvalidArgument: http.StatusBadRequest,
}
)
func UnwrapRPCError(st *status.Status) interface{} {
switch st.Code() { //nolint: exhaustive
case codes.NotFound:
return ErrRecordNotFound
case codes.Unavailable:
return ErrNoMethod
case codes.Internal:
return ErrServerError
case codes.InvalidArgument:
details := st.Details()
violations := getViolations(details)
return GRPCValidationError{Violations: violations}
default:
return fmt.Errorf("%w: %s", st.Err(), st.Message())
}
}
func WrapErrorWithStatus(err error, lang string) error {
l := langName(lang)
httpCode, msg := getErrCode(err)
code, ok := getGRPCCode(httpCode)
if !ok {
return err
}
st := status.New(code, msg)
if code == codes.InvalidArgument {
//nolint: errorlint
if errs, ok := err.(validator.ValidationErrors); ok {
var e error
br := errdetails.BadRequest{}
for _, ee := range errs {
field := getFieldName(ee.Namespace(), ee.Field())
msg := getErrMessage(validationRule(ee.ActualTag()), field, ee.Param(), l)
violation := &errdetails.BadRequest_FieldViolation{
Field: string(field),
Description: string(msg),
}
br.FieldViolations = append(br.FieldViolations, violation)
}
st, e = st.WithDetails(&br)
if e != nil {
return err
}
}
}
return st.Err()
}
// getGRPCCode returns grpc error code by first value and its existence by second.
func getGRPCCode(httpCode int) (codes.Code, bool) {
c, ok := httpToGRPCCodes[httpCode]
return c, ok
}
// getHTTPCode returns http error code by first value and its existence by second.
func getHTTPCode(grpcCode codes.Code) (int, bool) {
c, ok := grpcToHTTPCodes[grpcCode]
return c, ok
}
func getViolations(details []interface{}) []*errdetails.BadRequest_FieldViolation {
if len(details) == 0 {
return nil
}
violations := make([]*errdetails.BadRequest_FieldViolation, 0)
for _, detail := range details {
if d, ok := detail.(*errdetails.BadRequest); ok {
violations = append(violations, d.FieldViolations...)
}
}
return violations
}