Golang CRUD REST API with MySQL

In this tutorial, you'll learn how to build a CRUD (Create, Read, Update, Delete) REST API using Golang and MySQL. We'll guide you step-by-step through the process of setting up a Go project, interacting with a MySQL database, and testing all REST APIs using Postman. Whether you're a beginner or have experience with Golang, this tutorial will provide a solid foundation for building robust web APIs.

Prerequisites

Before we get started, ensure that the following tools and software are installed on your machine:

  1. Go (Golang) – Make sure you have the latest version of Go installed.
  2. MySQL – Ensure that MySQL is installed, running, and accessible.
  3. Postman – This tool will help us test the APIs.

Step 1: Set Up Your Go Project

Start by creating a directory for your Go project and initializing it:

mkdir go-crud-api cd go-crud-api go mod init go-crud-api 

This will set up a new Go module and allow you to manage dependencies for your project.

Step 2: Install Required Packages

Next, install the required packages for handling HTTP requests and interacting with MySQL.

go get -u github.com/go-sql-driver/mysql go get -u github.com/gorilla/mux 
  • github.com/go-sql-driver/mysql: MySQL driver for Go.
  • github.com/gorilla/mux: A powerful routing library for building web APIs.

Step 3: Set Up MySQL Database

3.1 Create a Database

Start MySQL and create a new database for our project:

CREATE DATABASE go_crud_api; 

3.2 Create the users Table

Now, create the users table within the go_crud_api database:

USE go_crud_api; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); 

This table will store user data, including an auto-incrementing ID, name, email, and timestamp.

Step 4: Create the Main Application File

Create a file called main.go and set up the basic structure of the Go web application.

package main import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "github.com/gorilla/mux" _ "github.com/go-sql-driver/mysql" ) // User represents the user model for our CRUD operations type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt string `json:"created_at"` } var db *sql.DB func main() { // Initialize database connection var err error db, err = sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/go_crud_api") if err != nil { log.Fatal(err) } defer db.Close() // Initialize router router := mux.NewRouter() // Define API routes router.HandleFunc("/users", getUsers).Methods("GET") // Fetch all users router.HandleFunc("/user/{id}", getUser).Methods("GET") // Fetch a user by ID router.HandleFunc("/user", createUser).Methods("POST") // Create a new user router.HandleFunc("/user/{id}", updateUser).Methods("PUT") // Update a user by ID router.HandleFunc("/user/{id}", deleteUser).Methods("DELETE") // Delete a user by ID // Start server on port 8000 log.Fatal(http.ListenAndServe(":8000", router)) } 

Explanation of the Code

  1. MySQL Connection: We establish a connection to the MySQL database using sql.Open.
  2. Routing: The Gorilla Mux router is used to define routes and handle API requests.
  3. Server Setup: The HTTP server listens on port 8000 for incoming requests.

Step 5: Implement CRUD Operations

5.1 Fetch All Users

Let's create a function that retrieves all users from the database and returns them in JSON format.
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) }

5.2 Fetch a Single User by ID

Let's create a function that retrieves a single user by their ID and returns it in JSON format. If no user is found, it returns a 404 error.
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 = ?", 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) }

5.3 Create a New User

Let's create a function that decodes the JSON request body and inserts a new user into the database. It returns the created user in JSON format.
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 } result, err := db.Exec("INSERT INTO users (name, email) VALUES (?, ?)", user.Name, user.Email) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } id, err := result.LastInsertId() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } user.ID = int(id) user.CreatedAt = "now" // Placeholder json.NewEncoder(w).Encode(user) }

5.4 Update an Existing User

Let's create a function that updates an existing user in the database by their ID, returning the updated user as JSON.
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 = ?, email = ? WHERE id = ?", user.Name, user.Email, id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } user.ID = int(id) user.CreatedAt = "now" // Placeholder json.NewEncoder(w).Encode(user) }

5.5 Delete a User

Let's create a function that deletes a user from the database by their ID, returning a 204 No Content status upon success.
func deleteUser(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["id"] _, err := db.Exec("DELETE FROM users WHERE id = ?", id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }

Testing the CRUD API with Postman

You can test the endpoints using Postman by performing the following actions:

  1. Get All Users

    • Method: GET
    • URL: http://localhost:8000/users
  2. Get a Single User

    • Method: GET
    • URL: http://localhost:8000/user/{id}
  3. Create a New User

    • Method: POST
    • URL: http://localhost:8000/user
    • Body (JSON):
    { "name": "Ramesh Fadatare", "email": "ramesh.fadatare@example.com" } 
  4. Update a User

    • Method: PUT
    • URL: http://localhost:8000/user/{id}
    • Body (JSON):
    { "name": "Ramesh Fadatare",
    "email": "ramesh@example.com" }
  5. Delete a User

    • Method: DELETE
    • URL: http://localhost:8000/user/{id}

Best Practices

  1. Error Handling: Always handle errors gracefully and return meaningful HTTP status codes.
  2. Input Validation: Validate user input to ensure data integrity before interacting with the database. 
  3. Logging: Implement logging to monitor your application and catch issues early. 
  4. Environment Variables: Use environment variables for sensitive information like database credentials.

Conclusion

In this tutorial, we covered creating a CRUD REST API using Golang and MySQL. We set up the project, created a MySQL database, and built the necessary API endpoints to manage users. You can extend this example by adding features like authentication, input validation, and more complex querying.


Comments