In my adventures using Laravel to develop all sorts of applications, I have consistently ran into one rather annoying pain point. AJAX routing.

Lets back up a bit. In Laravel you have two main middleware groups, "web" and "api." One is meant to be used by your normal users, the other to be used with an external facing API. If your application requires authenticated AJAX queries you have a choice to make. Do you authenticate your requests via some sort of API authentication, or do you use the session token already loaded onto the page?

Here is a practical example. Lets say you have a blog. You have the normal resource routes: index, create, show, store, patch, delete. The index, create, and show routes can be normal web routes, but to store, patch, or delete a blog post your browser fires off an AJAX request. If you place everything in a single controller using your session authentication, you would handle your routes like this:

/* routes/web.php */
Route::resource('/blog', 'ArticleController');

This would grant you the following routes:

App\Http\ArticleController.php

  • GET /blog
  • GET /blog/create
  • GET /blog/{article}
  • POST /blog
  • PATCH /blog/{article}
  • DELETE /blog/{article}

This here looks fine, but the first three routes return HTML and the last three return JSON responses. Mixing the response type within a single controller seems messy, so what about using separate API routes?

// routes/web.php
Route::get('/blog', 'ArticleController@index');
Route::get('/blog/create', 'ArticleController@create');
Route::get('/blog/{article}', 'ArticleController@show');

// routes/api.php
Route::post('/blog', 'ArticleController@store');
Route::patch('/blog/{article}', 'ArticleController@update');
Route::delete('/blog/{article}', 'ArticleController@destroy');

App\Http\ArticleController

  • GET /blog #index
  • GET /blog/create #create
  • GET /blog/{article} #show

App\Http\Api\ArticleController

  • POST /blog #store
  • PATCH /blog/{article} #patch/update
  • DELETE /blog/{article} #destroy

Here you have separated the controllers that give HTML responses from the ones that give JSON responses, and it feels a lot cleaner. There will be some work to get your JavaScript application authenticated with the API, but this is better right? For some use cases, maybe. For others, maybe not. What if your AJAX operations need to be separated from your API for some reason? Well this is what this blog post is all about.

You see, laravel makes manipulating the route groups a breeze. It even has a nifty file, the "App\Providers\RouteServiceProvider" class is here to save the day. This is where the application registers the difference between the web and the API routes, but who is to say we cant add our own groups?

I almost always add my own handy function to the bottom of the 'map' function.

Route::middleware('web')
    ->namespace($this->namespace.'\Ajax')
    ->as('ajax.')
    ->group(base_path('routes/ajax.php'));

Lets go through step by step exactly what this will do.

It creates a new route group inside of the 'web' middleware group (which gives us session authentication) It adds it to the controller namespace, plus "\Ajax" It prepends "ajax." to the route names, so instead of route names looking like "foo.index" it will look like "ajax.foo.index" It pulls everything in the "routes/ajax.php" file into the route group Now you can add AJAX routes to your hearts content without needing to worry about authenticating against your API routes or cluttering up your web routes.