-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
response.go
84 lines (74 loc) · 3.08 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package httpsuite
import (
"bytes"
"encoding/json"
"log"
"net/http"
)
// Response represents the structure of an HTTP response, including a status code, message, and optional body.
// T represents the type of the `Data` field, allowing this structure to be used flexibly across different endpoints.
type Response[T any] struct {
Data T `json:"data,omitempty"`
Errors []Error `json:"errors,omitempty"`
Meta *Meta `json:"meta,omitempty"`
}
// Error represents an error in the aPI response, with a structured format to describe issues in a consistent manner.
type Error struct {
// Code unique error code or HTTP status code for categorizing the error
Code int `json:"code"`
// Message user-friendly message describing the error.
Message string `json:"message"`
// Details additional details about the error, often used for validation errors.
Details interface{} `json:"details,omitempty"`
}
// Meta provides additional information about the response, such as pagination details.
// This is particularly useful for endpoints returning lists of data.
type Meta struct {
// Page the current page number
Page int `json:"page,omitempty"`
// PageSize the number of items per page
PageSize int `json:"page_size,omitempty"`
// TotalPages the total number of pages available.
TotalPages int `json:"total_pages,omitempty"`
// TotalItems the total number of items across all pages.
TotalItems int `json:"total_items,omitempty"`
}
// SendResponse sends a JSON response to the client, using a unified structure for both success and error responses.
// T represents the type of the `data` payload. This function automatically adapts the response structure
// based on whether `data` or `errors` is provided, promoting a consistent API format.
//
// Parameters:
// - w: The http.ResponseWriter to send the response.
// - code: HTTP status code to indicate success or failure.
// - data: The main payload of the response. Use `nil` for error responses.
// - errs: A slice of Error structs to describe issues. Use `nil` for successful responses.
// - meta: Optional metadata, such as pagination information. Use `nil` if not needed.
func SendResponse[T any](w http.ResponseWriter, code int, data T, errs []Error, meta *Meta) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
response := &Response[T]{
Data: data,
Errors: errs,
Meta: meta,
}
// Attempt to encode the response as JSON
var buffer bytes.Buffer
if err := json.NewEncoder(&buffer).Encode(response); err != nil {
log.Printf("Error writing response: %v", err)
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(&Response[T]{
Errors: []Error{{
Code: http.StatusInternalServerError,
Message: "Internal Server Error",
Details: err.Error(),
}},
})
return
}
// Set the status code after success encoding
w.WriteHeader(code)
// Write the encoded response to the ResponseWriter
if _, err := w.Write(buffer.Bytes()); err != nil {
// Note: Cannot change status code here as headers are already sent
log.Printf("Failed to write response body (status=%d): %v", code, err)
}
}