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

sh1r3f's avatar

How to share code between web and api controllers?

I'm working on building an API for mobile that will fetch and do the same code as my main web code. I already know that the common logic code will be moved inside a service and use this service in both API and web controllers so it's not a problem for me. My question is what about eloquent queries? for example I've in all index methods in all controllers I have Model::*Do some queries*paginate($request->perPage);. How would I share this between both API and web controllers for same resource? Or I would repeat it here and there? What is the best practices for such solution?

0 likes
5 replies
vincent15000's avatar

There aren't web controller or api controllers, there are only controllers.

If you need to explicitely manage cases where you need to return either a collection or JSON datas, you can do like this.

if ($request->expectsJson()) {
	// ...
} else {
	// ...
}

Or like this.

if ($request->ajax())
{
   	// ...
} else {
	// ...
}
1 like
martinbean's avatar

How would I share this between both API and web controllers for same resource? Or I would repeat it here and there? What is the best practices for such solution?

@sh1r3f If you have common code that you want to use in multiple places, then this is where you would re-factor by extracting it to a single place. So as you mentioned in your post, a service or something.

Extract the Eloquent queries to a service, and then use that service in both your web and API controllers. If you need to update the query, you then only need to do it in one location:

namespace App\Services;

use Illuminate\Pagination\LengthAwarePaginator;

class ArticleService
{
    public function getPaginatedList(): LengthAwarePaginator
    {
        return Article::query()->paginate();
    }
}
namespace App\Http\Controllers\Api;

class ArticleController extends Controller
{
    protected $articleService;

    public function __construct(ArticleService $articleService)
    {
        $this->articleService = $articleService;
    }

    public function index()
    {
        return ArticleResource::collection($this->articleService->getPaginatedList());
    }
}
namespace App\Http\Controllers\Web;

class ArticleController extends Controller
{
    protected $articleService;

    public function __construct(ArticleService $articleService)
    {
        $this->articleService = $articleService;
    }

    public function index()
    {
        return view('articles.index')->with([
            'articles' => $this->articleService->getPaginatedList(),
        ]);
    }
}

So as you see, both controllers get the ArticleService injected and then the same method is called on that service, but the controller presents the result different depending on if it is an API controller or a web controller.

3 likes
vincent15000's avatar

@martinbean Ok you suggest to really use two different controllers but extract the business logic to services.

What do you think about my suggestion ? I already had coded like this on my very first Laravel projects. I needed to return either a JSON object (to dynamically add a new option in a select options field inside a form) or a collection to display the list of the data, for example for the admin.

martinbean's avatar

What do you think about my suggestion ?

@vincent15000 Not ideal, because it means you’re then going to have controllers stuffed full of conditional logic.

Also, web and API controllers tend to have different URIs (i.e. /api/articles versus `/articles), and web controllers can return a whole multitude of data for a single page, whereas an API endpoint is usually focused around one resource and returns zero-to-many of those resources only in a single request.

For example, a home page. A “home page” is not a resource, but will most likely display many different entities.

2 likes
vincent15000's avatar

@martinbean Ok I understand.

I had used my suggestion for a case where I only needed to pass exactly the same datas to the view or as a JSON object.

And your suggestion is more adapted for situations where the datas and / or the business logic are different between the view and the JSON object.

Please or to participate in this conversation.