Skip to content

Go package to easily convert a URL's query parameters/values into usable struct values of the correct types.

License

Notifications You must be signed in to change notification settings

TomWright/queryparam

Folders and files

NameName
Last commit message
Last commit date

Latest commit

349c90f · Sep 23, 2020

History

29 Commits
Dec 5, 2019
Nov 27, 2019
Jun 14, 2018
Sep 23, 2020
Dec 5, 2019
Dec 6, 2019
Dec 6, 2019
Dec 6, 2019
Dec 6, 2019
Dec 6, 2019
Dec 6, 2019
Dec 6, 2019

Repository files navigation

Query Param

Build Status codecov Go Report Card Documentation Mentioned in Awesome Go

Stop accessing query strings and repeatedly parsing them into your preferred values - queryparam can do that for you!

Installation

go get -u github.com/tomwright/queryparam

Usage

Please use the latest major version. This requires the /v4 at the end of the import as per the go mod documentation.

import github.com/tomwright/queryparam/v4

Examples

For examples see godoc examples.

Quickstart

Transform your http handlers from this...

func searchUsersHandler(r *http.Request, rw http.ResponseWriter) {
	values := r.URL.Query()

	userIDs := make([]string, 0)
	if userIDsStr := values.Get("id"); userIDsStr != "" {
		userIDs = strings.Split(userIDsStr, ",")
	}
	teamIDs := make([]string, 0)
	if teamIDsStr := values.Get("team-id"); teamIDsStr != "" {
		teamIDs = strings.Split(teamIDsStr, ",")
	}
	mustBeActive := false
	switch strings.ToLower(values.Get("must-be-active")) {
	case "true", "yes", "y":
		mustBeActive = true
	case "":
		break
	default:
		// unhandled bool value... handle as 400 or ignore to default as false
	}
	createdAfter := time.Time{}
	if createdAfterStr := values.Get("must-be-active"); createdAfterStr != "" {
		var err error
		createdAfter, err = time.Parse(time.RFC3339, createdAfterStr)
		if err != nil {
			// bad time value
		}
	}

	users, err := searchUsers(userIDs, teamIDs, mustBeActive, createdAfter)

	// handle users and err...
}

To this...

func searchUsersHandler(r *http.Request, rw http.ResponseWriter) {
	req := struct {
		UserIDs      []string  `queryparam:"id"`
		TeamIDs      []string  `queryparam:"team-id"`
		MustBeActive bool      `queryparam:"must-be-active"`
		CreatedAfter time.Time `queryparam:"created-after"`
	}{}

	err := queryparam.Parse(r.URL.Query(), &req)
	switch err {
	case nil:
		break
	case queryparam.ErrInvalidBoolValue: // only necessary if the request contains a bool value
		// they have entered a non-bool value.
		// this can be handled this as a 400 or ignored to default to false.
		return
	default:
		// something went wrong when parsing a value.
		// send a 500.
		return
	}

	users, err := searchUsers(req.UserIDs, req.TeamIDs, req.MustBeActive, req.CreatedAfter)

	// handle users and err...
}

Types

By default queryparam can parse the following types.

  • string
  • []string
  • int
  • int32
  • int64
  • float32
  • float64
  • bool
  • time.Time
  • queryparam.Present

Custom Types

You can add custom type parsers and setters with the following:

// your custom type.
type MyCustomStringType string

// add a value parser for the custom type.
queryparam.DefaultParser.ValueParsers[reflect.TypeOf(MyCustomStringType(""))] = func(value string, _ string) (reflect.Value, error) {
    return reflect.ValueOf(MyCustomStringType(value)), nil
}

You can override the default value parsers in a similar manner...

queryparam.DefaultParser.ValueParsers[reflect.TypeOf("")] = func(value string, _ string) (reflect.Value, error) {
    // my custom string parser
    return reflect.ValueOf(value), nil
}