Build a Complete REST API in Go – From Zero to Production!
KodeNimbus Team • Golang

Build a Complete REST API in Go – From Zero to Production!

October 30, 2025

Are you ready to master Golang for backend development? Whether you're just starting or want to level up your Go skills, this guide is designed to walk you through the entire process of building a fully functional REST API with MySQL integration and unit tests. By the end of this guide, you'll be able to confidently create scalable, production-ready APIs using Go.

In this blog, I'll break down the key steps to building a RESTful API that includes creating a simple database connection, implementing CRUD (Create, Read, Update, Delete) operations, and writing unit tests to ensure your code is reliable.



Step 1: Setting Up Your Golang Environment

Before we get started, you need to set up Go and MySQL on your local machine or in a cloud environment.


1.1 Installing Golang

If you haven’t installed Go yet, you can download it from the official website: Go Downloads.

Follow the installation instructions for your platform, and then verify the installation:

go version


1.2 Installing MySQL

You can use a local MySQL instance or a cloud-based solution like AWS RDS or Google Cloud SQL. If you're running MySQL locally, install it via your package manager (Linux) or use tools like XAMPP or Docker to run MySQL on your machine.

Create a new database called go_rest_api for this project:

CREATE DATABASE go_rest_api;


Step 2: Initializing the Go Project

Now that you have your environment ready, let's initialize a new Go project.

Create a new directory
for your project:

mkdir go-rest-api cd go-rest-api Initialize your Go module:
go mod init go-rest-api Install MySQL driver for Go:
go get github.com/go-sql-driver/mysql


This will allow you to easily connect and interact with your MySQL database.



Step 3: Structuring the Project


It's always a good practice to structure your project in a way that promotes maintainability and scalability. Here's a basic project structure:

go-rest-api/ │ ├── main.go # Entry point of the application ├── handlers/ # Contains HTTP handlers for the API │ └── user_handlers.go ├── models/ # Defines the database models │ └── user.go ├── database/ # Contains the MySQL connection code │ └── connection.go ├── routes/ # Routing logic │ └── routes.go └── tests/ # Contains unit tests └── user_test.go


Step 4: Connecting Go with MySQL


4.1 Create a Database Connection


In the database folder, create a file connection.go to handle the MySQL connection. Here's how you can do it:

package database import ( "database/sql" "fmt" "log" _ "github.com/go-sql-driver/mysql" ) func InitDB() *sql.DB { // MySQL connection string (username:password@protocol(address)/dbname) dsn := "root:password@tcp(127.0.0.1:3306)/go_rest_api" db, err := sql.Open("mysql", dsn) if err != nil { log.Fatal("Error connecting to the database:", err) } // Ping the database to ensure connection is established err = db.Ping() if err != nil { log.Fatal("Error pinging database:", err) } fmt.Println("Successfully connected to the database") return db }

In this example:

  • The DSN (Data Source Name) specifies the connection string with the format: username:password@protocol(address)/dbname.

  • The InitDB() function initializes the connection and returns the database instance.



Step 5: Defining Models


Next, we need to define the model for our User resource. In the models folder, create user.go with the following content:

package models import ( "time" ) type User struct { ID int `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` }

This User struct defines the fields we'll be using for the CRUD operations. The json tags are for JSON serialization when the data is returned in API responses.



Step 6: Implementing CRUD Operations


6.1 Create User


In the handlers folder, create user_handlers.go to handle HTTP requests. Here’s how to implement a Create user function:

package handlers import ( "encoding/json" "fmt" "net/http" "time" "github.com/gorilla/mux" "github.com/go-rest-api/models" "github.com/go-rest-api/database" ) func CreateUser(w http.ResponseWriter, r *http.Request) { var user models.User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } db := database.InitDB() defer db.Close() query := `INSERT INTO users (first_name, last_name, email, created_at, updated_at) VALUES (?, ?, ?, ?, ?)` _, err = db.Exec(query, user.FirstName, user.LastName, user.Email, time.Now(), time.Now()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) fmt.Fprintln(w, "User created successfully!") }

This handler function:

  • Decodes the JSON body into a User object.

  • Executes the SQL query to insert the user into the database.

  • Responds with a success message.


6.2 Read User (Get User)

func GetUser(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] db := database.InitDB() defer db.Close() var user models.User query := `SELECT id, first_name, last_name, email, created_at, updated_at FROM users WHERE id = ?` err := db.QueryRow(query, id).Scan(&user.ID, &user.FirstName, &user.LastName, &user.Email, &user.CreatedAt, &user.UpdatedAt) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } json.NewEncoder(w).Encode(user) }


6.3 Update User

func UpdateUser(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] var user models.User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } db := database.InitDB() defer db.Close() query := `UPDATE users SET first_name = ?, last_name = ?, email = ?, updated_at = ? WHERE id = ?` _, err = db.Exec(query, user.FirstName, user.LastName, user.Email, time.Now(), id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) fmt.Fprintln(w, "User updated successfully!") }


6.4 Delete User

func DeleteUser(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] db := database.InitDB() defer db.Close() query := `DELETE FROM users WHERE id = ?` _, err := db.Exec(query, id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) fmt.Fprintln(w, "User deleted successfully!") }


Step 7: Routing the API Endpoints


In routes/routes.go, set up the routes to map the HTTP requests to the respective handler functions:

package routes import ( "github.com/gorilla/mux" "github.com/go-rest-api/handlers" ) func SetupRouter() *mux.Router { r := mux.NewRouter() r.HandleFunc("/users", handlers.CreateUser).Methods("POST") r.HandleFunc("/users/{id:[0-9]+}", handlers.GetUser).Methods("GET") r.HandleFunc("/users/{id:[0-9]+}", handlers.UpdateUser).Methods("PUT") r.HandleFunc("/users/{id:[0-9]+}", handlers.DeleteUser).Methods("DELETE") return r }


Step 8: Running the Application


In main.go, set up the server to start the API:

package main import ( "fmt" "log" "net/http" "github.com/go-rest-api/routes" ) func main() { r := routes.SetupRouter() fmt.Println("Server is running on port 8080...") log.Fatal(http.ListenAndServe(":8080", r)) }


Step 9: Writing Unit Tests


Unit tests are crucial to ensure your API works as expected. In the tests folder, create user_test.go to test the handlers.

package tests import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/go-rest-api/handlers" "github.com/go-rest-api/models" ) func TestCreateUser(t *testing.T) { user := models.User{ FirstName: "John", LastName: "Doe", Email: "john.doe@example.com", } jsonData, _ := json.Marshal(user) req, _ := http.NewRequest("POST", "/users", bytes.NewBuffer(jsonData)) rr := httptest.NewRecorder() handler := http.HandlerFunc(handlers.CreateUser) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusCreated { t.Errorf("Expected status code %d, got %d", http.StatusCreated, status) } }


Conclusion

By following this guide, you’ll be able to:

Connect Go with MySQL and perform basic CRUD operations.

  • Build production-ready REST APIs with Go.

  • Write unit tests to ensure your application works as expected.