Go back

Creating a CRUD API with Golang

Here’s a complete article for creating a CRUD API with Golang, formatted in Markdown with code blocks specifying folder paths.

Introduction

This guide walks you through building a simple CRUD (Create, Read, Update, Delete) API using Golang with the Gin framework and GORM for database interaction.

Project Structure

Here’s the folder structure for our project:

crud-api/ │ ├── cmd/ │ └── server/main.go │ ├── config/ │ └── config.go │ ├── models/ │ └── book.go │ ├── routes/ │ └── routes.go │ └── database/ └── database.go


## Step 1: Initialize the Project

First, create a new Go module and install the necessary dependencies.

```bash
go mod init crud-api
go get -u github.com/gin-gonic/gin
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

Step 2: Database Setup

database/database.go:

Set up the database connection and migrations using GORM.

package database

import (
    "log"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

var DB *gorm.DB

func ConnectDatabase() {
    var err error
    DB, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        log.Fatal("Failed to connect to database!", err)
    }
}

Step 3: Define the Model

models/book.go:

Define the Book model for storing data.

package models

import "gorm.io/gorm"

type Book struct {
    gorm.Model
    Title  string `json:"title"`
    Author string `json:"author"`
    Price  float64 `json:"price"`
}

Step 4: Create the Routes

routes/routes.go:

Define all the routes for CRUD operations.

package routes

import (
    "github.com/gin-gonic/gin"
    "crud-api/models"
    "crud-api/database"
    "net/http"
)

func SetupRoutes(router *gin.Engine) {
    router.GET("/books", getBooks)
    router.POST("/books", createBook)
    router.GET("/books/:id", getBook)
    router.PUT("/books/:id", updateBook)
    router.DELETE("/books/:id", deleteBook)
}

func getBooks(c *gin.Context) {
    var books []models.Book
    database.DB.Find(&books)
    c.JSON(http.StatusOK, books)
}

func createBook(c *gin.Context) {
    var book models.Book
    if err := c.ShouldBindJSON(&book); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    database.DB.Create(&book)
    c.JSON(http.StatusOK, book)
}

func getBook(c *gin.Context) {
    var book models.Book
    id := c.Param("id")
    if err := database.DB.First(&book, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Book not found!"})
        return
    }
    c.JSON(http.StatusOK, book)
}

func updateBook(c *gin.Context) {
    var book models.Book
    id := c.Param("id")
    if err := database.DB.First(&book, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Book not found!"})
        return
    }
    if err := c.ShouldBindJSON(&book); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    database.DB.Save(&book)
    c.JSON(http.StatusOK, book)
}

func deleteBook(c *gin.Context) {
    var book models.Book
    id := c.Param("id")
    if err := database.DB.Delete(&book, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Book not found!"})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "Book deleted successfully!"})
}

Step 5: Configure the Server

cmd/server/main.go:

Initialize the server, connect to the database, and register the routes.

package main

import (
    "github.com/gin-gonic/gin"
    "crud-api/database"
    "crud-api/models"
    "crud-api/routes"
)

func main() {
    // Initialize database
    database.ConnectDatabase()
    database.DB.AutoMigrate(&models.Book{})

    // Set up Gin
    router := gin.Default()

    // Register routes
    routes.SetupRoutes(router)

    // Run the server
    router.Run(":8080")
}

Running the API

  1. Start the server:
    go run cmd/server/main.go
    
  2. Test the endpoints using tools like Postman or cURL.

Sample Endpoints

  • Create a Book:
    POST /books
    Content-Type: application/json
    {
      "title": "Golang 101",
      "author": "John Doe",
      "price": 29.99
    }
    
  • Get All Books:
    GET /books
    
  • Get a Single Book:
    GET /books/:id
    
  • Update a Book:
    PUT /books/:id
    Content-Type: application/json
    {
      "title": "Golang for Experts",
      "author": "Jane Doe",
      "price": 39.99
    }
    
  • Delete a Book:
    DELETE /books/:id
    

Conclusion

Category Type Description Example
Basic `int` Integer numbers. Size depends on the architecture (32 or 64 bits). `42`
Basic `float64` Double-precision floating-point numbers. `3.14159`
Basic `string` A sequence of characters. Immutable in Go. `"Hello, Go!"`
Basic `bool` Boolean values. Either `true` or `false`. `true`
Composite `array` Fixed-size, ordered collection of elements of the same type. `[3]int{1, 2, 3}`
Composite `slice` Dynamic-size version of an array. `[]int{1, 2, 3}`
Composite `map` Key-value pairs. `map[string]int`
Composite `struct` Custom composite data type. Groups fields with different types. `type Point struct`
Reference `pointer` Stores memory addresses of variables. `*int`
Interface `interface{}` Represents zero or more method signatures. Can hold any value. `var x interface{}`
Function `func` A first-class function type in Go. `func(x int) int`

You now have a fully functional CRUD API built with Golang, Gin, and GORM. You can expand this project by adding authentication, validation, or more complex relationships in the database.

Share this post on: