Codebase list golang-github-go-kit-kit / 4e56ac2
Renames Peter Bourgon 8 years ago
4 changed file(s) with 474 addition(s) and 474 deletion(s). Raw diff Collapse all Expand all
+0
-212
examples/profilesvc/endpoint.go less more
0 package main
1
2 import (
3 "github.com/go-kit/kit/endpoint"
4 "golang.org/x/net/context"
5 )
6
7 type endpoints struct {
8 postProfileEndpoint endpoint.Endpoint
9 getProfileEndpoint endpoint.Endpoint
10 putProfileEndpoint endpoint.Endpoint
11 patchProfileEndpoint endpoint.Endpoint
12 deleteProfileEndpoint endpoint.Endpoint
13 getAddressesEndpoint endpoint.Endpoint
14 getAddressEndpoint endpoint.Endpoint
15 postAddressEndpoint endpoint.Endpoint
16 deleteAddressEndpoint endpoint.Endpoint
17 }
18
19 func makeEndpoints(s ProfileService) endpoints {
20 return endpoints{
21 postProfileEndpoint: makePostProfileEndpoint(s),
22 getProfileEndpoint: makeGetProfileEndpoint(s),
23 putProfileEndpoint: makePutProfileEndpoint(s),
24 patchProfileEndpoint: makePatchProfileEndpoint(s),
25 deleteProfileEndpoint: makeDeleteProfileEndpoint(s),
26 getAddressesEndpoint: makeGetAddressesEndpoint(s),
27 getAddressEndpoint: makeGetAddressEndpoint(s),
28 postAddressEndpoint: makePostAddressEndpoint(s),
29 deleteAddressEndpoint: makeDeleteAddressEndpoint(s),
30 }
31 }
32
33 type postProfileRequest struct {
34 Profile Profile
35 }
36
37 type postProfileResponse struct {
38 Err error `json:"err,omitempty"`
39 }
40
41 func (r postProfileResponse) error() error { return r.Err }
42
43 // Regarding errors returned from service methods, we have two options. We can
44 // return the error via the endpoint itself. That makes certain things a
45 // little bit easier, like providing non-200 HTTP responses to the client. But
46 // Go kit assumes that endpoint errors are (or may be treated as) transport-
47 // level errors. For example, an endpoint error will count against a circuit
48 // breaker error count. Therefore, it's almost certainly better to return
49 // service method (business logic) errors in the response object. This means
50 // we have to do a bit more work in the HTTP response encoder to detect e.g. a
51 // not-found error and provide a proper HTTP status code.
52
53 func makePostProfileEndpoint(s ProfileService) endpoint.Endpoint {
54 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
55 req := request.(postProfileRequest)
56 e := s.PostProfile(ctx, req.Profile)
57 return postProfileResponse{Err: e}, nil
58 }
59 }
60
61 type getProfileRequest struct {
62 ID string
63 }
64
65 type getProfileResponse struct {
66 Profile Profile `json:"profile,omitempty"`
67 Err error `json:"err,omitempty"`
68 }
69
70 func (r getProfileResponse) error() error { return r.Err }
71
72 func makeGetProfileEndpoint(s ProfileService) endpoint.Endpoint {
73 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
74 req := request.(getProfileRequest)
75 p, e := s.GetProfile(ctx, req.ID)
76 return getProfileResponse{Profile: p, Err: e}, nil
77 }
78 }
79
80 type putProfileRequest struct {
81 ID string
82 Profile Profile
83 }
84
85 type putProfileResponse struct {
86 Err error `json:"err,omitempty"`
87 }
88
89 func (r putProfileResponse) error() error { return nil }
90
91 func makePutProfileEndpoint(s ProfileService) endpoint.Endpoint {
92 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
93 req := request.(putProfileRequest)
94 e := s.PutProfile(ctx, req.ID, req.Profile)
95 return putProfileResponse{Err: e}, nil
96 }
97 }
98
99 type patchProfileRequest struct {
100 ID string
101 Profile Profile
102 }
103
104 type patchProfileResponse struct {
105 Err error `json:"err,omitempty"`
106 }
107
108 func (r patchProfileResponse) error() error { return r.Err }
109
110 func makePatchProfileEndpoint(s ProfileService) endpoint.Endpoint {
111 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
112 req := request.(patchProfileRequest)
113 e := s.PatchProfile(ctx, req.ID, req.Profile)
114 return patchProfileResponse{Err: e}, nil
115 }
116 }
117
118 type deleteProfileRequest struct {
119 ID string
120 }
121
122 type deleteProfileResponse struct {
123 Err error `json:"err,omitempty"`
124 }
125
126 func (r deleteProfileResponse) error() error { return r.Err }
127
128 func makeDeleteProfileEndpoint(s ProfileService) endpoint.Endpoint {
129 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
130 req := request.(deleteProfileRequest)
131 e := s.DeleteProfile(ctx, req.ID)
132 return deleteProfileResponse{Err: e}, nil
133 }
134 }
135
136 type getAddressesRequest struct {
137 ProfileID string
138 }
139
140 type getAddressesResponse struct {
141 Addresses []Address `json:"addresses,omitempty"`
142 Err error `json:"err,omitempty"`
143 }
144
145 func (r getAddressesResponse) error() error { return r.Err }
146
147 func makeGetAddressesEndpoint(s ProfileService) endpoint.Endpoint {
148 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
149 req := request.(getAddressesRequest)
150 a, e := s.GetAddresses(ctx, req.ProfileID)
151 return getAddressesResponse{Addresses: a, Err: e}, nil
152 }
153 }
154
155 type getAddressRequest struct {
156 ProfileID string
157 AddressID string
158 }
159
160 type getAddressResponse struct {
161 Address Address `json:"address,omitempty"`
162 Err error `json:"err,omitempty"`
163 }
164
165 func (r getAddressResponse) error() error { return r.Err }
166
167 func makeGetAddressEndpoint(s ProfileService) endpoint.Endpoint {
168 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
169 req := request.(getAddressRequest)
170 a, e := s.GetAddress(ctx, req.ProfileID, req.AddressID)
171 return getAddressResponse{Address: a, Err: e}, nil
172 }
173 }
174
175 type postAddressRequest struct {
176 ProfileID string
177 Address Address
178 }
179
180 type postAddressResponse struct {
181 Err error `json:"err,omitempty"`
182 }
183
184 func (r postAddressResponse) error() error { return r.Err }
185
186 func makePostAddressEndpoint(s ProfileService) endpoint.Endpoint {
187 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
188 req := request.(postAddressRequest)
189 e := s.PostAddress(ctx, req.ProfileID, req.Address)
190 return postAddressResponse{Err: e}, nil
191 }
192 }
193
194 type deleteAddressRequest struct {
195 ProfileID string
196 AddressID string
197 }
198
199 type deleteAddressResponse struct {
200 Err error `json:"err,omitempty"`
201 }
202
203 func (r deleteAddressResponse) error() error { return r.Err }
204
205 func makeDeleteAddressEndpoint(s ProfileService) endpoint.Endpoint {
206 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
207 req := request.(deleteAddressRequest)
208 e := s.DeleteAddress(ctx, req.ProfileID, req.AddressID)
209 return deleteAddressResponse{Err: e}, nil
210 }
211 }
0 package main
1
2 import (
3 "github.com/go-kit/kit/endpoint"
4 "golang.org/x/net/context"
5 )
6
7 type endpoints struct {
8 postProfileEndpoint endpoint.Endpoint
9 getProfileEndpoint endpoint.Endpoint
10 putProfileEndpoint endpoint.Endpoint
11 patchProfileEndpoint endpoint.Endpoint
12 deleteProfileEndpoint endpoint.Endpoint
13 getAddressesEndpoint endpoint.Endpoint
14 getAddressEndpoint endpoint.Endpoint
15 postAddressEndpoint endpoint.Endpoint
16 deleteAddressEndpoint endpoint.Endpoint
17 }
18
19 func makeEndpoints(s ProfileService) endpoints {
20 return endpoints{
21 postProfileEndpoint: makePostProfileEndpoint(s),
22 getProfileEndpoint: makeGetProfileEndpoint(s),
23 putProfileEndpoint: makePutProfileEndpoint(s),
24 patchProfileEndpoint: makePatchProfileEndpoint(s),
25 deleteProfileEndpoint: makeDeleteProfileEndpoint(s),
26 getAddressesEndpoint: makeGetAddressesEndpoint(s),
27 getAddressEndpoint: makeGetAddressEndpoint(s),
28 postAddressEndpoint: makePostAddressEndpoint(s),
29 deleteAddressEndpoint: makeDeleteAddressEndpoint(s),
30 }
31 }
32
33 type postProfileRequest struct {
34 Profile Profile
35 }
36
37 type postProfileResponse struct {
38 Err error `json:"err,omitempty"`
39 }
40
41 func (r postProfileResponse) error() error { return r.Err }
42
43 // Regarding errors returned from service methods, we have two options. We can
44 // return the error via the endpoint itself. That makes certain things a
45 // little bit easier, like providing non-200 HTTP responses to the client. But
46 // Go kit assumes that endpoint errors are (or may be treated as) transport-
47 // level errors. For example, an endpoint error will count against a circuit
48 // breaker error count. Therefore, it's almost certainly better to return
49 // service method (business logic) errors in the response object. This means
50 // we have to do a bit more work in the HTTP response encoder to detect e.g. a
51 // not-found error and provide a proper HTTP status code.
52
53 func makePostProfileEndpoint(s ProfileService) endpoint.Endpoint {
54 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
55 req := request.(postProfileRequest)
56 e := s.PostProfile(ctx, req.Profile)
57 return postProfileResponse{Err: e}, nil
58 }
59 }
60
61 type getProfileRequest struct {
62 ID string
63 }
64
65 type getProfileResponse struct {
66 Profile Profile `json:"profile,omitempty"`
67 Err error `json:"err,omitempty"`
68 }
69
70 func (r getProfileResponse) error() error { return r.Err }
71
72 func makeGetProfileEndpoint(s ProfileService) endpoint.Endpoint {
73 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
74 req := request.(getProfileRequest)
75 p, e := s.GetProfile(ctx, req.ID)
76 return getProfileResponse{Profile: p, Err: e}, nil
77 }
78 }
79
80 type putProfileRequest struct {
81 ID string
82 Profile Profile
83 }
84
85 type putProfileResponse struct {
86 Err error `json:"err,omitempty"`
87 }
88
89 func (r putProfileResponse) error() error { return nil }
90
91 func makePutProfileEndpoint(s ProfileService) endpoint.Endpoint {
92 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
93 req := request.(putProfileRequest)
94 e := s.PutProfile(ctx, req.ID, req.Profile)
95 return putProfileResponse{Err: e}, nil
96 }
97 }
98
99 type patchProfileRequest struct {
100 ID string
101 Profile Profile
102 }
103
104 type patchProfileResponse struct {
105 Err error `json:"err,omitempty"`
106 }
107
108 func (r patchProfileResponse) error() error { return r.Err }
109
110 func makePatchProfileEndpoint(s ProfileService) endpoint.Endpoint {
111 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
112 req := request.(patchProfileRequest)
113 e := s.PatchProfile(ctx, req.ID, req.Profile)
114 return patchProfileResponse{Err: e}, nil
115 }
116 }
117
118 type deleteProfileRequest struct {
119 ID string
120 }
121
122 type deleteProfileResponse struct {
123 Err error `json:"err,omitempty"`
124 }
125
126 func (r deleteProfileResponse) error() error { return r.Err }
127
128 func makeDeleteProfileEndpoint(s ProfileService) endpoint.Endpoint {
129 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
130 req := request.(deleteProfileRequest)
131 e := s.DeleteProfile(ctx, req.ID)
132 return deleteProfileResponse{Err: e}, nil
133 }
134 }
135
136 type getAddressesRequest struct {
137 ProfileID string
138 }
139
140 type getAddressesResponse struct {
141 Addresses []Address `json:"addresses,omitempty"`
142 Err error `json:"err,omitempty"`
143 }
144
145 func (r getAddressesResponse) error() error { return r.Err }
146
147 func makeGetAddressesEndpoint(s ProfileService) endpoint.Endpoint {
148 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
149 req := request.(getAddressesRequest)
150 a, e := s.GetAddresses(ctx, req.ProfileID)
151 return getAddressesResponse{Addresses: a, Err: e}, nil
152 }
153 }
154
155 type getAddressRequest struct {
156 ProfileID string
157 AddressID string
158 }
159
160 type getAddressResponse struct {
161 Address Address `json:"address,omitempty"`
162 Err error `json:"err,omitempty"`
163 }
164
165 func (r getAddressResponse) error() error { return r.Err }
166
167 func makeGetAddressEndpoint(s ProfileService) endpoint.Endpoint {
168 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
169 req := request.(getAddressRequest)
170 a, e := s.GetAddress(ctx, req.ProfileID, req.AddressID)
171 return getAddressResponse{Address: a, Err: e}, nil
172 }
173 }
174
175 type postAddressRequest struct {
176 ProfileID string
177 Address Address
178 }
179
180 type postAddressResponse struct {
181 Err error `json:"err,omitempty"`
182 }
183
184 func (r postAddressResponse) error() error { return r.Err }
185
186 func makePostAddressEndpoint(s ProfileService) endpoint.Endpoint {
187 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
188 req := request.(postAddressRequest)
189 e := s.PostAddress(ctx, req.ProfileID, req.Address)
190 return postAddressResponse{Err: e}, nil
191 }
192 }
193
194 type deleteAddressRequest struct {
195 ProfileID string
196 AddressID string
197 }
198
199 type deleteAddressResponse struct {
200 Err error `json:"err,omitempty"`
201 }
202
203 func (r deleteAddressResponse) error() error { return r.Err }
204
205 func makeDeleteAddressEndpoint(s ProfileService) endpoint.Endpoint {
206 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
207 req := request.(deleteAddressRequest)
208 e := s.DeleteAddress(ctx, req.ProfileID, req.AddressID)
209 return deleteAddressResponse{Err: e}, nil
210 }
211 }
+0
-262
examples/profilesvc/http.go less more
0 package main
1
2 import (
3 "encoding/json"
4 "errors"
5 stdhttp "net/http"
6
7 "github.com/gorilla/mux"
8 "golang.org/x/net/context"
9
10 kitlog "github.com/go-kit/kit/log"
11 kithttp "github.com/go-kit/kit/transport/http"
12 )
13
14 var (
15 errBadRouting = errors.New("inconsistent mapping between route and handler (programmer error)")
16 )
17
18 func makeHandler(ctx context.Context, s ProfileService, logger kitlog.Logger) stdhttp.Handler {
19 e := makeEndpoints(s)
20 r := mux.NewRouter()
21
22 commonOptions := []kithttp.ServerOption{
23 kithttp.ServerErrorLogger(logger),
24 kithttp.ServerErrorEncoder(encodeError),
25 }
26
27 // POST /profiles adds another profile
28 // GET /profiles/:id retrieves the given profile by id
29 // PUT /profiles/:id post updated profile information about the profile
30 // PATCH /profiles/:id partial updated profile information
31 // DELETE /profiles/:id remove the given profile
32 // GET /profiles/:id/addresses retrieve addresses associated with the profile
33 // GET /profiles/:id/addresses/:addressID retrieve a particular profile address
34 // POST /profiles/:id/addresses add a new address
35 // DELETE /profiles/:id/addresses/:addressID remove an address
36
37 r.Methods("POST").Path("/profiles/").Handler(kithttp.NewServer(
38 ctx,
39 e.postProfileEndpoint,
40 decodePostProfileRequest,
41 encodeResponse,
42 commonOptions...,
43 ))
44 r.Methods("GET").Path("/profiles/{id}").Handler(kithttp.NewServer(
45 ctx,
46 e.getProfileEndpoint,
47 decodeGetProfileRequest,
48 encodeResponse,
49 commonOptions...,
50 ))
51 r.Methods("PUT").Path("/profiles/{id}").Handler(kithttp.NewServer(
52 ctx,
53 e.putProfileEndpoint,
54 decodePutProfileRequest,
55 encodeResponse,
56 commonOptions...,
57 ))
58 r.Methods("PATCH").Path("/profiles/{id}").Handler(kithttp.NewServer(
59 ctx,
60 e.patchProfileEndpoint,
61 decodePatchProfileRequest,
62 encodeResponse,
63 commonOptions...,
64 ))
65 r.Methods("DELETE").Path("/profiles/{id}").Handler(kithttp.NewServer(
66 ctx,
67 e.deleteProfileEndpoint,
68 decodeDeleteProfileRequest,
69 encodeResponse,
70 commonOptions...,
71 ))
72 r.Methods("GET").Path("/profiles/{id}/addresses/").Handler(kithttp.NewServer(
73 ctx,
74 e.getAddressesEndpoint,
75 decodeGetAddressesRequest,
76 encodeResponse,
77 commonOptions...,
78 ))
79 r.Methods("GET").Path("/profiles/{id}/addresses/{addressID}").Handler(kithttp.NewServer(
80 ctx,
81 e.getAddressEndpoint,
82 decodeGetAddressRequest,
83 encodeResponse,
84 commonOptions...,
85 ))
86 r.Methods("POST").Path("/profiles/{id}/addresses/").Handler(kithttp.NewServer(
87 ctx,
88 e.postAddressEndpoint,
89 decodePostAddressRequest,
90 encodeResponse,
91 commonOptions...,
92 ))
93 r.Methods("DELETE").Path("/profiles/{id}/addresses/{addressID}").Handler(kithttp.NewServer(
94 ctx,
95 e.deleteAddressEndpoint,
96 decodeDeleteAddressRequest,
97 encodeResponse,
98 commonOptions...,
99 ))
100 return r
101 }
102
103 func decodePostProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
104 var req postProfileRequest
105 if e := json.NewDecoder(r.Body).Decode(&req.Profile); e != nil {
106 return nil, e
107 }
108 return req, nil
109 }
110
111 func decodeGetProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
112 vars := mux.Vars(r)
113 id, ok := vars["id"]
114 if !ok {
115 return nil, errBadRouting
116 }
117 return getProfileRequest{ID: id}, nil
118 }
119
120 func decodePutProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
121 vars := mux.Vars(r)
122 id, ok := vars["id"]
123 if !ok {
124 return nil, errBadRouting
125 }
126 var profile Profile
127 if err := json.NewDecoder(r.Body).Decode(&profile); err != nil {
128 return nil, err
129 }
130 return putProfileRequest{
131 ID: id,
132 Profile: profile,
133 }, nil
134 }
135
136 func decodePatchProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
137 vars := mux.Vars(r)
138 id, ok := vars["id"]
139 if !ok {
140 return nil, errBadRouting
141 }
142 var profile Profile
143 if err := json.NewDecoder(r.Body).Decode(&profile); err != nil {
144 return nil, err
145 }
146 return patchProfileRequest{
147 ID: id,
148 Profile: profile,
149 }, nil
150 }
151
152 func decodeDeleteProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
153 vars := mux.Vars(r)
154 id, ok := vars["id"]
155 if !ok {
156 return nil, errBadRouting
157 }
158 return deleteProfileRequest{ID: id}, nil
159 }
160
161 func decodeGetAddressesRequest(r *stdhttp.Request) (request interface{}, err error) {
162 vars := mux.Vars(r)
163 id, ok := vars["id"]
164 if !ok {
165 return nil, errBadRouting
166 }
167 return getAddressesRequest{ProfileID: id}, nil
168 }
169
170 func decodeGetAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
171 vars := mux.Vars(r)
172 id, ok := vars["id"]
173 if !ok {
174 return nil, errBadRouting
175 }
176 addressID, ok := vars["addressID"]
177 if !ok {
178 return nil, errBadRouting
179 }
180 return getAddressRequest{
181 ProfileID: id,
182 AddressID: addressID,
183 }, nil
184 }
185
186 func decodePostAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
187 vars := mux.Vars(r)
188 id, ok := vars["id"]
189 if !ok {
190 return nil, errBadRouting
191 }
192 var address Address
193 if err := json.NewDecoder(r.Body).Decode(&address); err != nil {
194 return nil, err
195 }
196 return postAddressRequest{
197 ProfileID: id,
198 Address: address,
199 }, nil
200 }
201
202 func decodeDeleteAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
203 vars := mux.Vars(r)
204 id, ok := vars["id"]
205 if !ok {
206 return nil, errBadRouting
207 }
208 addressID, ok := vars["addressID"]
209 if !ok {
210 return nil, errBadRouting
211 }
212 return deleteAddressRequest{
213 ProfileID: id,
214 AddressID: addressID,
215 }, nil
216 }
217
218 // errorer is implemented by all concrete response types. It allows us to
219 // change the HTTP response code without needing to trigger an endpoint
220 // (transport-level) error. For more information, read the big comment in
221 // endpoint.go.
222 type errorer interface {
223 error() error
224 }
225
226 // encodeResponse is the common method to encode all response types to the
227 // client. I chose to do it this way because I didn't know if something more
228 // specific was necessary. It's certainly possible to specialize on a
229 // per-response (per-method) basis.
230 func encodeResponse(w stdhttp.ResponseWriter, response interface{}) error {
231 if e, ok := response.(errorer); ok && e.error() != nil {
232 // Not a Go kit transport error, but a business-logic error.
233 // Provide those as HTTP errors.
234 encodeError(w, e.error())
235 return nil
236 }
237 return json.NewEncoder(w).Encode(response)
238 }
239
240 func encodeError(w stdhttp.ResponseWriter, err error) {
241 w.WriteHeader(codeFrom(err))
242 json.NewEncoder(w).Encode(map[string]interface{}{
243 "error": err.Error(),
244 })
245 }
246
247 func codeFrom(err error) int {
248 switch err {
249 case nil:
250 return stdhttp.StatusOK
251 case errNotFound:
252 return stdhttp.StatusNotFound
253 case errAlreadyExists, errInconsistentIDs:
254 return stdhttp.StatusBadRequest
255 default:
256 if _, ok := err.(kithttp.BadRequestError); ok {
257 return stdhttp.StatusBadRequest
258 }
259 return stdhttp.StatusInternalServerError
260 }
261 }
0 package main
1
2 import (
3 "encoding/json"
4 "errors"
5 stdhttp "net/http"
6
7 "github.com/gorilla/mux"
8 "golang.org/x/net/context"
9
10 kitlog "github.com/go-kit/kit/log"
11 kithttp "github.com/go-kit/kit/transport/http"
12 )
13
14 var (
15 errBadRouting = errors.New("inconsistent mapping between route and handler (programmer error)")
16 )
17
18 func makeHandler(ctx context.Context, s ProfileService, logger kitlog.Logger) stdhttp.Handler {
19 e := makeEndpoints(s)
20 r := mux.NewRouter()
21
22 commonOptions := []kithttp.ServerOption{
23 kithttp.ServerErrorLogger(logger),
24 kithttp.ServerErrorEncoder(encodeError),
25 }
26
27 // POST /profiles adds another profile
28 // GET /profiles/:id retrieves the given profile by id
29 // PUT /profiles/:id post updated profile information about the profile
30 // PATCH /profiles/:id partial updated profile information
31 // DELETE /profiles/:id remove the given profile
32 // GET /profiles/:id/addresses retrieve addresses associated with the profile
33 // GET /profiles/:id/addresses/:addressID retrieve a particular profile address
34 // POST /profiles/:id/addresses add a new address
35 // DELETE /profiles/:id/addresses/:addressID remove an address
36
37 r.Methods("POST").Path("/profiles/").Handler(kithttp.NewServer(
38 ctx,
39 e.postProfileEndpoint,
40 decodePostProfileRequest,
41 encodeResponse,
42 commonOptions...,
43 ))
44 r.Methods("GET").Path("/profiles/{id}").Handler(kithttp.NewServer(
45 ctx,
46 e.getProfileEndpoint,
47 decodeGetProfileRequest,
48 encodeResponse,
49 commonOptions...,
50 ))
51 r.Methods("PUT").Path("/profiles/{id}").Handler(kithttp.NewServer(
52 ctx,
53 e.putProfileEndpoint,
54 decodePutProfileRequest,
55 encodeResponse,
56 commonOptions...,
57 ))
58 r.Methods("PATCH").Path("/profiles/{id}").Handler(kithttp.NewServer(
59 ctx,
60 e.patchProfileEndpoint,
61 decodePatchProfileRequest,
62 encodeResponse,
63 commonOptions...,
64 ))
65 r.Methods("DELETE").Path("/profiles/{id}").Handler(kithttp.NewServer(
66 ctx,
67 e.deleteProfileEndpoint,
68 decodeDeleteProfileRequest,
69 encodeResponse,
70 commonOptions...,
71 ))
72 r.Methods("GET").Path("/profiles/{id}/addresses/").Handler(kithttp.NewServer(
73 ctx,
74 e.getAddressesEndpoint,
75 decodeGetAddressesRequest,
76 encodeResponse,
77 commonOptions...,
78 ))
79 r.Methods("GET").Path("/profiles/{id}/addresses/{addressID}").Handler(kithttp.NewServer(
80 ctx,
81 e.getAddressEndpoint,
82 decodeGetAddressRequest,
83 encodeResponse,
84 commonOptions...,
85 ))
86 r.Methods("POST").Path("/profiles/{id}/addresses/").Handler(kithttp.NewServer(
87 ctx,
88 e.postAddressEndpoint,
89 decodePostAddressRequest,
90 encodeResponse,
91 commonOptions...,
92 ))
93 r.Methods("DELETE").Path("/profiles/{id}/addresses/{addressID}").Handler(kithttp.NewServer(
94 ctx,
95 e.deleteAddressEndpoint,
96 decodeDeleteAddressRequest,
97 encodeResponse,
98 commonOptions...,
99 ))
100 return r
101 }
102
103 func decodePostProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
104 var req postProfileRequest
105 if e := json.NewDecoder(r.Body).Decode(&req.Profile); e != nil {
106 return nil, e
107 }
108 return req, nil
109 }
110
111 func decodeGetProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
112 vars := mux.Vars(r)
113 id, ok := vars["id"]
114 if !ok {
115 return nil, errBadRouting
116 }
117 return getProfileRequest{ID: id}, nil
118 }
119
120 func decodePutProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
121 vars := mux.Vars(r)
122 id, ok := vars["id"]
123 if !ok {
124 return nil, errBadRouting
125 }
126 var profile Profile
127 if err := json.NewDecoder(r.Body).Decode(&profile); err != nil {
128 return nil, err
129 }
130 return putProfileRequest{
131 ID: id,
132 Profile: profile,
133 }, nil
134 }
135
136 func decodePatchProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
137 vars := mux.Vars(r)
138 id, ok := vars["id"]
139 if !ok {
140 return nil, errBadRouting
141 }
142 var profile Profile
143 if err := json.NewDecoder(r.Body).Decode(&profile); err != nil {
144 return nil, err
145 }
146 return patchProfileRequest{
147 ID: id,
148 Profile: profile,
149 }, nil
150 }
151
152 func decodeDeleteProfileRequest(r *stdhttp.Request) (request interface{}, err error) {
153 vars := mux.Vars(r)
154 id, ok := vars["id"]
155 if !ok {
156 return nil, errBadRouting
157 }
158 return deleteProfileRequest{ID: id}, nil
159 }
160
161 func decodeGetAddressesRequest(r *stdhttp.Request) (request interface{}, err error) {
162 vars := mux.Vars(r)
163 id, ok := vars["id"]
164 if !ok {
165 return nil, errBadRouting
166 }
167 return getAddressesRequest{ProfileID: id}, nil
168 }
169
170 func decodeGetAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
171 vars := mux.Vars(r)
172 id, ok := vars["id"]
173 if !ok {
174 return nil, errBadRouting
175 }
176 addressID, ok := vars["addressID"]
177 if !ok {
178 return nil, errBadRouting
179 }
180 return getAddressRequest{
181 ProfileID: id,
182 AddressID: addressID,
183 }, nil
184 }
185
186 func decodePostAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
187 vars := mux.Vars(r)
188 id, ok := vars["id"]
189 if !ok {
190 return nil, errBadRouting
191 }
192 var address Address
193 if err := json.NewDecoder(r.Body).Decode(&address); err != nil {
194 return nil, err
195 }
196 return postAddressRequest{
197 ProfileID: id,
198 Address: address,
199 }, nil
200 }
201
202 func decodeDeleteAddressRequest(r *stdhttp.Request) (request interface{}, err error) {
203 vars := mux.Vars(r)
204 id, ok := vars["id"]
205 if !ok {
206 return nil, errBadRouting
207 }
208 addressID, ok := vars["addressID"]
209 if !ok {
210 return nil, errBadRouting
211 }
212 return deleteAddressRequest{
213 ProfileID: id,
214 AddressID: addressID,
215 }, nil
216 }
217
218 // errorer is implemented by all concrete response types. It allows us to
219 // change the HTTP response code without needing to trigger an endpoint
220 // (transport-level) error. For more information, read the big comment in
221 // endpoint.go.
222 type errorer interface {
223 error() error
224 }
225
226 // encodeResponse is the common method to encode all response types to the
227 // client. I chose to do it this way because I didn't know if something more
228 // specific was necessary. It's certainly possible to specialize on a
229 // per-response (per-method) basis.
230 func encodeResponse(w stdhttp.ResponseWriter, response interface{}) error {
231 if e, ok := response.(errorer); ok && e.error() != nil {
232 // Not a Go kit transport error, but a business-logic error.
233 // Provide those as HTTP errors.
234 encodeError(w, e.error())
235 return nil
236 }
237 return json.NewEncoder(w).Encode(response)
238 }
239
240 func encodeError(w stdhttp.ResponseWriter, err error) {
241 w.WriteHeader(codeFrom(err))
242 json.NewEncoder(w).Encode(map[string]interface{}{
243 "error": err.Error(),
244 })
245 }
246
247 func codeFrom(err error) int {
248 switch err {
249 case nil:
250 return stdhttp.StatusOK
251 case errNotFound:
252 return stdhttp.StatusNotFound
253 case errAlreadyExists, errInconsistentIDs:
254 return stdhttp.StatusBadRequest
255 default:
256 if _, ok := err.(kithttp.BadRequestError); ok {
257 return stdhttp.StatusBadRequest
258 }
259 return stdhttp.StatusInternalServerError
260 }
261 }