Routing in Recess! Screencast
In the first ever Recess Framework screencast we will be walking through the exciting Routing features of the framework.
What is routing?
Routing is the machinery that takes a requested URL path like “/product/23” and ‘routes’ or dispatches control to some other place your application. In most frameworks, including Recess, this is to a method in a controller. Using a framework that has fast, flexible, RESTful routing is important because URLs are fundamental to how people, search engines, and web services interact with you web application.
Simple Routing Techniques (Screencast 0:20)
Let’s dive right into some code and take a look at how we can set up a route to a method in a controller:
class TestController extends Controller {
/** !Route GET, /hello/world */
function aMethod() {
echo 'Hello PHP Community!'; exit;
}
}
What’s that funny stuff above the function? It’s a Recess Route annotation. Recess annotations may look a bit strange but they’re really simple. They are written inside of doccomments, a language construct in PHP which begins with a forward slash and two asterisks. Recess annotations are banging. Literally, they start with an exclamation point, or, BANG! (as opposed to the @-symbol if you’re used to Java style annotations). The Route annotation has two parameters. The first is the HTTP method such as GET, POST, PUT, or DELETE and the second is the URL path.
Parametric Routes
When a part of the route is preceded with a dollar sign it becomes a method parameter. Here is an example:
class TestController extends Controller {
/** !Route GET, /hello/$first/$last */
function aMethod($first, $last) {
echo "Hello $first $last!"; exit;
}
}
Now if we browse to /hello/PHP/Community the browser will print “Hello PHP Community”. Parametric routes are often used with ID or primary key columns in a database. For example, if I were building a store in Recess I might have a Product Details page that used a route like: !Route GET, /product/$id
Multiple Routes per Method
Controller methods can have multiple routes. For example, we can combine the previous two methods into one:
class TestController extends Controller {
/**
* !Route GET, /hello/world
* !Route GET, /hello/$first/$last
* */
function aMethod($first = "PHP", $last = "Community") {
echo "Hello $first $last!"; exit;
}
}
If you accidentally add a route that conflicts with another somewhere else in your app Recess will tell you where the conflict occurred. The Recess Diagnostics error screen shows you where in your code the conflict occurred.
Keeping it DRY
If you’re familiar with Cake or Rails you may be wondering what is the upside to specifying routes in-line with my methods? The long and short of it is, it is more DRY. With a separate routes file you must duplicate the name of a controller and method which a route maps to. So if you refactor your controller code you must remember to go and update your routes file as well. By keeping the two together it’s never a mystery what URL will take you to the controller method you’re working on.
Advanced Routing Techniques (Screencast 3:00)
HTTP METHOD Aware Routes for RESTful Routing
Routing in Recess is HTTP method-aware. To demonstrate this we can have two controller methods mapped to the same URL but differing HTTP METHODs:
class TestController extends Controller {
/** !Route GET, /same/url */
function comingFromGet() {
echo ''; exit;
}
/** !Route POST, /same/url */
function comingFromPost() {
echo 'POSTed!'; exit;
}
}
The first method will handle a GET to the url “/same/url” and the second a POST to “/same/url”. For an actual demonstration of this running check out the screen cast at minute 7:00! Having a routing system aware of HTTP methods is one way in which Recess helps simplify RESTful application develop in PHP.
Relative Routes
In Recess, Routes can be relative to their context. What does that even mean? There are three logical levels of organization for the purposes of Routing. The most general level is the application. Recess allows multiple applications to be installed at once a la Django. Within an application there may be multiple controllers and a controller can have many methods.
Implicit routes are different from explicit routes in that they do not begin with a forward slash. Check out the !Route annotation for the world method below. By adding a !RoutesPrefix annotation to a controller we will prepend any relative route in the controller with "hello/" so we can now reach the world method using "hello/world/".
/** !RoutesPrefix hello/ */
class TestController extends Controller {
/** !Route GET, world */
function world() {
echo 'Hello World!'; exit;
}
}
Implicit Routes
If you’re familiar with Rails or Cake you’re probably wondering why I needed specify routes for the world and universe methods. In many frameworks these routes would be implicit. In Recess they can be implicit too. We can delete the route annotations and still access the methods in the same way. The important difference between the way implicit routes work in Recess and other frameworks is that Recess does not rely on the name of a controller to determine the route, but rather on the routing prefixes of the application and the controller.
/** !RoutesPrefix hello/ */
class TestController extends Controller {
function world() {
echo 'Hello World!'; exit;
}
}
Because we've set up a route prefix for the Tests controller we can reach the world method by using the URL: "hello/world". Implicit routes can have parameters too.
/** !RoutesPrefix hello/ */
class TestController extends Controller {
function world($first, $last) {
echo "Hello $first $last!"; exit;
}
}
Now, "hello/world/Michael/Scott" will rest in the world method being called and printing "Hello Michael Scott!"
Tools (Screencast 8:00)
With routes being sprinkled throughout controllers don’t you lose the ability to look in a single place and get a sense of all of the routes in your application?
Recess! Tools is first class Recess! application that runs in the browser and is designed to help you along in development mode writing apps. With Tools we can see all of the routes explicit and implicit, relative and absolute, for any given application. The table lists the HTTP method and route corresponding which map to a controller class and method. With Recess Tools you can get a global picture of Routes in your application.
Performance (Screencast 9:00)
How in the world can you expect to get any kind of performance out of an app when you have to reflect over every single controller in order to know all routes?
This is a great question. Routing changes as shown in the screencast take immediate effect. This is because the screencast was taken while Recess was in development mode. By switching to deployment mode the routing computation would only have to happen once because the routes won’t change. On the first request in deployment mode Recess will build up the routing data structure, a tree, and cache it either to disk or memory depending on what your server has available. Subsequent requests simply unserialize the routing tree and Recess is off to the races. Perf has been a top priority while developing Recess and this technique enables great performance while allowing your code to stay simple, nimble, and DRY.
Wrap-up
So this has been a quick look at routing in Recess! I hope you’ll sign up to be notified when the alpha bits go public and try routing out for yourself. For more info on Recess! and other screen casts subscribe to the RSS feed and/or follow me on Twitter: KrisJordan. Would love to hear your reactions, thoughts, and questions in the comments!
