Skip to content

Generate restful APIs by defining struct model, based on Gin and Gorm, with a optional web interface for administrator.

License

Notifications You must be signed in to change notification settings

restsend/gormpher

Repository files navigation

Gormpher - Generate restful APIs by defining struct model, based on Gin and Gorm

Quick Start

go get github.com/restsend/gormpher

reference to example

package main

import (
	"errors"
	"flag"
	"math/rand"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/restsend/gormpher"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type User struct {
	ID        uint       `json:"id" gorm:"primarykey"`
	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
	Name      string     `json:"name"`
	Age       int        `json:"age"`
	Enabled   bool       `json:"enabled"`
	LastLogin *time.Time `json:"lastLogin"`
}

type Product struct {
	UUID      string    `json:"id" gorm:"primarykey"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	GroupID   int       `json:"-"`
	Group     Group     `json:"group" gorm:"foreignKey:GroupID;references:ID"` // association
	Name      string    `json:"name"`
	Enabled   bool      `json:"enabled"`
}

type Group struct {
	ID   uint   `json:"id" gorm:"primarykey"`
	Name string `json:"name"`
}

func main() {
	var dsn string
	var addr string

	flag.StringVar(&dsn, "n", "", "DB DSN")
	flag.StringVar(&addr, "a", ":8890", "Api Server Addr")
	flag.Parse()

	db, _ := gorm.Open(sqlite.Open(dsn), nil)
	db.AutoMigrate(Product{}, User{})

	r := gin.Default()

	objs := GetWebObjects(db)
	// visit API: http://localhost:8890/api
	gormpher.RegisterObjects(r, objs)
	// visit Admin: http://localhost:8890/admin/v1
	gormpher.RegisterObjectsWithAdmin(r.Group("admin"), objs)

	r.Run(addr)
}

func GetWebObjects(db *gorm.DB) []gormpher.WebObject {
	return []gormpher.WebObject{
		// Basic Demo
		// Check API File: user.http
		// PUT 		http://localhost:8890/user
		// GET 		http://localhost:8890/user/:key
		// PATCH	http://localhost:8890/user/:key
		// POST 	http://localhost:8890/user
		// DELETE http://localhost:8890/user/:key
		// DELETE http://localhost:8890/user
		{
			Name:         "user",
			Model:        &User{},
			SearchFields: []string{"Name", "Enabled"},
			EditFields:   []string{"Name", "Age", "Enabled", "LastLogin"},
			FilterFields: []string{"Name", "CreatedAt", "Age", "Enabled"},
			OrderFields:  []string{"CreatedAt", "Age", "Enabled"},
			GetDB:        func(ctx *gin.Context, isCreate bool) *gorm.DB { return db },
		},
		// Advanced Demo
		// Check API File: product.http
		// PUT 		http://localhost:8890/product
		// GET 		http://localhost:8890/product/:key
		// PATCH	http://localhost:8890/product/:key
		// POST 	http://localhost:8890/product
		// DELETE http://localhost:8890/product/:key
		// DELETE http://localhost:8890/product
		{
			Name:         "product",
			Model:        &Product{},
			SearchFields: []string{"Name"},
			EditFields:   []string{"Name", "Enabled", "Model"},
			FilterFields: []string{"Name", "CreatedAt", "Enabled"},
			OrderFields:  []string{"CreatedAt"},
			GetDB:        func(c *gin.Context, isCreate bool) *gorm.DB { return db },
			BeforeCreate: func(ctx *gin.Context, vptr any, vals map[string]any) error {
				p := (vptr).(*Product)
				p.UUID = MockUUID(8)

				// create group
				group := Group{Name: "group" + MockUUID(4)}
				if err := db.Create(&group).Error; err != nil {
					return err
				}

				p.GroupID = int(group.ID)
				return nil
			},
			BeforeDelete: func(ctx *gin.Context, vptr any) error {
				p := (vptr).(*Product)
				if p.Enabled {
					return errors.New("product is enabled, can not delete")
				}
				return nil
			},
			// Custom Query View
			// GET http://localhost:8890/product/all_enabled
			Views: []gormpher.QueryView{
				{
					Name:   "all_enabled",
					Method: "GET",
					Prepare: func(db *gorm.DB, c *gin.Context, pagination bool) (*gorm.DB, *gormpher.QueryForm, error) {
						// SELECT (id, name) FROM products WHERE enabled = true
						queryForm := &gormpher.QueryForm{
							Limit: -1,
							Filters: []gormpher.Filter{
								{Name: "enabled", Op: "=", Value: true}, // JSON format
							},
							ViewFields: []string{"UUID", "Name"},
						}
						return db, queryForm, nil
					},
				},
			},
		},
	}
}

func MockUUID(n int) string {
	source := []rune("0123456789abcdefghijklmnopqrstuvwxyz")
	b := make([]rune, n)
	for i := range b {
		b[i] = source[rand.Intn(len(source))]
	}
	return string(b)
}

Run the project and visit http://localhost:8890/admin , you can see a web interface for administrator.

image

Features

Generate CRUD Restful API

Optional Admin Web UI

Generic Gorm Function

About

Generate restful APIs by defining struct model, based on Gin and Gorm, with a optional web interface for administrator.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages