visionmedia / express-resource

Resourceful routing for Express
1.41k stars 140 forks source link

url helpers #20

Open tj opened 13 years ago

pacovell commented 13 years ago

Are you referring to rails-style route helpers?

Along the lines of: /**

I am working on these, would be happy to style them for better integration into express-resource. Right now I am attaching them as dynamicHelpers, but I haven't worked out the best way to make them available in the controllers.

tj commented 13 years ago

kinda yeah. controllers can just use regular modules, no need for helpers really, and most helpers are view related so controllers shouldn't really be using them anyway.

pacovell commented 13 years ago

If we write the functions to construct a route from the resource, those can be useful in both the view and the controller:

It would be nice to get two-for-one, at least if people want it. I think this can be done cleanly by writing a module for the controllers and then a wrapper module for the dynamicViewHelper that people can use if desired, but I am new to this architecture so please "redirect" to your vision.

Bigger picture, am I understanding the types of methods you are thinking of, or did you have something else in mind?

tj commented 13 years ago

yeah, but it's JS so you'll never have something "clean" like list_path() automatically injected into the scope, you'll have req.list_path() or something, but yeah I agree there that it would be handy.

japj commented 13 years ago

this ticket looks like something I am also looking for in relation to a django 'reverse' use I have at the moment, see also https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse

Basically in django I have something like:

url(r'^(?P<version>[0-9.]+)/(?P<product>[^/]+)/*$', name="specific-product");

And later I have something like:

fullUrl = request.build_absolute_uri(reverse("specific-product", args=["foo", "bar"]))

and fullUrl is then basically "http://server:port/baseurl/foo/bar" which I currently return in an existing rest api.

Specially important here is that 'my code' would not need to know about server, port or baseurl. Just 'specific-product' and the fact that it expects 2 parameters (version and product).

tj commented 13 years ago

yikes! what a verbose way to get a url :s I know what you mean though, rails (and I guess every mvc framework) has similar.

pacovell commented 13 years ago

japj, if I understand you correctly, you are actually using two segments of the path to identify a unique resource (foo+bar), and that is how your example differs from mine, am I right?

In normal RESTful routing, you would have /resource_name/:id/sub_resource_name/:sub_resource_id

So I think you need /resource_name/:id_part_1/:id_part_2

Correct? I have not looked into the guts of express-resource enough to know if this is a major change or not. If express-resource can accommodate it reasonably, then I suspect I could maneuver the URL generation code I have in mind to handle it as well. TJ?

pacovell commented 13 years ago

OK, I have this a first pass, please have a look at https://github.com/donedotcom/express-resource/commit/cd8e08c6e07433335525e528a0506ca72938ca48 (and https://github.com/donedotcom/express-resource/commit/544123a1659c1dd4f06dd87c04f57f916cd6abfa, I missed the test resources the first time around).

I've made a few design decisions that I am happy to take other directions on so that we can get this integrated: 1 - Top level object (app.resource.path.forum(forumObj)) 2 - A bit hacky way to delete when resources become nested (but this is maybe a necessary evil) 3 - I chose to call the unnamed top level object (if present) "roots" so the plural works. This is a little weird (resource.app.path.roots()) and I am open to better suggestions. Without plural you have overloaded methods. This is related to how express resource handles this route -- for example, if this.name were still "forum" and the this.param were :forum even if it's the unnamed root object, we could implement this naturally as well. IMO, this would be preferable overall because I may choose to move it later and I should not need to change my code from :id to :forum,etc, to do that.

I am still new to JS so please feel free to aggressively comment on implementation decisions.

pacovell commented 13 years ago

Additional changes, see the head of my fork. Bug fixes and also I renamed functions to be _path for consistency when I integrate into the dynamicViewHelper -- it turns out to be a bad idea to have functions like 'users' injected into the view scope as they can often be the same name as local objects defined by the controller.

pacovell commented 13 years ago

Dynamic View Helpers implemented here, not sure where/if to include them in express-resource, please advise. If nothing else, maybe we can make them an example.

https://gist.github.com/1078292

japj commented 13 years ago

sorry for the late reply, but I have been a bit busy with work. I am going to look at this tomorrow evening and give you feedback then, is that ok?

pacovell commented 13 years ago

Excellent, any time you can get to it.

On Wed, Jul 13, 2011 at 2:43 AM, japj < reply@reply.github.com>wrote:

sorry for the late reply, but I have been a bit busy with work. I am going to look at this tomorrow evening and give you feedback then, is that ok?

Reply to this email directly or view it on GitHub:

https://github.com/visionmedia/express-resource/issues/20#issuecomment-1560497

japj commented 13 years ago

Regarding

/resource_name/:id/sub_resource_name/:sub_resource_id 

I think that correctly resembles how I should have modeled my rest api. (I will need to update my server and client to correctly behave that way, but it makes sense to have it behave as nested resources).

For 'id' your example currently uses integers. Would this also work when 'id' is actual a word or something like "192.168.1.2"?

I note that the path functions expect an object with 'id' to be passed to it. However since action information is provided in the req.params, it might be usefull if one can do:

app.resource.path.forum_thread(req.params.forum, req.params.thread)

Last question, since I'm not entirely familiar with how this is done in nodejs: where would one get the server/ip part for the url? i.e. when app.resource.path.forum_thread(forumObj, threadObj) returns '/forums/5/threads/50', where does one get "http://servername:port/" from to combine it to a full url?

pacovell commented 13 years ago
japj commented 13 years ago

With req.params.forum I meant the routing behaviour from http://expressjs.com/guide.html#routing where '/user/:id' ends up as req.params.id. I think it makes sense for the app.resource.path.xxx calls that information in req.params could be passed for some of the information.

tj commented 13 years ago

yeah :foo essentially attempts to consume as much as possible within a path segment, whereas * grabs as much as it can spanning segments ("/")

pacovell commented 13 years ago

I've updated my fork to behave as described above:

user_path(5) or user_path("5") will result in /users/5. user_path({id: 5}) still works, of course. If there is a collision the object property version will win out.

antitoxic commented 12 years ago

Hi guys, I know this is an old thread but I've been working on a router that allows named routes and generating back a URL by route name and parameters. I closely investigated how the express router works especially dispatch area which almost kept the same.

If you can have a look at https://github.com/web-napopa/node-reversable-router.

I have a single url() helper that generates the URLs. If you think though I can change the logic and create a helper per route.

I also have other features in there. Give me shout if you find them useful or not.

I got it all working with XRegExp and your methods module.