Skip to content

Instantly share code, notes, and snippets.

@atrakeur
Created June 10, 2014 21:01
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save atrakeur/2801c42d9ff51e42d0a2 to your computer and use it in GitHub Desktop.
Save atrakeur/2801c42d9ff51e42d0a2 to your computer and use it in GitHub Desktop.
An laravel's style implementation of API handler.
<?php
/*************************************************
* API base controller for laravel
*************************************************/
class ApiController extends Controller {
/**
* Create a json Response including errors and no data
* @param array $errors the errors
* @return responce The responce including error data
*/
private function jsonError(array $errors)
{
return $this->jsonReply(array(), $errors);
}
/**
* Create a json Response, including data and errors
* @param array $data The data
* @param array $errors The errors
* @return Responce The responce containing json encoded data
*/
private function jsonReply(array $data, array $errors = array())
{
if(!empty($errors))
{
//Crée le contenant
if(!isset($data['errors']))
{
$data['errors'] = new MessageBag();
}
if(!($data['errors'] instanceof MessageBag))
{
throw new Exception('errors element in json must be a MessageBag instance');
}
//ajoute les erreurs au contenant actuel
if ($errors instanceof MessageProviderInterface)
{
$data['errors']->merge($errors->getMessageBag()->toArray());
}
else
{
$data['errors']->merge((array) $errors);
}
//converti en array pour le transfert en json si la collection n'est pas vide, détruit sinon
if($data['errors']->any())
$data['errors'] = $data['errors']->toArray();
else
unset($data['errors']);
//erreur, defini le success a false
$data['success'] = false;
}
//retourne la reponse contenant les données et le json
return Response::json($data);
}
/**
* Execute the passed function then return the result (or exceptions) as json
* @param Closure $f The function to execute
* @return string data as json encoded string
*/
public function apiOutput(Closure $f)
{
try
{
$default['success'] = true;
$return = $f();
$return = array_merge($default, (array) $return);
return $this->jsonReply($return);
}
catch (AppException $e)
{
$return['exception'] = $e->getMessage();
return $this->jsonError($return);
}
catch (Exception $e)
{
$return['exception'] = $e->getMessage();
Log::error($e->__toString());
return $this->jsonError($return);
}
}
}
/*************************************************
* Usage example (API side)
*************************************************/
class TestAPI extends ApiController {
function index()
{
return $this->apiOutput(function(){
if(!Auth::check())
{
//exceptions are returned in JSON in the form :
//{success:false, exception: "Exception message"}
throw new AppException('errors.mustlogin');
}
//prepare some random data
$view_data = array();
$view_data['var1'] = 17;
$view_data['var2'] = "SomeTest";
$view_data['var3'] = Auth::user()->toArray();
//the view data is translated into json form
//Resulting output is in the form:
//{success:true, var1:17, var2:"SomeTest", var3:{UserAsJson}}
return $view_data;
});
}
}
/*************************************************
* Non API base controller for laravel
*************************************************/
class BaseController extends Controller {
/**
* Call an internal api url
*
* @return \StdClass response
*/
protected function callApi($url, $method = 'GET', $input = null)
{
Profiler::startTimer('Api call to '.$url);
if(is_null($input))
{
$input = Request::input();
}
//save original input
$originalInput = Request::input();
Request::replace($input);
//dispatch the request, then parse the responce
$request = Request::create($url, $method);
$responce = json_decode(Route::dispatch($request)->getContent());
//get error array from JSON (if any)
if(isset($responce->errors) && !empty($responce->errors))
{
$data = App::make('view')->getShared();
if(isset($data['errors']))
{
$data['errors']->merge((array) $responce->errors);
}
else
{
$data['errors'] = new MessageBag((array) $responce->errors);
}
App::make('view')->share('errors', $data['errors']);
}
//Replace original input
Request::replace($originalInput);
Profiler::endTimer('Api call to '.$url);
return $responce;
}
}
/*************************************************
* Non API controller (frontend) Usage example
*************************************************/
class TestFrontend extends BaseController {
public function index()
{
//just in case?
if(!Auth::check())
{
return Redirect::to(action('Home@index'));
}
$view_data = array();
$responce = $this->callApi('/api/test');
if ($view_data['success'] == 1)
{
$view_data['var1'] = $responce->var1;
$view_data['var2'] = $responce->var2;
$view_data['var3'] = $responce->var3;
return View::make('testapi', $view_data);
}
else
{
//Display error using message in $responce['exception']
return View::make('errorpage', $responce);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment