Code Monkey home page Code Monkey logo

go-querystring's Introduction

go-querystring

Go Reference Test Status Test Coverage

go-querystring is a Go library for encoding structs into URL query parameters.

Usage

import "github.com/google/go-querystring/query"

go-querystring is designed to assist in scenarios where you want to construct a URL using a struct that represents the URL query parameters. You might do this to enforce the type safety of your parameters, for example, as is done in the go-github library.

The query package exports a single Values() function. A simple example:

type Options struct {
  Query   string `url:"q"`
  ShowAll bool   `url:"all"`
  Page    int    `url:"page"`
}

opt := Options{ "foo", true, 2 }
v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"

See the package godocs for complete documentation on supported types and formatting options.

Alternatives

If you are looking for a library that can both encode and decode query strings, you might consider one of these alternatives:

go-querystring's People

Contributors

anthonyjpratti avatar bouwdie avatar dependabot[bot] avatar ernesto-jimenez avatar ftdave avatar ggicci avatar karstengresch avatar micanzhang avatar mmorel-35 avatar rican7 avatar sqs avatar willnorris avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-querystring's Issues

Querystring not adding [] for the array types

I have this code. Playground Link: https://play.golang.org/p/9ot5J7BkmYI

package main

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

type Options struct {
	Filter struct {
		ShipmentTypes []string `url:"shipmentTypes"`
	} `url:"filter"`
}

func main() {
	opt := Options{}
	opt.Filter.ShipmentTypes = []string{"NORMAL", "DROP"}
	v, _ := query.Values(opt)
	fmt.Println(v.Encode())
}

Returns

filter[shipmentTypes]=NORMAL&filter[shipmentTypes]=DROP

I want the result to return in below format how do i do that ?

filter[shipmentTypes][]=NORMAL&filter[shipmentTypes][]=DROP

Support alternative struct tags (instead of `url`)

We use Gin, and we're looking at using this library. Gin provides a BindQuery method, which decodes query params from a request into a struct, so long as the incoming request matches the expected names, expressed via the struct tag form.

We'd like to be able to use the same struct tags for encoding and decoding. In order to do so, we'd like to be able to configure this library to reflect on a different struct tag during encoding. In our case, we'd like to be able to configure this library to use the same struct tag as Gin, i.e., the form tag.

Would you be open to a PR that implements configurable struct tags?

I'm not sure what the best mechanism would be, perhaps a build flag or ENV_VAR. Any suggestions here would be most welcome.

Parsing query strings into a map

Parsing query strings into a struct is sufficient and works well in many situations. But, in situations where the input data contains dynamic field names it is not possible to match the input into a struct.

For instance, consider the following example where a set of filters are passed:

/test?filter[size]=large&filter[size]=small&filter[color]=red&filter[color]=blue

If the endpoint is always supposed to filter based on size and color it is then possible to decode the query strings into a URL. But, if size and color are just examples (and many other values can be used instead) decoding into a struct will not work.

