Go is idiomatic, opinionated, and frequents a do-it-yourself approach. One case in particular is when it comes to implementing pagination. That's where pagy comes in. It's a strongly opinionated utility package aimed at getting rid of the pesky task of writing your own pagination utilities.
pagy works with the stdlib http.Request so it can easily be dropped into any project or handler that implements such.
- Scans the http.Request for pagination values
- Formats pagination values into simplified structure
- Can be passed into ctx or as a parameter to your repository layer
- Easily extendable
go get github.com/DLzer/pagy
pagy will output a consistent top level structure containing important pagination info to your client
{
"total_count": 150,
"total_pages": 15,
"page": 1,
"size": 10
"has_more": true
"values": {
...
}
}
package main
import (
"fmt"
"net/http"
)
// @Param page query int
// @Param size query int
// @Param orderBy query string
// @Param orderDir query string optional
// @Example GET /users?page=1&size=10&orderBy=first_name
func getUsersList(w http.ResponseWriter, req *http.Request) {
pq, err := pagy.GetPaginationFromRequest(r)
if err != nil {
http.Error(w, err.Error())
return
}
}
func main() {
http.HandleFunc("/users", getUsersList)
http.ListenAndServe(":8090", nil)
}
pagy uses generics so it's agnostic and doesn't really care what type of structure your data response will be. Instead of responding with nil you can use the DefaultPaginationResponse
to return a basic empty structure that your client can interpret.
func (p *postgresUserRepository) GetList(ctx context.Context, pq *pagy.PaginationQuery) (*pagy.PaginationResponse[domain.User], error) {{
var count int
countQuery := "SELECT count(uuid) FROM users;"
if err := p.conn.QueryRow(ctx, countQuery).Scan(&count); err != nil {
return nil, err
}
if count == 0 {
return pagy.DefaultPaginationResponse[domain.User](pq), nil
}
query := "SELECT * FROM users ORDER BY $1::text OFFSET $2 LIMIT $3"
rows, err := p.conn.Query(ctx, query, pq.GetOrderBy(), pq.GetOffset(), pq.GetLimit())
if err != nil {
return nil, err
}
defer rows.Close()
var uu []domain.User
for rows.Next() {
//... Scan your user
}
return pagy.PaginatedResponse(count, pq, uu), nil
}
This project is licensed under the terms of the MIT license.