Codebase list golang-gopkg-httprequest.v1 / HEAD
HEAD

Tree @HEAD (Download .tar.gz)

  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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
# httprequest
--
    import "gopkg.in/httprequest.v1"

Package httprequest provides functionality for marshaling unmarshaling HTTP
request parameters into a struct type. It also provides a way to define methods
as HTTP routes using the same approach.

It requires at least Go 1.7, and Go 1.9 is required if the importing program
also uses golang.org/x/net/context.

## Usage

```go
const (
	CodeBadRequest   = "bad request"
	CodeUnauthorized = "unauthorized"
	CodeForbidden    = "forbidden"
	CodeNotFound     = "not found"
)
```
These constants are recognized by DefaultErrorMapper as mapping to the similarly
named HTTP status codes.

```go
var (
	ErrUnmarshal        = errgo.New("httprequest unmarshal error")
	ErrBadUnmarshalType = errgo.New("httprequest bad unmarshal type")
)
```

```go
var DefaultErrorMapper = defaultErrorMapper
```
DefaultErrorMapper is used by Server when ErrorMapper is nil. It maps all errors
to RemoteError instances; if an error implements the ErrorCoder interface, the
Code field will be set accordingly; some codes will map to specific HTTP status
codes (for example, if ErrorCode returns CodeBadRequest, the resulting HTTP
status will be http.StatusBadRequest).

```go
var DefaultErrorUnmarshaler = ErrorUnmarshaler(new(RemoteError))
```
DefaultErrorUnmarshaler is the default error unmarshaler used by Client.

#### func  AddHandlers

```go
func AddHandlers(r *httprouter.Router, hs []Handler)
```
AddHandlers adds all the handlers in the given slice to r.

#### func  ErrorUnmarshaler

```go
func ErrorUnmarshaler(template error) func(*http.Response) error
```
ErrorUnmarshaler returns a function which will unmarshal error responses into
new values of the same type as template. The argument must be a pointer. A new
instance of it is created every time the returned function is called.

If the error cannot by unmarshaled, the function will return an
*HTTPResponseError holding the response from the request.

#### func  Marshal

```go
func Marshal(baseURL, method string, x interface{}) (*http.Request, error)
```
Marshal is the counterpart of Unmarshal. It takes information from x, which must
be a pointer to a struct, and returns an HTTP request using the given method
that holds all of the information.

The Body field in the returned request will always be of type BytesReaderCloser.

If x implements the HeaderSetter interface, its SetHeader method will be called
to add additional headers to the HTTP request after it has been marshaled. If x
is pointer to a CustomHeader object then Marshal will use its Body member to
create the HTTP request.

The HTTP request will use the given method. Named fields in the given baseURL
will be filled out from "path"-tagged fields in x to form the URL path in the
returned request. These are specified as for httprouter.

If a field in baseURL is a suffix of the form "*var" (a trailing wildcard
element that holds the rest of the path), the marshaled string must begin with a
"/". This matches the httprouter convention that it always returns such fields
with a "/" prefix.

If a field is of type string or []string, the value of the field will be used
directly; otherwise if implements encoding.TextMarshaler, that will be used to
marshal the field, otherwise fmt.Sprint will be used.

An "omitempty" attribute on a form or header field specifies that if the form or
header value is zero, the form or header entry will be omitted. If the field is
a nil pointer, it will be omitted; otherwise if the field type implements
IsZeroer, that method will be used to determine whether the value is zero,
otherwise if the value is comparable, it will be compared with the zero value
for its type, otherwise the value will never be omitted. One notable
implementation of IsZeroer is time.Time.

An "inbody" attribute on a form field specifies that the field will be marshaled
as part of an application/x-www-form-urlencoded body. Note that the field may
still be unmarshaled from either a URL query parameter or a form-encoded body.

