options

package module
v1.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 29, 2024 License: MIT Imports: 6 Imported by: 8

README

JSONAPI Compliant Querystring Parser

godoc license Coverage GoReportCard example

This package provides JSONAPI compliant querystring parsing. This package can be used to extract filters, pagination and sorting details from the querystring.

Installation

go get -u go.jtlabs.io/query

Usage

The query options package is designed to be used either as middleware, or in a route handler for an HTTP request. The package can be used to parse out JSONAPI style filters, pagination details and sorting instructions as supplied via the querystring.

package main

import (
	"fmt"
	"log"
	"net/http"

	options "go.jtlabs.io/query"
)

func handler(w http.ResponseWriter, r *http.Request) {
	opt, err := options.FromQuerystring(r.URL.RawQuery)
	if err != nil {
		fmt.Fprint(w, err)
		return
	}

	// work with the options...
	for field, filter := range opt.Filter {
		for _, value := range filter {
			fmt.Println("found supplied filter (", field, ": ", value, ")")
		}
	}

	// handle pagination
	limit := 100
	offset := 0

	if l, ok := opt.Page["limit"]; ok {
		limit = l
	}

	if o, ok := opt.Page["offset"]; ok {
		offset = o
	}

	fmt.Println("pagination provided with a limit of ", limit, ", and an offset of ", offset)

	for _, field := range opt.Fields {
		fmt.Println("limit response to include (or exclude) field: ", field)
	}

	for _, field := range opt.Sort {
		fmt.Println("sort by field: ", field)
	}

	fmt.Fprint(w, "request complete")
}

func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
working example

Please see examples/usage.go for an example of the usage. To run the example, see as follows:

go run examples/usage.go

The above starts a server on :8080 for subsequent testing. In a separate terminal window, issue a request to the example server with the following:

$ curl "localhost:8080?filter[fieldA]=value1,value2&filter[fieldB]=*test&page[offset]=10&page[limit]=10&sort=-fieldA,fieldB"

Notice the output in the server terminal window is as follows:

$ go run examples/usage.go
found supplied filter ( fieldA :  value1 )
found supplied filter ( fieldA :  value2 )
found supplied filter ( fieldB :  *test )
pagination provided with a limit of  10 , and an offset of  10
sort by field:  -fieldA
sort by field:  fieldB
queryoptions.Options

The Options struct contains properties for the provided filters, pagination details and sorting details from the querystring.

Options.Filter is a map[string][]string, Options.Page is a map[string]int and Options.Sort is a []string.

options := &queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{},
  Page: map[string]int{},
  Sort: []string{}
}
options.Filter

JSONAPI specifications are agnostic about how filters can be provided. However, as noted in JSONAPI recommendations (https://jsonapi.org/recommendations/#filtering), there is an approach that many favor for clarity.

It’s recommended that servers that wish to support filtering of a resource collection based upon associations do so by allowing query parameters that combine filter with the association name. For example, the following is a request for all comments associated with a particular post:

GET /comments?filter[post]=1 HTTP/1.1

The above would result in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{
    "post": {"1"}
  },
  Page: map[string]int{},
  Sort: []string{}
}

Multiple filter values can be combined in a comma-separated list. For example:

GET /comments?filter[post]=1,2 HTTP/1.1

The above would result in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{
    "post": {"1", "2"}
  },
  Page: map[string]int{},
  Sort: []string{}
}

Furthermore, multiple filters can be applied to a single request:

GET /comments?filter[post]=1,2&filter[author]=12 HTTP/1.1

... which results in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{
    "post": {"1", "2"},
    "author": {"12"}
  },
  Page: map[string]int{},
  Sort: []string{}
}
options.Page

JSONAPI is also agnostic regarding pagination strategies (https://jsonapi.org/format/#fetching-pagination), but it is noted that numerous strategies may be used (i.e. page[number] and page[size] or page[limit] and page[offset]). The queryoptions package supports any strategy the API implements.

GET /comments?page[number]=2&page[size]=100 HTTP/1.1

The above results in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{},
  Page: map[string]int{
		"number": 2,
		"size": 100
	},
  Sort: []string{}
}

Alternatively, limit and offset may be specified:

GET /comments?page[limit]=20&page[offset]=12 HTTP/1.1

The above results in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{},
  Page: map[string]int{
		"limit": 20,
		"offset": 12
	},
  Sort: []string{}
}

Ultimately, any term provided in the brackets for sort will be translated to an entry in the map[string]int struct value.

GET /comments?page[whatever]=2121 HTTP/1.1

... is parsed as follows:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{},
  Page: map[string]int{
		"whatever": 2121,
	},
  Sort: []string{}
}
options.Fields

