package api import ( "encoding/json" "net/http" "time" "github.com/lerko/nib/internal/db" ) type ErrorResponse struct { Error string `json:"error"` Message string `json:"message"` } type EntityResponse struct { ID string `json:"id"` CreatedAt string `json:"created_at"` ModifiedAt string `json:"modified_at"` Body string `json:"body"` Title *string `json:"title"` Description *string `json:"description"` Glyph string `json:"glyph"` TimeAnchor *string `json:"time_anchor"` CompletedAt *string `json:"completed_at"` Pinned bool `json:"pinned"` DeletedAt *string `json:"deleted_at"` Tags []string `json:"tags"` CardType *string `json:"card_type"` CardData *string `json:"card_data"` UseCount int `json:"use_count"` LastUsedAt *string `json:"last_used_at"` } func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(v) } func writeError(w http.ResponseWriter, status int, code, message string) { writeJSON(w, status, ErrorResponse{Error: code, Message: message}) } func decodeJSON(w http.ResponseWriter, r *http.Request, dst any) bool { if err := json.NewDecoder(r.Body).Decode(dst); err != nil { writeError(w, http.StatusBadRequest, "invalid_input", "malformed JSON: "+err.Error()) return false } return true } func entityToResponse(e *db.Entity) EntityResponse { resp := EntityResponse{ ID: e.ID, CreatedAt: e.CreatedAt.Format(time.RFC3339), ModifiedAt: e.ModifiedAt.Format(time.RFC3339), Body: e.Body, Title: e.Title, Description: e.Description, Glyph: string(e.Glyph), Pinned: e.Pinned, Tags: e.Tags, UseCount: e.UseCount, } if resp.Tags == nil { resp.Tags = []string{} } resp.TimeAnchor = e.TimeAnchor resp.CompletedAt = formatTimeRespPtr(e.CompletedAt) resp.DeletedAt = formatTimeRespPtr(e.DeletedAt) resp.LastUsedAt = formatTimeRespPtr(e.LastUsedAt) if e.CardType != nil { s := string(*e.CardType) resp.CardType = &s } resp.CardData = e.CardData return resp } func formatTimeRespPtr(t *time.Time) *string { if t == nil { return nil } s := t.Format(time.RFC3339) return &s }