package response import ( "encoding/json" "net/http" "reflect" ) type envelope struct { Data any `json:"data,omitempty"` Error string `json:"error,omitempty"` } func JSON(w http.ResponseWriter, status int, data any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(envelope{Data: leereListeStattNull(data)}) } // leereListeStattNull macht aus einer nicht belegten Liste eine leere. // // In Go ist eine Liste ohne Einträge oft nil, und `encoding/json` schreibt // dafür `null` statt `[]`. Jede Store-Funktion, die ihre Liste mit // `var out []T` beginnt, liefert das bei leerem Ergebnis – und jede // Oberfläche, die darüber läuft, bricht dann ab. // // Genau so ist die Kalenderansicht bei einem Konto ohne Kalender // weiß geblieben: `for (const cal of calendars)` über `null`. // // Der Ort dafür ist hier und nicht in den Stores: Es gibt Dutzende // Listenendpunkte, und der nächste wird wieder mit `var out []T` anfangen. // Eine Regel, an die man sich erinnern muss, ist keine. func leereListeStattNull(data any) any { if data == nil { return data } v := reflect.ValueOf(data) if v.Kind() == reflect.Slice && v.IsNil() { return reflect.MakeSlice(v.Type(), 0, 0).Interface() } return data } func Error(w http.ResponseWriter, status int, msg string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(envelope{Error: msg}) } func NoContent(w http.ResponseWriter) { w.WriteHeader(http.StatusNoContent) }