Building a RESTful API in Go with Gin Framework: CRUD Operations for a Recipe Management System
Introduction
This blog will guide you through building a RESTful API using the Gin framework in Golang to manage recipes and orders. We'll cover various CRUD operations like creating, reading, updating, and deleting orders. This API reads data from a JSON file, processes it, and returns or modifies it based on the API requests. If you're looking to create a lightweight, efficient, and easy-to-use API server in Go, this tutorial is for you.
Prerequisites
Before starting, ensure you have the following:
Go: Installed on your machine (version 1.16 or above recommended).
Gin Framework: A fast and lightweight web framework for building HTTP servers in Go.
Basic Go knowledge: Understanding of Go syntax and packages like
net/http
,encoding/json
, etc.
For the sake of simplicity i have coded api in one file but you can choose to take these into their specific modules and also you can add database of your own (here we have used json files)
Getting Started
Let's start by creating a new Go project. Initialize a new directory with go mod init your-module-name
.
go mod init recipe-api
Next, install the Gin framework:
go get -u github.com/gin-gonic/gin
Create a file named main.go
and paste the following code into it:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"github.com/gin-gonic/gin"
)
// MenuItem represents a single recipe item with its details
type MenuItem struct {
Item string `json:"item"`
Recipe string `json:"recipe"`
Price float64 `json:"price"`
}
// Order represents a customer's order, containing a list of item names
type Order struct {
Order []string `json:"orders"`
}
var total float64
// GetRecipes retrieves all available recipes from a JSON file
func GetRecipes(c *gin.Context) {
var items []MenuItem
data, err := ioutil.ReadFile("recipes.json")
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
if err = json.Unmarshal(data, &items); err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, items)
}
// CreateOrder processes a new order and calculates the total cost
func CreateOrder(c *gin.Context) {
var orders Order
if err := c.ShouldBindJSON(&orders); err != nil {
c.JSON(http.StatusBadGateway, gin.H{"Error": err.Error()})
return
}
var items []MenuItem
data, err := ioutil.ReadFile("recipes.json")
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
if err = json.Unmarshal(data, &items); err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
// Create a map to store item prices for quick lookup
priceMap := make(map[string]float64)
for _, item := range items {
priceMap[item.Item] = item.Price
}
// Calculate the total price
total = 0
for _, orderItem := range orders.Order {
if price, exists := priceMap[orderItem]; exists {
total += price
}
}
c.JSON(http.StatusOK, gin.H{
"total": total,
})
}
// UpdateOrder updates the current order by recalculating the total
func UpdateOrder(c *gin.Context) {
CreateOrder(c)
}
// GetOrder retrieves the current orders
func GetOrder(c *gin.Context) {
var orders *Order
c.JSON(http.StatusOK, gin.H{
"orders": orders,
})
}
// DeleteOrder removes an item from the order and recalculates the total
func DeleteOrder(c *gin.Context) {
var orders *Order
if orders == nil {
orders = &Order{}
}
// Get the item name from the URL parameter
itemToDelete, err := url.QueryUnescape(c.Param("item"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid item name"})
return
}
var index = -1
for i, orderItem := range orders.Order {
if orderItem == itemToDelete {
index = i
break
}
}
orders.Order = append(orders.Order[:index], orders.Order[index+1:]...)
var items []MenuItem
// Create a map to store item prices for quick lookup
priceMap := make(map[string]float64)
for _, item := range items {
priceMap[item.Item] = item.Price
}
c.JSON(http.StatusOK, gin.H{
"total": total,
})
}
// main sets up the routes and starts the Gin server
func main() {
routes := gin.Default()
routes.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "welcome to recipes api"})
})
routes.GET("/recipes", GetRecipes)
routes.POST("/orders", CreateOrder)
routes.PUT("/orders", UpdateOrder)
routes.DELETE("/orders/:item", DeleteOrder)
fmt.Println("server is running on port 8080...")
routes.Run(":8080")
}
Key Features
CRUD Operations: Create, read, update, and delete orders.
JSON Parsing: Efficiently handle JSON data using the
encoding/json
package.Error Handling: Properly handle errors to ensure the API is robust.
Gin Framework: A fast, lightweight web framework that simplifies HTTP handling in Go.
API Endpoints
GET /recipes: Retrieves all available recipes from
recipes.json
.POST /orders: Creates a new order and calculates the total price.
PUT /orders: Updates an existing order by recalculating the total price.
DELETE /orders/:item: Deletes an item from the order and updates the total.
Running the Application
- Ensure your
recipes.json
file is in the same directory asmain.go
. Here's an example of what your JSON file might look like:
[
{"item": "Pasta", "recipe": "Boil pasta and add sauce", "price": 10.99},
{"item": "Pizza", "recipe": "Bake pizza dough with toppings", "price": 15.99}
]
- Run the server:
go run main.go
- The server will start on
http://localhost:8080
. You can use tools like Postman or cURL to interact with the API.
Conclusion
Building a RESTful API with the Gin framework in Go is both straightforward and efficient. This tutorial provides a foundational example that you can expand upon to suit your specific requirements. Whether you're managing recipes or building another type of CRUD-based application, the principles covered here will serve as a solid starting point.
Subscribe to my newsletter
Read articles from Sundaram Kumar Jha directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Sundaram Kumar Jha
Sundaram Kumar Jha
I Like Building Cloud Native Stuff , the microservices, backends, distributed systemsand cloud native tools using Golang