OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / tmlibs / common / http.go
1 package common
2
3 import (
4         "encoding/json"
5         "io"
6         "net/http"
7
8         "gopkg.in/go-playground/validator.v9"
9
10         "github.com/pkg/errors"
11 )
12
13 type ErrorResponse struct {
14         Success bool `json:"success,omitempty"`
15
16         // Err is the error message if Success is false
17         Err string `json:"error,omitempty"`
18
19         // Code is set if Success is false
20         Code int `json:"code,omitempty"`
21 }
22
23 // ErrorWithCode makes an ErrorResponse with the
24 // provided err's Error() content, and status code.
25 // It panics if err is nil.
26 func ErrorWithCode(err error, code int) *ErrorResponse {
27         return &ErrorResponse{
28                 Err:  err.Error(),
29                 Code: code,
30         }
31 }
32
33 // Ensure that ErrorResponse implements error
34 var _ error = (*ErrorResponse)(nil)
35
36 func (er *ErrorResponse) Error() string {
37         return er.Err
38 }
39
40 // Ensure that ErrorResponse implements httpCoder
41 var _ httpCoder = (*ErrorResponse)(nil)
42
43 func (er *ErrorResponse) HTTPCode() int {
44         return er.Code
45 }
46
47 var errNilBody = errors.Errorf("expecting a non-nil body")
48
49 // FparseJSON unmarshals into save, the body of the provided reader.
50 // Since it uses json.Unmarshal, save must be of a pointer type
51 // or compatible with json.Unmarshal.
52 func FparseJSON(r io.Reader, save interface{}) error {
53         if r == nil {
54                 return errors.Wrap(errNilBody, "Reader")
55         }
56
57         dec := json.NewDecoder(r)
58         if err := dec.Decode(save); err != nil {
59                 return errors.Wrap(err, "Decode/Unmarshal")
60         }
61         return nil
62 }
63
64 // ParseRequestJSON unmarshals into save, the body of the
65 // request. It closes the body of the request after parsing.
66 // Since it uses json.Unmarshal, save must be of a pointer type
67 // or compatible with json.Unmarshal.
68 func ParseRequestJSON(r *http.Request, save interface{}) error {
69         if r == nil || r.Body == nil {
70                 return errNilBody
71         }
72         defer r.Body.Close()
73
74         return FparseJSON(r.Body, save)
75 }
76
77 // ParseRequestAndValidateJSON unmarshals into save, the body of the
78 // request and invokes a validator on the saved content. To ensure
79 // validation, make sure to set tags "validate" on your struct as
80 // per https://godoc.org/gopkg.in/go-playground/validator.v9.
81 // It closes the body of the request after parsing.
82 // Since it uses json.Unmarshal, save must be of a pointer type
83 // or compatible with json.Unmarshal.
84 func ParseRequestAndValidateJSON(r *http.Request, save interface{}) error {
85         if r == nil || r.Body == nil {
86                 return errNilBody
87         }
88         defer r.Body.Close()
89
90         return FparseAndValidateJSON(r.Body, save)
91 }
92
93 // FparseAndValidateJSON like FparseJSON unmarshals into save,
94 // the body of the provided reader. However, it invokes the validator
95 // to check the set validators on your struct fields as per
96 // per https://godoc.org/gopkg.in/go-playground/validator.v9.
97 // Since it uses json.Unmarshal, save must be of a pointer type
98 // or compatible with json.Unmarshal.
99 func FparseAndValidateJSON(r io.Reader, save interface{}) error {
100         if err := FparseJSON(r, save); err != nil {
101                 return err
102         }
103         return validate(save)
104 }
105
106 var theValidator = validator.New()
107
108 func validate(obj interface{}) error {
109         return errors.Wrap(theValidator.Struct(obj), "Validate")
110 }
111
112 // WriteSuccess JSON marshals the content provided, to an HTTP
113 // response, setting the provided status code and setting header
114 // "Content-Type" to "application/json".
115 func WriteSuccess(w http.ResponseWriter, data interface{}) {
116         WriteCode(w, data, 200)
117 }
118
119 // WriteCode JSON marshals content, to an HTTP response,
120 // setting the provided status code, and setting header
121 // "Content-Type" to "application/json". If JSON marshalling fails
122 // with an error, WriteCode instead writes out the error invoking
123 // WriteError.
124 func WriteCode(w http.ResponseWriter, out interface{}, code int) {
125         blob, err := json.MarshalIndent(out, "", "  ")
126         if err != nil {
127                 WriteError(w, err)
128         } else {
129                 w.Header().Set("Content-Type", "application/json")
130                 w.WriteHeader(code)
131                 w.Write(blob)
132         }
133 }
134
135 type httpCoder interface {
136         HTTPCode() int
137 }
138
139 // WriteError is a convenience function to write out an
140 // error to an http.ResponseWriter, to send out an error
141 // that's structured as JSON i.e the form
142 //    {"error": sss, "code": ddd}
143 // If err implements the interface HTTPCode() int,
144 // it will use that status code otherwise, it will
145 // set code to be http.StatusBadRequest
146 func WriteError(w http.ResponseWriter, err error) {
147         code := http.StatusBadRequest
148         if httpC, ok := err.(httpCoder); ok {
149                 code = httpC.HTTPCode()
150         }
151
152         WriteCode(w, ErrorWithCode(err, code), code)
153 }