----
Kyle Lemons
Georgia Tech Computer Engineering '10
Sent from my iPhone, so pardon any spelling or punctuation issues!
On Jun 12, 2011, at 3:40 PM, Michael Beale
The easiest way without using third-party packages would be to use
regular expressions and capture the portions you want. For your
example, you could do something like:
r := regexp.MustCompile(`/v1/items/([0-9]*)\.(.*)`)
vars := r.FindStringSubmatch(req.URL.Path)
(Assuming that id is a number and formatvar can be anything.)
The downside is that you can't name your submatches, so you have to
know the order. You also probably don't want to compile the regular
expression every single time you run the handler. :)
- Evan
If you don't mind using http query urls (e.g.: /v1/items/?id={id}
&formatvar={formatvar} ) you can use http.ParseQuery or
http.Request.FormValue.
router.post = append(router.post, route)
You could do something similar to what the http package does and
create a Handler interface:
type Handler interface {
Serve(w http.ResponseWriter, r *http.Request, v map[string]string)
}
if you want to continue passing lone functions as handlers, you can
follow the http package again and create a HandlerFunc type.
> Also with the
> mapping of url variables , the best way I thought of was using
> a map that contains key/values for the url variables, anybody have any
> different ideas?
That's probably the best way without getting into reflection. Even
with reflection your options are somewhat limited since function
parameter names aren't exposed.
> Another question I have that was confusing me a bit was the slices
> that I created to store routes. I tried to add routes to the slices
> without
> initializing them but got an "out of bounds" error. My code is this:
That's because the zero value for a slice has a length and capacity of
zero. Thus any index into it is out of bounds and when you want to
expand, there's nowhere to go.
> n := len(router.post)
> router.post = router.post[0:n+1]
> router.post[n] = route
A better way to do it would be to use append. Replace those three lines with:
router.post = append(router.post, route)
If you do this, you don't necessarily have to preallocate the slices,
but you can choose to for efficiency reasons.
You're going to be unnecessarily redoing a lot of work for every
request in findRouterMatch. You should move some of that work into
AddRoute so it's done only once.
Also, I'd find your code easier to read if you ran gofmt on it. ;)
- Evan
> You could do something similar to what the http package> does and create a Handler interface:>> type Handler interface {> Serve(w http.ResponseWriter, r *http.Request, v map[string]string)> }The problem with this approach is that the handlers don't compose with other handlers written to the http Handler interface. It would be nice if http.Request had a map[string]interface{} field where gorouter and other handlers can store arbitrary data associated with the request.
If the following field is added to http.RequestEnv map[string]interface{}
> I think the whole point of it is to not standardize, right?A standard can not and should not enumerate everything that an application might want to associate with a request. Example: The appengine.Context object can be passed through the map[string]interface{}, but it's not appropriate to declare the context object in the standard library.
Russ
In your proposal, the map[string]interface{} becomes something
that we have to keep in the API forever. If someone imports
"http" it's not clear whether they're trying to use this magic map.
In Brad's proposal, the RequestVariable can be in your own
package. You can use it no matter what we do to the API
and we don't have to maintain your code for you.
It really seems like a great solution.
If you care a lot about having a map then you could
put a
func Env(req *http.Request) map[string]interface{}
in gorouter or whatever is dispatching the requests,
using Brad's code, and still not need to change package http.
Russ