Packages
paginate
Offset pagination parameters with sane defaults and hard limits. Binds straight from the query string, clamps hostile input, and computes the SQL OFFSET for you.
In the handler
import "github.com/BounkhongDev/bkgo/paginate"
// In your handler — bind the query string, then clamp it
var p paginate.Params
c.QueryParser(&p)
p.Normalize() // ?page=0&limit=999 → page=1, limit=20
users, total, err := h.usecase.List(c.Context(), p)
return c.JSON(response.Paginated(users, p.Page, p.Limit, total))In the repository
// In your repository — Offset() computes the SQL OFFSET
func (r *repository) List(
ctx context.Context, p paginate.Params,
) ([]User, int, error) {
var users []User
var total int64
r.db.Session(ctx).Model(&User{}).Count(&total)
err := r.db.Session(ctx).
Limit(p.Limit).
Offset(p.Offset()).
Find(&users).Error
return users, int(total), err
}What Normalize() clamps
Call Normalize() once, right after binding the query string. It rewrites the params in place — anything out of range falls back to the default rather than erroring:
| Query | After Normalize() |
|---|---|
?page=0 | page = 1 |
?page=-5 | page = 1 |
?limit=0 | limit = 20 |
?limit=999 | limit = 20 |
?limit=50 | limit = 50 |
API
const (
DefaultPage = 1
DefaultLimit = 20
MaxLimit = 100
)
type Params struct {
Page int `json:"page" query:"page"`
Limit int `json:"limit" query:"limit"`
}
// Normalize clamps Page and Limit to valid ranges in-place.
func (p *Params) Normalize()
// Offset returns the SQL OFFSET value for the current page.
// It reads Page and Limit without mutating the receiver.
func (p *Params) Offset() int