package main import ( "database/sql" "encoding/json" "io" "log" "net/http" _ "github.com/mattn/go-sqlite3" ) var db *sql.DB type Note struct { Id int64 `json:"id"` Content string `json:"content"` } func httpError(err error, statusCode int, message string, w http.ResponseWriter) bool { if err != nil { w.WriteHeader(statusCode) io.WriteString(w, message) return true } return false } func getNotes(w http.ResponseWriter, req *http.Request) { res, err := db.Query(`SELECT Id, Content FROM Notes`) if httpError(err, http.StatusInternalServerError, "Failed to load notes", w) { return } defer res.Close() var notes []Note = []Note{} for res.Next() { if httpError(res.Err(), http.StatusInternalServerError, "Failed to load notes", w) { return } var note Note res.Scan(¬e.Id, ¬e.Content) notes = append(notes, note) } json, err := json.Marshal(notes) if httpError(err, http.StatusInternalServerError, "Failed to create JSON", w) { return } w.Write(json) } func postNotes(w http.ResponseWriter, req *http.Request) { data, err := io.ReadAll(req.Body) if httpError(err, http.StatusBadRequest, "Failed to read data", w) { return } var note Note err = json.Unmarshal(data, ¬e) if httpError(err, http.StatusBadRequest, "Invalid request", w) { return } if len(note.Content) == 0 { w.WriteHeader(http.StatusBadRequest) io.WriteString(w, "Missing note content") return } stmt, err := db.Prepare(`INSERT INTO Notes(Content) VALUES(?) RETURNING Id`) if httpError(err, http.StatusInternalServerError, "Failed to store note", w) { return } defer stmt.Close() res := stmt.QueryRow(note.Content) err = res.Scan(¬e.Id) if httpError(err, http.StatusInternalServerError, "Failed to store note", w) { return } json, err := json.Marshal(note) if httpError(err, http.StatusInternalServerError, "Failed to create JSON", w) { return } w.WriteHeader(http.StatusCreated) w.Write(json) } func putNote(w http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPut { w.WriteHeader(http.StatusBadRequest) io.WriteString(w, "Invalid method") return } } func handleNotes(w http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodGet: getNotes(w, req) case http.MethodPost: postNotes(w, req) default: w.WriteHeader(http.StatusBadRequest) io.WriteString(w, "Invalid method") } } func main() { log.Println("Starting NoteServer") log.Println("Loading database") var err error db, err = sql.Open("sqlite3", "./notes.sqlite") if err != nil { log.Fatalln("Failed to load db:", err) } log.Println("Creating missing tables") _, err = db.Exec(`CREATE TABLE IF NOT EXISTS Notes(Id INTEGER PRIMARY KEY AUTOINCREMENT, Content TEXT)`) if err != nil { log.Fatalln("Failed to create table:", err) } log.Println("Listening") http.HandleFunc("/api/notes", handleNotes) http.HandleFunc("/api/note/", putNote) http.ListenAndServe(":8080", nil) // TODO: configure host, port, TLS }