Awesome
rabbit
Rabbit is a golang library for simplifying backend develop.
⭐ Open source project using Rabbit, which can be a reference for an example project:
Features
All features have corresponding unit tests, which is convenient for developers to learn and use.
Dynamic Handlers & Dynamic Gorm Functions
Reference: ./handler_common_test.go
func HandleGet[T any](c *gin.Context, db *gorm.DB, onRender onRenderFunc[T])
func HandleDelete[T any](c *gin.Context, db *gorm.DB, onDelete onDeleteFunc[T])
func HandleCreate[T any](c *gin.Context, db *gorm.DB, onCreate onCreateFunc[T])
func HandleEdit[T any](c *gin.Context, db *gorm.DB, editables []string, onUpdate onUpdateFunc[T])
func HandleQuery[T any](c *gin.Context, db *gorm.DB, ctx *QueryOption)
func ExecuteGet[T any, V Key](db *gorm.DB, key V) (*T, error)
func ExecuteEdit[T any, V Key](db *gorm.DB, key V, vals map[string]any) (*T, error)
func ExecuteQuery[T any](db *gorm.DB, form QueryForm) (items []T, count int, err error)
About how to use: Please refer to the corresponding unit tests.
Integration Web Objects - Generate RESTful API
Reference https://github.com/restsend/gormpher
Env Config
Load environment variables
Functions:
func GetEnv(key string) string
func LookupEnv(key string) (string, bool)
Examples:
# .env
xx
EXIST_ENV=100
# run with env
EXIST_ENV=100 go run .
rabbit.GetEnv("EXIST_ENV") // 100
rabbit.LookupEnv("EXIST_ENV") // 100, true
Load config from DB
Functions:
func CheckValue(db *gorm.DB, key, default_value string)
func SetValue(db *gorm.DB, key, value string)
func GetValue(db *gorm.DB, key string) string
func GetIntValue(db *gorm.DB, key string, default_value int) int
func GetBoolValue(db *gorm.DB, key string) bool
Examples:
db, _ := gorm.Open(sqlite.Open("file::memory:"), nil)
db.AutoMigrate(&rabbit.Config{})
rabbit.SetValue(db, "test_key", "test_value")
value := rabbit.GetValue(db, "test_key") // test_value
rabbit.CheckValue(db, "check_key", "default_value")
value = rabbit.GetValue(db, "check_key") // default_value
rabbit.SetValue(db, "int_key", "42")
intValue := rabbit.GetIntValue(db, "int_key", -1) // 42
rabbit.SetValue(db, "bool_key", "true")
boolValue := rabbit.GetBoolValue(db, "bool_key") // true
Built-in Handlers
Permission models
User <-UserRole-> Role
Role <-RolePermission-> Permission
User <-GroupMember-> Group
User
- ID
- Email
- Password
- ...
// for association
UserRole
- UserID
- RoleID
Role
- Name
- Label
// for association
RolePermission
- RoleID
- PermissionID
Permission
- Name
- Uri
- Method
- Anonymous
- ParentID // for tree struct
- Children // for tree struct
Group
- Name
// for association
GroupMember
- UserID
- GroupID
Authentication handlers
RegisterAuthenticationHandlers("/auth", db, r)
GET /auth/info
POST /auth/login
POST /auth/register
GET /auth/logout
POST /auth/change_password
Authorization handlers
rabbit.RegisterAuthorizationHandlers(db, r.Group("/api"))
PUT /api/role
PATCH /api/role/:key
DELETE /api/role/:key
PUT /api/permission
PATCH /api/permission/:key
DELETE /api/permission/:key
Middleware
ar := r.Group("/api").Use(
rabbit.WithAuthentication(),
rabbit.WithAuthorization("/api"),
)
rabbit.RegisterAuthorizationHandlers(db, ar)
Unit Tests Utils
Reference: tests_test.go
Example:
type user struct {
ID uint `json:"id" gorm:"primarykey"`
Name string `json:"name"`
Age int `json:"age"`
}
r := gin.Default()
r.GET("/ping", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, true)
})
r.POST("/pong", func(ctx *gin.Context) {
var form user
ctx.BindJSON(&form)
ctx.JSON(http.StatusOK, gin.H{
"name": form.Name,
"age": form.Age,
})
})
Example Test:
c := rabbit.NewTestClient(r)
// CallGet
{
var result bool
err := c.CallGet("/ping", nil, &result)
assert.Nil(t, err)
assert.True(t, result)
}
// Get
{
w := c.Get("/ping")
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "true", w.Body.String())
}
// Native
{
req := httptest.NewRequest(http.MethodGet, "/ping", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "true", w.Body.String())
}
// CallPost
{
var result map[string]any
err := c.CallPost("/pong", user{Name: "test", Age: 11}, &result)
assert.Nil(t, err)
assert.Equal(t, "test", result["name"])
assert.Equal(t, float64(11), result["age"])
}
// Post
{
b, _ := json.Marshal(user{Name: "test", Age: 11})
w := c.Post("/pong", b)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, `{"age":11,"name":"test"}`, w.Body.String())
}
// Native
{
b, _ := json.Marshal(user{Name: "test", Age: 11})
req := httptest.NewRequest(http.MethodPost, "/pong", bytes.NewReader(b))
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, `{"age":11,"name":"test"}`, w.Body.String())
}