I have a Laravel application with Eloquent entities and their respective RESTful resource controllers, like the following:
The model
class Entity extends Eloquent {
...
}
The controller
class EntityContoller {
public function index() {
Entity $entities = Entity::all();
return view('entity.index', compact($entities));
}
... // And many more routes like that
}
Now I am building an android application, and instead of returning views, I need the data as JSON.
In my current solution, for every request I make from my Android application, I add a get query parameter contentType=JSON
. I detect that in the controller, and send the data accordingly like the following. But this seems tedious, and I have to write the same condition everywhere.
class EntityContoller {
public function index() {
Entity $entities = Entity::all();
if(Request::get('contentType', 'JSON')) return $entities;
return view('entity.index', compact($entities));
}
... // And many more routes like that
}
What is the best way I can do this, without having to write this condition in every controller action?
If you don't want to change your controllers, then you could use a middleware that alters the response after it is returned from the controller.
The middleware would receive the response from the controller, check for contentType == JSON
and then return the proper response.
The middleware would look like this:
use Closure;
class JsonMiddleware {
public function handle($request, Closure $next) {
// Get the response from the controller
$response = $next($request);
// Return JSON if necessary
if ($request->input('contentType') == 'JSON') {
// If you want to return some specific JSON response
// when there are errors, do that here.
// If response is a view, extract the data and return it as JSON
if (is_a($response, \Illuminate\View\View::class)) {
return response()->json($response->getData());
}
}
return $response;
}
}
You would then register the middleware in app/Http/Kernel.php
by appending it to the $routeMiddleware
array.
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
// New Middleware
'json' => \App\Http\Middleware\JsonMiddleware::class,
];
Then you would just assign the middleware to routes that might return JSON.
Route::get('user/{user_id}', ['middleware' => 'json', 'uses' => 'App\UserController@getUser']);
You can read more about middleware here and registering and assigning middleware here.
You can read about sending JSON responses in Laravel here.
How about a custom response class? Let me give you an idea. Create a new class or service:
class ResourceResponse{
public function __construct($request, $object, $view = null){
// setting values
}
public function __toString(){
if ($this->request->get('contentType') == 'JSON'){
return $this->object;
}
// view as fallback
return view($this->view, compact($this->object));
}
}
Then in your resources just call the function like using the view name as a fallback if json type is not specified:
public function index(Request $request) {
$entities = Entity::all();
return new ResourceResponse($request, $entities, 'entity.index');
}
If you are pretty sure that the response should be JSON format, then you can forget the view name:
public function index(Request $request) {
$entities = Entity::all();
return new ResourceResponse($request, $entities);
}
$request
parameter at index()
method make use of type-hint as described at Laravel 5's docs
First create BaseController with protected function createView
class BaseController extends Controller
{
protected function createView($object)
{
if (Request::get('contentType', 'JSON')) return $object;
return view('entity.index', compact($object));
}
}
Then in every controller extends this Base Controller
class EntityController extends BaseController
{
public function index()
{
$entities = Entity::all()
return $this->createView($entites);
}
public function get($id)
{
$entity = Entity::find($id);
return $this->createView($entity);
}
}
If there any others exception like multiple object or error, there is no other way to handle it individually.