For example, this code:

    type UserDetails struct {
        Age int
    }

    type Test struct {
        Username string `httprequest:"user,path"`
        ContextId int64 `httprequest:"context,form"`
        Extra string `httprequest:"context,form,omitempty"`
        Details UserDetails `httprequest:",body"`
    }
    req, err := Marshal("http://example.com/users/:user/details", "GET", &Test{
        Username: "bob",
        ContextId: 1234,
        Details: UserDetails{
            Age: 36,
        }
    })
    if err != nil {
        ...
    }

will produce an HTTP request req with a URL of
http://example.com/users/bob/details?context=1234 and a JSON-encoded body
holding `{"Age":36}`.

It is an error if there is a field specified in the URL that is not found in x.

#### func  ToHTTP

```go
func ToHTTP(h httprouter.Handle) http.Handler
```
ToHTTP converts an httprouter.Handle into an http.Handler. It will pass no path
variables to h.

#### func  Unmarshal

```go
func Unmarshal(p Params, x interface{}) error
```
Unmarshal takes values from given parameters and fills out fields in x, which
must be a pointer to a struct.

Tags on the struct's fields determine where each field is filled in from.
Similar to encoding/json and other encoding packages, the tag holds a
comma-separated list. The first item in the list is an alternative name for the
field (the field name itself will be used if this is empty). The next item
specifies where the field is filled in from. It may be:

    "path" - the field is taken from a parameter in p.PathVar
    	with a matching field name.

    "form" - the field is taken from the given name in p.Request.Form
    	(note that this covers both URL query parameters and
    	POST form parameters).

    "header" - the field is taken from the given name in
    	p.Request.Header.

    "body" - the field is filled in by parsing the request body
    	as JSON.

For path and form parameters, the field will be filled out from the field in
p.PathVar or p.Form using one of the following methods (in descending order of
preference):

- if the type is string, it will be set from the first value.

- if the type is []string, it will be filled out using all values for that field

    (allowed only for form)

- if the type implements encoding.TextUnmarshaler, its UnmarshalText method will
be used

- otherwise fmt.Sscan will be used to set the value.

When the unmarshaling fails, Unmarshal returns an error with an ErrUnmarshal
cause. If the type of x is inappropriate, it returns an error with an
ErrBadUnmarshalType cause.

#### func  UnmarshalJSONResponse

```go
func UnmarshalJSONResponse(resp *http.Response, x interface{}) error
```
UnmarshalJSONResponse unmarshals the given HTTP response into x, which should be
a pointer to the result to be unmarshaled into.

If the response cannot be unmarshaled, an error of type *DecodeResponseError
will be returned.

#### func  WriteJSON

```go
func WriteJSON(w http.ResponseWriter, code int, val interface{}) error
```
WriteJSON writes the given value to the ResponseWriter and sets the HTTP status
to the given code.

If val implements the HeaderSetter interface, the SetHeader method will be
called to add additional headers to the HTTP response. It is called after the
Content-Type header has been added, so can be used to override the content type
if required.

#### type BytesReaderCloser

```go
type BytesReaderCloser struct {
	*bytes.Reader
}
```

BytesReaderCloser is a bytes.Reader which implements io.Closer with a no-op
Close method.

#### func (BytesReaderCloser) Close

```go
func (BytesReaderCloser) Close() error
```
Close implements io.Closer.Close.

#### type Client

```go
type Client struct {
	// BaseURL holds the base URL to use when making
	// HTTP requests.
	BaseURL string

	// Doer holds a value that will be used to actually
	// make the HTTP request. If it is nil, http.DefaultClient
	// will be used instead. If Doer implements DoerWithContext,
	// DoWithContext will be used instead.
	Doer Doer

	// If a request returns an HTTP response that signifies an
	// error, UnmarshalError is used to unmarshal the response into
	// an appropriate error. See ErrorUnmarshaler for a convenient
	// way to create an UnmarshalError function for a given type. If
	// this is nil, DefaultErrorUnmarshaler will be used.
	UnmarshalError func(resp *http.Response) error
}
```

Client represents a client that can invoke httprequest endpoints.

