In this tutorial, you’ll learn how to build a CRUD (Create, Read, Update, Delete) REST API using Golang and MongoDB. We’ll walk you through each step of setting up a Go project, interacting with a MongoDB database, and testing your API with Postman. This tutorial is ideal for both beginners and experienced developers looking to expand their knowledge of Golang and MongoDB integration.
Prerequisites
Before we start, ensure you have the following tools and software installed:
- Go (Golang) – Ensure that the latest version of Go is installed.
- MongoDB – MongoDB should be installed and running.
- Postman – A tool for testing APIs.
Step 1: Set Up Your Go Project
Start by creating a directory for your project and initializing the Go module:
mkdir go-crud-api-mongodb
cd go-crud-api-mongodb
go mod init go-crud-api-mongodb
This sets up a new Go module, which allows you to manage your project dependencies easily.
Step 2: Install Required Packages
Install the required Go packages for MongoDB and HTTP request handling:
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/mongo/options
go get github.com/gorilla/mux
go.mongodb.org/mongo-driver/mongo
: Official MongoDB driver for Go.github.com/gorilla/mux
: A powerful routing library for creating APIs in Go.
Step 3: Set Up the MongoDB Database
3.1 Create a Database and Collection
Start MongoDB and create a new database called go_crud_api
and a collection called users
:
use go_crud_api;
db.createCollection("users");
This will serve as the collection where we’ll store user data.
Step 4: Create the Main Application File
Create a file called main.go
to define the structure of the Go web application:
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// User represents the model for our resource
type User struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Name string `json:"name,omitempty" bson:"name,omitempty"`
Email string `json:"email,omitempty" bson:"email,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"`
}
var client *mongo.Client
func main() {
// Initialize MongoDB client
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
client, _ = mongo.Connect(ctx, clientOptions)
router := mux.NewRouter()
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")
log.Fatal(http.ListenAndServe(":8000", router))
}
Explanation of the Code
- MongoDB Connection: We connect to MongoDB using
mongo.Connect()
and specify a 10-second timeout. - Router Setup: We use Gorilla Mux to define the routes for each API endpoint.
- CRUD Endpoints:
/users
: Fetch all users./user/{id}
: Fetch a user by ID./user
: Create a new user./user/{id}
: Update a user by ID./user/{id}
: Delete a user by ID.
Step 5: Implement CRUD Operations
5.1 Fetch All Users
users
collection and encodes them as JSON.func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var users []User
collection := client.Database("go_crud_api").Collection("users")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
cursor, err := collection.Find(ctx, bson.M{})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var user User
cursor.Decode(&user)
users = append(users, user)
}
json.NewEncoder(w).Encode(users)
}
5.2 Fetch a Single User by ID
users
collection and returns it as JSON. If no user is found, it returns a 404 error.func getUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
id, _ := primitive.ObjectIDFromHex(params["id"])
var user User
collection := client.Database("go_crud_api").Collection("users")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := collection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(user)
}
5.3 Create a New User
users
collection, and returns the newly created user as JSON.func createUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var user User
_ = json.NewDecoder(r.Body).Decode(&user)
user.ID = primitive.NewObjectID()
user.CreatedAt = time.Now()
collection := client.Database("go_crud_api").Collection("users")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err := collection.InsertOne(ctx, user)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(user)
}
5.4 Update an Existing User
users
collection by their ID and returns the updated user as JSON.func updateUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
id, _ := primitive.ObjectIDFromHex(params["id"])
var user User
_ = json.NewDecoder(r.Body).Decode(&user)
collection := client.Database("go_crud_api").Collection("users")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
update := bson.M{
"$set": user,
}
_, err := collection.UpdateOne(ctx, bson.M{"_id": id}, update)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
user.ID = id
json.NewEncoder(w).Encode(user)
}
5.5 Delete a User
users
collection by their ID and returns a 204 No Content status on success.func deleteUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
id, _ := primitive.ObjectIDFromHex(params["id"])
collection := client.Database("go_crud_api").Collection("users")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err := collection.DeleteOne(ctx, bson.M{"_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 API endpoints using Postman with the following requests:
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 (JSON):
{ "name": "John Doe", "email": "john@example.com" }
- Method:
Update an Existing User
- Method:
PUT
- URL:
http://localhost:8000/user/{id}
- Body (JSON):
{ "name": "John Doe", "email": "john@example.com" }
- Method:
- Delete a User
- Method:
DELETE
- URL:
http://localhost:8000/user/{id}
- Method:
Best Practices
- Error Handling: Implement comprehensive error handling and return appropriate HTTP status codes.
- Input Validation: Validate user input before interacting with MongoDB to maintain data integrity.
- Logging: Integrate logging to capture useful information for debugging and monitoring.
- Environment Variables: Use environment variables to store sensitive information like MongoDB URIs.
Conclusion
In this tutorial, you learned how to create a Golang CRUD REST API that interacts with MongoDB. We covered the project setup, API creation, and tested the APIs using Postman. You can extend this example by adding features like authentication, more complex queries, and additional validations.
Comments
Post a Comment