package api import ( "encoding/json" "io" "net/http" "regexp" "strconv" "strings" "time" ) var entityIDPattern = regexp.MustCompile(`^[A-Z]{2,3}-[0-9]{7}$`) func parseID(path, prefix string) (string, bool) { if !strings.HasPrefix(path, prefix) { return "", false } trimmed := strings.TrimPrefix(path, prefix) if trimmed == "" || strings.Contains(trimmed, "/") { return "", false } if !entityIDPattern.MatchString(trimmed) { return "", false } return trimmed, true } func parseSubresourceID(path, prefix, suffix string) (string, bool) { if !strings.HasPrefix(path, prefix) || !strings.HasSuffix(path, suffix) { return "", false } trimmed := strings.TrimPrefix(path, prefix) trimmed = strings.TrimSuffix(trimmed, suffix) if trimmed == "" || strings.Contains(trimmed, "/") { return "", false } if !entityIDPattern.MatchString(trimmed) { return "", false } return trimmed, true } func decodeJSON(r *http.Request, dest any) error { decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() if err := decoder.Decode(dest); err != nil { return err } if err := decoder.Decode(&struct{}{}); err != io.EOF { return err } return nil } func writeJSON(w http.ResponseWriter, status int, payload any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(payload) } func writeError(w http.ResponseWriter, status int, message string) { writeJSON(w, status, map[string]string{"error": message}) } func parseTimeParam(value string) (time.Time, error) { return time.Parse(time.RFC3339, value) } func parseIntParam(value string) (int, error) { parsed, err := strconv.Atoi(value) if err != nil { return 0, err } return parsed, nil } func parseFloatParam(value string) (float64, error) { return strconv.ParseFloat(value, 64) }