I am developing a restful laravel application and I need to know what is the best practice to implement the routes, controllers and methods in the Laravel to both support the restful requests
and HTTP web requests
we can easily create a resource controller and then add the following line to the routes file in Laravel:
Route::resource('Photo', 'PhotoController');
and then in the PhotoController
we just need to add the following lines of codes which returns a json
response from all the photos:
class PhotoController {
public function index()
{
$photos = Photo::all();
return response()->
json(['result' => $photos]);
}
}
we also need a Controller
and a method
which responds to web HTTP
request and returns a web page instead of a json
response which displays all the photos to the web users
Question:
where is the best place to put this method and Controller is it a good practice to put it inside the same Controller and returns a view? like following example
class PhotoController{
public function getAll(){
$photos = Photo::getAll();
return view('views',['photos'=>$photos]);
}
}
or creating another Controller
and handling the web requests there and adding a new rout
in the routes
file for example : mysite.com\photos\all
to the routes file?
or do I have to keep this in another Controller
or do I have to decide whether or not the request is from the web inside the same method like the below example:
public function index()
{
$photos = Photo::all();
if ( from web ){
return view('views',['photos'=>$photos]);
} else {
return response()->
json(['result' => $photos]);
}
}
I also have to mention that I previously asked the below question:
Best design practice to implement routes and controllers for a RESTFul Laravel app
but didn't get any answer.
There's probably a reason why you didn't get an answer the last time you asked that question. It really depends on your project. I will share my own preference:
I have two sets of routes, middleware, controllers and common services.
Routes:
//For web
Route::resource('photo', 'PhotoController');
/For API, with versioning
Route::resource('api/v1/photo', 'API\PhotoController');
Middlewares
//For web
public function handle($request, Closure $next, $role="view")
{
if(Gate::denies($role.'-photo', $photo)){
if($role == "view"){
abort(404);
}
return $this->redirect($photo)->withErrors(['You are not authorized to see this photo']);;
}
}
return $next($request);
/For API, with versioning
public function handle($request, Closure $next, $role="view")
{
if(Gate::forUser(Auth::guard('api')->user())->denies($role.'-photo', $photo)){
if($role == "view"){
return Response::json([], 404);
}
return Response::json([], 403);
}
}
return $next($request);
Controllers
//PhotoController
class PhotoController{
//RESTful name here
public function index(){
$photoService = new PhotoService();
$photos = $photoService->getAll();
return view('views',['photos'=>$photos]);
}
}
//API\PhotoController
class PhotoController{
//RESTful name here
public function index(){
$photoService = new PhotoService();
$photos = $photoService->getAll();
return Response::json($photos, 200);
}
}
Service
class PhotoService(){
//You could add a _construct() that would accept Request $request or User $user
public function getAll(){
return Photo::all();
}
}
Bonus: Exception Handler
You should take a look at this RestExceptionHandlerTrait.
It may seems like a lot of duplication but to me this is much more readable and clear than adding $request->wantsJson()
everywhere. You might think that this is an overkill and, in some cases, it is probably an overkill.
However, I like this because the request and response logic from my api and my web are separated. Therefore I can deal with the different requests (ex: accessing the user information) and the different responses (ex: JSON or view). It also creates dedicated space for each type of request which allow you to execute extra logic if needed for each part of your app.
Again, it's a question of preference and project but I hope it answers your question.