Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom context for mux.Vars #187

Closed
Southern opened this issue Aug 20, 2016 · 8 comments
Closed

Custom context for mux.Vars #187

Southern opened this issue Aug 20, 2016 · 8 comments
Assignees
Labels

Comments

@Southern
Copy link

Southern commented Aug 20, 2016

Is there a particular reason that varsKey and routeKey are using the contextKey type? https://github.com/gorilla/mux/blob/master/mux.go#L322-L327

This causes problems when attempting to use request.WithContext(context.WithValue(request.Context(), 0, map[string]string{...})) for testing route params because mux.Vars is looking for contextKey(0) as the key rather than int(0).

@Southern Southern changed the title Custom context in mux.Vars Custom context for mux.Vars Aug 20, 2016
@elithrar
Copy link
Contributor

elithrar commented Aug 20, 2016

The custom, private types exist so that other packages won't clobber over it. If any other user was using int(0) as a key, it would override mux's vars.

@elithrar elithrar self-assigned this Aug 20, 2016
@Southern
Copy link
Author

Southern commented Aug 21, 2016

Ah. In that case, could we expose ContextKey or something so that mux.Vars can be used without having to setup a route and use httptest?

@elithrar
Copy link
Contributor

Would the solution in #167 not work for you? Directly mutating internal state should be avoidable.

@Southern
Copy link
Author

Southern commented Aug 21, 2016

Of course it would work, but I'm not trying to handle the response or even care about the route itself. I'm just pulling params from the *http.Request.

It would be so much easier for people to use something like:

request, _ := http.NewRequest("PATCH", "", nil)
ctx := context.WithValue(request.Context(), 0, map[string]string{
    "param1": param1,
    "param2": param2,
})
data := mapParams(request.WithContext(ctx))
// assertions to check data

Verses having all of this to achieve the same result:

router := mux.NewRouter()
router.HandleFunc("/{param1}/{param2}", func (response http.ResponseWriter, request *http.Request) {
    data := mapParams(request)
    // assertions to check data
})

ts := httptest.NewServer(router)
defer ts.Close()

url := fmt.Sprintf("%s/%s/%s", ts.URL, param1, param2)
request, _ := http.NewRequest("PATCH", url, nil)

c := &http.Client{}

response, e := c.Do(request)
if e != nil {
    t.Error(e)
}

@elithrar
Copy link
Contributor

If you're testing multiple routes via table-driven testing, I would think
the extra 5-10 lines of boilerplate would be a wash?

The benefit to not just injecting into the context is that you also ensure
that mux's own route/var parsing is what your application expects over
time, rather than shortcutting it.
On Sat, Aug 20, 2016 at 7:36 PM Colton Baker [email protected]
wrote:

Of course it would work, but I'm not trying to handle the response or even
care about the route itself. I'm just pulling params from the
*http.Request.

It would be so much easier for people to use this:

request, _ := http.NewRequest("PATCH", "", nil)ctx := context.WithValue(request.Context(), 0, map[string]string{
"param1": param1,
"param2": param2,
})data := mapParams(request.WithContext(ctx))// assertions to check data

Verses having all of this to achieve the same result:

router := mux.NewRouter()
router.HandleFunc("/%s/%s", func (response http.ResponseWriter, request *http.Request) {
data := mapParams(request)
// assertions to check data
})
ts := httptest.NewServer(router)defer ts.Close()
url := fmt.Sprintf("/%s/%s", param1, param2)request, _ := http.NewRequests("PATCH", url, nil)
c := &http.Client{}
response, e := c.Do(request)if e != nil {
t.Error(e)
}


You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
#187 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABIcPl2tvEpi5xITBoyThUgOEzwFY3Zks5qh7mhgaJpZM4JpFkr
.

@Southern
Copy link
Author

I'm not testing routes at all. I would just like to be able to force a context with params during testing instead of setting up a router, handler, httptest server, http client, and then finally be able to send my request for testing.

I'm not sure that's a benefit because I highly doubt most people will ever want to modify the context during runtime in the first place.

@chr0n1x
Copy link

chr0n1x commented Sep 13, 2016

I'm not testing routes either. Instead, I have collections of func(ResponseWriter, *Request)s that I would just like to test without having to set up an http server. All I want to do is call http.NewRequest and throw the object directly into the handlers to test specific cases.

That being said, I do see my doing this as a code smell in my application. I guess that it would be preferable to have middleware that passes mux.Vars(r) as a separate argument to all of my handlers, however that's a fairly large refactor in my apps current state.

@elithrar - do you have any other suggestions on how to test functions that use mux.Vars(r)? I kind of want to avoid splitting mux.Vars(r) calls into a separate object that I can swap out with some sort of test dummy object.

@grim-fendango
Copy link
Contributor

Hey we can close this now 🎉 since this PR has been merged.

To set context vars you just need to do the following:

request, _ := http.NewRequest("PATCH", "", nil)
request = mux.SetURLVars(request, map[string]string{
    "param1": param1,
    "param2": param2,
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants