Routes
Modify main.go to add the CRUD routes for the Book
:
Add CRUD operations
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"literank.com/rest-books/model"
)
// Initialize a database instance
var db *gorm.DB
func main() {
// Create a new Gin router
r := gin.Default()
// Initialize database
initDB()
// Define a health endpoint handler
r.GET("/", func(c *gin.Context) {
// Return a simple response indicating the server is healthy
c.JSON(http.StatusOK, gin.H{
"status": "ok",
})
})
r.GET("/books", getBooks)
r.GET("/books/:id", getBook)
r.POST("/books", createBook)
r.PUT("/books/:id", updateBook)
r.DELETE("/books/:id", deleteBook)
// Run the server on port 8080
r.Run(":8080")
}
// Initialize database
func initDB() {
// Open SQLite database
var err error
db, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// Auto Migrate
db.AutoMigrate(&model.Book{})
}
// Get all books
func getBooks(c *gin.Context) {
var books []model.Book
db.Find(&books)
c.JSON(http.StatusOK, books)
}
// Get single book
func getBook(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var book model.Book
if err := db.First(&book, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
return
}
c.JSON(http.StatusOK, book)
}
// Create a new book
func createBook(c *gin.Context) {
var reqBody model.Book
if err := c.ShouldBindJSON(&reqBody); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.Create(&reqBody)
c.JSON(http.StatusCreated, reqBody)
}
// Update an existing book
func updateBook(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var book model.Book
if err := db.First(&book, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
return
}
var reqBody model.Book
if err := c.ShouldBindJSON(&reqBody); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.Model(&book).Updates(&reqBody)
c.JSON(http.StatusOK, book)
}
// Delete an existing book
func deleteBook(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var book model.Book
if err := db.First(&book, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
return
}
db.Delete(&book)
c.JSON(http.StatusNoContent, nil)
}
At this point, we use a local SQLite
1 database for demo purpose.
GORM(gorm.io/gorm
) stands for "Go ORM," is a popular Object-Relational Mapping library for Golang. It provides a convenient way to interact with databases.
Try with curl
Create a new book:
curl -X POST \
http://localhost:8080/books \
-H 'Content-Type: application/json' \
-d '{
"title": "Sample Book",
"author": "John Doe",
"published_at": "2023-01-01",
"description": "A sample book description",
"isbn": "1234567890",
"total_pages": 200
}'
It should respond with this:
{"id":1,"title":"Sample Book","author":"John Doe","published_at":"2023-01-01","description":"A sample book description","isbn":"1234567890","total_pages":200,"created_at":"2023-11-01T00:00:00Z","updated_at":"2023-11-01T00:00:00Z"}
Fetch a single book by ID:
curl -X GET http://localhost:8080/books/1
Result:
{
"id": 1,
"title": "Sample Book",
"author": "John Doe",
"published_at": "2023-01-01",
"description": "A sample book description",
"isbn": "1234567890",
"total_pages": 200,
"created_at": "2023-11-01T00:00:00Z",
"updated_at": "2023-11-01T00:00:00Z"
}
List all books:
curl -X GET http://localhost:8080/books
Result list:
[
{
"id": 1,
"title": "Sample Book",
"author": "John Doe",
"published_at": "2023-01-01T00:00:00Z",
"description": "A sample book description",
"isbn": "1234567890",
"total_pages": 200,
"created_at": "2024-02-23T22:19:55.263649+08:00",
"updated_at": "2024-02-23T22:19:55.263649+08:00"
},
{
"id": 2,
"title": "Great Book",
"author": "Rob Smith",
"published_at": "2022-01-01T00:00:00Z",
"description": "Another sample book description",
"isbn": "8334567890",
"total_pages": 3880,
"created_at": "2024-02-23T22:25:55.067976+08:00",
"updated_at": "2024-02-23T22:25:55.067976+08:00"
}
]
Update an existing book
curl -X PUT \
http://localhost:8080/books/1 \
-H 'Content-Type: application/json' \
-d '{
"title": "Updated Book Title",
"author": "Jane Smith"
}'
Result:
{
"id": 1,
"title": "Updated Book Title",
"author": "Jane Smith",
"published_at": "2023-01-01T00:00:00Z",
"description": "A sample book description",
"isbn": "1234567890",
"total_pages": 200,
"created_at": "2024-02-23T22:19:55.263649+08:00",
"updated_at": "2024-02-23T22:32:55.881294+08:00"
}
Delete an existing book:
curl -X DELETE http://localhost:8080/books/1
It returns code 204 for a sucessful deletion.
The REST api server has formed its basic shape now. Not bad!
Footnotes
-
SQLite: https://www.sqlite.org/index.html ↩