Go and Gin: Building a Task Manager REST API

Zahid
8 min readJun 3, 2023

--

REST API with Go and Gin

In the fast-paced world of web development, REST APIs have become a fundamental building block of modern applications. Go, known for its simplicity and efficiency, has emerged as a favored language for building such APIs. When paired with the Gin framework, crafting powerful and efficient APIs becomes a streamlined process.

In this blog post, we will delve directly into into creating a REST API using Go and the Gin framework, using a Task Manager API project as an example. This post assumes that you are already familiar with the basic syntax of the Go language.

By the end of this guide, you will have a good understanding of how to design and implement your own APIs using these powerful tools.

We’ll cover everything from setting up your development environment, to routing and handling requests, and all the way through to refactoring code and testing your API using Postman.

Without further ado, let’s dive in!

1. Set up your development Environment

Install Go

You can install Go from the official Go website: https://go.dev/doc/install

2. Create the Project Structure

Create a project directory by using the command:

mkdir task_manager_api && cd task_manager_api

3. Create main.go File

In this step, we will create a main.go file and print the basic text "Task Manager API".

main.go

4. Execute the code

Run the code by using the Go command:

go run main.go

5. Check the Console Output

Task Manager API

6. Initialize the Module

Initialize the Go module for your project using the following command:

go mod init github.com/zaahidali/task_manager_api

7. Installing and Setting up Gin

To start working with Gin, you first need to install the package. You can install Gin by running the following command in your terminal:

go get -u github.com/gin-gonic/gin

After you’ve installed Gin, you can import it into your main.go file:

package main

import "github.com/gin-gonic/gin"

8. Creating Your First Route with Gin

Gin allows you to easily set up routes for your API. Here’s an example of how to set up a simple GET route:

Basic GET request Code

First, we create the router with gin.Default(), which sets up a basic routing engine with default middleware included.

Next, we register a GET route for /ping using router.GET("/ping", ...). When you navigate to http://localhost:8080/ping in your web browser, the server will respond with a JSON message {"message":"pong"}.

Finally, we run the router using router.Run(), which starts the server and listens for incoming requests on 0.0.0.0:8080.

9. Building Your Task Manager API

Now that we have covered the basics and have a clear understanding of the application, let’s delve into it.

The API that we build will supports the following operations:

  • GET /tasks: Get a list of all tasks.
  • GET /tasks/:id: Get the details of a specific task.
  • PUT /tasks/:id: Update a specific task. This endpoint accepts a JSON body with the new details of the task.
  • DELETE /tasks/:id: Delete a specific task.
  • POST /tasks: Create a new task. This endpoint accepts a JSON body with the task's title, description, due date, and status.

a. Define a Structure and Mock Data

In this section, we define the Task structure and initialize mock data to populate our task list.

b. Getting All Tasks (GET /tasks)

First, we will implement GET /tasks endpoint to return the slice of tasks

router.GET("/tasks", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"tasks": tasks})
})

c. Getting a Specific Task (GET /tasks/:id)

Next, we’ll implement the GET /tasks/:id endpoint for getting a specific task by ID.

To handle the GET /tasks/:id endpoint, we extract the path parameter :id from the URL using ctx.Param("id"). We then retrieve the corresponding task by comparing the ID with the tasks in our data source. If a match is found, we return the task details as JSON with status code 200 (OK). If no match is found, we respond with JSON and status code 404 (Not Found) to indicate that the task was not found.

d. Updating a Specific Task (PUT /tasks/:id)

Next, we will implement the PUT /tasks/:id endpoint, which will allow users to update a specific task.

This code snippet handles the PUT /tasks/:id endpoint. It extracts the :id path parameter, binds the JSON data to updatedTask, and performs the necessary updates based on the specified fields. It responds with appropriate JSON messages and status codes based on the outcome of the operation.

e. Deleting a Specific Task (DELETE /tasks/:id)

Next, we’ll write the code for DELETE /tasks/:id which allows user to deleting a task by ID.

