response.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package http
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "google.golang.org/genproto/googleapis/rpc/errdetails"
  6. "google.golang.org/grpc/status"
  7. "io"
  8. "net/http"
  9. "strings"
  10. )
  11. type Response struct {
  12. Code int `json:"code"`
  13. Reason string `json:"reason"`
  14. Message string `json:"message"`
  15. Metadata interface{} `json:"metadata"`
  16. w http.ResponseWriter
  17. ct string
  18. }
  19. func NewResponse(w http.ResponseWriter) *Response {
  20. return &Response{
  21. w: w,
  22. }
  23. }
  24. func (r *Response) StatusCode(code int) *Response {
  25. r.Code = code
  26. return r
  27. }
  28. func (r *Response) ContentType(ct string) *Response {
  29. r.ct = ct
  30. return r
  31. }
  32. func (r *Response) getCode(defaultCode int) int {
  33. if r.Code != 0 {
  34. return r.Code
  35. }
  36. return defaultCode
  37. }
  38. func (r *Response) getContentType(defaultContentType string) string {
  39. if r.ct != "" {
  40. return r.ct
  41. }
  42. return defaultContentType
  43. }
  44. func (r *Response) Error(err error) {
  45. r.buildResponseBody(err)
  46. r.w.Header().Set("Content-Type", r.getContentType("application/json"))
  47. r.w.WriteHeader(r.getCode(http.StatusInternalServerError))
  48. body, err := json.Marshal(r)
  49. if err != nil {
  50. r.w.Write([]byte(err.Error()))
  51. return
  52. }
  53. r.w.Write(body)
  54. }
  55. func (r *Response) Json(body []byte) {
  56. r.w.Header().Set("Content-Type", r.getContentType("application/json"))
  57. r.w.WriteHeader(r.getCode(http.StatusOK))
  58. r.w.Write(body)
  59. }
  60. func (r *Response) Raw(rc io.Reader) {
  61. r.w.Header().Set("Content-Type", r.getContentType("application/octet-stream"))
  62. r.w.WriteHeader(r.getCode(http.StatusOK))
  63. io.Copy(r.w, rc)
  64. }
  65. func (r *Response) Redirect(url string) {
  66. r.w.Header().Set("Location", url)
  67. r.w.WriteHeader(r.getCode(http.StatusOK))
  68. r.w.Write([]byte(""))
  69. }
  70. func (r *Response) JsonOk(ok bool) {
  71. j, _ := json.Marshal(map[string]bool{
  72. "ok": ok,
  73. })
  74. r.Json(j)
  75. }
  76. func (r *Response) Abort() {
  77. r.ContentType("text/plain").Raw(strings.NewReader(http.StatusText(r.getCode(http.StatusInternalServerError))))
  78. }
  79. func (r *Response) Download(body io.Reader, filename string) {
  80. r.w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
  81. r.Raw(body)
  82. }
  83. func (r *Response) buildResponseBody(err error) {
  84. s := status.Convert(err)
  85. pb := s.Proto()
  86. st := httpStatusFromGrpcCode(s.Code())
  87. if len(s.Details()) > 0 {
  88. for _, detail := range s.Details() {
  89. switch d := detail.(type) {
  90. case *errdetails.ErrorInfo:
  91. r.Reason = d.Reason
  92. r.Metadata = d.Metadata
  93. break
  94. }
  95. }
  96. } else {
  97. r.Reason = "UNKNOWN_ERROR"
  98. }
  99. r.Message = pb.GetMessage()
  100. r.Code = st
  101. }