File size: 1,525 Bytes
6a7089a | 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 | package web
import (
"bufio"
"context"
"encoding/json"
"fmt"
"log/slog"
"net"
"net/http"
)
func JSON(w http.ResponseWriter, code int, data any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
if err := json.NewEncoder(w).Encode(data); err != nil {
slog.Error("json encode", "err", err)
}
}
func Error(w http.ResponseWriter, code int, err error) {
ErrorCode(w, code, "error", err.Error(), false, nil)
}
func ErrorCode(w http.ResponseWriter, status int, code, message string, retryable bool, details map[string]any) {
payload := map[string]any{
"error": message,
"code": code,
}
if retryable {
payload["retryable"] = true
}
if len(details) > 0 {
payload["details"] = details
}
JSON(w, status, payload)
}
// CancelOnClientDone cancels the given cancel func when the HTTP client disconnects.
func CancelOnClientDone(reqCtx context.Context, cancel context.CancelFunc) {
<-reqCtx.Done()
cancel()
}
type StatusWriter struct {
http.ResponseWriter
Code int
}
func (w *StatusWriter) Unwrap() http.ResponseWriter {
return w.ResponseWriter
}
func (w *StatusWriter) WriteHeader(code int) {
w.Code = code
w.ResponseWriter.WriteHeader(code)
}
func (w *StatusWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if h, ok := w.ResponseWriter.(http.Hijacker); ok {
return h.Hijack()
}
return nil, nil, fmt.Errorf("underlying ResponseWriter is not a Hijacker")
}
func (w *StatusWriter) Flush() {
if f, ok := w.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}
|