package util
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// DecodeJSON reads and decodes JSON from r into v. It limits body size to maxBytes.
func DecodeJSON(r io.Reader, maxBytes int64, v any) error {
lr := io.LimitReader(r, maxBytes+1)
body, err := io.ReadAll(lr)
if err != nil {
return err
}
if int64(len(body)) > maxBytes {
return fmt.Errorf("json body exceeds max size %d", maxBytes)
}
dec := json.NewDecoder(bytes.NewReader(body))
dec.DisallowUnknownFields()
return dec.Decode(v)
}
// WriteJSON writes v as JSON with Content-Type application/json.
func WriteJSON(w http.ResponseWriter, status int, v any) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
return enc.Encode(v)
}
// MergeHeaders copies named headers from src to dst if present.
func MergeHeaders(dst, src http.Header, names ...string) {
for _, n := range names {
if v := src.Get(n); v != "" {
dst.Set(n, v)
}
}
}