#### func (*Client) Call

```go
func (c *Client) Call(ctx context.Context, params, resp interface{}) error
```
Call invokes the endpoint implied by the given params, which should be of the
form accepted by the ArgT argument to a function passed to Handle, and
unmarshals the response into the given response parameter, which should be a
pointer to the response value.

If params implements the HeaderSetter interface, its SetHeader method will be
called to add additional headers to the HTTP request.

If resp is nil, the response will be ignored if the request was successful.

If resp is of type **http.Response, instead of unmarshaling into it, its element
will be set to the returned HTTP response directly and the caller is responsible
for closing its Body field.

Any error that c.UnmarshalError or c.Doer returns will not have its cause
masked.

If the request returns a response with a status code signifying success, but the
response could not be unmarshaled, a *DecodeResponseError will be returned
holding the response. Note that if the request returns an error status code, the
Client.UnmarshalError function is responsible for doing this if desired (the
default error unmarshal functions do).

#### func (*Client) CallURL

```go
func (c *Client) CallURL(ctx context.Context, url string, params, resp interface{}) error
```
CallURL is like Call except that the given URL is used instead of c.BaseURL.

#### func (*Client) Do

```go
func (c *Client) Do(ctx context.Context, req *http.Request, resp interface{}) error
```
Do sends the given request and unmarshals its JSON result into resp, which
should be a pointer to the response value. If an error status is returned, the
error will be unmarshaled as in Client.Call.

If resp is nil, the response will be ignored if the response was successful.

If resp is of type **http.Response, instead of unmarshaling into it, its element
will be set to the returned HTTP response directly and the caller is responsible
for closing its Body field.

Any error that c.UnmarshalError or c.Doer returns will not have its cause
masked.

If req.URL does not have a host part it will be treated as relative to
c.BaseURL. req.URL will be updated to the actual URL used.

If the response cannot by unmarshaled, a *DecodeResponseError will be returned
holding the response from the request. the entire response body.

#### func (*Client) Get

```go
func (c *Client) Get(ctx context.Context, url string, resp interface{}) error
```
Get is a convenience method that uses c.Do to issue a GET request to the given
URL. If the given URL does not have a host part then it will be treated as
relative to c.BaseURL.

#### type CustomHeader

```go
type CustomHeader struct {
	// Body holds the JSON-marshaled body of the response.
	Body interface{}

	// SetHeaderFunc holds a function that will be called
	// to set any custom headers on the response.
	SetHeaderFunc func(http.Header)
}
```

CustomHeader is a type that allows a JSON value to set custom HTTP headers
associated with the HTTP response.

#### func (CustomHeader) MarshalJSON

```go
func (h CustomHeader) MarshalJSON() ([]byte, error)
```
MarshalJSON implements json.Marshaler by marshaling h.Body.

#### func (CustomHeader) SetHeader

```go
func (h CustomHeader) SetHeader(header http.Header)
```
SetHeader implements HeaderSetter by calling h.SetHeaderFunc.

#### type DecodeRequestError

```go
type DecodeRequestError struct {
	// Request holds the problematic HTTP request.
	// The body of this does not need to be closed
	// and may be truncated if the response is large.
	Request *http.Request

	// DecodeError holds the error that was encountered
	// when decoding.
	DecodeError error
}
```

DecodeRequestError represents an error when an HTTP request could not be
decoded.

#### func (*DecodeRequestError) Error

```go
func (e *DecodeRequestError) Error() string
```

#### type DecodeResponseError

```go
type DecodeResponseError struct {
	// Response holds the problematic HTTP response.
	// The body of this does not need to be closed
	// and may be truncated if the response is large.
	Response *http.Response

	// DecodeError holds the error that was encountered
	// when decoding.
	DecodeError error
}
```

DecodeResponseError represents an error when an HTTP response could not be
decoded.

#### func (*DecodeResponseError) Error

```go
func (e *DecodeResponseError) Error() string
```

#### type Doer

