We will generate the REST API for blog application in golang.
1. Prerequisites
- Go installed (
go version
) - Git installed
- PostgreSQL installed (optional for database use)
- Basic understanding of HTTP & JSON
2. Create Project Structure
mkdir go-api-example
cd go-api-example
go mod init github.com/yourname/go-api-example
go mod init
is used to initialize a new Go module in your project directory.github.com/yourname/go-api-example
is the module path, typically a repository path (like GitHub). It's used as the import path for your code and any sub-packages
What Gets Created:
A new file named go.mod
is created in the root of your project directory . It will contain something like:
module github.com/yourname/go-api-example
go 1.21 // (or whatever your current Go version is)
This go.mod
file:
- Declares the module path.
- Specifies the Go version your project is using.
- Will later list all dependencies (external packages) your code uses.
Why Use Modules?
Go modules help you:
- Manage dependencies (versions of external packages).
- Avoid issues with
GOPATH
and legacy$GOPATH/src
structure. - Easily fetch and upgrade dependencies using
go get
,go mod tidy
, etc.
you can also run the command
go mod tidy
Which:
- Scans your code.
- Downloads any missing dependencies.
- Removes unused ones.
- Updates your
go.mod
and creates ago.sum
file (used to verify the integrity of downloaded modules).
i.e Cleans up and ensures dependencies are downloaded and correctly listed.
3. Install Required Packages
go get github.com/gorilla/mux
go get github.com/joho/godotenv
go get github.com/lib/pq
go get github.com/gorilla/mux
This installs the Gorilla Mux package, which is a powerful HTTP router and URL matcher for Go.
Why Use It:
- It allows you to define routes with parameters like
/users/{id}
. - Supports:
- Route variables (
/user/{id}
) - Middleware chaining
- Hostname/Method matching
- Schemes (http/https)
- Route variables (
Example:
r := mux.NewRouter()
r.HandleFunc("/users/{id}", getUserHandler).Methods("GET")
http.ListenAndServe(":8000", r)
go get github.com/joho/godotenv
This installs the godotenv package, used for loading environment variables from a .env
file.
Why Use It:
- You can keep sensitive config like API keys, DB credentials, etc., out of your code.
- Easy to switch environments (development, production, etc.)
Example:
err := godotenv.Load()
dbHost := os.Getenv("DB_HOST")
go get github.com/lib/pq
This installs the PostgreSQL driver for Go's database/sql
package.
Why Use It:
- Enables your Go application to connect to and query a PostgreSQL database.
- You can use it with standard SQL operations like
SELECT
,INSERT
, etc.
Connect and interact with PostgreSQL DB
Example:
import (
"database/sql"
_ "github.com/lib/pq"
)
connStr := "user=username dbname=mydb sslmode=disable"
db, err := sql.Open("postgres", connStr)
4. Project Structure Example
go-api-example/
main.go
.env
go.mod
go.sum
handlers/
article.go
models/
article.go
db/
connection.go
5. Create .env
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=yourpassword
DB_NAME=goapi
6. Create Database Connection (db/connection.go
)
package db
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/lib/pq"
"github.com/joho/godotenv"
)
var DB *sql.DB
func Init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
connStr := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
os.Getenv("DB_HOST"), os.Getenv("DB_PORT"),
os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"),
os.Getenv("DB_NAME"))
DB, err = sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
if err = DB.Ping(); err != nil {
log.Fatal(err)
}
fmt.Println("? Connected to the database")
}
7. Create Model (models/article.go
)
package models
type Article struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}
8. Create Handlers (handlers/article.go
)
package handlers
import (
"database/sql"
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/yourname/go-api-example/db"
"github.com/yourname/go-api-example/models"
)
func GetArticles(w http.ResponseWriter, r *http.Request) {
rows, err := db.DB.Query("SELECT id, title, content FROM articles")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
var articles []models.Article
for rows.Next() {
var a models.Article
err := rows.Scan(&a.ID, &a.Title, &a.Content)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
articles = append(articles, a)
}
json.NewEncoder(w).Encode(articles)
}
func GetArticle(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
var a models.Article
err := db.DB.QueryRow("SELECT id, title, content FROM articles WHERE id=$1", id).
Scan(&a.ID, &a.Title, &a.Content)
if err == sql.ErrNoRows {
http.NotFound(w, r)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(a)
}
func CreateArticle(w http.ResponseWriter, r *http.Request) {
var a models.Article
_ = json.NewDecoder(r.Body).Decode(&a)
err := db.DB.QueryRow("INSERT INTO articles(title, content) VALUES($1, $2) RETURNING id",
a.Title, a.Content).Scan(&a.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(a)
}
func UpdateArticle(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
var a models.Article
_ = json.NewDecoder(r.Body).Decode(&a)
_, err := db.DB.Exec("UPDATE articles SET title=$1, content=$2 WHERE id=$3",
a.Title, a.Content, id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
a.ID, _ = strconv.Atoi(id)
json.NewEncoder(w).Encode(a)
}
func DeleteArticle(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
_, err := db.DB.Exec("DELETE FROM articles WHERE id=$1", id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
9. Main File (main.go
)
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/yourname/go-api-example/db"
"github.com/yourname/go-api-example/handlers"
)
func main() {
db.Init()
r := mux.NewRouter()
r.HandleFunc("/articles", handlers.GetArticles).Methods("GET")
r.HandleFunc("/articles/{id}", handlers.GetArticle).Methods("GET")
r.HandleFunc("/articles", handlers.CreateArticle).Methods("POST")
r.HandleFunc("/articles/{id}", handlers.UpdateArticle).Methods("PUT")
r.HandleFunc("/articles/{id}", handlers.DeleteArticle).Methods("DELETE")
log.Println("Server started at http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", r))
}
10. SQL to Create Table
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL
);
11. Run the App
go run main.go
Open browser or use tools like Postman, curl, or Thunder Client to test your API.
Example API Endpoints
GET /articles
? List allGET /articles/1
? Get onePOST /articles
? CreatePUT /articles/1
? UpdateDELETE /articles/1
? Delete