forked from go-kit/kit
/
transport_http.go
141 lines (124 loc) · 4.48 KB
/
transport_http.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package addsvc
// This file provides server-side bindings for the HTTP transport.
// It utilizes the transport/http.Server.
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
stdopentracing "github.com/opentracing/opentracing-go"
"golang.org/x/net/context"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/tracing/opentracing"
httptransport "github.com/go-kit/kit/transport/http"
)
// MakeHTTPHandler returns a handler that makes a set of endpoints available
// on predefined paths.
func MakeHTTPHandler(ctx context.Context, endpoints Endpoints, tracer stdopentracing.Tracer, logger log.Logger) http.Handler {
options := []httptransport.ServerOption{
httptransport.ServerErrorEncoder(errorEncoder),
httptransport.ServerErrorLogger(logger),
}
m := http.NewServeMux()
m.Handle("/sum", httptransport.NewServer(
ctx,
endpoints.SumEndpoint,
DecodeHTTPSumRequest,
EncodeHTTPGenericResponse,
append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "Sum", logger)))...,
))
m.Handle("/concat", httptransport.NewServer(
ctx,
endpoints.ConcatEndpoint,
DecodeHTTPConcatRequest,
EncodeHTTPGenericResponse,
append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "Concat", logger)))...,
))
return m
}
func errorEncoder(_ context.Context, err error, w http.ResponseWriter) {
code := http.StatusInternalServerError
msg := err.Error()
if e, ok := err.(httptransport.Error); ok {
msg = e.Err.Error()
switch e.Domain {
case httptransport.DomainDecode:
code = http.StatusBadRequest
case httptransport.DomainDo:
switch e.Err {
case ErrTwoZeroes, ErrMaxSizeExceeded, ErrIntOverflow:
code = http.StatusBadRequest
}
}
}
w.WriteHeader(code)
json.NewEncoder(w).Encode(errorWrapper{Error: msg})
}
func errorDecoder(r *http.Response) error {
var w errorWrapper
if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
return err
}
return errors.New(w.Error)
}
type errorWrapper struct {
Error string `json:"error"`
}
// DecodeHTTPSumRequest is a transport/http.DecodeRequestFunc that decodes a
// JSON-encoded sum request from the HTTP request body. Primarily useful in a
// server.
func DecodeHTTPSumRequest(_ context.Context, r *http.Request) (interface{}, error) {
var req sumRequest
err := json.NewDecoder(r.Body).Decode(&req)
return req, err
}
// DecodeHTTPConcatRequest is a transport/http.DecodeRequestFunc that decodes a
// JSON-encoded concat request from the HTTP request body. Primarily useful in a
// server.
func DecodeHTTPConcatRequest(_ context.Context, r *http.Request) (interface{}, error) {
var req concatRequest
err := json.NewDecoder(r.Body).Decode(&req)
return req, err
}
// DecodeHTTPSumResponse is a transport/http.DecodeResponseFunc that decodes a
// JSON-encoded sum response from the HTTP response body. If the response has a
// non-200 status code, we will interpret that as an error and attempt to decode
// the specific error message from the response body. Primarily useful in a
// client.
func DecodeHTTPSumResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp sumResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
// DecodeHTTPConcatResponse is a transport/http.DecodeResponseFunc that decodes
// a JSON-encoded concat response from the HTTP response body. If the response
// has a non-200 status code, we will interpret that as an error and attempt to
// decode the specific error message from the response body. Primarily useful in
// a client.
func DecodeHTTPConcatResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp concatResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
// EncodeHTTPGenericRequest is a transport/http.EncodeRequestFunc that
// JSON-encodes any request to the request body. Primarily useful in a client.
func EncodeHTTPGenericRequest(_ context.Context, r *http.Request, request interface{}) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(request); err != nil {
return err
}
r.Body = ioutil.NopCloser(&buf)
return nil
}
// EncodeHTTPGenericResponse is a transport/http.EncodeResponseFunc that encodes
// the response as JSON to the response writer. Primarily useful in a server.
func EncodeHTTPGenericResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
return json.NewEncoder(w).Encode(response)
}