In this case, using a map[string][]string would work. But, there could be more generic cases (e.g., nested deep objects). See this discussion in the OpenAPI spec repo for some examples. (see also https://github.com/ljharb/qs for an implementation in nodejs)

Would you consider adding support for parsing query strings into a map? What about an even more generic solution like the ones being proposed in the OpenAPI spec repo?

Slice (Array) pointer does not result in array query values

type A struct {
B *[]string url:"b,omitempty"
}

l := []string{"c", "d"}
a := A{B: &l}
v, _ := query.Values(a)
v.Get("b")[0] //expected "foo" -> got "[ foo bar ]"

This is because pointers are not passed to the reflectValue again, but rather just become the element value. 🔢

can you please update the tag?

Hi,
There are some recent updates in this package that I'd like to import via dependency, but when I get the latest release, it is several years old.
Thanks,

Unable to handle nil pointers when implementing Encoder

With the default decoding, a nil pointer is encoded as an empty string (unless omitempty was specified) so a nil *int will encode to an empty string. But when implementing a custom encoder, there is no way to check if value was nil as the value will be initialized to the zero value before EncodeValues is called.

Support RFC Specific Encoding

I have a Go client that is communicating with a server that follows RFC 1738 URL encoding rules. RFC 1738 has since been updated (replaced) by RFC 3986, which is what Go seems to be using, at least in v1.17.7.

s := "blue+~light blue"
s = url.QueryEscape(s)
fmt.Println(s) // blue%2B~light+blue

In RFC 1738, ~ is a reserved ("unsafe") character and should be encoded as %7E, whereas in RFC 3986 it's not necessary to encode ~. This is just one difference between the two RFCs, there are likely others that I've not looked into yet, which is why a naive approach of replacing ~ with %7E isn't the path I want to go down.

Can you provide a way to generate "RFC 1738 compatible" encoded URL, perhaps by accepting an RFC number parameter? time already does this:

t.Format(time.RFC822)
t.Format(time.RFC850)
t.Format(time.RFC1123)
t.Format(time.RFC3339)

Non-nil pointer to slice not encoded properly

What
Pointers to non-nil values are not being encoded properly. The options are not being considered when encoding a pointer to a slice with the brackets options.

Sample Code
Below is a snippet that is able to reproduce the issue:

package main

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

type Query struct {
	List []string `url:"list,omitempty,brackets"`
}

type QueryWithPointer struct {
	List *[]string `url:"list,omitempty,brackets"`
}

func main() {
	q1 := Query{List: []string{"value1", "value2"}}
	qs1, _ := query.Values(q1)

	q2 := QueryWithPointer{List: &[]string{"value1", "value2"}}
	qs2, _ := query.Values(q2)

	fmt.Println(qs1.Encode()) // list%5B%5D=value1&list%5B%5D=value2 <- CORRECT
	fmt.Println(qs2.Encode()) // list=%5Bvalue1+value2%5D <- INCORRECT. Output doesn't consider brackets option
}

I believe moving the pointer dereferencing check above the slice/array logic handler solves the issue. I'm happy to put up a PR if you think this is a valid solution!

Is there a way to write a custom marshaller for my custom type?

Here is a code sample:

type Options struct {
	Level Level `url:"level,omitempty"`
}

opt := Options{Info}
v, _ := query.Values(opt)
fmt.Println(v.Encode()) // got "level=info", want "level=1"

Where the custom type is:

type Level int

const (
	Info Level = iota + 1
	Error
)

func (l Level) String() string {
	switch l {
	case Info:
		return "info"
	case Error:
		return "error"
	default:
		return ""
	}
}

How to encode nested structure by my way?

As you showed in the demo, for a struct, the encoded value is “user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO”, If I don't want to use "[]" to split, but ".", like“user.name=acme&user.addr.postcode=1234&user.addr.city=SFO”,Is there a way to achieve this?Thank you.

Supporting slices

👋🏻

I'm trying to encode:

type Example struct 
	Services  []string   `url:"services,omitempty"`
}

But I'm seeing the encoded values equate to services=A&services=B as apposed to what I was hoping to get back, which was services[]=A&services[]=B.

Is there a way to achieve this using this library?

I'm taking over a project which has a similar bug but the project uses https://github.com/ajg/form where it encodes as services.0=A&services.1=B.

Thanks.

Parsing?

Golang's standard net/url parse builds flat query params:

?a[]=1&a[]=2&b[c]=d

results:

map[string][]string{
"a[]": []string{"1", "2"},
"b[c]": []string{"d"}
}

what is needed:

map[string]interface{}{
"a": []string{"1", "2"},
"b": map[string]string{"c": "d"}
}

how to convert from JSON to querystring

// data from client rpc request in bytes

data := []byte({ "a": { "b": 1 }, "c": [1, 2, 3] })

Now we need make url request with querystring from this json

How can we do it with your module if we don't know struct exactly?

Add support for struct field name casing options

TL;DR: Add support for camelCase and snake_case (commonly used formats for URL encoding) options in query.Values() function.

This package, by default, uses the struct's field names for URL query parameters. While the package supports defining custom field names using the url field tag, it is not possible add custom tags in certain scenarios, for example:

  1. When using external packages' struct definitions.
  2. When using structs that are tool-generated (protobuf, for example).

query/encode.go

package query
...

type Case int32
const (
    CASE_DEFAULT    Case = 0
    CASE_CAMEL      Case = 1
    CASE_SNAKE      Case = 2
    CASE_PASCAL     Case = 3
)

type Options struct {
    EncodingCase  Case
}

func Values(v interface{}, opts Options) (url.Values, error) {
...
}

usage.go

import "github.com/google/go-querystring/query"
import "some/external/package"
...
v, _ := query.Values(package.SomeStruct{}, Options{EncodingCase: query.CASE_CAMEL})

Clean up tests

I wrote most of the tests for this package, and even I have trouble following what they're actually doing, much less have confidence that they're actually covering all of the cases that we care about. I don't have a lot of immediate ideas for what needs to happen, though using better type and field names is probably a good start.

Custom `String` implementations are not respected

Hello! I expect the following example to print int=23&foo=bar, but instead it prints int=23. It looks like this was previously working in #45, so there might have been a regression.

package main

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

type Foo struct{}

func (f Foo) String() string {
	return "bar"
}

type Options struct {
	Int int `url:"int"`
	Foo Foo `url:"foo"`
}

func main() {
	opt := Options{23, Foo{}}
	v, _ := query.Values(opt)
	fmt.Println(v.Encode())
}

Adding support to encoding of nested struct arrays

I plan to fix the issue described below for encoding nested struct arrays.

Currently this structure

