AG-Grid with Go API

Create an API for AG-Grid with Go

AG-Grid is a powerful JavaScript data grid library, ideal for building dynamic, high-performance tables with features like sorting, filtering, and pagination. In this article, we’ll create an API in Go to support AG-Grid, enabling efficient server-side data operations, including filtering, sorting, and pagination. By integrating AG-Grid with Go API, we’ll develop a robust solution that ensures smooth performance, even when working with large datasets.

Prerequisites

  • Go 1.21
  • MySQL

Setup project

Setting up the Go project dependencies.

go mod init app
go get github.com/gin-gonic/gin
go get gorm.io/gorm
go get gorm.io/driver/mysql
go get github.com/joho/godotenv

Create a testing database named "example" and run the database.sql file to import the table and data.

Project structure

├─ .env
├─ main.go
├─ config
│  └─ db.go
├─ controllers
│  └─ product_controller.go
├─ models
│  └─ product.go
├─ public
│  └─ index.html
└─ router
   └─ router.go

Project files

.env

This file contains the database connection information.

DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=example
DB_USER=root
DB_PASSWORD=

db.go

This file sets up the database connection using GORM. It declares a global variable DB to hold the database connection instance to use later in our application.

package config

import (
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

var DB *gorm.DB

func SetupDatabase() {
	godotenv.Load()
	connection := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true", os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_DATABASE"))
	db, _ := gorm.Open(mysql.Open(connection), &gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}})
	DB = db
}

router.go

This file sets up routing for a Gin web application. It initializes a router for a DataTables API and serves a static index.html file at the root URL.

package router

import (
	"app/controllers"

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

func SetupRouter() {
	productController := controllers.ProductController{}
	router := gin.Default()
	router.StaticFile("/", "./public/index.html")
	router.GET("/api/products", productController.Index)
	router.Run()
}

product.go

This file defines the Product model for the application.

package models

type Product struct {
	Id    int
	Name  string
	Price float64
}

product_controller.go

This file defines a function to handle incoming requests and return the DataTables data.

package controllers

import (
	"app/config"
	"app/models"
	"net/http"
	"strconv"

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

type ProductController struct {
}

func (con *ProductController) Index(c *gin.Context) {
	size, _ := strconv.Atoi(c.DefaultQuery("length", "10"))
	start, _ := strconv.Atoi(c.Query("start"))
	order := "id"
	if c.Query("order[0][column]") != "" {
		order = c.Query("columns[" + c.Query("order[0][column]") + "][data]")
	}
	direction := c.DefaultQuery("order[0][dir]", "asc")
	var products []models.Product
	query := config.DB.Model(&products)
	var recordsTotal, recordsFiltered int64
	query.Count(&recordsTotal)
	search := c.Query("search[value]")
	if search != "" {
		search = "%" + search + "%"
		query.Where("name like ?", search)
	}
	query.Count(&recordsFiltered)
	query.Order(order + " " + direction).
		Offset(start).
		Limit(size).
		Find(&products)
	c.JSON(http.StatusOK, gin.H{"draw": c.Query("draw"), "recordsTotal": recordsTotal, "recordsFiltered": recordsFiltered, "data": products})
}

The product_controller.go file defines a controller for managing product-related API requests in a Go application using the Gin framework. It features an Index method that retrieves a paginated list of products based on query parameters for pagination, sorting, and searching. The method extracts parameters for pagination, constructs a query to fetch products from the database, and applies filtering if a search term is provided. After counting the total matching products, it orders and limits the results before returning a JSON response containing the product data and total count, facilitating integration with frontend applications.

main.go

This file is the main entry point of our application. It will create and setting up the Gin web application.

package main

import (
	"app/config"
	"app/router"
)

func main() {
	config.SetupDatabase()
	router.SetupRouter()
}

index.html

<!DOCTYPE html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
</head>
<body>
    <div id="grid" class="ag-theme-alpine" style="height: 400px; width: 640px; margin: 1em"></div>
    <script>
        function getQuery(params) {
            let query = new URLSearchParams()
            let size = params.endRow - params.startRow
            let page = Math.floor(params.startRow / size) + 1
            query.append('page', page)
            query.append('size', size)
            if (params.sortModel.length) {
                let sort = params.sortModel[0]
                query.append('order', sort.colId)
                query.append('direction', sort.sort)
            }
            if (params.filterModel.name) {
                query.append('search', params.filterModel.name.filter)
            }
            return query.toString()
        }
        let columns = [
            { headerName: 'ID', field: 'Id', sortable: true },
            {
                headerName: 'Name', field: 'Name', sortable: true, filter: true,
                filterParams: {
                    filterOptions: ['contains'],
                    maxNumConditions: 1,
                }
            },
            { headerName: 'Price', field: 'Price', sortable: true }
        ]
        let gridOptions = {
            columnDefs: columns,
            rowModelType: 'infinite',
            pagination: true,
            paginationPageSize: 20,
            cacheBlockSize: 20,
            datasource: {
                getRows: function (params) {
                    let query = getQuery(params)
                    fetch(`/api/products?${query}`)
                        .then(response => response.json())
                        .then(json => {
                            params.successCallback(json.data, json.count)
                        })
                }
            }
        }
        document.addEventListener('DOMContentLoaded', () => {
            agGrid.createGrid(document.querySelector('#grid'), gridOptions)
        })
    </script>
</body>
</html>

The index.html file sets up a web page that uses the AG-Grid library to display a dynamic data grid for products. It includes a grid styled with the AG-Grid theme and a JavaScript section that constructs query parameters for pagination, sorting, and filtering. The grid is configured with columns for ID, Name, and Price, and it fetches product data from an API endpoint based on user interactions. Upon loading, the grid is initialized, allowing users to view and manipulate the product list effectively.

Run project

go run main.go

Open the web browser and goto http://localhost:8080
You will find this test page.

test page

Testing

Page size test

Change page size by selecting 50 from the "Page Size" drop-down. You will get 50 records per page, and the last page will change from 5 to 2.

page size test

Sorting test

Click on the header of the first column. You will see that the id column will be sorted in descending order.

sorting test

Search test

Enter "no" in the search text-box of the "Name" column, and you will see the filtered result data.

search test

Conclusion

In conclusion, we’ve effectively integrated AG-Grid with a Go API to create a robust and efficient data grid solution. By utilizing Go's backend capabilities, we enabled AG-Grid to handle server-side filtering, sorting, and pagination, ensuring smooth performance even with large datasets. This integration not only optimizes data management but also enhances the user experience with dynamic, responsive tables on the frontend. With AG-Grid and Go working in harmony, we’ve built a scalable and high-performance grid system that is well-suited for real-world applications.

Source code: https://github.com/stackpuz/Example-AG-Grid-Go

Create a CRUD Web App in Minutes: https://stackpuz.com

Related post