DEV Community

Cover image for Golang for Web (Part-II): Gofiber REST API + Mongo DB Atlas
Smruti Ranjan Rana
Smruti Ranjan Rana

Posted on • Updated on

Golang for Web (Part-II): Gofiber REST API + Mongo DB Atlas

Here is our second part of the Golang for Web series. In this article, we will see how we can add database to our app to store our todos.
Before that if you didn't follow the first part of this series, check that here.

If you've done that, let's dive into our code.

What will we build? 🤔

We will continue our Todo application from our first part of this series. Here we will add Mongo DB as our database to store our todos.

Prerequisites 📝

  • A basic knowledge of Golang syntax.
  • Go version 1.14 or above installed on your machine. Install from here
  • Postman or any other related app installed on your machine. Download Postman
  • Part-I of this project. Clone the project from here

If you have these, Let's get started 🚀

Let's Begin

Let’s Begin 🏁

1. Setup our Project

First, Let's open our previous project in our VS Code (or any other Code Editor/ IDE).

Now, run the below command to install all the dependencies.

go get
Enter fullscreen mode Exit fullscreen mode

Let's install mongo-driver for Mongo DB and godotenv to manage environment variables.

go get -u go.mongodb.org/mongo-driver github.com/joho/godotenv
Enter fullscreen mode Exit fullscreen mode

Now, create models, config directories, and .env file in our root directory.

Our root directory will look like this:

.
|____config
|____controllers
| |____todo.go
|____models
|____routes
| |____todo.go
|____.env
|____go.mod
|____go.sum
|____main.go
Enter fullscreen mode Exit fullscreen mode

2. Setup Mongo DB

Let's create an account at https://www.mongodb.com/ or you can sign in to your existing account.

Now create a new project, named gofiber-todo-api (or anything you want) and build a cluster.

Wait some time, while mongo db is creating a cluster for you.

Waiting

Now click on connect
Then, add a database user and choose Allow Acess from Anywhere under Add a connection IP address and click on Add IP Address
Add IP Address

Then choose Connect your application under connection method. Choose Go from the driver dropdown and 1.4 or later from the version dropdown.

Connection

Now copy that connection string. and paste it in .env file like below.

MONGO_URI=mongodb+srv://<dbUser>:<password>@cluster0.oynlp.mongodb.net/<dbname>?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

Here replace <dbUser> with your database username, <password> with your user password, and <dbname> with a database name.

Additionally, add another two variables in .env file as below.

DATABASE_NAME=<dbname>
TODO_COLLECTION=todos
Enter fullscreen mode Exit fullscreen mode

Here DATABASE_NAME is same as <dbname> in the MONGO_URI.

3. Configure Mongo DB

Let's create a db.go file inside config directory.

Now declare the package and import our required imports as below.

config/db.go will look like :

package config

import (
    "context"
    "log"
    "os"
    "time"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)
Enter fullscreen mode Exit fullscreen mode

Then add MongoInstance as below.

// MongoInstance : MongoInstance Struct
type MongoInstance struct {
    Client *mongo.Client
    DB     *mongo.Database
}

// MI : An instance of MongoInstance Struct
var MI MongoInstance
Enter fullscreen mode Exit fullscreen mode

config/db.go will look like :

package config

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)

// MongoInstance : MongoInstance Struct
type MongoInstance struct {
    Client *mongo.Client
    DB     *mongo.Database
}

// MI : An instance of MongoInstance Struct
var MI MongoInstance
Enter fullscreen mode Exit fullscreen mode

Now let's create a ConnectDB() method with all the connection configuration.

// ConnectDB - database connection
func ConnectDB() {
    client, err := mongo.NewClient(options.Client().ApplyURI(os.Getenv("MONGO_URI")))
    if err != nil {
        log.Fatal(err)
    }

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    err = client.Connect(ctx)
    if err != nil {
        log.Fatal(err)
    }

    err = client.Ping(ctx, readpref.Primary())
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Database connected!")

    MI = MongoInstance{
        Client: client,
        DB:     client.Database(os.Getenv("DATABASE_NAME")),
    }
}

Enter fullscreen mode Exit fullscreen mode

Let's go to main.go and import the following packages

import (
    "log" // new

    "github.com/devsmranjan/golang-fiber-basic-todo-app/config" // new
    "github.com/devsmranjan/golang-fiber-basic-todo-app/routes"
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/logger"
    "github.com/joho/godotenv" // new
)
Enter fullscreen mode Exit fullscreen mode

