Welcome to this lesson, where we will focus on handling PUT and DELETE requests to update and delete resources in a web application using the Gin framework. In previous lessons, you've become familiar with setting up a Gin application and handling GET and POST requests. As a quick reminder, Gin is a popular framework in the Go language used to build web applications and APIs efficiently.
Before we dive into the examples, let's briefly go over what PUT and DELETE HTTP methods entail. As part of the fundamentals of building RESTful APIs, these methods play a critical role:
-
PUT: This method is used to update existing resources. For instance, if your to-do app has a task with certain attributes, using a PUT request, you can change those attributes to different values.
-
DELETE: This method is used to remove resources. When a task is completed and no longer needed in your to-do list, a DELETE request will remove it.
Understanding these methods is crucial as they allow you to modify the state of resources within your web application.
To handle a PUT request that updates a todo item by its ID, you'll need to understand what kind of data is being sent. Here's an example JSON body that you might send with a PUT request to update a todo item:
JSON1{ 2 "title": "Learn HTTP Methods", 3 "completed": false 4}
This JSON object represents a todo item with the title
attribute and a completed
status. These are the fields that can be updated.
Let’s look at the code to implement this:
router.go
:
Go1package router 2 3import ( 4 "github.com/gin-gonic/gin" 5 6 "codesignal.com/todoapp/internal/controllers" 7) 8 9func SetupRouter() *gin.Engine { 10 r := gin.Default() 11 r.PUT("/api/todos/:id", controllers.UpdateTodo) 12 return r 13}
controllers.go
:
Go1package controllers 2 3import ( 4 "net/http" 5 "strconv" 6 7 "github.com/gin-gonic/gin" 8 9 "codesignal.com/todoapp/internal/models" 10 "codesignal.com/todoapp/internal/services" 11) 12 13var todos []models.Todo 14 15func UpdateTodo(c *gin.Context) { 16 id, err := strconv.Atoi(c.Param("id")) 17 if err != nil { 18 c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"}) 19 return 20 } 21 var updateData models.Todo 22 if err := c.ShouldBindJSON(&updateData); err != nil { 23 c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON"}) 24 return 25 } 26 if updatedTodo, err := services.UpdateTodoService(id, updateData, todos); err != nil { 27 c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"}) 28 } else { 29 c.JSON(http.StatusOK, updatedTodo) 30 } 31}
services.go
:
Go1package services 2 3import ( 4 "errors" 5 6 "codesignal.com/todoapp/internal/models" 7) 8 9func UpdateTodoService(id int, updateData models.Todo, todos []models.Todo) (*models.Todo, error) { 10 for i, todo := range todos { 11 if todo.ID == id { 12 todos[i].Title = updateData.Title 13 todos[i].Completed = updateData.Completed 14 return &todos[i], nil 15 } 16 } 17 return nil, errors.New("Todo not found") 18}
- Parsing the ID: The path parameter
:id
is extracted from the URL and converted to an integer. We handle any errors that might arise if the ID provided is invalid. - Binding JSON Data: The
c.ShouldBindJSON
method is used to bind the incoming JSON payload to theupdateData
variable, which is of typeTodo
. If this binding fails, due to invalid JSON format for instance, aBadRequest
response is returned. - Router Setup and Handler Function: We define the PUT route in the router setup. The route is connected to the
UpdateTodo
handler function, which handles the logic of managing HTTP status codes and binding JSON data. - Business Logic and Updating the Resource: The
UpdateTodoService
function in the business logic package is responsible for the actual updating of the todo item. It loops through thetodos
list to find the matchingTodo
by ID and updates theTitle
andCompleted
fields. - Response Handling: If the todo is successfully updated, the new data is sent back with a
StatusOK
response. If no matching todo is found, aNotFound
response is returned.
Now, we'll look at implementing a DELETE request to remove a todo item using its ID:
router.go
:
Go1package router 2 3import ( 4 "github.com/gin-gonic/gin" 5 6 "codesignal.com/todoapp/internal/controllers" 7) 8 9func SetupRouter() *gin.Engine { 10 r := gin.Default() 11 r.DELETE("/api/todos/:id", controllers.DeleteTodo) 12 return r 13}
controllers.go
:
Go1package controllers 2 3import ( 4 "net/http" 5 "strconv" 6 7 "github.com/gin-gonic/gin" 8 9 "codesignal.com/todoapp/internal/models" 10 "codesignal.com/todoapp/internal/services" 11) 12 13var todos []models.Todo 14 15func DeleteTodo(c *gin.Context) { 16 id, err := strconv.Atoi(c.Param("id")) 17 if err != nil { 18 c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"}) 19 return 20 } 21 if deletedTodo, err := services.DeleteTodoService(id, todos); err != nil { 22 c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"}) 23 } else { 24 c.JSON(http.StatusOK, deletedTodo) 25 } 26}
services.go
:
Go1package services 2 3import ( 4 "errors" 5 6 "codesignal.com/todoapp/internal/models" 7) 8 9func DeleteTodoService(id int, todos []models.Todo) (*models.Todo, error) { 10 for i, todo := range todos { 11 if todo.ID == id { 12 deletedTodo := todos[i] 13 todos = append(todos[:i], todos[i+1:]...) 14 return &deletedTodo, nil 15 } 16 } 17 return nil, errors.New("Todo not found") 18}
- Extracting and Validating the ID: Similar to PUT, the ID is extracted from the path and validated. Any errors in conversion result in a
BadRequest
response. - Router Setup and Handler Function: The DELETE route is defined in the router setup and linked to the
DeleteTodo
handler function. This function manages the removal process and returns appropriate HTTP status codes. - Finding and Removing the Resource: The
DeleteTodoService
function in the business logic package iterates through thetodos
list to find the todo with the matching ID and removes it from the slice using optimized slice operations. - Response Management: A successful deletion results in a
StatusOK
response with the removed todo. If the todo is not found, aNotFound
response is provided.
In this lesson, you learned how to handle PUT and DELETE requests with Gin. We explored how these HTTP methods work within RESTful APIs and walked through implementing them in code with practical examples. Understanding how to update and remove resources is fundamental as you continue to build dynamic web applications.
Get ready to apply what you've learned through upcoming practice exercises that will reinforce your understanding by implementing these techniques on your own. You are making excellent progress — keep experimenting and practicing to deepen your knowledge and skills further!