This tutorial will guide you through creating a CRUD (Create, Read, Update, Delete) API using Golang and PostgreSQL. We'll test all the REST APIs using Postman.
Prerequisites
- Go installed on your machine (latest version).
- PostgreSQL installed and running.
- Postman for testing APIs.
Step 1: Set Up Your Go Project
-
Create a new directory for your project and navigate into it:
mkdir go-crud-api-postgresql cd go-crud-api-postgresql
-
Initialize a new Go module:
go mod init go-crud-api-postgresql
Step 2: Install Required Packages
Install the necessary packages for handling PostgreSQL database and HTTP requests:
go get github.com/lib/pq go get github.com/gorilla/mux
Step 3: Set Up PostgreSQL Database
-
Start PostgreSQL and create a new database:
CREATE DATABASE go_crud_api;
-
Create a new table:
\c go_crud_api; CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
Step 4: Create the Main Application File
Create a new file main.go
and set up the basic structure:
package main import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "time" "github.com/gorilla/mux" _ "github.com/lib/pq" ) // User represents the model for our resource type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` } var db *sql.DB func main() { // Initialize PostgreSQL database connection var err error connStr := "user=yourusername password=yourpassword dbname=go_crud_api sslmode=disable" db, err = sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } defer db.Close() // Create a new router router := mux.NewRouter() // Define endpoints router.HandleFunc("/users", getUsers).Methods("GET") router.HandleFunc("/user/{id}", getUser).Methods("GET") router.HandleFunc("/user", createUser).Methods("POST") router.HandleFunc("/user/{id}", updateUser).Methods("PUT") router.HandleFunc("/user/{id}", deleteUser).Methods("DELETE") // Start server log.Fatal(http.ListenAndServe(":8000", router)) } // getUsers fetches all users from the database func getUsers(w http.ResponseWriter, r *http.Request) { var users []User rows, err := db.Query("SELECT id, name, email, created_at FROM users") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() for rows.Next() { var user User if err := rows.Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } users = append(users, user) } json.NewEncoder(w).Encode(users) } // getUser fetches a single user by ID from the database func getUser(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] var user User err := db.QueryRow("SELECT id, name, email, created_at FROM users WHERE id = $1", id).Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt) if err != nil { if err == sql.ErrNoRows { http.NotFound(w, r) } else { http.Error(w, err.Error(), http.StatusInternalServerError) } return } json.NewEncoder(w).Encode(user) } // createUser creates a new user in the database func createUser(w http.ResponseWriter, r *http.Request) { var user User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } err = db.QueryRow( "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, created_at", user.Name, user.Email).Scan(&user.ID, &user.CreatedAt) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } json.NewEncoder(w).Encode(user) } // updateUser updates an existing user in the database func updateUser(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] var user User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } _, err = db.Exec("UPDATE users SET name = $1, email = $2 WHERE id = $3", user.Name, user.Email, id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } user.ID = int(id) json.NewEncoder(w).Encode(user) } // deleteUser deletes a user from the database func deleteUser(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] _, err := db.Exec("DELETE FROM users WHERE id = $1", id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
Explanation of the Code and REST APIs
-
Package and Imports
- The
main
package is used, and necessary packages are imported. github.com/lib/pq
is the PostgreSQL driver.github.com/gorilla/mux
is used for routing.
- The
-
User Struct
- Represents the
User
model with JSON tags for marshalling/unmarshalling.
- Represents the
-
Global DB Variable
db
is a global variable to hold the database connection.
-
Main Function
- Initializes the PostgreSQL database connection.
- Creates a new router using
mux.NewRouter()
. - Defines the REST endpoints and associates them with handler functions.
- Starts the HTTP server on port 8000.
-
getUsers Function
- Retrieves all users from the
users
table. - Encodes the result as JSON and writes it to the response.
- Retrieves all users from the
-
getUser Function
- Retrieves a single user by ID.
- Returns a 404 error if the user is not found.
-
createUser Function
- Decodes the JSON request body to a
User
struct. - Inserts the new user into the
users
table. - Returns the created user as JSON.
- Decodes the JSON request body to a
-
updateUser Function
- Decodes the JSON request body to a
User
struct. - Updates the user with the specified ID in the
users
table. - Returns the updated user as JSON.
- Decodes the JSON request body to a
-
deleteUser Function
- Deletes the user with the specified ID from the
users
table. - Returns a 204 No Content status on successful deletion.
- Deletes the user with the specified ID from the
Testing with Postman
-
Get All Users
- Method:
GET
- URL:
http://localhost:8000/users
- Response: JSON array of users.
- Method:
-
Get a Single User
- Method:
GET
- URL:
http://localhost:8000/user/{id}
- Response: JSON object of the user.
- Method:
-
Create a New User
- Method:
POST
- URL:
http://localhost:8000/user
- Body:
{ "name": "John Doe", "email": "john@example.com" }
- Response: JSON object of the created user.
- Method:
-
Update an Existing User
- Method:
PUT
- URL:
http://localhost:8000/user/{id}
- Body:
{ "name": "Jane Doe", "email": "jane@example.com" }
- Response: JSON object of the updated user.
- Method:
-
Delete a User
- Method:
DELETE
- URL:
http://localhost:8000/user/{id}
- Response: 204 No Content status.
- Method:
Comments
Post a Comment