In the JSONAPI specification, sparse fieldsets are supported as an array of field names: https://jsonapi.org/format/#fetching-sparse-fieldsets.

GET /comments?fields=fieldA&fields=-fieldB HTTP/1.1

and this request...

GET /comments?fields=fieldA,fieldB HTTP/1.1

Both result in the following Options:

&queryoptions.Options{
  Fields: []string{"fieldA","-fieldB"},
  Filter: map[string][]string{},
  Page: map[string]int{},
  Sort: []string{}
}
options.Sort

In the JSONAPI specification, sorting is a simple array of fields: https://jsonapi.org/format/#fetching-sorting.

GET /comments?sort=fieldA&sort=fieldB HTTP/1.1

and this request...

GET /comments?sort=fieldA,fieldB HTTP/1.1

Both result in the following Options:

&queryoptions.Options{
  Fields: []string{},
  Filter: map[string][]string{},
  Page: map[string]int{},
  Sort: []string{"fieldA","fieldB"}
}

Documentation

Overview

options provides a lightweight options object for parsing query parameters sent in a JSONAPI friendly way via querystring parameters

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type IPaginationStrategy

type IPaginationStrategy interface {
	Current(map[string]int) string
	First(map[string]int) string
	Last(map[string]int, int) string
	Next(map[string]int) string
	Prev(map[string]int) string
}

IPaginationStrategy is an interface for providing First, Last, Next and Prev links based on the pagination mechanism that is being implemented

type OffsetStrategy

type OffsetStrategy struct{}

OffsetStrategy is a pagination strategy for page[offset] and page[limit] parameters

func (OffsetStrategy) Current added in v1.6.0

func (os OffsetStrategy) Current(c map[string]int) string

Current returns a link to the current page

func (OffsetStrategy) First

func (os OffsetStrategy) First(c map[string]int) string

First returns a link to the first page

func (OffsetStrategy) Last

func (os OffsetStrategy) Last(c map[string]int, total int) string

Last returns a link to the last page

func (OffsetStrategy) Next

func (os OffsetStrategy) Next(c map[string]int) string

Next returns a link to the next page

func (OffsetStrategy) Prev

func (os OffsetStrategy) Prev(c map[string]int) string

Prev returns a link to the previous page

type Options

type Options struct {
	Fields []string            `json:"fields,omitempty"`
	Filter map[string][]string `json:"filter,omitempty"`
	Page   map[string]int      `json:"page"`
	Sort   []string            `json:"sort,omitempty"`
	// contains filtered or unexported fields
}

Options contain filtering, pagination and sorting instructions provided via the querystring in bracketed object notation

func FromQuerystring

func FromQuerystring(qs string) (Options, error)

FromQuerystring parses an Options object from the provided querystring

func (Options) ContainsFilterField added in v1.4.0

func (o Options) ContainsFilterField(field string) bool

ContainsFilterField confirms whether or not the provided filter parameters include the requested field

func (Options) ContainsSortField added in v1.4.0

func (o Options) ContainsSortField(field string) bool

ContainsSortField confirms whether or not the provided sort options contains the requested field

func (Options) First

func (o Options) First() string

First returns a querystring for the first page

func (Options) Last

func (o Options) Last(total int) string

Last returns a querystring for the last page

func (Options) Next

func (o Options) Next() string

Next returns a querystring for the next page

func (Options) PaginationStrategy

func (o Options) PaginationStrategy() IPaginationStrategy

PaginationStrategy can be used to retrieve the current IPaginationStrategy that the Options struct will use for generating Prev, Next, First and Last querystring values

func (Options) Prev

func (o Options) Prev() string

Prev returns a querystring for the previous page

func (*Options) SetPaginationStrategy

func (o *Options) SetPaginationStrategy(ps IPaginationStrategy)

SetPaginationStrategy can be used to specify custom pagination increments for Next, Prev, First and Last

func (Options) String added in v1.6.0

func (o Options) String() string

String returns a querystring for the current page

type PageSizeStrategy

type PageSizeStrategy struct{}

PageSizeStrategy is a pagination strategy for page[size] and page[page] parameters

func (PageSizeStrategy) Current added in v1.6.0

func (ps PageSizeStrategy) Current(c map[string]int) string

Current returns a link to the current page

func (PageSizeStrategy) First

func (ps PageSizeStrategy) First(c map[string]int) string

First returns a link to the first page

func (PageSizeStrategy) Last

func (os PageSizeStrategy) Last(c map[string]int, total int) string

Last returns a link to the last page

func (PageSizeStrategy) Next

func (ps PageSizeStrategy) Next(c map[string]int) string

Next returns a link to the next page

func (PageSizeStrategy) Prev

func (ps PageSizeStrategy) Prev(c map[string]int) string

Prev returns a link to the previous page

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL