├── .gitignore ├── README.md ├── handlers └── tasks.go ├── models └── tasks.go ├── public └── index.html └── todo.go /.gitignore: -------------------------------------------------------------------------------- 1 | storage.db 2 | todo 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go TODO 2 | 3 | This is a simple todo web app written in Go and using the Echo Framework 4 | 5 | Just run the folowing 6 | 7 | ``` 8 | go get github.com/labstack/echo 9 | go get github.com/mattn/go-sqlite3 10 | go run todo.go 11 | ``` 12 | 13 | Then point your browser to http://localhost:8000 14 | -------------------------------------------------------------------------------- /handlers/tasks.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "database/sql" 5 | "net/http" 6 | "strconv" 7 | 8 | "go-echo-vue/models" 9 | 10 | "github.com/labstack/echo" 11 | ) 12 | 13 | type H map[string]interface{} 14 | 15 | // GetTasks endpoint 16 | func GetTasks(db *sql.DB) echo.HandlerFunc { 17 | return func(c echo.Context) error { 18 | return c.JSON(http.StatusOK, models.GetTasks(db)) 19 | } 20 | } 21 | 22 | // PutTask endpoint 23 | func PutTask(db *sql.DB) echo.HandlerFunc { 24 | return func(c echo.Context) error { 25 | // Instantiate a new task 26 | var task models.Task 27 | // Map imcoming JSON body to the new Task 28 | c.Bind(&task) 29 | // Add a task using our new model 30 | id, err := models.PutTask(db, task.Name) 31 | // Return a JSON response if successful 32 | if err == nil { 33 | return c.JSON(http.StatusCreated, H{ 34 | "created": id, 35 | }) 36 | // Handle any errors 37 | } else { 38 | return err 39 | } 40 | } 41 | } 42 | 43 | // DeleteTask endpoint 44 | func DeleteTask(db *sql.DB) echo.HandlerFunc { 45 | return func(c echo.Context) error { 46 | id, _ := strconv.Atoi(c.Param("id")) 47 | // Use our new model to delete a task 48 | _, err := models.DeleteTask(db, id) 49 | // Return a JSON response on success 50 | if err == nil { 51 | return c.JSON(http.StatusOK, H{ 52 | "deleted": id, 53 | }) 54 | // Handle errors 55 | } else { 56 | return err 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /models/tasks.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "database/sql" 5 | 6 | _ "github.com/mattn/go-sqlite3" 7 | ) 8 | 9 | // Task is a struct containing Task data 10 | type Task struct { 11 | ID int `json:"id"` 12 | Name string `json:"name"` 13 | } 14 | 15 | // TaskCollection is collection of Tasks 16 | type TaskCollection struct { 17 | Tasks []Task `json:"items"` 18 | } 19 | 20 | // GetTasks from the DB 21 | func GetTasks(db *sql.DB) TaskCollection { 22 | sql := "SELECT * FROM tasks" 23 | rows, err := db.Query(sql) 24 | // Exit if the SQL doesn't work for some reason 25 | if err != nil { 26 | panic(err) 27 | } 28 | // make sure to cleanup when the program exits 29 | defer rows.Close() 30 | 31 | result := TaskCollection{} 32 | for rows.Next() { 33 | task := Task{} 34 | err2 := rows.Scan(&task.ID, &task.Name) 35 | // Exit if we get an error 36 | if err2 != nil { 37 | panic(err2) 38 | } 39 | result.Tasks = append(result.Tasks, task) 40 | } 41 | return result 42 | } 43 | 44 | // PutTask into DB 45 | func PutTask(db *sql.DB, name string) (int64, error) { 46 | sql := "INSERT INTO tasks(name) VALUES(?)" 47 | 48 | // Create a prepared SQL statement 49 | stmt, err := db.Prepare(sql) 50 | // Exit if we get an error 51 | if err != nil { 52 | panic(err) 53 | } 54 | // Make sure to cleanup after the program exits 55 | defer stmt.Close() 56 | 57 | // Replace the '?' in our prepared statement with 'name' 58 | result, err2 := stmt.Exec(name) 59 | // Exit if we get an error 60 | if err2 != nil { 61 | panic(err2) 62 | } 63 | 64 | return result.LastInsertId() 65 | } 66 | 67 | // DeleteTask from DB 68 | func DeleteTask(db *sql.DB, id int) (int64, error) { 69 | sql := "DELETE FROM tasks WHERE id = ?" 70 | 71 | // Create a prepared SQL statement 72 | stmt, err := db.Prepare(sql) 73 | // Exit if we get an error 74 | if err != nil { 75 | panic(err) 76 | } 77 | 78 | // Replace the '?' in our prepared statement with 'id' 79 | result, err2 := stmt.Exec(id) 80 | // Exit if we get an error 81 | if err2 != nil { 82 | panic(err2) 83 | } 84 | 85 | return result.RowsAffected() 86 | } 87 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TODO App 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |
27 |

My Tasks

28 |
    29 |
  • 30 | {{ task.name }} 31 | 32 | 35 | 36 |
  • 37 |
38 |
39 | 44 | 45 | 46 | 47 |
48 |
49 |
50 |
51 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /todo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "go-echo-vue/handlers" 7 | 8 | "github.com/labstack/echo" 9 | _ "github.com/mattn/go-sqlite3" 10 | ) 11 | 12 | func main() { 13 | 14 | db := initDB("storage.db") 15 | migrate(db) 16 | 17 | e := echo.New() 18 | 19 | e.File("/", "public/index.html") 20 | e.GET("/tasks", handlers.GetTasks(db)) 21 | e.PUT("/tasks", handlers.PutTask(db)) 22 | e.DELETE("/tasks/:id", handlers.DeleteTask(db)) 23 | 24 | e.Start(":8000") 25 | } 26 | 27 | func initDB(filepath string) *sql.DB { 28 | db, err := sql.Open("sqlite3", filepath) 29 | 30 | // Here we check for any db errors then exit 31 | if err != nil { 32 | panic(err) 33 | } 34 | 35 | // If we don't get any errors but somehow still don't get a db connection 36 | // we exit as well 37 | if db == nil { 38 | panic("db nil") 39 | } 40 | return db 41 | } 42 | 43 | func migrate(db *sql.DB) { 44 | sql := ` 45 | CREATE TABLE IF NOT EXISTS tasks( 46 | id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 47 | name VARCHAR NOT NULL 48 | ); 49 | ` 50 | 51 | _, err := db.Exec(sql) 52 | // Exit if something goes wrong with our SQL statement above 53 | if err != nil { 54 | panic(err) 55 | } 56 | } 57 | --------------------------------------------------------------------------------