[[toc]]
The API response format must stay consistent along the application. Ideally it would be good to follow a standard as the JSON:API so your frontend app could align with the API.
Restify provides several different approaches to respond consistent to the application’s incoming request.
By default, Restify’s base rest controller class uses a RestResponse
structure which provides a convenient
method to respond to the HTTP request with a variety of handy magic methods.
To learn about Restify’s handy response, let’s look at a complete example of responding a request and returning the data back to the client.
First, let’s assume we have the following routes defined in our routes/api.php
file:
Route::post('users', 'UserController@store');
Route::get('users/{id}', 'UserController@show');
The GET
route will return back a user for the given id
.
Next, let’s take a look at a simple API
controller that handles this route. We’ll leave the show
and store
methods empty for now:
<?php
namespace App\Http\Controllers;
use Binaryk\LaravelRestify\Controllers\RestController;
class UserController extends RestController
{
/**
* Store a newly created user in storage.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// The only way to do great work is to love what you do.
}
/**
* Display the user entity
*
* @param int $id
* @return Response
*/
public function show($id)
{
// Very little is needed to make a happy life.
}
}
Now we are ready to fill in our show
method with the logic to respond with the user resource.
To do this, we will use the respond
method provided by the parent Binaryk\LaravelRestify\Controllers\RestController
class.
A JSON response will be sent for API
request containing data
and errors
properties.
To get a better understanding of the respond
method, let’s jump back into the show
method:
/**
* Display the user entity
*
* @param int $id
* @return Response
*/
public function show($id)
{
return $this->response(User::find($id));
}
As you can see, we pass the desired data into the respond
method. This method will wrap the passed data into a
JSON object and attach it to the data
response property.
Once the respond
method wrapping the data, the HTTP request will receive back a response having always the
structure:
{
"data": {
"id": 1,
"name": "User name",
"email": "kshlerin.hertha@example.com",
"email_verified_at": "2019-12-20 09:48:54",
"created_at": "2019-12-20 09:48:54",
"updated_at": "2020-01-10 12:01:17"
}
}
or:
{
"errors": [...]
}
In addition the parent RestController
provides a powerful response
factory method.
To understand this let’s return back to our store
method from the UserController
:
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
return $this->response();
}
The response()
method will be an instance of Binaryk\LaravelRestify\Controllers\RestResponse
. For more information on working with this object instance,
check out its documentation.
$this->response()
->data($user)
->message('This is the first user');
The response will look like:
{
"data": {
"id": 1,
"name": "User name",
"email": "kshlerin.hertha@example.com",
"email_verified_at": "2019-12-20 09:48:54",
"created_at": "2019-12-20 09:48:54",
"updated_at": "2020-01-10 12:01:17"
},
"meta": {
"message": "This is the first user"
}
}
As we saw above, the response always contains an errors
property. This can be either an empty array, or a list with errors.
For example, what if the incoming request parameters do not pass the given validation rules? This can be handled by the errors
proxy
method:
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
try {
$this->validate($request, [
'title' => 'required|unique:users|max:255',
]);
// The user is valid
} catch (ValidationException $exception) {
// The user is not valid
return $this->errors($exception->errors());
}
}
And returned API
response will have the 400
HTTP code and the following format:
{
"errors": {
"title": [
"The title field is required."
]
}
}
Sometimes you may need to respond with a custom header, for example according with JSON:API
after storing an entity, we should respond with a Location
header which has the value endpoint to the resource:
return $this->response()
->header('Location', 'api/users/1')
->data($user);
By default Restify returns data
and errors
attributes in the API response. It also wrap the message into a meta
object.
But what if we have to send some custom attributes. In addition to generating default fields, you may add extra fields to the
response by using setMeta
method from the RestResponse
object:
return $this->response()
->data($user)
->setMeta('related', [ 'William Shakespeare', 'Agatha Christie', 'Leo Tolstoy' ]);
Restify has a list of predefined attributes: 'line', 'file', 'stack', 'data', 'errors', 'meta'
.
Some of those are hidden in production: 'line', 'file', 'stack'
, since they are only used for tracking exceptions.
If you would like the API response to not contain any of these fields (or hiding a specific one, errors
for example),
this can be done by setting in the application provider the:
RestResponse::$RESPONSE_DEFAULT_ATTRIBUTES = ['data', 'meta'];
The $this->response()
returns an instance of Binaryk\LaravelRestify\Controllers\RestResponse
. This expose multiple
magic methods for your consistent API response.
As we already have seen, attaching data to the response can be done by using:
->data($info)
Header could be set by using header
method, it accept two arguments, the header name and header value:
->header('Location', 'api/users/1')
In addition with data
you may want to send some extra attributes to the client, a message for example, or anything else:
->setMeta('name', 'Eduard Lupacescu')
->message(__('Silence is golden.'))
Very often we have to send an informative response code. The follow methods are used for setting the response code:
->auth()
->refresh()
->created()
->deleted()
->blank()
->invalid()
->unauthorized()
->forbidden()
->missing()
->success()
->unavailable()
->throttle()
The follow methods could be used to debug some information in the dev mode:
$lineNumber = 201;
$this->line($lineNumber)
This could be used for debugging the file name
$this->file($exception->getFile())
With this you may log the exception stach trace
$this->stack($exception->getTraceAsString())
The follow methods could be used for adding errors to the response:
Adding a set of errors at once:
$this->errors([ 'Something went wrong' ])
Adding error by error in a response instance:
$this->addError('Something went wrong')