ggicci/httpin

querystring directive

davidalpert opened this issue · 5 comments

would a querystring directive which extracts values from the request.URL.Query() values be of use?

I would be happy to draft a pull request...

something like:

type Pagination struct {
	Page int `in:"form=page;query=page"`

	// Decode from multiple keys in the same source, the former with higher priority
	PerPage int `in:"form=per_page,page_size;query=page_size"`
}

I took a look at implementing one as a custom directive in my own project but it seems like it would share so much logic with the form directive extractor that I thought it may be simpler to offer it in the box alongside the form extractor.

A common use case might be an API which allows a short query value passed in a URL param in a GET request but a longer or more complex query value to be passed in the form body of a POST

in fact, after a bit of experimentation all it needs is:

// queryValueExtractor implements the "query" executor who extracts values from
// the querystring of an HTTP request.
func queryValueExtractor(ctx *DirectiveContext) error {
	return extractFromKVS(ctx, ctx.Request.URL.Query(), false)
}

and

	RegisterDirectiveExecutor("query", DirectiveExecutorFunc(queryValueExtractor), nil)

and then this test passes:

type SearchQuery struct {
	Query      string `in:"query=q;required"`
	PageNumber int    `in:"query=p"`
	PageSize   int    `in:"query=page_size"`
}

func TestEngine(t *testing.T) {
                  
	Convey("Get with QueryString params", t, func() {
		r, _ := http.NewRequest("GET", "/?q=doggy&p=2&page_size=5", nil)
		expected := &SearchQuery{
			Query:      "doggy",
			PageNumber: 2,
			PageSize:   5,
		}

		core, err := New(SearchQuery{})
		So(err, ShouldBeNil)
		got, err := core.Decode(r)
		So(err, ShouldBeNil)
		So(got, ShouldResemble, expected)
	})

}

I cannot do this from outside the library as extractFromKVS is unexported.

I would be happy to provide these changes as a pull request, if this syntax is acceptable for inclusion into the core library.

query directive is offered as PR #6

Sorry for the late response and thanks for the PR. However, does the query directive work just like form? The form directive had already implemented the way of extracting parameters from the querystring. In my opinion, they are the same thing.

For example,

type SearchQuery struct {
	Query      string `in:"query=q;required"`
	PageNumber int    `in:"query=p"`
	PageSize   int    `in:"query=page_size"`
}

you could just replace query with form. It should work.

Or did I miss something?

this is interesting.

it seems that you are correct; when I updated the tags in that unit test to use the form directive in the QueryString test it passed.

I will go back to the project that I attempted to use this library in and try it again.

If I can make it work there as well I propose to:

  • update the PR to use the form tag and
  • update the documentation to demonstrate using the form tag to parse querysting values.

#6 was merged; the PR contains some discussion about the nuance between the query directive (which pulls only from the request.URL.Query() collection) and the form directive (which merges values, first from request.URL.Query() then from request.Form where form values will override query values when the keys match).