Renames
Peter Bourgon
8 years ago
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 | 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 | } |