```go
type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}
```

Doer is implemented by HTTP client packages to make an HTTP request. It is
notably implemented by http.Client and httpbakery.Client.

#### type DoerWithContext

```go
type DoerWithContext interface {
	DoWithContext(ctx context.Context, req *http.Request) (*http.Response, error)
}
```

DoerWithContext is implemented by HTTP clients that can use a context with the
HTTP request.

#### type ErrorCoder

```go
type ErrorCoder interface {
	ErrorCode() string
}
```

ErrorCoder may be implemented by an error to cause it to return a particular
RemoteError code when DefaultErrorMapper is used.

#### type ErrorHandler

```go
type ErrorHandler func(Params) error
```

ErrorHandler is like httprouter.Handle except it returns an error which may be
returned as the error body of the response. An ErrorHandler function should not
itself write to the ResponseWriter if it returns an error.

#### type Handler

```go
type Handler struct {
	Method string
	Path   string
	Handle httprouter.Handle
}
```

Handler defines a HTTP handler that will handle the given HTTP method at the
given httprouter path

#### type HeaderSetter

```go
type HeaderSetter interface {
	SetHeader(http.Header)
}
```

HeaderSetter is the interface checked for by WriteJSON. If implemented on a
value passed to WriteJSON, the SetHeader method will be called to allow it to
set custom headers on the response.

#### type IsZeroer

```go
type IsZeroer interface {
	IsZero() bool
}
```

IsZeroer is used when marshaling to determine if a value is zero (see Marshal).

#### type JSONHandler

```go
type JSONHandler func(Params) (interface{}, error)
```

JSONHandler is like httprouter.Handle except that it returns a body (to be
converted to JSON) and an error. The Header parameter can be used to set custom
headers on the response.

#### type Params

```go
type Params struct {
	Response http.ResponseWriter
	Request  *http.Request
	PathVar  httprouter.Params
	// PathPattern holds the path pattern matched by httprouter.
	// It is only set where httprequest has the information;
	// that is where the call was made by Server.Handler
	// or Server.Handlers.
	PathPattern string
	// Context holds a context for the request. In Go 1.7 and later,
	// this should be used in preference to Request.Context.
	Context context.Context
}
```

Params holds the parameters provided to an HTTP request.

#### type RemoteError

```go
type RemoteError struct {
	// Message holds the error message.
	Message string

	// Code may hold a code that classifies the error.
	Code string `json:",omitempty"`

	// Info holds any other information associated with the error.
	Info *json.RawMessage `json:",omitempty"`
}
```

RemoteError holds the default type of a remote error used by Client when no
custom error unmarshaler is set. This type is also used by DefaultErrorMapper to
marshal errors in Server.

#### func  Errorf

```go
func Errorf(code string, f string, a ...interface{}) *RemoteError
```
Errorf returns a new RemoteError instance that uses the given code and formats
the message with fmt.Sprintf(f, a...). If f is empty and there are no other
arguments, code will also be used for the message.

#### func (*RemoteError) Error

```go
func (e *RemoteError) Error() string
```
Error implements the error interface.

#### func (*RemoteError) ErrorCode

```go
func (e *RemoteError) ErrorCode() string
```
ErrorCode implements ErrorCoder by returning e.Code.

#### type Route

```go
type Route struct{}
```

Route is the type of a field that specifies a routing path and HTTP method. See
Marshal and Unmarshal for details.

#### type Server

```go
type Server struct {
	// ErrorMapper holds a function that can convert a Go error
	// into a form that can be returned as a JSON body from an HTTP request.
	//
	// The httpStatus value reports the desired HTTP status.
	//
	// If the returned errorBody implements HeaderSetter, then
	// that method will be called to add custom headers to the request.
	//
	// If this both this and ErrorWriter are nil, DefaultErrorMapper will be used.
	ErrorMapper func(ctxt context.Context, err error) (httpStatus int, errorBody interface{})

	// ErrorWriter is a more general form of ErrorMapper. If this
	// field is set, ErrorMapper will be ignored and any returned
	// errors will be passed to ErrorWriter, which should use
	// w to set the HTTP status and write an appropriate
	// error response.
	ErrorWriter func(ctx context.Context, w http.ResponseWriter, err error)
}
```

