Config-Based Routing with Laravel An alternative method of adding routes in Laravel

The Problem

Laravel makes an unbelievable number of things so much easier, a lot of magic is provided for you right out of the box. This, for example, is undoubtedly useful:

Route::resource('user', 'UserController');

...in a smaller, simpler API. Phil Sturgeon mentions in Build APIs You Won't Hate that, yes, while that's all well and fine, specificity in your routes is better in the long run, and I happen to agree. Routes serve as the basis for your API documentation, so let's spell them out.

To the point: I've been developing a large-ish API for my 9-5 over the past two years. As we mapped out all of the endpoints at the beginning of the project, all I could think about was what that routes.php file was going to look like. It seemed unwieldy at best.

The Solution

Here's what I wanted:

  • Organization
  • Accessibility
  • Clarity

Here's what I came up with: generating the routes from a set of config files. Basically, there is a config/routes/main.php file that looks something like this:

return [
  'user' => 'App\Http\Controllers\UserController',
  'product' => 'App\Http\Controllers\ProductController',
  'cart' => 'App\Http\Controllers\CartController',
  ...
];

So right out of the gate, you are aware of the main resources that your API is concerned with and which controllers they are generally associated with. The keys of this array correspond to the config file that the actual routes are in. For example, config/routes/user.php might look something like this:

return [
  [
    'path' => '/', // relative to the resource
    'method' => 'create', // the method within the controller
    'verb' => 'post', // the HTTP verb
  ],
  [
    'path' => '/{user_id}',
    'method' => 'get',
    'verb' => 'get',
  ],
  [
    'path' => '/{user_id}',
    'method' => 'update',
    'verb' => 'put',
  ],
  [
    'path' => '/{user_id}',
    'method' => 'destroy',
    'verb' => 'delete',
    'middleware' => 'admin',
  ],
  [
    'path' => '/{user_id}/photos',
    'method' => 'getPhotos',
    'verb' => 'get',
  ],
  ...
];

I then generate the routes using a custom service provider and we're good to go.

It's not a perfect solution, but it has generally served me well, and I find it to be very clear. I've on-boarded a couple of developers while working on this project and they seem to like the config-based routing.

Benefits

  • A quick cmd + p + 'route user' and you're looking at all of the user-specific endpoints
  • It's organized, keeps route files smaller and more focused
  • It's centrally configurable and/or overridable from the service provider generating the routes

Drawbacks

  • Sometimes it's not immediately clear to a newcomer what exactly is going on without an explanation

Eh?

What are you thoughts on this method? Is a large routes.php file not of concern to you in the first place? Is there a better way of attacking this problem? Do you have any questions? Let me know your thoughts in the comments below or hit me up on Twitter.

The Future

I've already started converting my service provider into a composer package, but I'm putting a pause on it to see if there is any interest in even using such a thing. I'm happy to put it together and flesh it out a bit more if people want to use it. Let me know.

Title background image by Dmitrii Vaccinium