This code snippet handles the DELETE /tasks/:id endpoint. It extracts the :id path parameter and searches for a matching task in the tasks slice. If a match is found, the task is removed from the slice using the append function to concatenate the tasks before and after the matched task. It responds with a JSON message indicating the successful removal of the task or a message stating that the task was not found, depending on the outcome of the operation.

f. Creating Tasks (POST /tasks)

Lastly, let’s write code for POST /tasks endpoint, which lets user to create a task. The handler function will read a new Task from the JSON body of the request, then save it to in-memory slice.

This code snippet handles the POST /tasks endpoint. It retrieves the JSON payload from the request body and binds it to a new Task struct using ctx.ShouldBindJSON. If there are any binding errors, it responds with a JSON message indicating the error and returns. Otherwise, it appends the new task to the tasks slice and responds with a JSON message indicating the successful creation of the task using the HTTP status code 201 (Created).

The final code of main.gowill look like this:

Basic REST API Code

10. Testing API Endpoints with Postman

In this section, we’ll utilize Postman, a VS Code extension, for testing our API endpoints. It will help us to easily send HTTP requests and inspect the responses. Let’s explore how to do this.

Postman extension for VS Code

But first, make sure you have run the following command

go run main.go

This command starts the Go application, allowing us to test the API endpoints. Now, let’s proceed with testing using Postman.

  1. Get All Tasks

In Postman, select the GET method and enter the URL http://localhost:8080/tasks. Click "Send" to see the list of all tasks in the response.

GET all tasks

2. Get a Specific Task

Select the GET method in Postman and enter http://localhost:8080/tasks/:id into the URL bar. Replace :id with the ID of the task you wish to retrieve (e.g., http://localhost:8080/tasks/1). Click "Send" and you should see the details of the requested task.

GET task by id

3. Remove a Task

To delete a task, select the DELETE method in Postman and enter http://localhost:8080/tasks/:id into the URL bar, replacing :id with the ID of the task you wish to delete. Click "Send". The response should confirm the successful deletion of the task.

DELETE a task by id

you can see that a task has been removed. We can verify it with GET /tasks request.

GET all tasks using GET /tasks

4. Update a Task

To update a task, choose the PUT method in Postman. In the URL bar, enter http://localhost:8080/tasks/:id, replacing :id with the ID of the task you want to update. In the "Body" tab, select "raw" and choose "JSON" from the dropdown menu. Enter the new details of the task in a JSON format, like this:

Update a task using PUT /tasks/:id

We can verify the updated task using GET tasks/:id

GET the updated task using GET tasks/:id

5. Add a new Task

For creating a new task, select the POST method in Postman. Enter http://localhost:8080/tasks into the URL bar. In the "Body" tab, select "raw" and choose "JSON" from the dropdown menu. Here, you'll need to input the new task's details in a JSON format, like this

Add a new task using POST /tasks

We can verify, if the task is properly created using GET /tasks

GET all tasks using GET /tasks

We have completed our testing and found that all our endpoints are returning the correct results. The next step is to refactor the code. We will dive into this in the next section.

11. Refactoring Code: Creating Separate Handler Functions

Let’s move forward to refactoring our code. Our first step will be to create separate functions for each handler, enhancing the readability and maintainability of our application. Let’s delve into this process.

Handlers
Refactored code

Final code

The final code of main.go will look like this:

Final Refactored code

You can find the final code at the following location:

If you find the code helpful, don’t forget to give it a star to show your support.

Let’s end this blog with a beautiful quote:

“The secret to getting ahead is getting started.” — Mark Twain

Final Notes / Extras

Please keep in mind the following important point:

Note:

  1. Data Persistence: Currently, the data in our Go application is not persistent. This means that if you exit the program and re-run it using go run main.go, all the operations you performed, such as adding new data or removing existing data, will be lost. In our blog post link to the blog post, we have addressed this issue and provided a solution for adding database support to our Task Manager REST API.

--

--

Zahid
Zahid

Written by Zahid

Full Stack Software Engineer | Active Learner

Responses (1)