github.com/grafviktor/keep-my-secret@v0.9.10-0.20230908165355-19f35cce90e5/internal/api/utils/http.go (about) 1 package utils 2 3 import ( 4 "encoding/json" 5 "errors" 6 "io" 7 "net/http" 8 ) 9 10 // JSONResponse is a convenience structure to marshal generic JSON responses and requests 11 type JSONResponse struct { 12 Error bool `json:"error"` 13 Message string `json:"message"` 14 Data interface{} `json:"data,omitempty"` 15 } 16 17 // WriteJSON writes a JSON response to the client 18 // w - http.ResponseWriter 19 // status - http status code 20 // data - data to be marshaled into JSON 21 // headers - optional headers to be written to the response 22 func WriteJSON(w http.ResponseWriter, status int, data interface{}, headers ...http.Header) error { 23 out, err := json.Marshal(data) 24 if err != nil { 25 return err 26 } 27 28 if len(headers) > 0 { 29 for key, value := range headers[0] { 30 w.Header()[key] = value 31 } 32 } 33 34 w.Header().Set("Content-Type", "application/json") 35 w.WriteHeader(status) 36 _, err = w.Write(out) 37 if err != nil { 38 return err 39 } 40 41 return nil 42 } 43 44 // ReadJSON writes a response to the client 45 // w - http.ResponseWriter 46 // r - http.Request 47 // data - data to be marshaled into JSON 48 func ReadJSON(w http.ResponseWriter, r *http.Request, data interface{}) error { 49 maxBytes := 1024 * 1024 // one megabyte 50 r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes)) 51 52 dec := json.NewDecoder(r.Body) 53 dec.DisallowUnknownFields() 54 55 err := dec.Decode(data) 56 if err != nil { 57 return err 58 } 59 60 err = dec.Decode(&struct{}{}) 61 if !errors.Is(err, io.EOF) { 62 return errors.New("body must only contain a single JSON value") 63 } 64 65 return nil 66 }