56 lines
1.6 KiB
Go
56 lines
1.6 KiB
Go
package httpapi
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"net/http"
|
||
|
|
)
|
||
|
|
|
||
|
|
type responseEnvelope struct {
|
||
|
|
RequestID string `json:"request_id"`
|
||
|
|
Data any `json:"data,omitempty"`
|
||
|
|
Error *Error `json:"error,omitempty"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type Error struct {
|
||
|
|
Code string `json:"code"`
|
||
|
|
Message string `json:"message"`
|
||
|
|
Retryable bool `json:"retryable"`
|
||
|
|
FieldErrors []FieldError `json:"field_errors"`
|
||
|
|
Details map[string]any `json:"details"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type FieldError struct {
|
||
|
|
Field string `json:"field"`
|
||
|
|
Message string `json:"message"`
|
||
|
|
}
|
||
|
|
|
||
|
|
func WriteJSON(writer http.ResponseWriter, request *http.Request, status int, data any) {
|
||
|
|
write(writer, status, responseEnvelope{RequestID: RequestID(request.Context()), Data: data})
|
||
|
|
}
|
||
|
|
|
||
|
|
func WriteError(writer http.ResponseWriter, request *http.Request, status int, code, message string) {
|
||
|
|
WriteAPIError(writer, request, status, Error{
|
||
|
|
Code: code, Message: message, Retryable: false,
|
||
|
|
FieldErrors: []FieldError{}, Details: map[string]any{},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func WriteAPIError(writer http.ResponseWriter, request *http.Request, status int, apiError Error) {
|
||
|
|
if apiError.FieldErrors == nil {
|
||
|
|
apiError.FieldErrors = []FieldError{}
|
||
|
|
}
|
||
|
|
if apiError.Details == nil {
|
||
|
|
apiError.Details = map[string]any{}
|
||
|
|
}
|
||
|
|
write(writer, status, responseEnvelope{
|
||
|
|
RequestID: RequestID(request.Context()),
|
||
|
|
Error: &apiError,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func write(writer http.ResponseWriter, status int, body responseEnvelope) {
|
||
|
|
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
|
|
writer.WriteHeader(status)
|
||
|
|
_ = json.NewEncoder(writer).Encode(body)
|
||
|
|
}
|