OSDN Git Service

94c3f14cd57b46d6ab13a311af4b866ad7d97712
[bytom/vapor.git] / net / http / httpjson / io.go
1 package httpjson
2
3 import (
4         "context"
5         "encoding/json"
6         "io"
7         "net/http"
8         "reflect"
9
10         log "github.com/sirupsen/logrus"
11         "github.com/bytom/vapor/errors"
12 )
13
14 const logModule = "httpjson"
15
16 // ErrBadRequest indicates the user supplied malformed JSON input,
17 // possibly including a datatype that doesn't match what we expected.
18 var ErrBadRequest = errors.New("httpjson: bad request")
19
20 // Read decodes a single JSON text from r into v.
21 // The only error it returns is ErrBadRequest
22 // (wrapped with the original error message as context).
23 func Read(r io.Reader, v interface{}) error {
24         dec := json.NewDecoder(r)
25         dec.UseNumber()
26         err := dec.Decode(v)
27         if err != nil {
28                 detail := errors.Detail(err)
29                 if detail == "" || detail == err.Error() {
30                         detail = "check request parameters for missing and/or incorrect values"
31                 }
32                 return errors.WithDetail(ErrBadRequest, err.Error()+": "+detail)
33         }
34         return err
35 }
36
37 // Write sets the Content-Type header field to indicate
38 // JSON data, writes the header using status,
39 // then writes v to w.
40 // It logs any error encountered during the write.
41 func Write(ctx context.Context, w http.ResponseWriter, status int, v interface{}) {
42         w.Header().Set("Content-Type", "application/json; charset=utf-8")
43         w.WriteHeader(status)
44
45         err := json.NewEncoder(w).Encode(Array(v))
46         if err != nil {
47                 log.WithFields(log.Fields{"module": logModule, "error": err}).Error("Error encountered during writing the Content-Type header using status")
48         }
49 }
50
51 // Array returns an empty JSON array if v is a nil slice,
52 // so that it renders as "[]" rather than "null".
53 // Otherwise, it returns v.
54 func Array(v interface{}) interface{} {
55         if rv := reflect.ValueOf(v); rv.Kind() == reflect.Slice && rv.IsNil() {
56                 v = []struct{}{}
57         }
58         return v
59 }