Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

url helpers #20

Open
tj opened this Issue · 18 comments

4 participants

@tj
Owner
tj commented

No description provided.

@pacovell

Are you referring to rails-style route helpers?

Along the lines of:
/**

  • resource: lists @ /lists
  • 1. lists_path() === /lists
  • 2. list_path(list) === /lists/
  • 3. edit_list_path(list) == /lists//edit
  • 4. lists_url() === http://:/lists *
  • resource: tasks @ /lists//tasks
  • 1. tasks_path(list) === /lists//tasks
  • 2. task_path(list, task) === /lists//tasks/
  • 3. edit_task_path(list, task) === /lists//tasks//edit */ ?

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
Owner
tj commented

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

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

  • Controller:
    res.redirect(list_path(list))

  • View (Jade format)
    a(href=list_path(list)) My List

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
Owner
tj commented

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

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
Owner
tj commented

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

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

OK, I have this a first pass, please have a look at donedotcom@cd8e08c (and donedotcom@544123a, 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

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

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

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
@japj

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
  • Yes, you're right that this is the more common / REST standard method for addressing nested resources.

  • :id is a placeholder, and so I imagine anything that is a valid URL would be accepted here, although it is possible that it gets munged somewhere along the line. You would want to test it. In that case, of course, your autoload function (if any) should be sure to behave appropriately.

  • Do you mean that your req.params.forum objects would be ID objects? Ie, not hashes or objects, but actually the id is the value of req.params.forum? I think this could be an easy change to check if typeof obj.id === 'undefined' and if not, just use the object value directly. Please let me know if I'm on the right track.

  • I am not sure off the top of my head about your last question -- I would poke around in the server object, since it should be in there. Then the only question is making it available to your controllers or views. If you need help with that I can suggest some info.

@japj

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
Owner
tj commented

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

@donedotcom donedotcom referenced this issue from a commit in donedotcom/express-resource
@pacovell pacovell Use object if object[idField] is undefined for path ID. Per discussio…
…n on Issue #20.
b4e69aa
@pacovell

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.