Using Explicit Pattern Matching With ResourceMapper.cfc
Last year, I released a ColdFusion component - ResourceMapper.cfc - that allows you to easily translate RESTful resource requests into a server-side event and a collection of URL parameters. Today, I added a small, but powerful feature that allows you to define custom regular expression patterns for your named resource components.
Project: View the ResourceMapper.cfc project on my GitHub account.
By default, the ResourceMapper.cfc ColdFusion component would replace your named-parameters with the regalar expression pattern:
([^/]+)
... such that the sample resource:
/blog/:blogID/comments
... would be compiled down to the pattern:
/blog/([^/]+)/comments
This works great if you're using mechanical SES (Search Engine Safe) resource definitions. But, this completely fails if your resources are formed somewhat more loosely.
To accomodate a more flexible resource scheme, you can now provide an explicit regular expression pattern for a given named parameter:
:name(YOUR_PATTERN)
The explicit pattern much be enclosed within a set of parenthesis; and, for obvious reasons, your pattern cannot, itself, contain parenthesis. So, imagine that my resources were named such that the blogID was actually just the start of the URI component, and not the entire URI component. Example:
/blog/123-hello-world.htm
In this case, I could tell the ResourceMapper.cfc that my "ID" was the leading, numeric portion of the resource:
/blog/:id(\d+)-.*?.htm
Now, the ResourceMapper.cfc will return only the numeric value as the :id and leave the rest of the URI component as generic cruft.
If you use a framework that generates URLs for you, you probably won't need a feature (or a component) like this. But, if you do things with a more high-touch approach, like I generally do, the ResourceMapper.cfc can now accomodate your URLs.
Reader Comments
Very cool, Ben.
I'm writing my own framework (for the life experience), and one of the things I did was generate application paths to common locations. Not sure if it's just me, but I always find myself double-guessing if what I'm doing is the most optimized way, or even if its close to the standard which the vast majority of developers use.
In my current incarnation, it's a bit of a chopping block. A call like:
aaronmartone.com/this/that
...would be URL rewritten by IIS to serve as:
/www/this/that
Because my host won't allow me to create as many sites as I want to host each subdomain, I have to use URL rewriting so that it looks at the hostname and then rewrites the URL to include that as the root folder before appending the value after the hostname.
Not to mention, from the root of the subdomain folder, I hold my page data in a directory below that, so:
aaronmartone.com/this/that
is looking for a page at:
/www/cf/pages/this/that.cfm
It's working, but I sometimes wonder if my process is too convoluted.
@Aaron,
Striking the right balance between complexity and ease-of-use is definitely a hard balance. Especially when your hosting provide has limitations that you have to work around.
One example of this, that I always wrestle with is, should I use a leading slash for my public assets paths? Or should I use dot-dot-notation. Example:
/img/foo.png
vs.
../../img/foo.png
The first is *clearly* easier to use since it is complete ignorant of where you are in the current site architecture. But, the trade-off is that you have to have "/" be the webroot of your application.
The latter, is harder to calculate (since its relative to the current URL); but, it also means that you site doesn't necessarily have to have "/" be the webroot, which makes your code *much* more portable.
Of course, one could argue that portable code is not necessarily a "win." And, the more complicated and client-side-oriented your site becomes, the more I might agree.
All to say, always a tradeoff. But, I do love building stuff for the experience! So, I respect your effort on that front!
@Ben
What's great is that you QUESTION all things. Nothing like personal experience and case studies to help you feel like the decision you make is the right one, no? :)
Everytime I find myself coding this thing, I want to bring it one step closer to self-awareness. I feel the ultimate application is one that can be dropped in place and almost configure itself to just hit the ground running. Of course, that's the concept, getting my code to a level where I can proof such a concept... well, that's a doozy!
Absolute pathing vs. relative pathing: The debate rages on. (Funny how we, as coders, are so intimately concerned with such intricacies, right? ) I mean, you could stop at the fact of whether or not your solution resulted in an HTTP/200 or an HTTP/404, but developers always take it one step further. :D
@Aaron,
I love to dig! The more I can tear this stuff apart the more I can hopefully make sense of it. I'm so frustrated by how much of this stuff still feels like such a mystery. And, it seems to go the wrong way - the more I learn, the more (and more complicated) questions I start to have.
Some of my thinking over the relative-vs-absolute stuff comes from the fact that for years, I've had a local development environment for my blog that has the structure:
bennadel.com/site_v5/wwwroot/
bennadel.com/site_v6/wwwroot/
bennadel.com/testing/
Now, "testing" is where I do a lot of my testing (there gotta be thousands of files in there). But, since I needed to access it via the URL, I couldn't make "local.bennadel.com" go to the "wwwroot" folder (since I needed to choose whether to go into "testing" or into "wwwroot").
So, once I got into the wwwroot folder, I couldn't use "/" otherwise it would take my outside of the wwwroot folder.
Now, keep in mind, that was all set up waaay before I knew anything about setting up virtual hosts and really even knew how domain names (and sub-domains) got resolved via the hosts file. Basically, I had one "root" for my entire local server and then had to use relative paths for all the sites :D
@Ben
That's fantastic man. In design, as in development, we have to embrace our constraints. There's simply no point in fighting them; it gets us nowhere.
You know, what I've done to adapt to the fact that my host does not allow me more than 1 "site" in IIS to manage. My "site root" actually contains nothing but folders of my subdomains. So you might see something like:
/clients
/testing
/www
And they respectively map to:
clients.aaronmartone.com
testing.aaronmartone.com
www.aaronmartone.com
Then, I use IIS' URL rewrite engine so that it looks at the host in the request, and then rewrites the request. A request to:
www.aaronmartone.com/folder/file.cfm
Would rewrite to:
/www/folder/file.cfm
This allowed me to have 1 site, but as many subdomains as I wanted. Traditionally, I've found many people who have FULL access to IIS will make 1 site per subdomain, so that when you do a "/", it goes to the root of the folder intended, rather than up "outside" the intended root of that subdomain.
Also, I use the <base> tag in my <head>. Very few people do. You can specify the base URL for all relatively mapped links. So, traditionally, if a link reads:
<li href="file.cfm">File</li>, the document interprets where it is in the directory structure, and then assumes there is a file.cfm at the same location. But I add:
<base href="//aaronmartone.com/">
in the <head> (notice I use protocol-less syntax), so that the browser interprets the link as:
//aaronmartone.com/file.cfm
This, along with URL rewriting allows me to write URLS which are absolute, don't begin with '/' and give me an idea of where they link to from an absolute reference, ie:
<li href="blog/2013/oct/2">Article<li>
will always link to: //aaronmartone.com/blog/2013/oct/2
Pathing was tough to understand, but in the end, we just keep at it with good ol fashioned trial and error! :)
@Aaron,
The "base" tag in the head is something that I've seen, but I don't think I've ever used it before. I do remember, years ago, jumping onto a project where there was a base tag that I *didn't* know about and it confused the heck out of me! I couldn't figure out why certain paths just didn't work!
Philosophically, though, the tag makes a lot of sense! I wonder why it didn't catch on more than it did. I almost never hear it mentioned.
@Ben
Yeah, <base> finds a home in many of my apps. As well as protocol-less hostnames. I found that if you specified href="http://myHostname" then if you were on a HTTPS connection, you'd get protocol mis-match errors, so you can use '//myHostname' as a protocol-less version and it will look at the current protocol the request was made off and prepend that automatically.
@Aaron,
The protocolless approach is awesome. I first saw Paul Irish doing that a while back and it *blew* my mind!