package client import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "strings" "time" ) const baseURL = "http://localhost:8080" var httpClient = &http.Client{} func doRequest(method, url string, body any) []byte { var reqBody io.Reader if body != nil { data, err := json.Marshal(body) if err != nil { log.Fatalf("Failed to marshal request body: %v", err) } reqBody = bytes.NewReader(data) } req, err := http.NewRequest(method, url, reqBody) if err != nil { log.Fatalf("Failed to create request: %v", err) } if body != nil { req.Header.Set("Content-Type", "application/json") } resp, err := httpClient.Do(req) if err != nil { log.Fatalf("Failed to send request: %v", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { log.Fatalf("Failed to read response body: %v", err) } return respBody } func ListNotes() { body := doRequest(http.MethodGet, baseURL+"/notes", nil) var notes []struct { ID int `json:"id"` Content string `json:"content"` LastUpdate time.Time `json:"last_update"` } if err := json.Unmarshal(body, ¬es); err != nil { log.Fatalf("Failed to parse notes: %v", err) } if len(notes) == 0 { fmt.Println("No notes found.") return } // Calculate column widths from headers and content idW, updatedW, contentW := 2, 7, 7 // minimums: "ID", "Updated", "Content" for _, n := range notes { if w := len(fmt.Sprintf("%d", n.ID)); w > idW { idW = w } if w := len(n.LastUpdate.Format("2006-01-02 15:04:05")); w > updatedW { updatedW = w } if w := len(n.Content); w > contentW { contentW = w } } row := func(id, updated, content string) { fmt.Printf("| %-*s | %-*s | %-*s |\n", idW, id, updatedW, updated, contentW, content) } sep := fmt.Sprintf("|-%s-|-%s-|-%s-|", strings.Repeat("-", idW), strings.Repeat("-", updatedW), strings.Repeat("-", contentW)) row("ID", "Updated", "Content") fmt.Println(sep) for _, n := range notes { row(fmt.Sprintf("%d", n.ID), n.LastUpdate.Format("2006-01-02 15:04:05"), n.Content) } } func CreateNote(content string) { body := doRequest(http.MethodPost, baseURL+"/notes", map[string]string{"content": content}) var note struct { ID int `json:"id"` Content string `json:"content"` } if err := json.Unmarshal(body, ¬e); err != nil { log.Fatalf("Failed to parse note: %v", err) } fmt.Printf("Created note #%d: %s\n", note.ID, note.Content) } func GetNoteByID(id int) { body := doRequest(http.MethodGet, fmt.Sprintf("%s/note/%d", baseURL, id), nil) var note struct { ID int `json:"id"` Content string `json:"content"` LastUpdate time.Time `json:"last_update"` } if err := json.Unmarshal(body, ¬e); err != nil { log.Fatalf("Failed to parse note: %v", err) } fmt.Printf("Note #%d (updated %s):\n %s\n", note.ID, note.LastUpdate.Format("2006-01-02 15:04:05"), note.Content) } func UpdateNoteByID(id int, content string) { body := doRequest(http.MethodPut, fmt.Sprintf("%s/note/%d", baseURL, id), map[string]string{"content": content}) var note struct { ID int `json:"id"` Content string `json:"content"` } if err := json.Unmarshal(body, ¬e); err != nil { log.Fatalf("Failed to parse note: %v", err) } fmt.Printf("Updated note #%d: %s\n", note.ID, note.Content) } func DeleteNoteByID(id int) { doRequest(http.MethodDelete, fmt.Sprintf("%s/note/%d", baseURL, id), nil) fmt.Printf("Deleted note #%d\n", id) }