I've been toying with the idea of using uritemplates for go-github for a little while now. In particular, I'm interested in trying to clean up some of the code I have for appending query parameters, that currently looks something like:
type ListOptions struct {
Page int
}
func (s *OrganizationsService) List(user string, opt *ListOptions) ([]Organization, error) {
u := fmt.Sprintf("users/%v/orgs", user)
if opt != nil {
params := url.Values{
"page": []string{strconv.Itoa(opt.Page)},
}
u += "?" + params.Encode()
}
...
}
For small option types this isn't too bad, but gets worse with larger ones and just seems like it could be cleaner. What I've been thinking about is mimicking how encoding/json
and encoding/xml
use field tags. So something like:
type ListOptions struct {
Page int `url:"page"`
}
func (s *OrganizationsService) List(user string, opt *ListOptions) ([]Organization, error) {
u := fmt.Sprintf("users/%v/orgs", user)
u += uritemplates.Parse("{?page}").Expand(ListOptions)
...
}
Of course, I would ideally just have a single line with a template of users/{user}/orgs{?page}
, but I haven't decided on the best way to pass the user into Expand()
yet. I don't want to put it in ListOptions
since it's a required parameter to the List()
function and I want that to be explicit.
There are of course ways to do this by converting the struct into a map first, and then passing that to Expand()
, but I figured I'd float this idea to you and see what you thought.