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 }