~/Golang Todo App With Database and Frontend

Mar 12, 2022


This guide shows how to make a simple Golang todo app with a SQLite database and a React frontend.

Backend using Go and SQLite:

Simple API code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
  "database/sql"
  "encoding/json"
  "net/http"
  _ "github.com/mattn/go-sqlite3"
)

type Todo struct {
  ID   int    `json:"id"`
  Task string `json:"task"`
}

func main() {
  db, _ := sql.Open("sqlite3", "todo.db")
  db.Exec("CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY, task TEXT)")

  http.HandleFunc("/todos", func(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
      rows, _ := db.Query("SELECT id, task FROM todos")
      var todos []Todo
      for rows.Next() {
        var t Todo
        rows.Scan(&t.ID, &t.Task)
        todos = append(todos, t)
      }
      json.NewEncoder(w).Encode(todos)
    }
    if r.Method == "POST" {
      var t Todo
      json.NewDecoder(r.Body).Decode(&t)
      db.Exec("INSERT INTO todos(task) VALUES(?)", t.Task)
      w.WriteHeader(http.StatusCreated)
    }
  })
  http.ListenAndServe(":8080", nil)
}

Frontend using React:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, { useState, useEffect } from "react";

function App() {
  const [todos, setTodos] = useState([]);
  const [task, setTask] = useState("");

  useEffect(() => {
    fetch("/todos").then(res => res.json()).then(setTodos);
  }, []);

  function addTodo(e) {
    e.preventDefault();
    fetch("/todos", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ task })
    }).then(() => setTask("")).then(() =>
      fetch("/todos").then(res => res.json()).then(setTodos)
    );
  }

  return (
    <div>
      <ul>
        {todos.map(t => <li key={t.id}>{t.task}</li>)}
      </ul>
      <form onSubmit={addTodo}>
        <input value={task} onChange={e => setTask(e.target.value)} />
        <button type="submit">Add</button>
      </form>
    </div>
  );
}

Run Go and React servers separately. Adjust the API url for cross-origin requests.

For more on React and Go, see React docs and Golang web guide.

This structure offers a basic and extendable todo app with persistent storage.

Tags: [golang] [todo] [web]