package rest import ( "encoding/json" "io" "log/slog" "net/http" "strconv" ) const ( maxRequestBody = 1 << 20 defaultLimit = 50 maxLimit = 200 ) type errorResponse struct { Error string `json:"error"` } func writeJson(w http.ResponseWriter, status int, value any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) if value == nil { return } if err := json.NewEncoder(w).Encode(value); err != nil { slog.Error("encode response", slog.String("op", "rest.writeJson"), slog.Any("error", err)) } } func writeError(w http.ResponseWriter, status int, message string) { writeJson(w, status, errorResponse{Error: message}) } func writeNoContent(w http.ResponseWriter) { w.WriteHeader(http.StatusNoContent) } func decodeJson(r *http.Request, dst any) error { decoder := json.NewDecoder(io.LimitReader(r.Body, maxRequestBody)) decoder.DisallowUnknownFields() return decoder.Decode(dst) } func pagination(r *http.Request) (limit, offset int64) { limit = defaultLimit query := r.URL.Query() if value := query.Get("limit"); value != "" { if parsed, err := strconv.ParseInt(value, 10, 64); err == nil && parsed > 0 { limit = parsed } } if limit > maxLimit { limit = maxLimit } if value := query.Get("offset"); value != "" { if parsed, err := strconv.ParseInt(value, 10, 64); err == nil && parsed >= 0 { offset = parsed } } return limit, offset }