Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Demers94's avatar

Controllers structure for API and "regular" routes

I'm building an application where the the users can view job offers.

The /offers endpoint calls a controller method that shows the view with all the offers.

Route::get('/offers', 'OffersController@index');

public function index()
{
    return view('offers.index');
}

From the front-end, a Vue component makes an API call to fetch the latest offers.

What's the best approach regarding controllers structure for this case?

The way I see it I have three options :

  1. Call the same controller, same method and return a different response type depending on if the request was made via AJAX or not
    // Offers.vue
    axios.get('/offers').then(response => {...})

    // routes/web.php
    Route::get('/offers', 'OffersController@index');

    // OffersController.php
    public function index()
    {
        if(request()->isAjax()){
            return Offer::get();
        }

        return view('offers.index');
    }
  1. Call another method on the same controller
    // Offers.vue
    axios.get('/api/offers').then(response => {...})

    // routes/web.php
    Route::get('/offers', 'OffersController@index');
    Route::get('/api/offers', 'OffersController@api');

    // OffersController.php
    public function index()
    {
        return view('offers.index');
    }

    public function api()
    {
        return Offer::get();
    }
  1. Call the index() method of a new controller specifically for API routes
    // Offers.vue
    axios.get('/api/offers').then(response => {...})

    // routes/web.php
    Route::get('/offers', 'OffersController@index');
    Route::get('/api/offers', 'Api\OffersController@index');

    // OffersController.php
    public function index()
    {
        return view('offers.index');
    }

    // Api/OffersController.php
    public function index()
    {
        return Offer::get();
    }

What is the best approach in this case?

I like #3 since it allows me to use only CRUD names for my controller methods and I don't have to pollute all the methods with the request()->isAjax() call, but I'm wondering if there would be another solution that would allow me to keep the code in the same place. I'm not convinced it makes sense to use different controllers like that for the same type of data.

0 likes
4 replies
bobbybouwmann's avatar

I personally would go for option 3. You might even use a repository or some class that fetches all the offers which both controllers may use to return the data. Also another advantage of an ApiController is that you might return different results there.

audunru's avatar

Yes, definetely #3. That’s the default, recommended option, I would say. Your web route, the one that returns the blade view, will be very simple. But the API route will most likely deal with authorization, validation and so on, so there’s good reason why you want that in two different classes.

martinbean's avatar

@demers94 I create separate controllers, in an Api namespace.

I update the mapApiRoutes() method in my RouteServiceProvider class to automatically load files from that namespace:

protected function mapApiRoutes()
{
    Route::prefix('api')
         ->middleware('api')
         ->namespace($this->namespace.'\Api')
         ->group(base_path('routes/api.php'));
}

Then I can just create controllers as normal:

namespace App\Http\Controllers\Api;

use App\Offer;
use App\Http\Controllers\Controller;
use App\Http\Resources\OfferResource;

class OfferController extends Controller
{
    public function show(Offer $offer)
    {
        return new OfferResource($offer);
    }
}
shez1983's avatar

i have done this thing by using Option 3 - but now think i may prefer to just have ONE controller rather than multiple - everything in one place.. :/

Please or to participate in this conversation.