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  }