| Page 1 of 2 | [ 16 posts ] | Go to page 1, 2 Next |
|
I am experimenting with Y.Controller,and I think it is really a fresh way to do
this. I am mostly a backend developer, so being able to use a similar dispatch strategy as, e.g., Perl's CGI::Application, is a nice complement. In fact, I believe a solution that uses CGI::Application on the back end to handle asynchronous persistent data requests and initial HTML/JS deployment of the application and Y.Control on the front end to handle the "application" state is very elegant. However, I am running into some things with Y.Control that seem to make it a little more difficult for those of us on primarily focused on the back end. I am running through the "pie" example for Y.Controller. My first stumbling block had to do with what URL should I use to make the initial call to the application. The example seems to favor a URL that ends in a directory and therefore defaults to "index.html". So, for my testing, I created an index.html so that I could mirror as closely as possible this effect. This seemed to work fine. I then realized that a URL is a URL, so I set my rootpath as "/myapp/index.html". This worked fine (since it's just string, after all) on the browser. It becomes ambigious and breaks the intent of using the server as a fallthrough if a stateful URL gets accidentally sent to the server. So you get URLs "save"d or "replace"d as, "/myapp/index.html/pie". In the documentation, there is an example with a query string and rootpath, however, my main problem is not on the client side, but when a manufactured URL is for some reason sent to the server. The documentation says that one may implement server logic to handle the identical set of URLs, and infact it's common to use a "/" as a parameter delimiter. However, it's also the case that it's a lot more common that these "path variables" are not used. What's more common is that the query string is used to pass parameters and to maintain state in the URL. Query variables also have the nice quality that they are both benign to the webserver but significant tothe browser (i.e., index.html?x is treated as different than index.html?y by the browser, but not by the webserver if not set up to). Since it's extra work on the server side to make path variables (delimited with a "/") as benign as a query string (everything after the "?"), it's much more likely that an errant stateful URL sent to the server will cause "Internal Error" or 404 than a URL that is hiding everything after the "?" - particular if it's an HTML file. For this reason, I am looking for a way to use a "?" as the URL dispatch root rather than the "/". I know this brings into it the can of worms that is the query string, but since variables in the query string must be taken as unordered, it is okay for Y.Controller to enforce order. It won't break anything on the server, and if the request is sent to the server, it will be dutifully iqnored if not handled explicitly. On the other hand, "/" will break at the webn server level almost every time. So what am I suggesting? Here's an example. Instead of doing this: Code: // myapp/index.html is implied controller = new Y.Controller({ root: '/myapp', routes: [{ path: '/', callback: init }, { path: '/pie', callback: eatPie }, { path: '/wantsmore', callback: wantsMore }, { path: '/stillhungry', callback: stillHungry }, ] }); I'd like to be able to do this: Code: // using /myapp.html directly controller = new Y.Controller({ root: '/myapp.html', routes: [{ path: '?', callback: init }, { path: '?pie=yes', callback: eatPie }, { path: '?wantsmore', callback: wantsMore }, { path: '?stillhungry=dogballs', callback: stillHungry }, ] }); And, as the urls are built, they are done so like: [*] /myapp.html?pie=yes [*] /myapp.html?wantmore [*] /myapp.html?stillhungry=dogballs Rather than the following, which which isn't nearly as benign since the webserver really has no other choice than to interpret "myapp.html" as a directory. [*] /myapp.html/pie [*] /myapp.html/wantmore [*] /myapp.html/stillhungry If there is a way to do this immediately, that would be great for me and I think I could start using this immediately. If not, then I'd like to request the ability to use "?" in place of "/" for defining routes. I think the primary disambiguator here would be to either have a corresponding "root" or somehow denote that we want to append state to the root using a "?" rather than the "/". Thank you, Brett |
|
Controller is inherently path-based by design, and this is not something I want to change. However, it already supports query strings. You just have to treat them as query strings and not as paths. For example (untested, but should work):
Code: var controller = new Y.Controller(); controller.route('*path', function (req) { switch(req.query.action) { case 'pie': doPie(req); break; case 'cookies': doCookies(req); break; case 'ice-cream': doIceCream(req); break; } }); controller.save('?action=pie'); // dispatches to doPie() controller.save('?action=cookies'); // dispatches to doCookies() controller.save('?action=ice-cream'); // dispatches to doIceCream() Route definitions are a little less convenient this way, but that's the price you pay for doing query-based routing with a path-based router. Alternatively, you could subclass Y.Controller, duckpunch the crap out of it, and come up with a Y.QueryController that would do exactly what you want. Then, when you've finished it, throw it in the gallery. |
|
Thanks for the response.
I'm not really trying to make this about path-based vs query-based routing. I understand that the hierarchical nature of paths makes it a lot more convenient to deal with, but my primary point is that query-based routing is really a general case of how you're solving the path-based routing. I'll see what I can do, but I feel pretty strongly that you're missing the boat by forcing server application writers to deal with "paths-as-variables" if one of the major selling points of this approach is that the URL can fall through to the server in the event that, for example, the browser doesn't support JavaScript. I can understand why you're sort of stuck. Path-routing takes advantage of the hierarchical nature of URLs. I get that. Query strings are unordered, and therefore it's not as straightforward to compare isomorphic query strings (i.e., same key/values, different positions). But to this, I say that simply being able to set a bit that uses "?" and subsequent "&" to append rather than just the "/" to the URL would be a huge value added for a lot of people. As it stands right now, the path-based routing is decidedly biased towards directory-only root paths and it's not nearly as easy to implement fall through logic on the server side as you think without the option to treat the root as a "file" and therefore use "?"/"&" to build the paths as opposed to "/". That's really all I'm looking for. I am not asking that you treat isomorphic query strings as the same - or that you even see the query string as a key/value pair. If I could have the routing match on "?x=1&y=2&z=3" just as easily as "/x=1/y=2/z=3" (do you see the similarity?), I'd be a happy camper. I don't need the query string parsed, just a string matched and for the route to be triggered. I'll take a look at subclassing, but I really hope that you take what I am saying (as a backend developer) into consideration. Thank you, Brett |
|
I tried your workaround, and both .replace and .save prepend a "/" to whatever is passed to .save or .replace, breaking the purpose of the "?". This is the crux of my problem. I think it's a fine default behavior, but if it can't be turned off without subclassing, then that to me seems to be a problem. What is someone wants "root" to be a file? It'll break server requests almost every time.
Code: var controller = new Y.Controller({ root: '/index.html', }); controller.route('*path', function(req) { //alert(req.query.action); switch (req.query.action) { case 'pie1': eatPie(req); break; case 'pie2': wantsMore(req); break; case 'stillhungry': stillHungry(req); break; default: eatPie(req); break; }; }); controller.replace('?action=pie1'); controller.save('?action=pie2'); Given the code above, what I'd like to do is get the root based URL to reflect "/index.html?action=pie1" and "/index.html?action=pie2". What I get are: "/index.html/?action=pie1" and "/index.html/?action=pie2". This fundamental behavior/assumption makes Y.Controller unusable for my purposes, and I am not doing anything unusual. Update: If I take "index.html" out of "root" and add it to replace/save, it works: Code: var controller = new Y.Controller({ root: '/', }); var rootfile = 'index.html'; // ...... controller.replace(rootfile+'?action=pie1'); controller.save(rootfile+'?action=pie2'); I can work with this, but may I suggest the future ability to deal with both directory *and* file-based roots? Also, the documentation isn't particularly clear on the point of how to deal with file sensitive URLs, which is a pretty important detail when providing this "server side" fall through. Thank you, Brett |
|
The root should always be a directory, never a file. I'll clarify this in the docs.
It's important to note that Y.Controller is simply a convenient abstraction built on top of Y.History. There's nothing at all preventing someone from implementing a similar abstraction (or even just modifying Y.Controller) that uses query-based routing instead of path-based routing. I'm not interested in being that person because I think query-based routing is less broadly useful than path-based routing, but you and anyone else who wants this functionality are welcome to build it on top of the same foundational components that Y.Controller uses. |
|
Thank you. A clarification in the documentation would be nice, particularly addressing how to work with a file in the manner I am. I don't think that what I am doing is unusual for someone who's mostly used to backend stuff. Using the server request only as a fallback method is a very attractive technique, but as it stands now, it's incredibly easy (practically unavoidable) to fall into the trap that I did.
Note also that the "to do list" example uses Y.Model/ModeList and Y.View, but it doesn't use Y.Controller. It'd be nice to throw Y.Controller in there for show. I appreciate your time. Once I get through with what I am doing, I'll report back on the experience and workarounds I ended up having to use. Thank you, Brett |
|
Quote: I'll see what I can do, but I feel pretty strongly that you're missing the boat by forcing server application writers to deal with "paths-as-variables" if one of the major selling points of this approach is that the URL can fall through to the server in the event that, for example, the browser doesn't support JavaScript. On this point I disagree: Every web application framework I've worked with in the past three-ish years (Zend, CodeIgniter, Grails, Express, a few others) has adopted a default routing strategy similar to "/{controller}/{action}", where controller is a simple-string name of an MVC controller, and the action is a particular action that the controller supports. Y.Controller is ideal for this routing strategy. That's not to say that this is the best model for client side routing, but it has become extremely common. |
|
Quote: That's not to say that this is the best model for client side routing, but it has become extremely common. While this may be the case, there is quite a bit of server side code that could provide for server side URL fall through with little or not modification if using the query string, rather then that path, as the basis for state was simply an option. Also, I am not sure anyone who wants to play with Y.Controller won't run into the following scenerio: 1. on server - create myapp/index.html 2. create Y.Controller that appends to "myapp/" 3. play with it client side, accident reload or make request back to server with something like "myapp/pie/cherry" as the URL 4. bam - 404 in your face Who would do such a silly, naive thing just to test Y.Controller? Anyone on a shared host or on an machine where they do not posses root. That's a lot of people, let me tell you; and Y.Controller/Model/View based apps practically beg for delivery through just an html file. Why would you need anything else? Now, If you named it something other than index.html, then you have a whole new bag of problems since it's not clear that "myapp/whatever.html" isn't a suitable root; it must be be a directory. Optionally manipulating the URL with a query string rather than a path and having root able to also be a file would solve that problem immediately with no modifications to the webserver. Try to run through 1-4 above and tell me you don't trip over 404s. Regarding what is common on the client vs the server, as I said, a lot of legacy code uses query strings (e.g., Perl's still relevant CGI::Application). More "modern" Perl frameworks do use URL routing, but they also provide easy access to query parameters. But, this doesn't make a bit of difference since the problem that I see here is path-only routing on the *client* - if a server is doing path only routing, then there's a strong chance that it's already set up to do this from the webserver on down. Client based URL path routing doesn't reflect the reality of most webserver setups - it breaks the Y.Controller's promise of easy server side fall through. And note, that what I may be asking for isn't necessarily the best solution to what I want. Honestly, if all I could do was change what .save or .replace appended the state path to the root with (currently forced to be "/") to us "?" instead, what I am suggesting would be possible. Thank you, Brett |
|
Quote: While this may be the case, there is quite a bit of server side code that could provide for server side URL fall through with little or not modification if using the query string, rather then that path, as the basis for state was simply an option. It is an option. I described above how to use queries with Y.Controller. Queries are absolutely the right way to maintain state in a Y.Controller-based application. It's important to understand the distinction between routing and state. They aren't the same thing. Paths are for routing. Queries are for state. It's possible to use queries for routing. It's also possible to drive your car down the freeway in reverse. Neither of these things is a good idea. Quote: Honestly, if all I could do was change what .save or .replace appended the state path to the root with (currently forced to be "/") to us "?" instead, what I am suggesting would be possible. You can. https://github.com/yui/yui3/blob/master ... s#L800-830 |
|
Thank you. I have massaged your example above to suit my needs. I really do want to create some sort of QueryController extension to the Controller, but that will have to take a back seat to my primary task atm - I also want to do it in the right way.
So what problem will this solve for me if such a modification existed? It would allow one to use the idiomatic dispatch/router code rather than doing something non-idiomatic just because of some arbitrary distinction between paths/query params, routes/states. I get the distinction between routes and query states. What I am trying to deal with is a situation where there is no direct/physical server side analog to "/myapp/pie/cherry", there is only "/myapp" (which may be a directory or may be a server side script). In this situation "/myapp/pie/cherry" is handled in one of two ways: 1. you get a 404 because, literally, "/myapp/pie/cherry" is neither a directory, file, (or a default index.html, etc doesn't exist in /myapp/pie/cherry) 2. "/myapp/pie/cherry" is handle by the webserver and passes "/pie/cherry" as an input parameter to an application file located at "/myapp" In #1, you get a 404. Instant fail. In #2, because the server is configured to handle this, "/pie/cherry" is passed to "/myapp" as a runtime parameter, and is therefore no longer a route to the server side application. It is equivalent in nature to anything passed via the query string, after "?". To demonstrate what I mean, the following two things *could* be treated equivalently on the server if the physical "route" doesn't exist: /myapp?pie=cherry /myapp/pie/cherry The difference is the query based string is by default handled by the webserver and any Perl CGI:: based applications. The "route" based string isn't unless you're using something like Perl's "Dancer" framework. My point is that there is *a lot* of stuff out there based on CGI:: and other approaches that base state strictly on the query params. So, I believe a query based "route" controller would make it fairly straightforward for applications using this approach to benefit from client side routing as well. Does this make sense? I don't know how more clearly I can explain this. Because of this reasoning (i.e., a "route" can degrade to the equivalent of a query parameter on a server), my contention is that in some (many for me) circumstances, being able to treat a query idiomatically as a route on the client via the Controller would make handling the case outlined in #2 much, much simpler on the server. I hope my POV is clear. It is not an unusual situation I am facing, and I believe my effort to explain this will not be in vain. And as I said before, it is true that the more recent Perl web frameworks do use routes directly, but I am not using those - and there are a lot of others not using this either. Thank you, Brett |
| Page 1 of 2 | [ 16 posts ] | Go to page 1, 2 Next |
| You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum |
© 2006-2013 Yahoo! Inc. All rights reserved.
All code on this site is licensed under the BSD License unless stated otherwise.
About This Site · Security Contact Info
Powered by phpBB® Forum Software © phpBB Group