ggicci/httpin

How do I use nested structs from query?

vamshiaruru32 opened this issue ยท 5 comments

I have a type like this:

type ListPagesInput struct {
	CustomerID       string                  `in:"path=customerID" validate:"required"`
	PaginationParams PaginationParams `in:"query=pagination{}" validate:"required"`
}
type PaginationParams struct {
	Cursor    string `in:"query=cursor"`
	SortOrder string `in:"query=sortOrder"` 
	Limit     int32  `in:"query=limit"`
}

I am unable to figure out how to send it as part of query string. I tried making a request like this: http://localhost:8701/v1/customer/shop/pages?pagination={limit:1}, but the PaginationParams doesn't seem to be getting values from the query string (limit is always zero).
Any help is appreciated, thanks.

httpin doesn't support nested fields. The input struct should be flat, so the embedding can work, like this:

type ListPagesInput struct {
	PaginationParams
	CustomerID string `in:"path=customerID" validate:"required"`
}

type PaginationParams struct {
	Cursor    string `in:"query=cursor"`
	SortOrder string `in:"query=sortOrder"`
	Limit     int32  `in:"query=limit"`
}

For the query, it can be:

/v1/customers/:customerID/shop/pages?limit=1&cursor=xxx

Thank you @ggicci , that is how I ended up doing it. Are there any plans to support nested params?
And thanks for the great library, it has saved me a lot of effort :)

Sorry, I won't accept the idea of supporting nested parameters. It just make things complicated. I will document this limitation in an obvious location.

Thank you for your appreciation, I am also very happy that this package helped you.

ggicci commented

I reconsidered about the feature of supporting nested parameters today. It can be useful for cases like the following:

type Apperance struct {
	Foreground string `in:"form=fg"`
	Background string `in:"form=bg"`
	Opacity    int    `in:"form=opacity"`
}

type RequestForm struct {
	Light Appearance
	Dark  Appearance
}

In one request, we are going to submit a form that having multiple form data (i.e. Light and Dark) of a same data structure (i.e. Apperance). And for the HTTP request form, it'd be better off distinguishing same name sub-fields under different fields by a "namespace". For example, for the fields of Light, we can prefix with a "light". In the same way, for the fields of Dark, we can prefix with a "dark". The form request now looks like:

POST /settings/appearances

light.fg=black&light.bg=white&light.opacity=10&dark.fg=white&dark.bg=black&dark.opacity=90

Currently, since the input struct needs to be flat, we can archive this by defining the Appearance twice, like this:

type LightApperance struct {
	Foreground string `in:"form=light.fg"`
	Background string `in:"form=light.bg"`
	Opacity    int    `in:"form=light.opacity"`
}

type DarkApperance struct {
	Foreground string `in:"form=dark.fg"`
	Background string `in:"form=dark.bg"`
	Opacity    int    `in:"form=dark.opacity"`
}

type RequestForm struct {
	LightApperance 
	DarkApperance
}

It looks simple, but to some extent not flexible. Here I propose to add a new directive called ns (namespace), it can be applied to a field of a struct type to define the namespace of this field. The namespace will be visible to all its sub-fields. And how this namespace will be utilized is the business of the directives. Now, we can define the RequestForm like this:

type RequestForm struct {
	Light Appearance `in:"ns=light"`
	Dark  Appearnce  `in:"ns=dark"`
}

And, for the form directive, it should respect the namespace where the field resides.

I'll work on this ASAP. But it still can be subject to change.

Also updates #61

ggicci commented

After consideration, the above idea I finally rejected. The reason is: never make the query and form data complicated, post JSON/XML body for complicated usecases instead.