Introduction
Cartalyst's RESTful API package is designed to help you build modular, "API-first" RESTful applications. It makes it easy for you to build API's with support for authentication, rate limiting (coming soon) and versioning.
The application's different components are separated and talk to each other through the same RESTful API externally. Internally, object instances are returned (instead of JSON or arrays) and rate limits are bypassed.
The package follows the FIG standard PSR-0 to ensure a high level of interoperability between shared PHP code.
The package requires PHP 5.3+ and comes bundled with a Laravel 4 Facade and a Service Provider to simplify the optional framework integration.
Have a read through the Installation Guide and on how to Integrate it with Laravel 4.
Installation
Follow the steps below to install the API package in Laravel 4.
Install Sentry 2
On a default installation with Laravel, we use Sentry 2 as the authentication driver for our API package. You will need to install Sentry 2 yourself, or, use another authentication driver. Pull Requests are welcome and we can add new drivers to the default installation. We'll then provide it as a simple config option for our Laravel users.
Installing Sentry 2 in Laravel 4
Composer
Open your composer.json
file and add the following lines:
{
"require": {
"cartalyst/api": "1.0.*"
},
"repositories": [
{
"type": "composer",
"url": "https://packages.cartalyst.com"
}
],
"minimum-stability": "dev"
}
Note: The minimum-stability key is needed so that you can use the API (which isn't marked as stable, yet).
Run a composer update from the command line.
php composer.phar update
Service Provider
Add the following to the list of service providers in app/config/app.php
.
'Cartalyst\Api\ApiServiceProvider',
Note: If you are using the Sentry authentication driver for the API package (default with Laravel 4), you will need to ensure that the
SentryServiceProvider
is registered before yourApiServiceProvider
. This will ensure Sentry is prepared before the API package uses it.
Alias
Add the following to the to the list of class aliases in app/config/app.php
.
'API' => 'Cartalyst\Api\Facades\API',
Override the following aliases to allow the typical use of the Input
, Request
and Response
Facades (not required, but recommended). The examples in our documentation will use these Facades for simplicity.
'Input' => 'Cartalyst\Api\Facades\Input',
'Request' => 'Cartalyst\Api\Facades\Request',
'Response' => 'Cartalyst\Api\Facades\Response',
Configuration
After installing, you can publish the package's configuration file into you application by running the following command:
php artisan config:publish cartalyst/api
This will publish the config file to app/config/packages/cartalyst/api/config.php
where you can modify the package configuration.
Integration
Laravel 4
The Api package has optional support for Laravel 4 and it comes bundled with a
Service Provider and a Facade for easier integration.
After you have installed the package, just follow the instructions.
Open your Laravel config file app/config/app.php
and add the following lines.
In the $providers
array add the following service provider for this package.
'Cartalyst\Api\Laravel\ApiServiceProvider',
In the $aliases
array add the following facade for this package.
'API' => 'Cartalyst\Api\Laravel\Facades\API',
'ApiResponse' => 'Cartalyst\Api\Response',
Usage
Generating Responses
Cartalyst's API package allows you to easily create RESTFul API responses. It allows you to register routes with the {api}/<api version>
syntax to indicate your application's API calls.
Responses from an API route should be returned using the Cartalyst\Api\Http\Response
class (which extends Illuminate\Http\Response
). Using this class has a number of advantages over string-based responses:
- It allows you to pass objects through internal requests. String-based responses must cast the object to a string and then transform it back, so you lose the ability to interact with the responses returned on internal requests.
- It allows you to utilize special array keys, such as
message
anderrors
, which are utilized when creating internal API Exceptions.
Creating responses can be done in two different ways:
- Using the
Cartalyst\Api\Http\Response
class - Using the
Response::api()
function which acts as a layer on top of theCartalyst\Api\Http\Response
class
With every response an optional HTTP status code can be provided. You can read more about all the different HTTP status codes here.
Note: if you didn't register the
Response
alias, you must useApi::createResponse()
instead ofResponse::api()
.
Generating A Response
Creating API responses only requires you to send data through the Response::api()
function. This can be a string or an array. Optionally, you can pass along a HTTP status code and your custom headers.
$data = array('result' => 'foo');
$response = Response::api($data, $status, $headers);
The output of this response will result an instance of Cartalyst\Api\Http\Response
.
Note: When defining keys in the root of the data array make sure not to use the
message
orerror
key. Those keys are reserved by the API package to provide informative messages in your API response.
Registering Response Routes
When creating response routes for your API calls you have to prepend your routes with the {api}/<api version>
syntax. The {api}
part will allow Cartalyst's API package to intercept these routes when you're performing internal requests. The <api version>
allows you to easily create new versions for your API.
Registering a basic route could look like the following example.
Route::get('{api}/v1/foo', function()
{
return Response::api(array('bar'));
});
Grouping Responses
Grouping response routes by version number will allow you not to add the {api}/<api version>
for each route separately.
Route::group(array('prefix' => '{api}/v1'), function()
{
Route::get('foo', 'ApiV1\FooController@fooFunction');
Route::get('bar', 'ApiV1\BarController@BarFunction');
});
Route::group(array('prefix' => '{api}/v2'), function()
{
Route::get('foo', 'ApiV2\FooController@fooFunction');
Route::get('bar', 'ApiV2\BarController@BarFunction');
});
Creating Error Messages
You can provide error messages by sending a string with the error message through the API response and providing the correct HTTP status code.
Route::get('user/{id}', function($id)
{
$user = User::find($id);
if (is_null($user))
{
return Response::api("User [$id] was not found.", 404);
}
return Response::api(compact('user'));
});
Internal requests will be converted to an Exception which can be caught and interacted with. Read more about catching and handling internal request exceptions here.
Accessing Request Input
If you registered the Input
and Request
facade aliases you can use them to safely retrieve the request's input.
Route::post('{api}/v1/users', function()
{
$input = Input::get();
$user = new User($input);
// Return with a "201 Created" response.
return Response::api(compact('user'), 201);
});
Note: If you didn't register Cartalyst's aliases for Laravel's
Input
andRequest
facades you must useAPI::getCurrentRequest()->input()
instead. This makes sure to only retrieve the input for the current request.
Returned Responses
As you can see, for the most part, we are not doing anything different to a simple standard API. We are returning objects from our routes. On external requests, these responses are turned into arrays (and then JSON) before being sent to the browser. Internally, the objects you return are accessible.
The API is smart enough to transform any objects which inherit from Illuminate\Support\Contracts\ArrayableInterface
into arrays, no matter where they lie in the response array.
You can read more on Laravel 4 responses over at their documentation.
Internal Requests
Cartalyst's API package makes it dead-simple to make internal requests to your API within your application. Each method acts virtually identically and takes the same arguments. This allows for an easy way to integrate API calls directly into your application.
It also allows you to easily work with error exceptions being thrown by your API calls.
Making Internal Requests
Making internal requests to your API is pretty easy. Just execute the a restful request as a method on the API alias. The supported methods for internal requests are GET
, POST
, HEAD
, PUT
, PATCH
and DELETE
.
For example, if you had a API route set up to retrieve all the users for your application, you can make an internal call to that API route by using the get()
method.
$response = API::get('v1/users');
The response will return an instance of Cartalyst\Api\Http\Response
.
Sending Request Parameters
You can pass along request parameters for your API request by passing along an array of data as the second parameter.
$data = array(
'name' => 'John Doe',
'email' => 'john.doe@example.com'
);
$response = API::post('v1/users', $data);
Providing A Callback
You can provide a callback which is called after the request has been created and before the request is executed by passing along a closure as the third parameter. An instance of Cartalyst\Api\Http\Request
(which is an extension of Illuminate\Http\Request
) is provided to the callback.
$data = array(
'name' => 'John Doe',
'email' => 'john.doe@example.com'
);
$response = API::get('v1/users', $data, function($request)
{
// If the request doesn't provide a name input parameter,
// abort the application with a "Bad request" status code.
if ( ! $request->has('name'))
{
App::abort(400);
}
});
Catching Exceptions
When making internal requests, you can catch error exceptions thrown by the API package. The exception being thrown by the API package is Cartalyst\Api\Http\ApiHttpException
which extends the Symfony\Component\HttpKernel\Exception\HttpException
class.
try
{
$response = API::get('v1/users');
}
catch (Cartalyst\Api\Http\ApiHttpException $e)
{
// Handle exception.
}
Extending the Symfony\Component\HttpKernel\Exception\HttpException
class provides you with a few options to handle exceptions.
- You can use
isClientError()
andisServerError()
to determine the error source. - Using
getErrors()
will return an array with the errors for the request (as defined by the response generated by the request). - Using
getMessage()
will provide the message passed along to the response. - Using
getStatusCode()
will return the HTTP status code returned by the internal request.
Below is an example of how these functions can be used:
try
{
$result = API::get('v1/foo');
}
catch (Cartalyst\Api\Http\ApiHttpException $e)
{
// When something went wrong on the server end,
// let's abort the application.
if ($e->isServerError())
{
App::abort($e->getStatusCode());
}
// Else if the client did something wrong, redirect back to
// our previous screen with the errors and message that the
// response returned.
elseif ($e->isClientError())
{
return Redirect::to('bar')
->withErrors($e->getErrors())
->with('message', $e->getMessage());
}
}