github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/api/util/responses.go (about)

     1  package util
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  )
     7  
     8  // Response is the JSON API response object wrapper
     9  type Response struct {
    10  	Data     interface{}  `json:"data,omitempty"`
    11  	Meta     *Meta        `json:"meta,omitempty"`
    12  	NextPage *NextPageReq `json:"nextPage,omitempty"`
    13  	// TODO(dustmop): Cloud depends upon this. Remove once more
    14  	// methods have started using Cursor/NextPage and cloud is
    15  	// able to switch over.
    16  	Pagination *Page `json:"pagination,omitempty"`
    17  }
    18  
    19  // Meta is the JSON API response meta object wrapper
    20  type Meta struct {
    21  	Code    int    `json:"code,omitempty"`
    22  	Message string `json:"message,omitempty"`
    23  	Error   string `json:"error,omitempty"`
    24  }
    25  
    26  // NextPageReq is the request to get the next page of results
    27  type NextPageReq struct {
    28  	URL    string            `json:"url"`
    29  	Params map[string]string `json:"params"`
    30  }
    31  
    32  // WriteResponse wraps response data in an envelope & writes it
    33  func WriteResponse(w http.ResponseWriter, data interface{}) error {
    34  	env := Response{
    35  		Meta: &Meta{
    36  			Code: http.StatusOK,
    37  		},
    38  		Data: data,
    39  	}
    40  	return jsonResponse(w, env)
    41  }
    42  
    43  // WritePageResponse wraps response data and pagination information in an
    44  // envelope and writes it
    45  // TODO(dustmop): Cloud depends upon this
    46  func WritePageResponse(w http.ResponseWriter, data interface{}, r *http.Request, p Page) error {
    47  	if p.PrevPageExists() {
    48  		p.PrevURL = p.Prev().SetQueryParams(r.URL).String()
    49  	}
    50  	if p.NextPageExists() {
    51  		p.NextURL = p.Next().SetQueryParams(r.URL).String()
    52  	}
    53  	env := Response{
    54  		Meta: &Meta{
    55  			Code: http.StatusOK,
    56  		},
    57  		Data:       data,
    58  		Pagination: &p,
    59  	}
    60  	return jsonResponse(w, env)
    61  }
    62  
    63  // WriteResponseWithNextPage writes the http response and includes
    64  // the body data usable to get the next page of results
    65  func WriteResponseWithNextPage(w http.ResponseWriter, data interface{}, nextURL string, nextParams map[string]string) error {
    66  	env := Response{
    67  		Meta: &Meta{
    68  			Code: http.StatusOK,
    69  		},
    70  		NextPage: &NextPageReq{
    71  			URL:    nextURL,
    72  			Params: nextParams,
    73  		},
    74  		Data: data,
    75  	}
    76  	return jsonResponse(w, env)
    77  }
    78  
    79  // WriteMessageResponse includes a message with a data response
    80  func WriteMessageResponse(w http.ResponseWriter, message string, data interface{}) error {
    81  	env := Response{
    82  		Meta: &Meta{
    83  			Code:    http.StatusOK,
    84  			Message: message,
    85  		},
    86  		Data: data,
    87  	}
    88  
    89  	return jsonResponse(w, env)
    90  }
    91  
    92  // WriteErrResponse writes a JSON error response message & HTTP status
    93  func WriteErrResponse(w http.ResponseWriter, code int, err error) error {
    94  	env := Response{
    95  		Meta: &Meta{
    96  			Code:  code,
    97  			Error: err.Error(),
    98  		},
    99  	}
   100  
   101  	res, err := json.MarshalIndent(env, "", "  ")
   102  	if err != nil {
   103  		http.Error(w, err.Error(), http.StatusInternalServerError)
   104  		return err
   105  	}
   106  
   107  	w.WriteHeader(code)
   108  	_, err = w.Write(res)
   109  	return err
   110  }
   111  
   112  func jsonResponse(w http.ResponseWriter, env interface{}) error {
   113  	res, err := json.Marshal(env)
   114  	if err != nil {
   115  		http.Error(w, err.Error(), http.StatusInternalServerError)
   116  		return err
   117  	}
   118  
   119  	w.Header().Set("Content-Type", "application/json")
   120  	w.WriteHeader(http.StatusOK)
   121  	_, err = w.Write(res)
   122  	return err
   123  }