REST Methods

Introduction

The API response format must stay consistent throughout the application. Ideally, it would be good to follow a standard such as the JSON:API, so your frontend app could align with the API nicely.

Restify provides several different approaches to respond consistently 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 magical methods.

Restify Response Quickstart

To learn about Restify's helpful response, let's take a look at a complete example of responding to a request and returning the data back to the client.

Defining The Route

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.

Creating The Controller

Next, let's take a closer 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.
    }
}

Writing The API Response Logic

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's property.

Receiving API Response

Once the respond method wraps up the data, the HTTP request will receive back a response with the following structure:

{
  "data": {
    "id": 1,
    "name": "User name",
    "email": "[email protected]",
    "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": []
}

Response factory

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": "[email protected]",
    "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"
  }
}

Displaying Response Errors

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 can 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());
    }
}

The returned API response will have the 400 HTTP code and the following format:

{
  "errors": {
    "title": [
      "The title field is required."
    ]
  }
}

Custom Header

Sometimes you may need to respond with a custom header, according to JSON:API. After storing an entity, we should respond with a Location header that has the value endpoint to the resource:

return $this->response()
    ->header('Location', 'api/users/1')
    ->data($user);

Optional Attributes

Therefore, Restify returns the data and errors attributes in the API's response. It also wraps the message into a meta object. But what if we have to send some custom attributes? In addition to generating the default fields, you can add extra fields to the response by using the setMeta method from the RestResponse object:

return $this->response()
    ->data($user)
    ->setMeta('related', [ 'William Shakespeare', 'Agatha Christie', 'Leo Tolstoy' ]);

Hiding Default Attribute

Restify has a list of predefined attributes, such as: 'line', 'file', 'stack', 'data', 'errors', 'meta'.

Some of these are hidden in production though: 'line', 'file', 'stack', since they are only used for tracking exceptions.

If you would like the API's response to not contain any of these fields (or hide a specific one like errors, for example), this action can be done by setting in the application provider the:

RestResponse::$RESPONSE_DEFAULT_ATTRIBUTES = ['data', 'meta'];

Rest Response Methods

The $this->response() returns an instance of Binaryk\LaravelRestify\Controllers\RestResponse. This exposes multiple magical methods for your consistent API response.

Attach data

As we have already seen, attaching data to the response can be done by using:

->data($info)

Headers setup

The header could be set by using header method, as it accepts only two arguments - the header's name and header's value:

->header('Location', 'api/users/1')

Meta information

In addition to the data, you may want to send some extra attributes to the client. A message would be a good example, or even anything else for that matter:

->setMeta('name', 'Eduard Lupacescu')
->message(__('Silence is golden.'))

Response code modifiers

Oftentimes, we have to send an informative response code. The following methods are used for setting the code's response:

Refresh 103

->refresh()

Success 200

->success()

Created 201

->created()

Deleted (No Content) 204

->deleted()
->blank()

Invalid 400

->invalid()

Unauthorized 401

->unauthorized()

Forbidden 403

->forbidden()

Missing 404

->missing()

Throttle 429

->throttle()

Unavailable 503

->unavailable()

Debugging

The following methods could be used to debug some information in the dev mode:

Line debugging

$lineNumber = 201;
$this->line($lineNumber)

Debug to file

This could be used for debugging the file's name

$this->file($exception->getFile())

Stack traces

With this you can log the exception stach trace

$this->stack($exception->getTraceAsString())

Errors methods

The following methods could be used for adding errors to the response:

Adding multiple errors

Adding a set of errors at once:

$this->errors([ 'Something went wrong' ])

addError function

Adding error by error in a response's instance:

$this->addError('Something went wrong')

Custom Paginator

Every so often you have a customed paginator collection. You want to keep the same response format, just as the Repositorydoes.

You can use this static call:

        $paginator = User::query()->paginate(5);

        $response = Binaryk\LaravelRestify\Controllers\RestResponse::index(
            $paginator
        );

The $paginator argument should be an instance of: Illuminate\Pagination\AbstractPaginator.

The expected response will contain:

{
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "http://localhost",
    "per_page": 5,
    "to": 1,
    "total": 1
  },
  "links": {
    "first": "http://localhost?page=1",
    "last": "http://localhost?page=1",
    "prev": null,
    "next": null
  },
  "data": []
}

Edit this page on GitHub Updated at Sun, Aug 13, 2023