Inside the main() initiate dotenv like below.

// dotenv
err := godotenv.Load()
if err != nil {
    log.Fatal("Error loading .env file")
}
Enter fullscreen mode Exit fullscreen mode

and call the db configuration method ConnectDB()

// config db
config.ConnectDB()
Enter fullscreen mode Exit fullscreen mode

Now our main() will look like :

func main() {
    app := fiber.New()
    app.Use(logger.New())

    // dotenv
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }

    // config db
    config.ConnectDB()

    // setup routes
    setupRoutes(app)

    // Listen on server 8000 and catch error if any
    err = app.Listen(":8000")

    // handle error
    if err != nil {
        panic(err)
    }
}
Enter fullscreen mode Exit fullscreen mode

Now let's run our app

go run main.go
Enter fullscreen mode Exit fullscreen mode

You will get output like below

Database connected!

 ┌───────────────────────────────────────────────────┐
 │                    Fiber v2.2.0                   │
 │               http://127.0.0.1:8000               │
 │                                                   │
 │ Handlers ............ 12  Threads ............. 4 │
 │ Prefork ....... Disabled  PID ............. 55680 │
 └───────────────────────────────────────────────────┘

Enter fullscreen mode Exit fullscreen mode

It means our database successfully connected.

Additional: To reload the server automatically, you can install air globally in your machine.

Now to run our app, in your root directory run

air
Enter fullscreen mode Exit fullscreen mode

or for debug mode, you can run

air -d
Enter fullscreen mode Exit fullscreen mode

4. Create Model

Now create a file named todo.go inside models directory.
And create our Todo like below

package models

import (
    "time"
)

