├── Dockerfile ├── docker-compose.yml ├── go.mod ├── go.sum └── main.go /Dockerfile: -------------------------------------------------------------------------------- 1 | # use official Golang image 2 | FROM golang:1.16.3-alpine3.13 3 | 4 | # set working directory 5 | WORKDIR /app 6 | 7 | # Copy the source code 8 | COPY . . 9 | 10 | # Download and install the dependencies 11 | RUN go get -d -v ./... 12 | 13 | # Build the Go app 14 | RUN go build -o api . 15 | 16 | #EXPOSE the port 17 | EXPOSE 8000 18 | 19 | # Run the executable 20 | CMD ["./api"] -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | go-app: 5 | container_name: go-app 6 | image: francescoxx/go-app:1.0.1 7 | build: . 8 | environment: 9 | DATABASE_URL: "host=go_db user=postgres password=postgres dbname=postgres sslmode=disable" 10 | ports: 11 | - "8000:8000" 12 | depends_on: 13 | - go_db 14 | go_db: 15 | container_name: go_db 16 | image: postgres:12 17 | environment: 18 | POSTGRES_PASSWORD: postgres 19 | POSTGRES_USER: postgres 20 | POSTGRES_DB: postgres 21 | ports: 22 | - "5432:5432" 23 | volumes: 24 | - pgdata:/var/lib/postgresql/data 25 | 26 | volumes: 27 | pgdata: {} 28 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module api 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gorilla/mux v1.8.0 // indirect 7 | github.com/lib/pq v1.10.7 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= 2 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 3 | github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= 4 | github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 5 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "log" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/gorilla/mux" 11 | _ "github.com/lib/pq" 12 | ) 13 | 14 | type User struct { 15 | ID int `json:"id"` 16 | Name string `json:"name"` 17 | Email string `json:"email"` 18 | } 19 | 20 | func main() { 21 | //connect to database 22 | db, err := sql.Open("postgres", os.Getenv("DATABASE_URL")) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | defer db.Close() 27 | 28 | //create the table if it doesn't exist 29 | _, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT, email TEXT)") 30 | 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | 35 | //create router 36 | router := mux.NewRouter() 37 | router.HandleFunc("/users", getUsers(db)).Methods("GET") 38 | router.HandleFunc("/users/{id}", getUser(db)).Methods("GET") 39 | router.HandleFunc("/users", createUser(db)).Methods("POST") 40 | router.HandleFunc("/users/{id}", updateUser(db)).Methods("PUT") 41 | router.HandleFunc("/users/{id}", deleteUser(db)).Methods("DELETE") 42 | 43 | //start server 44 | log.Fatal(http.ListenAndServe(":8000", jsonContentTypeMiddleware(router))) 45 | } 46 | 47 | func jsonContentTypeMiddleware(next http.Handler) http.Handler { 48 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 49 | w.Header().Set("Content-Type", "application/json") 50 | next.ServeHTTP(w, r) 51 | }) 52 | } 53 | 54 | // get all users 55 | func getUsers(db *sql.DB) http.HandlerFunc { 56 | return func(w http.ResponseWriter, r *http.Request) { 57 | rows, err := db.Query("SELECT * FROM users") 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | defer rows.Close() 62 | 63 | users := []User{} 64 | for rows.Next() { 65 | var u User 66 | if err := rows.Scan(&u.ID, &u.Name, &u.Email); err != nil { 67 | log.Fatal(err) 68 | } 69 | users = append(users, u) 70 | } 71 | if err := rows.Err(); err != nil { 72 | log.Fatal(err) 73 | } 74 | 75 | json.NewEncoder(w).Encode(users) 76 | } 77 | } 78 | 79 | // get user by id 80 | func getUser(db *sql.DB) http.HandlerFunc { 81 | return func(w http.ResponseWriter, r *http.Request) { 82 | vars := mux.Vars(r) 83 | id := vars["id"] 84 | 85 | var u User 86 | err := db.QueryRow("SELECT * FROM users WHERE id = $1", id).Scan(&u.ID, &u.Name, &u.Email) 87 | if err != nil { 88 | w.WriteHeader(http.StatusNotFound) 89 | return 90 | } 91 | 92 | json.NewEncoder(w).Encode(u) 93 | } 94 | } 95 | 96 | // create user 97 | func createUser(db *sql.DB) http.HandlerFunc { 98 | return func(w http.ResponseWriter, r *http.Request) { 99 | var u User 100 | json.NewDecoder(r.Body).Decode(&u) 101 | 102 | err := db.QueryRow("INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id", u.Name, u.Email).Scan(&u.ID) 103 | if err != nil { 104 | log.Fatal(err) 105 | } 106 | 107 | json.NewEncoder(w).Encode(u) 108 | } 109 | } 110 | 111 | // update user 112 | func updateUser(db *sql.DB) http.HandlerFunc { 113 | return func(w http.ResponseWriter, r *http.Request) { 114 | var u User 115 | json.NewDecoder(r.Body).Decode(&u) 116 | 117 | vars := mux.Vars(r) 118 | id := vars["id"] 119 | 120 | _, err := db.Exec("UPDATE users SET name = $1, email = $2 WHERE id = $3", u.Name, u.Email, id) 121 | if err != nil { 122 | log.Fatal(err) 123 | } 124 | 125 | json.NewEncoder(w).Encode(u) 126 | } 127 | } 128 | 129 | // delete user 130 | func deleteUser(db *sql.DB) http.HandlerFunc { 131 | return func(w http.ResponseWriter, r *http.Request) { 132 | vars := mux.Vars(r) 133 | id := vars["id"] 134 | 135 | var u User 136 | err := db.QueryRow("SELECT * FROM users WHERE id = $1", id).Scan(&u.ID, &u.Name, &u.Email) 137 | if err != nil { 138 | w.WriteHeader(http.StatusNotFound) 139 | return 140 | } else { 141 | _, err := db.Exec("DELETE FROM users WHERE id = $1", id) 142 | if err != nil { 143 | //todo : fix error handling 144 | w.WriteHeader(http.StatusNotFound) 145 | return 146 | } 147 | 148 | json.NewEncoder(w).Encode("User deleted") 149 | } 150 | } 151 | } 152 | --------------------------------------------------------------------------------