type Nested struct {
    A string `url:"theA,omitempty"`
    B string `url:"theB,omitempty"`
}
type NestedArr []Nested
na := struct {
        A NestedArr `url:"arr"`
        B Nested    `url:"nested"`
    }{
        A: NestedArr{Nested{
            A: "aa",
            B: "bb",
        }, Nested{
            A: "aaa",
            B: "bbb"}},
        B: Nested{
            A: "zz",
            B: "xx",
        },
    }

encode to

arr={aa bb}&arr={aaa bbb}&nested[theA]=zz&nested[theB]=xx

To be consistent with the Ruby style parsing the result should look like this

 arr[0][theA]=aa&arr[0][theB]=bb&arr[1][theA]=aaa&arr[1][theB]=bbb&nested[theA]=zz&nested[theB]=xx

Add support for JSON encoding a struct field

Will be submitting a PR to add support for JSON encoding a nested struct field.

A specific API endpoint I am working on requires a URL encoded form but one of the form fields is JSON. The PR will add an option that will encode the field as a JSON string.

For example:

type A struct {
    V string `json:"v"`
}

type B struct {
    A A `url:"a,json"`
}

// url.Values{
//     "a": {`{"v": "abc"}`}
// }

Thanks and best regards,

schmorrison

Allow arbitrary delimiter for slice/array type params

Currently, only comma, space, and semicolon can be used as delimiters for parameters with multiple values. Lately, I came across multiple APIs which used encoded "I" as the delimiter.

It would be nice to use arbitrary delimiter with something like del:|

Support pointer method (*Type)EncodeValues on the Encoder interface

On the Encoder interface if the method will be defined as a pointer on the type it will be ignored even if it got implemented

type Working bool

func (d Working) EncodeValues(k string, v *url.Values) error {
	if d {
		v.Add(k, "yes")
	} else {
		v.Add(k, "no")
	}
	return nil
}

type NotWorking bool
// as a pointer EncodeValues
func (d *NotWorking) EncodeValues(k string, v *url.Values) error {
	if d != nil && *d {
		v.Add(k, "yes")
	} else {
		v.Add(k, "no")
	}
	return nil
}

go playground

Structure fields original order messed up

Hi
Thanks for your work!

Code sample from README states:

type Options struct {
  Query   string `url:"q"`
  ShowAll bool   `url:"all"`
  Page    int    `url:"page"`
}
opt := Options{ "foo", true, 2 }
v, _ := query.Values(opt)
fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"

Question is about this: fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"

But the actual output is all=true&page=2&q=foo for me. It could be critical, for example, if you need to generate payload based signature, since json.Marshal(opt) keeps original keys order:

type Options struct {
	Query   string `url:"q" json:"q"`
	ShowAll bool   `url:"all" json:"all"`
	Page    int    `url:"page" json:"page"`
}
opt := Options{ "foo", true, 2 }
v, _ := json.Marshal(opt)
fmt.Print(string(js)) // outputs {"q":"foo","all":true,"page":2}

allow any type to support IsZero()

The time.Time type has an IsZero func that determines if it is a zero value. There's no reason we couldn't allow other types to do the same. We just need to add our own interface:

type zeroable interface {
    IsZero() bool
}

please tag and version this project

Hello,

Can you please tag and version this project?

I am the Debian Maintainer for go-querystring and versioning would help Debian keep up with development.

Marshal & Unmarshal functions

Hi guys!
I would like to implement Marshal & Unmarshal functions like in encoding/json package.
Please, let me know what you think.

encode_test.go: Errorf format %q has arg s of wrong type

Go 1.12.2 on Fedora Rawhide

Testing in: /builddir/build/BUILD/go-querystring-1.0.0/_build/src
      PATH: /builddir/build/BUILD/go-querystring-1.0.0/_build/bin:/builddir/.local/bin:/builddir/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin
    GOPATH: /builddir/build/BUILD/go-querystring-1.0.0/_build:/usr/share/gocode
   command: go test -buildmode pie -compiler gc -ldflags "-X github.com/google/go-querystring/version=1.0.0 -extldflags '-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '"
   testing: github.com/google/go-querystring
github.com/google/go-querystring/query
# github.com/google/go-querystring/query
./encode_test.go:194:3: Errorf format %q has arg s of wrong type struct{a string; A string; B string "url:\",omitempty\""; C string "url:\"-\""; D string "url:\"omitempty\""; E *string "url:\",omitempty\""}
./encode_test.go:203:3: Errorf format %q has arg s of wrong type struct{a string; A string; B string "url:\",omitempty\""; C string "url:\"-\""; D string "url:\"omitempty\""; E *string "url:\",omitempty\""}
./encode_test.go:301:3: Errorf format %q has arg s of wrong type struct{Args *github.com/google/go-querystring/query.EncodedArgs "url:\"arg\""}
./encode_test.go:306:3: Errorf format %q has arg s of wrong type struct{Args *github.com/google/go-querystring/query.EncodedArgs "url:\"arg\""}
FAIL	github.com/google/go-querystring/query [build failed]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.