// Todo - todo model
type Todo struct {
    ID        *string   `json:"id,omitempty" bson:"_id,omitempty"`
    Title     *string   `json:"title"`
    Completed *bool     `json:"completed"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

Enter fullscreen mode Exit fullscreen mode

5. Connect Database with Controllers

Now go to controllers/todo.go and remove the following code first.

- // Todo : todo model
- type Todo struct {
-   ID        int    `json:"id"`
-   Title     string `json:"title"`
-   Completed bool   `json:"completed"`
- }
-
- var todos = []*Todo{
-   {
-       ID:        1,
-       Title:     "Walk the dog 🦮",
-       Completed: false,
-   },
-   {
-       ID:        2,
-       Title:     "Walk the cat 🐈",
-       Completed: false,
-   },
- }
Enter fullscreen mode Exit fullscreen mode

And let's import required packages

import (
    "os" // new
    "strconv"

    "github.com/devsmranjan/golang-fiber-basic-todo-app/config" // new
    "github.com/devsmranjan/golang-fiber-basic-todo-app/models" // new
    "github.com/gofiber/fiber/v2"
    "go.mongodb.org/mongo-driver/bson" // new
    "go.mongodb.org/mongo-driver/bson/primitive" // new
    "go.mongodb.org/mongo-driver/mongo" // new
)

Enter fullscreen mode Exit fullscreen mode

5.1 - GetTodos()

+   todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))
+
+   // Query to filter
+   query := bson.D{{}}
+
+   cursor, err := todoCollection.Find(c.Context(), query)
+
+   if err != nil {
+       return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
+           "success": false,
+           "message": "Something went wrong",
+           "error":   err.Error(),
+       })
+   }
+
+   var todos []models.Todo = make([]models.Todo, 0)
+
+   // iterate the cursor and decode each item into a Todo
+   err = cursor.All(c.Context(), &todos)
+   if err != nil {
+       return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
+           "success": false,
+           "message": "Something went wrong",
+           "error":   err.Error(),
+       })
+   }

    return c.Status(fiber.StatusOK).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todos": todos,
        },
    })
Enter fullscreen mode Exit fullscreen mode

Now the GetTodos() will look like:

// GetTodos : get all todos
func GetTodos(c *fiber.Ctx) error {
    todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // Query to filter
    query := bson.D{{}}

    cursor, err := todoCollection.Find(c.Context(), query)

    if err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
            "success": false,
            "message": "Something went wrong",
            "error":   err.Error(),
        })
    }

    var todos []models.Todo = make([]models.Todo, 0)

    // iterate the cursor and decode each item into a Todo
    err = cursor.All(c.Context(), &todos)
    if err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
            "success": false,
            "message": "Something went wrong",
            "error":   err.Error(),
        })
    }

    return c.Status(fiber.StatusOK).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todos": todos,
        },
    })
}

Enter fullscreen mode Exit fullscreen mode

5.2 - CreateTodo()

+   todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))
+
-   type Request struct {
-       Title string `json:"title"`
-   }
-
-   var data Request
+
+   data := new(models.Todo)

    err := c.BodyParser(&body)

    // if error
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse JSON",
            "error":   err,
        })
    }
-
-   // create a todo variable
-   todo := &Todo{
-       ID:        len(todos) + 1,
-       Title:     body.Title,
-       Completed: false,
-   }
-
-   // append in todos
-   todos = append(todos, todo)
-
+   data.ID = nil
+   f := false
+   data.Completed = &f
+   data.CreatedAt = time.Now()
+   data.UpdatedAt = time.Now()
+
+   result, err := todoCollection.InsertOne(c.Context(), data)
+
+   if err != nil {
+       return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
+           "success": false,
+           "message": "Cannot insert todo",
+           "error":   err,
+       })
+   }
+
+   // get the inserted data
+   todo := &models.Todo{}
+   query := bson.D{{Key: "_id", Value: result.InsertedID}}
+
+   todoCollection.FindOne(c.Context(), query).Decode(todo)

    return c.Status(fiber.StatusCreated).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todo": todo,
        },
    })

Enter fullscreen mode Exit fullscreen mode

Now CreateTodo() will look like:

// CreateTodo : Create a todo
func CreateTodo(c *fiber.Ctx) error {
    todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    data := new(models.Todo)

    err := c.BodyParser(&data)

    // if error
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse JSON",
            "error":   err,
        })
    }

    data.ID = nil
    f := false
    data.Completed = &f
    data.CreatedAt = time.Now()
    data.UpdatedAt = time.Now()

    result, err := todoCollection.InsertOne(c.Context(), data)

    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot insert todo",
            "error":   err,
        })
    }

    // get the inserted data
    todo := &models.Todo{}
    query := bson.D{{Key: "_id", Value: result.InsertedID}}

    todoCollection.FindOne(c.Context(), query).Decode(todo)

    return c.Status(fiber.StatusCreated).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todo": todo,
        },
    })
}
Enter fullscreen mode Exit fullscreen mode

5.3 - GetTodo()

+   todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // get parameter value
    paramID := c.Params("id")

    // convert parameter value string to int
-   id, err := strconv.Atoi(paramID)
+   id, err := primitive.ObjectIDFromHex(paramID)

    // if error in parsing string to int
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse Id",
            "error":   err,
        })
    }

    // find todo and return
-   for _, todo := range todos {
-       if todo.ID == id {
-           return c.Status(fiber.StatusOK).JSON(fiber.Map{
-               "success": true,
-               "data": fiber.Map{
-                   "todo": todo,
-               },
-           })
-       }
-   }
-
-   // if todo not available
-   return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-       "success": false,
-       "message": "Todo not found",
-   })
+
+   todo := &models.Todo{}
+
+   query := bson.D{{Key: "_id", Value: id}}
+
+   err = todoCollection.FindOne(c.Context(), query).Decode(todo)
+
+   if err != nil {
+       return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
+           "success": false,
+           "message": "Todo Not found",
+           "error":   err,
+       })
+   }
+
+   return c.Status(fiber.StatusOK).JSON(fiber.Map{
+       "success": true,
+       "data": fiber.Map{
+           "todo": todo,
+       },
+   })
Enter fullscreen mode Exit fullscreen mode

Now GetTodo() will look like:

// GetTodo : get a single todo
// PARAM: id
func GetTodo(c *fiber.Ctx) error {
    todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // get parameter value
    paramID := c.Params("id")

    // convert parameterID to objectId
    id, err := primitive.ObjectIDFromHex(paramID)

    // if error while parsing paramID
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse Id",
            "error":   err,
        })
    }

    // find todo and return

    todo := &models.Todo{}

    query := bson.D{{Key: "_id", Value: id}}

    err = todoCollection.FindOne(c.Context(), query).Decode(todo)

    if err != nil {
        return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
            "success": false,
            "message": "Todo Not found",
            "error":   err,
        })
    }

    return c.Status(fiber.StatusOK).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todo": todo,
        },
    })
}
Enter fullscreen mode Exit fullscreen mode

5.4 - UpdateTodo()

+   todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // find parameter
    paramID := c.Params("id")

    // convert parameter string to int
-   id, err := strconv.Atoi(paramID)

    // if parameter cannot parse
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse id",
            "error":   err,
        })
    }
-
-   // request structure
-   type Request struct {
-       Title     *string `json:"title"`
-       Completed *bool   `json:"completed"`
-   }

    var data Request
    err = c.BodyParser(&data)

    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse JSON",
            "error":   err,
        })
    }
-
-   var todo *Todo
-
-   for _, t := range todos {
-       if t.ID == id {
-           todo = t
-           break
-       }
-   }
-
-   if todo.ID == 0 {
-       return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-           "success": false,
-           "message": "Not found",
-       })
-   }
+
+   query := bson.D{{Key: "_id", Value: id}}
+
+   // updateData
+   var dataToUpdate bson.D

    if data.Title != nil {
-       todo.Title = *data.Title
+       dataToUpdate = append(dataToUpdate, bson.E{Key: "title", Value: data.Title})
    }

    if data.Completed != nil {
-       todo.Completed = *data.Completed
+       dataToUpdate = append(dataToUpdate, bson.E{Key: "completed", Value: data.Completed})
    }
+
+    dataToUpdate = append(dataToUpdate, bson.E{Key: "updatedAt", Value: time.Now()})
+
+   update := bson.D{
+       {Key: "$set", Value: dataToUpdate},
+   }
+
+   // update
+   err = todoCollection.FindOneAndUpdate(c.Context(), query, update).Err()
+
+   if err != nil {
+       if err == mongo.ErrNoDocuments {
+           return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
+               "success": false,
+               "message": "Todo Not found",
+               "error":   err,
+           })
+       }
+
+       return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
+           "success": false,
+           "message": "Cannot update todo",
+           "error":   err,
+       })
+   }
+
+   // get updated data
+   todo := &models.Todo{}
+
+   todoCollection.FindOne(c.Context(), query).Decode(todo)

    return c.Status(fiber.StatusOK).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todo": todo,
        },
    })

Enter fullscreen mode Exit fullscreen mode

Now UpdateTodo() will look like:

// UpdateTodo : Update a todo
// PARAM: id
func UpdateTodo(c *fiber.Ctx) error {
    todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // find parameter
    paramID := c.Params("id")

    // convert parameterID to objectId
    id, err := primitive.ObjectIDFromHex(paramID)

    // if parameter cannot parse
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse id",
            "error":   err,
        })
    }

    // var data Request
    data := new(models.Todo)
    err = c.BodyParser(&data)

    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse JSON",
            "error":   err,
        })
    }

    query := bson.D{{Key: "_id", Value: id}}

    // updateData
    var dataToUpdate bson.D

    if data.Title != nil {
        // todo.Title = *data.Title
        dataToUpdate = append(dataToUpdate, bson.E{Key: "title", Value: data.Title})
    }

    if data.Completed != nil {
        // todo.Completed = *data.Completed
        dataToUpdate = append(dataToUpdate, bson.E{Key: "completed", Value: data.Completed})
    }

    dataToUpdate = append(dataToUpdate, bson.E{Key: "updatedAt", Value: time.Now()})

    update := bson.D{
        {Key: "$set", Value: dataToUpdate},
    }

    // update
    err = todoCollection.FindOneAndUpdate(c.Context(), query, update).Err()

    if err != nil {
        if err == mongo.ErrNoDocuments {
            return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
                "success": false,
                "message": "Todo Not found",
                "error":   err,
            })
        }

        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot update todo",
            "error":   err,
        })
    }

    // get updated data
    todo := &models.Todo{}

    todoCollection.FindOne(c.Context(), query).Decode(todo)

    return c.Status(fiber.StatusOK).JSON(fiber.Map{
        "success": true,
        "data": fiber.Map{
            "todo": todo,
        },
    })
}
Enter fullscreen mode Exit fullscreen mode

5.5 - DeleteTodo()

+   todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // get param
    paramID := c.Params("id")
-
-   // convert param string to int
+   // convert parameter to object id
-   id, err := strconv.Atoi(paramID)
+   id, err := primitive.ObjectIDFromHex(paramID)

    // if parameter cannot parse
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse id",
            "error":   err,
        })
    }

    // find and delete todo
-   for i, todo := range todos {
-       if todo.ID == id {
-
-           todos = append(todos[:i], todos[i+1:]...)
-
-           return c.SendStatus(fiber.StatusNoContent)
-       }
-   }
+
+   query := bson.D{{Key: "_id", Value: id}}
+
+   err = todoCollection.FindOneAndDelete(c.Context(), query).Err()
+
+   if err != nil {
+       if err == mongo.ErrNoDocuments {
+           return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
+               "success": false,
+               "message": "Todo Not found",
+               "error":   err,
+           })
+       }
+
+       return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
+           "success": false,
+           "message": "Cannot delete todo",
+           "error":   err,
+       })
+   }
-
-   // if todo not found
-   return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-       "success": false,
-       "message": "Todo not found",
-   })
+
+    return c.SendStatus(fiber.StatusNoContent)
Enter fullscreen mode Exit fullscreen mode

Now DeleteTodo() will look like:

// DeleteTodo : Delete a todo
// PARAM: id
func DeleteTodo(c *fiber.Ctx) error {
    todoCollection := config.MI.DB.Collection(os.Getenv("TODO_COLLECTION"))

    // get param
    paramID := c.Params("id")

    // convert parameter to object id
    id, err := primitive.ObjectIDFromHex(paramID)

    // if parameter cannot parse
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot parse id",
            "error":   err,
        })
    }

    // find and delete todo
    query := bson.D{{Key: "_id", Value: id}}

    err = todoCollection.FindOneAndDelete(c.Context(), query).Err()

    if err != nil {
        if err == mongo.ErrNoDocuments {
            return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
                "success": false,
                "message": "Todo Not found",
                "error":   err,
            })
        }

        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "success": false,
            "message": "Cannot delete todo",
            "error":   err,
        })
    }

    return c.SendStatus(fiber.StatusNoContent)
}
Enter fullscreen mode Exit fullscreen mode

Awesome !!! We did great so far. 🤝

6. Test our endpoints 🧪

Let's test our API in Postman. Before that don't forget to run the server.

To get all Todos, give a GET request to localhost:8000/api/todos

Get all todos

To create a new todo, give a POST request to localhost:8000/api/todos with a title: <String> in the request body.

New Todo

Now, you can add more todos like:

  • Play Cricket 🏏
  • Watch WandaVision 🍿

Let's get all our todos again.
All todos

Yaaahooooo! Isn't this amazing? 🤩

Yes

Now, to get todo by id, give a GET request to localhost:8000/api/todos/:id
Here replace :id with a todo id.

Get single todo

Now, let's update a todo by giving a PUT request to localhost:8000/api/todos/:id with a title: <String> or completed: <Boolean> or both in the request body.
Here replace :id with a todo id.

Update todo

To delete a todo, give a DELETE request to localhost:8000/api/todos/:id
Here replace :id with a todo id.

Delete Todo

Congratulations 🥳 🥳 🥳 We did it 💪🏻

Woohoo!

Conclusion 📋

For more information about gofiber, I suggest taking a deeper look at the documentation here https://docs.gofiber.io/

Mongo DB official documentation.

Here is my GitHub link to this project - https://github.com/devsmranjan/golang-fiber-basic-todo-app/

Thank you for reading my article 🙂 . I hope you have learned something here.

If you want to improve this project, fork the repo here.

Happy coding 👨‍💻👩‍💻 and stay tuned for my next post in this series!

Thanks! Don't forget to give a ♥️ and follow :)

Top comments (3)

Collapse
 
balasaptanglabs profile image
bala-murugan • Edited

very good tutorial , but there is a change , while creating
type Todo struct {
ID *string
json:"id,omitempty" bson:"_id,omitempty"
Title *string
json:"title"
Completed *bool
json:"completed"
CreatedAt time.Time
json:"createdAt"
UpdatedAt time.Time
json:"updatedAt"
}

at the backend , mongo db reads it as createdAt, updated at (by making it all small letters)-> i have checked this in atlas, so we can put
type Todo struct {
Id *string
json:"id,omitempty" bson:"_id,omitempty"
Title *string
json:"title" bson:"title"
Completed *bool
json:"completed" bson:"completed"
CreatedAt time.Time
json:"createdAt" bson:"createdAt"
UpdateAt time.Time
json:"updatedAt" bson:"updatedAt"
}

this case problem occurs when you are editing , because at the update function we are using dataToUpdate = append(dataToUpdate, bson.E{Key: "updatedAt", Value: time.Now()})
, this will led to error(creates a new field "updateAt") if we dont manually give as bson

Collapse
 
auleki profile image
auleki

Lovely tutorials, you've brought me closer to understanding Go!

Collapse
 
codenoid_ profile image
codenoid_

Awesome, thankyou

Ummm, could you make the Gin tutorial?