Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Routing is enabled by default in the ColdBox application templates in order to work with URL's like this:
http://localhost/index.cfm/home/about
As you can see they still contain the index.cfm
in the URL. In order to enable full URL rewrites that eliminates that index.cfm
you must have a rewrite enabled webserver like Apache, nginx or IIS or a Java rewrite filter which ships with CommandBox by default.
http://localhost/home/about
CommandBox has built in rewrites powered by Tuckey and you can enable a server with rewrites by running:
Caution Some J2EE servlet containers do not support the forwarding of SES parameters via the routing template (index.cfm
) out of the box. You might need to enable full URL rewriting either through a web server or a J2EE filter.
Apache mod_rewrite via .htaccess or configuration files (Free)
Helicon Tech ISAPI rewrite filter for IIS (Paid)
IIS 7 native rewrite filter (Free)
nginx native web server (free)
Tuckey J2EE rewrite filter (free)
In your URL pattern you can also use the :
syntax to denote a variable placeholder. These position holders are alphanumeric by default:
Once a URL is matched to the route above, the placeholders (:year/:month?/:day?
) will become request collection (RC
) variables:
Sometimes we will want to declare routes that are very similar in nature and since order matters, they need to be delcared in the right order. Like this one:
However, we just wrote 4 routes for this approach when we can just use optional variables by using the ?
symbol at the end of the placeholder. This tells the processor to create the routes for you in the most detailed manner first instead of you doing it manually.
Caution Just remember that an optional placeholder cannot be followed by a non-optional one. It doesn't make sense.
ColdBox gives you also the ability to declare numerical only routes by appending -numeric
to the variable placeholder so the route will only match if the placeholder is numeric. Let's modify the route from above.
This route will only accept years, months and days as numbers.
ColdBox gives you also the ability to declare alpha only routes by appending -alpha
to the variable placeholder so the route will only match if the placeholder is alpha
only.
This route will only accept page names that are alpha only.
There are two ways to place a regex constraint on a placeholder, using the -regex:
placeholder or adding a constraints
structure to the route declaration.
You can also have the ability to declare a placeholder that must match a regular expression by using the -regex( {regex_here} )
placeholder.
The rc
variable format
must match the regex supplied: (xml|json)
You can also apply a structure of regular expressions to a route instead of inlining the regular expressions in the placeholder location. You will do this using the constraints()
method of the router.
The key in the structure must match the name of the placeholder and the value is a regex expression that must be enclosed by parenthesis ()
.
Here are just a few of those rewrite rules for you for major rewrite engines. You can spice them up as needed.
Please note that URL rewriting is handled by an optional module in IIS. More info here: https://www.iis.net/downloads/microsoft/url-rewrite
The ColdBox Routing DSL will be used to register routes for your application, which exists in your application or module router object. Routing takes place using several methods inside the router, which are divided into the following 3 categories:
Initiators - Starts a URL pattern registration, but does not fully register the route until a terminator is called (target).
Modifiers - Modifies the pattern with extra metdata to listen to from the incoming request.
Terminators - Finalizes the registration process usually by telling the router what happens when the route pattern is detected. This is refered to as the target.
Please note that order of declaration of the routes is imperative. Order matters.
Please remember to check out the latest API Docs for the latest methods and argument signatures.
The following methods are used to initiate a route registration process.
Please note that a route will not register unless a terminator is called or the inline target terminator is passed.
route( pattern, [target], [name] )
- Register a new route with optional target terminators and a name
get( pattern, [target], [name] )
- Register a new route with optional target terminators, a name and a GET http verb restriction
post( pattern, [target], [name] )
- Register a new route with optional target terminators, a name and a POST http verb restriction
put( pattern, [target], [name] )
- Register a new route with optional target terminators, a name and a PUT http verb restriction
patch( pattern, [target], [name] )
- Register a new route with optional target terminators, a name and a PATCH http verb restriction
options( pattern, [target], [name] )
- Register a new route with optional target terminators, a name and a OPTIONS http verb restriction
group( struct options, body )
- Group routes together with options that will be applied to all routes declared in the body
closure/lambda.
Modifiers will tell the routing service about certain restrictions, conditions or locations for the routing process. It will not register the route just yet.
header( name, value, overwrite=true )
- attach a response header if the route matches
headers( map, overwrite=true )
- attach multiple response headers if the route matches
as( name )
- Register the route as a named route
rc( name, value, overwrite=true )
- Add an RC
value if the route matched
rcAppend map, overwrite=true )
- Add multiple values to the RC
collection if the route matched
prc( name, value, overwrite=true )
- Add an PRC
value if the route matched
prcAppend map, overwrite=true )
- Add multiple values to the PRC
collection if the route matched
withHandler( handler )
- Map the route to execute a handler
withAction( action )
- Map the route to execute a single action or a struct that represents verbs and actions
withModule( module )
- Map the route to a module
withNamespace( namespace )
- Map the route to a namespace
withSSL()
- Force SSL
withCondition( condition )
- Apply a runtime closure/lambda enclosure
withDomain( domain )
- Map the route to a domain or subdomain
withVerbs( verbs )
- Restrict the route to listen to only these HTTP Verbs
packageResolver( toggle )
- Turn on/off convention for packages
valuePairTranslator( toggle )
- Turn on/off automatic name value pair translations
Terminators finalize the routing process by registering the route in the Router.
end()
- Register the route as it exists
toAction( action )
- Send the route to a specific action or RESTFul action struct
toView( view, layout, noLayout=false, viewModule, layoutModule )
- Send the route to a view/layout
toRedirect( target, statusCode=301 )
- Relocate the route to another event
to( event )
- Execute the event if the route matches
toHandler( handler )
- Execute the handler if the route matches
toResponse( body, statusCode=200, statusText="ok" )
- Inline response action
toModuleRouting( module )
- Send to the module router for evaluation
toNamespaceRouting( namespace )
- Send to the namespace router for evaluation
Every router has a default route already defined for you in the application templates, which we refer to as routing by convention:
The URL pattern in the default route includes two special position placeholders, meaning that the handler and the action will come from the URL. Also note that the :action
has a question mark (?
), which makes the placeholder optional, meaning it can exist or not from the incoming URL.
:handler
- The handler to execute (It can include a Package and/or Module reference)
:action
- The action to relocate to (See the ?
, this means that the action is optional)
Behind the scenes the router creates two routes due to the optional placeholder in the following order:
route( "/:handler/:action" )
route( "/:handler)
Tip The :handler
parameter allows you to nest module names and handler names. Ex: /module/handler/action
If no action is passed the default action is index
This route can handle pretty much all your needs by convention:
Any extra name-value pairs in the remaining URL of a discovered URL pattern will be translated to variables in the request collection (rc
) for you automagically.
Tip: You can turn this feature off by using the valuePairTranslator( false )
modifier in the routing DSL on a route by route basis
route( "/pattern" ).to( "users.show" ).valuePairTranslator( false );
You can register routes in ColdBox with a human friendly name so you can reference them later for link generation and more.
You will do this in two forms:
Using the route()
method and the name
argument
Using the as()
method
You will generate URLs to named routes by leveraging the route()
method in the request context object (event).
Let's say you register the following named routes:
Then we can create routing URLs to them easily with the event.route()
method:
The request context object (event) also has some handy methods to tell you the name or even the current route that was selected for execution:
getCurrentRouteName()
- Gives you the name of the current route, if any
getCurrentRoute()
- Gives you the currently executed route
getCurrentRoutedURL()
- Gives you the complete routed URL pattern that matched the route
getCurrentRoutedNamespace()
- Gives you the current routed namespace, if any
In ColdBox, you can register resourceful routes to provide automatic mappings between HTTP verbs and URLs to event handlers and actions by convention. By convention, all resources map to a handler with the same name or they can be customized if needed. This allows for a standardized convention when building routed applications.
You can leverage the resources()
method in your router to register resourceful routes.
This single resource declaration will create all the necessary variations of URL patterns and HTTP Verbs to actions to handle the resource. Please see the table below with all the permutations it will create for you.
For in-depth usage of the resources()
method, let's investigate the API Signature:
We have created a scaffolding command in CommandBox to help you register and generate resourceful routes. Just run the following command in CommandBox to get all the help you will need in generating resources:
Apart from routing by convention, you can also register your own expressive routes. Let's investigate the routing approaches.
The route()
method allows you to register a pattern and immediately assign it to execute an event or a response via the target argument.
The first pattern registers and if matched it will execute the wiki.page event. The second pattern if matched it will execute the profile.show event from the users module and register the route with the userprofile name.
You can also pass in a closure or lambda to the target argument and it will be treated as an inline action:
You can also pass just an HTML string with {rc_var}
replacements for the routed variables place in the request collection
to
EventsIf you will not use the inline terminators you can do a full expressive route definition to events using the to()
method, which allows you to concatenate the route pattern with modifiers:
You can also route to a handler and an action using the modifiers instead of the to()
method. This long-form is usually done for visibility or dynamic writing of routes. You can use the following methods:
withHandler()
withAction()
toHandler()
end()
You can also route to views and view/layout combinations by using the toView()
terminator:
You can also use the toRedirect()
method to re-route patterns to other patterns.
The default status code for redirects are 301 redirects which are PERMANENT redirects.
You can also redirect a pattern to a handler using the toHandler()
method. This is usually done if you have the action coming in via the URL or you are using RESTFul actions.
You can also route a pattern to HTTP RESTFul actions. This means that you can split the routing pattern according to incoming HTTP Verb. You will use a modifier withAction()
and then assign it to a handler via the toHandler()
method.
The Router allows you to create inline responses via closures/lambdas or enhanced strings to incoming URL patterns. You do not need to create handler/actions, you can put the actions inline as responses.
If you use a response closure/lambda, they each accepts three arguments:
event
- An object that models and is used to work with the current request (Request Context)
rc
- A struct that contains both URL/FORM
variables merged together (unsafe data)
prc
- A secondary struct that is private only settable from within your application (safe data)
If the response is an HTML string, then you can do {rc_var}
replacements on the strings as well:
You can also register routes that will respond to sub-domains and even capture portions of the sub-domain for multi-tenant applications or SaaS applications. You will do this using the withDomain()
method.
You can leverage the full routing DSL as long as you add the withDomain()
call with the domain you want to bind the route to. Also note that the domain string can contain placeholders which will be translated to RC
variables for you if matched.
You can also add variables to the RC and PRC structs on a per-route basis by leveraging the following methods:
rc( name, value, overwrite=true )
- Add an RC
value if the route matched
rcAppend map, overwrite=true )
- Add multiple values to the RC
collection if the route matched
prc( name, value, overwrite=true )
- Add an PRC
value if the route matched
prcAppend map, overwrite=true )
- Add multiple values to the PRC
collection if the route matched
This is a great way to manually set variables in the incoming structures:
You can also apply runtime conditions to a route in order for it to be matched. This means that if the route matches the URL pattern then we will execute a closure/lambda to make sure that it meets the runtime conditions. We will do this with the withCondition(
) method.
Let's say you only want to fire some routes if they are using Firefox, or a user is logged in, or whatever.
Every ColdBox application has a URL router and can be located by convention at config/Router.cfc
. This is called the application router and it is based on the router core class: coldbox.system.web.routing.Router
. Here is where you will configure router settings and define routes using our routing DSL.
Please see the latest for investigating all the methods and properties of the Router.
Tip: Unlike previous versions of ColdBox, the new routing services in ColdBox 5 are automatically configured to detect the base URLs and support multi-domain hosting. There is no more need to tell the Router about your base URL.
Router.cfc
The application router is a simple CFC that virtually inherits from the core ColdBox Router class and is configured via the configure()
method. It will be decorated with all the capabilities to work with any request much like any event handler or interceptor. In this router you will be doing 1 of 2 things:
Configuring the Router
Adding Routes via the Routing DSL
The router and indeed all module routers are also registered as full fledged ColdBox interceptors. So they can listen to any event within your application.
Once the routing service loads your Router it will create two application settings for you:
SESBaseURL
: The multi-domain URL base URL of your application: http://localhost
HTMLBaseURL
: The same path as SESBaseURL
but without any index.cfm
in it (Just in case you are using index.cfm
rewrite). This is a setting used most likely by the HTML <base>
tag.
You can use the following methods to fine tune the configuration and operation of the routing services:
The next sections will discus how to register routes for your application.
There will be a time where your routes will become very verbose and you would like to group them into logical declarations. These groupings can also help you prefixes repetitive patterns in many routes with a single declarative construct. These needs are met with the group()
method in the router.
The best way to see how it works is by example:
As you can see from the routes above, we have lots of repetitive code that we can clean out. So let's look at the same routes but using some nice grouping action.
The options struct can contain any values that you can use within the closure. Grouping can also be very nice when creating , which is our next section.
Tip: Please note that you can leverage as well for domains
By default, the URL mapping processor will detect routes by looking at the CGI.PATH_INFO
variable, but you can override this and provide your own function. This feature can be useful to set flags for each request based on a URL and then clean or parse the URL to a more generic form to allow for simple route declarations. Uses may include internationalization (i18n) and supporting multiple experiences based on devices such as Desktop, Tablet, Mobile and TV.
To modify the URI used by the Routing Services before route detection occurs simply follow the convention of adding a function called pathInfoProvider()
to your application Router (config/Router.cfc
).
The pathInfoProvider()
function is responsible for returning the string used to match a route.
The base
tag in HTML allows you to tell the browser what is the base URL for assets in your application. This is something that is always missed when using frameworks that enable routing.
base
tag defines the base location for links on a page. Relative links within a document (such as <a href="someplace.html"... or <img src="someimage.jpg"... ) will become relative to the URI specified in the base tag. The base tag must go inside the head element.
We definitely recommend using this HTML tag reference as it will simplify your asset retrievals.
Caution If you do not use this tag, then every asset reference must be an absolute URL reference.
You can create a-la-carte namespaces for URL routes. Namespaces are cool groupings of routes according to a specific URL entry point. So you can say that all URLs that start with /testing
will be found in the testing namespace and it will iterate through the namespace routes until it matches one of them.
Much how modules work, where you have a module entry point, you can create virtual entry point to ANY route by namespacing it. This route can be a module a non-module, package, or whatever you like. You start off by registering the namespace using the addNamespace( pattern, namespace )
method or the fluent route().toNamespaceRouting()
method.
Once you declare the namespace you can use the grouping functionality to declare all the namespace routes or you can use a route().withNamespace()
combination.
Hint You can also register multiple URL patterns that point to the same namespace
ColdBox supports a Routing Service that will provide you with robust URL mappings for building expressive applications and RESTFul services. By convention URL routing will allow you to create URL's without using verbose parameter delimiters like ?event=this.that&m1=val
and execute ColdBox events.
If you are leveraging CommandBox as your server, then full URL rewrites are enabled by default. This means you do not need a web server to remove the index.cfm
from the URL.
A route is a declared URL pattern that if matched it will translate the URL into one of the following:
A ColdBox event to execute
A View/Layout to render
A Reponse function to execute
A Redirection to occur
It will also inspect the URL for placeholders and translate them into the incoming Request Collection variables (RC
).
Examples
There are several benefits that you will get by using our routing system:
Complete control of how URL's are built and managed
Ability to create or build URLs' dynamically
Technology hiding
Greater application portability
URL's are more descriptive and easier to remember
As you create route-heavy applications visualizing the routes will be challenging especially for HMVC apps with lots of modules. Just install our ColdBox Route Visualizer and you will be able to visually see, test and debug all your routing needs.
Method | Description |
| Enable/Disable routing, enabled by default |
| If true, then no |
| Enables SES only URL's with permanent redirects for non-ses urls. Default is true. If true and a URL is detected with ? or & then the application will do a 301 Permanent Redirect and try to translate the URL to a valid SES URL. |
|
| By default URL pattern matching starts at the beginning of the URL, however, you can choose loose matching so it searches anywhere in the URL. Default is false. |
| By default ColdBox detects URL extensions like |
| Tell the interceptor what valid extensions your application can listen to. By default it listens to: |
| By default ColdBox does not throw an exception when an invalid extension is detected. If true, then the interceptor will throw a 406 Invalid Requested Format Extension: {extension} exception. Default is false. |
ColdBox allows you to detect incoming extensions from incoming paths automatically for you. This is great for building multi-type responses or to just create virtual extensions for events.
If an extension is detected in the incoming URL, ColdBox will grab it and store it in the request collection (RC
) as the variable format
. If there is no extension, then rc.format
will not be stored and thus will not exist.
You can configure the extension detection using the following configuration methods:
Please note that if you have set to throw exceptions if an invalid extension is detected then a 406 exception will be thrown.
In your views, layouts and handlers you can use the buildLink
method provided by the request context object (event) to build routable links in your application.
Just pass in the routed URL or event and it will create the appropriate routed URL for you:
The request context object (event) also has some handy methods to tell you the name or even the current route that was selected for execution:
getCurrentRouteName()
- Gives you the name of the current route, if any
getCurrentRoute()
- Gives you the currently executed route
getCurrentRoutedURL()
- Gives you the complete routed URL pattern that matched the route
getCurrentRoutedNamespace()
- Gives you the current routed namespace, if any
Although we have access to all the HTTP verbs, modern browsers still only support GET and POST. With ColdBox and HTTP Method Spoofing, you can take advantage of all the HTTP verbs in your web forms.
By convention, ColdBox will look for an _method
field in the FORM scope. If one exists, the value of this field is used as the HTTP method instead of the method from the execution. For instance, the following block of code would execute with the DELETE action instead of the POST action:
You can manually add these _method
fields yourselves, or you can take advantage of ColdBox's HTML Helper startForm()
method. Just pass the method you like, we will take care of the rest:
The base URL to use for URL writing and relocations. This is automatically detected by ColdBox 5 e.g. , ''
Method
Description
setExtensionDetection( boolean )
By default ColdBox detects URL extensions like json, xml, html, pdf
which can allow you to build awesome RESTful web services. Default is true.
setValidExtensions( list )
Tell the interceptor what valid extensions your application can listen to. By default it listens to: json, jsont, xml, cfm, cfml, html, htm, rss, pdf
setThrowOnInvalidExtensions( boolean )
By default ColdBox does not throw an exception when an invalid extension is detected. If true, then the interceptor will throw a 406 Invalid Requested Format Extension: {extension} exception. Default is false.