Server represents the server side of an HTTP servers, and can be used to create
HTTP handlers although it is not an HTTP handler itself.

#### func (*Server) Handle

```go
func (srv *Server) Handle(f interface{}) Handler
```
Handle converts a function into a Handler. The argument f must be a function of
one of the following six forms, where ArgT must be a struct type acceptable to
Unmarshal and ResultT is a type that can be marshaled as JSON:

    func(p Params, arg *ArgT)
    func(p Params, arg *ArgT) error
    func(p Params, arg *ArgT) (ResultT, error)

    func(arg *ArgT)
    func(arg *ArgT) error
    func(arg *ArgT) (ResultT, error)

When processing a call to the returned handler, the provided parameters are
unmarshaled into a new ArgT value using Unmarshal, then f is called with this
value. If the unmarshaling fails, f will not be called and the unmarshal error
will be written as a JSON response.

As an additional special case to the rules defined in Unmarshal, the tag on an
anonymous field of type Route specifies the method and path to use in the HTTP
request. It should hold two space-separated fields; the first specifies the HTTP
method, the second the URL path to use for the request. If this is given, the
returned handler will hold that method and path, otherwise they will be empty.

If an error is returned from f, it is passed through the error mapper before
writing as a JSON response.

In the third form, when no error is returned, the result is written as a JSON
response with status http.StatusOK. Also in this case, any calls to
Params.Response.Write or Params.Response.WriteHeader will be ignored, as the
response code and data should be defined entirely by the returned result and
error.

Handle will panic if the provided function is not in one of the above forms.

#### func (*Server) HandleErrors

```go
func (srv *Server) HandleErrors(handle ErrorHandler) httprouter.Handle
```
HandleErrors returns a handler that passes any non-nil error returned by handle
through the error mapper and writes it as a JSON response.

Note that the Params argument passed to handle will not have its PathPattern set
as that information is not available.

#### func (*Server) HandleJSON

```go
func (srv *Server) HandleJSON(handle JSONHandler) httprouter.Handle
```
HandleJSON returns a handler that writes the return value of handle as a JSON
response. If handle returns an error, it is passed through the error mapper.

Note that the Params argument passed to handle will not have its PathPattern set
as that information is not available.

#### func (*Server) Handlers

```go
func (srv *Server) Handlers(f interface{}) []Handler
```
Handlers returns a list of handlers that will be handled by the value returned
by the given argument, which must be a function in one of the following forms:

    func(p httprequest.Params) (T, context.Context, error)
    func(p httprequest.Params, handlerArg I) (T, context.Context, error)

for some type T and some interface type I. Each exported method defined on T
defines a handler, and should be in one of the forms accepted by Server.Handle
with the additional constraint that the argument to each of the handlers must be
compatible with the type I when the second form is used above.

The returned context will be used as the value of Params.Context when Params is
passed to any method. It will also be used when writing an error if the function
returns an error.

Handlers will panic if f is not of the required form, no methods are defined on
T or any method defined on T is not suitable for Handle.

When any of the returned handlers is invoked, f will be called and then the
appropriate method will be called on the value it returns. If specified, the
handlerArg parameter to f will hold the ArgT argument that will be passed to the
handler method.

If T implements io.Closer, its Close method will be called after the request is
completed.

#### func (*Server) WriteError

```go
func (srv *Server) WriteError(ctx context.Context, w http.ResponseWriter, err error)
```
WriteError writes an error to a ResponseWriter and sets the HTTP status code,
using srv.ErrorMapper to determine the actually written response.

It uses WriteJSON to write the error body returned from the ErrorMapper so it is
possible to add custom headers to the HTTP error response by implementing
HeaderSetter.