github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/net/http/httpjson/io.go (about) 1 package httpjson 2 3 import ( 4 "context" 5 "encoding/json" 6 "io" 7 "net/http" 8 "reflect" 9 10 "github.com/bytom/bytom/errors" 11 log "github.com/sirupsen/logrus" 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 }