Creating a CRUD application using GO and MongoDB
Recently I was going through some videos on www.youtube.com and a link popped up as ”HOT UPCOMING LANGUAGES in 2020". Out of curiosity I opened it and got to know about GO. After reading about it, I decided to give it a try and Voila!!!. It was FUN :).
So I tried to demonstrate CRUD operations through this post, keeping it as simple as I can. So let's GO…
The first step would be to install the MongoDB driver using go get
i.e
go get github.com/mongodb/mongo-go-driver
There might be a warning displaying something likepackage go.mongodb.org/mongo-driver: no Go files in (...)
. Don’t PANIC. This is expected output from go get
.
I’ve created three files named main.go ,db.go and controllers.go.
in /src folder under the directory mongoCRUD.
So the structure looks like
src/
mongoCRUD/
main.go # main file containing routes
db.go #for Database connection
controllers.go #Handelers for routes
Let’s go to the anatomy of files one by one, starting with main.go
package mainimport (
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
route := mux.NewRouter()s := route.PathPrefix("/api").Subrouter() //Base Path//Routess.HandleFunc("/createProfile", createProfile).Methods("POST")
s.HandleFunc("/getAllUsers", getAllUsers).Methods("GET")
s.HandleFunc("/getUserProfile", getUserProfile).Methods("POST")
s.HandleFunc("/updateProfile", updateProfile).Methods("PUT")
s.HandleFunc("/deleteProfile/{id}", deleteProfile).Methods("DELETE")log.Fatal(http.ListenAndServe(":8000", s)) // Run Server
}
I’ve used packagegorilla/mux
which implements a request router and dispatcher for matching incoming requests to their respective handlers.HandleFunc
registers a new route with a matcher for the URL path.
db.go
package mainimport (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)func db() *mongo.Client {clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")// Connect to //MongoDBclient, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}// Check the connection
err = client.Ping(context.TODO(), nil)if err != nil {
log.Fatal(err)
}fmt.Println("Connected to MongoDB!")
return client
}
A connection is set up using mongo.Connect(context.TODO(), clientOptions)
.Package context
tells about like deadlines, cancellation signals.Further TODO()
is used when it’s unclear which Context to use or it is not available.clientOptions
contains options like pool size,authentication.In the end client
returns *mongo.Client
which will be used to access different collections.
Now we will go through each function of controllers.go
.But before that, we will be accessing users collection as
var userCollection = db().Database("goTest").Collection("users")
where db()
contains the *mongo.Client
from db.go. Besides we have used user
struct to store information.
type user struct{
Name string `json:"name"`
City string `json:"city"`
Age int `json:"age"`
}
CREATE
func createProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json") // for adding //Content-typevar person usererr := json.NewDecoder(r.Body).Decode(&person) // storing in person //variable of type userif err != nil {fmt.Print(err)}insertResult, err := userCollection.InsertOne(context.TODO(),person)
if err != nil {
log.Fatal(err)
}json.NewEncoder(w).Encode(insertResult.InsertedID) // return the //mongodb ID of generated document}
READ
func getUserProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")var body usere := json.NewDecoder(r.Body).Decode(&body)if e != nil {
fmt.Print(e)
}var result primitive.M // an unordered representation of a BSON //document which is a Maperr := userCollection.FindOne(context.TODO(), bson.D{{"name", body.Name}}).Decode(&result)if err != nil {
fmt.Println(err)
}
json.NewEncoder(w).Encode(result) // returns a Map containing //mongodb document
}
UPDATE
func updateProfile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")type updateBody struct {
Name string `json:"name"` //value that has to be matched
City string `json:"city"` // value that has to be modified
}var body updateBody
e := json.NewDecoder(r.Body).Decode(&body)
if e != nil {
fmt.Print(e)
}filter := bson.D{{"name", body.Name}} // converting value to BSON after := options.After // for returning updated document returnOpt := options.FindOneAndUpdateOptions{
ReturnDocument: &after,
}update := bson.D{{"$set", bson.D{{"city", body.City}}}}updateResult := userCollection.FindOneAndUpdate(context.TODO(), filter, update, &returnOpt)var result primitive.M_ = updateResult.Decode(&result)json.NewEncoder(w).Encode(result)
}
DELETE
func deleteProfile(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)["id"] //get Parameter value as string_id, err := primitive.ObjectIDFromHex(params) // convert params to //mongodb Hex IDif err != nil {
fmt.Printf(err.Error())
}opts := options.Delete().SetCollation(&options.Collation{}) // to //specify language-specific rules for string comparison, such as //rules for lettercaseres, err := userCollection.DeleteOne(context.TODO(), bson.D{{"_id", _id}}, opts)if err != nil {
log.Fatal(err)
}json.NewEncoder(w).Encode(res.DeletedCount) // return number of //documents deleted}
In the end run the application using go run *go
.
Here is git repository for the whole code. I hope this tutorial was useful to get some insights into CRUD application.
Get here POSTMAN import link for APIs.
References :
- https://github.com/gorilla/mux
- https://www.mongodb.com/blog/post/mongodb-go-driver-tutorial
- https://godoc.org/go.mongodb.org/mongo-driver/mongo
PS: This is my first article. So any changes or suggests are heartly welcomed.