Skip to content

Commit 7a75dce

Browse files
authored
refactor: remove duplicated code (#2705)
1 parent 801f1ad commit 7a75dce

File tree

1 file changed

+51
-64
lines changed

1 file changed

+51
-64
lines changed

rest/httpx/responses.go

+51-64
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package httpx
33
import (
44
"context"
55
"encoding/json"
6+
"fmt"
67
"net/http"
78
"sync"
89

@@ -13,8 +14,8 @@ import (
1314

1415
var (
1516
errorHandler func(error) (int, interface{})
16-
lock sync.RWMutex
1717
errorHandlerCtx func(context.Context, error) (int, interface{})
18+
lock sync.RWMutex
1819
)
1920

2021
// Error writes err into w.
@@ -23,32 +24,26 @@ func Error(w http.ResponseWriter, err error, fns ...func(w http.ResponseWriter,
2324
handler := errorHandler
2425
lock.RUnlock()
2526

26-
if handler == nil {
27-
if len(fns) > 0 {
28-
fns[0](w, err)
29-
} else if errcode.IsGrpcError(err) {
30-
// don't unwrap error and get status.Message(),
31-
// it hides the rpc error headers.
32-
http.Error(w, err.Error(), errcode.CodeFromGrpcError(err))
33-
} else {
34-
http.Error(w, err.Error(), http.StatusBadRequest)
35-
}
27+
doHandleError(w, err, handler, WriteJson, fns...)
28+
}
3629

37-
return
38-
}
30+
// ErrorCtx writes err into w.
31+
func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error,
32+
fns ...func(w http.ResponseWriter, err error)) {
33+
lock.RLock()
34+
handlerCtx := errorHandlerCtx
35+
lock.RUnlock()
3936

40-
code, body := handler(err)
41-
if body == nil {
42-
w.WriteHeader(code)
43-
return
37+
var handler func(error) (int, interface{})
38+
if handlerCtx != nil {
39+
handler = func(err error) (int, interface{}) {
40+
return handlerCtx(ctx, err)
41+
}
4442
}
45-
46-
e, ok := body.(error)
47-
if ok {
48-
http.Error(w, e.Error(), code)
49-
} else {
50-
WriteJson(w, code, body)
43+
writeJson := func(w http.ResponseWriter, code int, v interface{}) {
44+
WriteJsonCtx(ctx, w, code, v)
5145
}
46+
doHandleError(w, err, handler, writeJson, fns...)
5247
}
5348

5449
// Ok writes HTTP 200 OK into w.
@@ -61,44 +56,47 @@ func OkJson(w http.ResponseWriter, v interface{}) {
6156
WriteJson(w, http.StatusOK, v)
6257
}
6358

59+
// OkJsonCtx writes v into w with 200 OK.
60+
func OkJsonCtx(ctx context.Context, w http.ResponseWriter, v interface{}) {
61+
WriteJsonCtx(ctx, w, http.StatusOK, v)
62+
}
63+
6464
// SetErrorHandler sets the error handler, which is called on calling Error.
6565
func SetErrorHandler(handler func(error) (int, interface{})) {
6666
lock.Lock()
6767
defer lock.Unlock()
6868
errorHandler = handler
6969
}
7070

71+
// SetErrorHandlerCtx sets the error handler, which is called on calling Error.
72+
func SetErrorHandlerCtx(handlerCtx func(context.Context, error) (int, interface{})) {
73+
lock.Lock()
74+
defer lock.Unlock()
75+
errorHandlerCtx = handlerCtx
76+
}
77+
7178
// WriteJson writes v as json string into w with code.
7279
func WriteJson(w http.ResponseWriter, code int, v interface{}) {
73-
bs, err := json.Marshal(v)
74-
if err != nil {
75-
http.Error(w, err.Error(), http.StatusInternalServerError)
76-
return
80+
if err := doWriteJson(w, code, v); err != nil {
81+
logx.Error(err)
7782
}
83+
}
7884

79-
w.Header().Set(ContentType, header.JsonContentType)
80-
w.WriteHeader(code)
81-
82-
if n, err := w.Write(bs); err != nil {
83-
// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
84-
// so it's ignored here.
85-
if err != http.ErrHandlerTimeout {
86-
logx.Errorf("write response failed, error: %s", err)
87-
}
88-
} else if n < len(bs) {
89-
logx.Errorf("actual bytes: %d, written bytes: %d", len(bs), n)
85+
// WriteJsonCtx writes v as json string into w with code.
86+
func WriteJsonCtx(ctx context.Context, w http.ResponseWriter, code int, v interface{}) {
87+
if err := doWriteJson(w, code, v); err != nil {
88+
logx.WithContext(ctx).Error(err)
9089
}
9190
}
9291

93-
// Error writes err into w.
94-
func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error, fns ...func(w http.ResponseWriter, err error)) {
95-
lock.RLock()
96-
handlerCtx := errorHandlerCtx
97-
lock.RUnlock()
98-
99-
if handlerCtx == nil {
92+
func doHandleError(w http.ResponseWriter, err error, handler func(error) (int, interface{}),
93+
writeJson func(w http.ResponseWriter, code int, v interface{}),
94+
fns ...func(w http.ResponseWriter, err error)) {
95+
if handler == nil {
10096
if len(fns) > 0 {
101-
fns[0](w, err)
97+
for _, fn := range fns {
98+
fn(w, err)
99+
}
102100
} else if errcode.IsGrpcError(err) {
103101
// don't unwrap error and get status.Message(),
104102
// it hides the rpc error headers.
@@ -110,7 +108,7 @@ func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error, fns ...func
110108
return
111109
}
112110

113-
code, body := handlerCtx(ctx, err)
111+
code, body := handler(err)
114112
if body == nil {
115113
w.WriteHeader(code)
116114
return
@@ -120,21 +118,15 @@ func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error, fns ...func
120118
if ok {
121119
http.Error(w, e.Error(), code)
122120
} else {
123-
WriteJsonCtx(ctx, w, code, body)
121+
writeJson(w, code, body)
124122
}
125123
}
126124

127-
// OkJson writes v into w with 200 OK.
128-
func OkJsonCtx(ctx context.Context, w http.ResponseWriter, v interface{}) {
129-
WriteJsonCtx(ctx, w, http.StatusOK, v)
130-
}
131-
132-
// WriteJson writes v as json string into w with code.
133-
func WriteJsonCtx(ctx context.Context, w http.ResponseWriter, code int, v interface{}) {
125+
func doWriteJson(w http.ResponseWriter, code int, v interface{}) error {
134126
bs, err := json.Marshal(v)
135127
if err != nil {
136128
http.Error(w, err.Error(), http.StatusInternalServerError)
137-
return
129+
return fmt.Errorf("marshal json failed, error: %w", err)
138130
}
139131

140132
w.Header().Set(ContentType, header.JsonContentType)
@@ -144,16 +136,11 @@ func WriteJsonCtx(ctx context.Context, w http.ResponseWriter, code int, v interf
144136
// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
145137
// so it's ignored here.
146138
if err != http.ErrHandlerTimeout {
147-
logx.WithContext(ctx).Errorf("write response failed, error: %s", err)
139+
return fmt.Errorf("write response failed, error: %w", err)
148140
}
149141
} else if n < len(bs) {
150-
logx.WithContext(ctx).Errorf("actual bytes: %d, written bytes: %d", len(bs), n)
142+
return fmt.Errorf("actual bytes: %d, written bytes: %d", len(bs), n)
151143
}
152-
}
153144

154-
// SetErrorHandler sets the error handler, which is called on calling Error.
155-
func SetErrorHandlerCtx(handlerCtx func(context.Context, error) (int, interface{})) {
156-
lock.Lock()
157-
defer lock.Unlock()
158-
errorHandlerCtx = handlerCtx
145+
return nil
159146
}

0 commit comments

Comments
 (0)