What is best practice in a Restful laravel app for

2019-07-25 03:10发布

问题:

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.

回答1:

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.