Cursor based pagination made easy.
go get -u github.com/oatovar/go-pager
You can use the provider binder to bind the values from
url.URL
into a QueryArgs
struct.
func Handler(w http.ResponseWriter, r *http.Request) {
var queryArgs pager.QueryArgs
err := pager.BindRequest(r, &queryArgs)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
p, err := pager.New()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
result := p.Process(&queryArgs)
// Use collected args further on...
}
You can utilize the github.com/gorilla/schema
package to parse the
the query args from the URL query values.
func Handler(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
var queryArgs pager.QueryArgs
err := schema.NewDecoder().Decode(queryArgs, r.Form)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
p, err := pager.New()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
result := p.Process(&queryArgs)
// Use collected args further on...
}
Additionally, you can use this with any framework that utilizes
the query
struct tags to bind query params to a struct. Notably,
this includes the Fiber and
Echo http frameworks. An example,
is provided below for each respectively.
// Echo Usage Example
func Handler(c echo.Context) error {
var queryArgs pager.QueryArgs
err := (&echo.DefaultBinder{}).BindQueryParams(c, &queryArgs)
if err != nil {
return fmt.Errorf("oops we encountered an error processing your request")
}
return c.JSON(http.StatusOK, queryArgs)
}
// Fiber Usage Example
func Handler(c *fiber.Ctx) error {
var queryArgs pager.QueryArgs
err := c.QueryParser(&queryArgs)
if err != nil {
return fmt.Errorf("oops we encountered an error processing your request")
}
return c.JSON(queryArgs)
}
Does this need to be used with GraphQL? No, you can use it as it best fits in your application.
Do you need to use it in query params? No, you can potentially utilize it to parse the request body if you're building a GraphQL API.
Why not use offset and limit? As applications begin to grow, cursor based pagination is a lot more efficient. If you use a relational database, the offset/limit approach will force the server to parse a lot of records potentially. You can read more about how Slack evaluated the usage of cursor based pagination to get the tradeoffs that should be considered.
This is a work in progress package. Once it has been finalized, it will
be released as v1.0.0
. If you have any recommendations or would like
a specific feature, please create an issue with your use case and any
solution recommendations.