Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consistent REST API Response in Laravel+Dingo

I have been developing a set of rest APIs to be exposed for mobile apps. I am following the repository pattern for the development on the Laravel project. How do I implement a presenter and transformer for formatting a constant JSON output throughout the set of all my APIs?

For example I have the following controller for login

public function authenticate()
    {
        $request = Request::all();  
        try {
                // If authenticated, issue JWT token
                //Showing a dummy response
                return $token;
            }  catch (ValidatorException $e) {
                return Response::json([
                    'error'   =>true,
                    'message' =>$e->getMessageBag()
                ]);
            }
    }

Now where does a transformer and presenter come into the picture? I know that both are used to format the output by converting the db object and produce a formatted JSON so that it remains uniform across my APIs.

The dingo API and fractal or even the framework (L5 repository) don't provide detailed documentation and I can't find any tutorials on this.

I have created the following presenter and transformer for another API which gives the list of products

namespace App\Api\V1\Transformers;

use App\Entities\Product;
use League\Fractal\TransformerAbstract;

class UserTransformer extends TransformerAbstract {

    public function transform(\Product $product)
    {
        return [
            'id'     => (int) $product->products_id
        ];
    }
}

Presenter

<?php

namespace App\Api\V1\Presenters;

use App\Api\V1\Transformers\ProductTransformer;
use Prettus\Repository\Presenter\FractalPresenter;

/**
 * Class ProductPresenter
 *
 * @package namespace App\Presenters;
 */
class ProductPresenter extends FractalPresenter
{
    /**
     * Transformer
     *
     * @return \League\Fractal\TransformerAbstract
     */
    public function getTransformer()
    {
        return new UserTransformer();
    }
}

How will I set the presenter in the controller and respond back? Tried

$this->repository->setPresenter("App\\Presenter\\PostPresenter");

But it doesn't seems to work and the doc doesn't shows the complete steps.

  1. In the above example, how can I make a template for an error response which I can use throughout my APIs and how will I pass my error exceptions to it?
  2. It seems like presenter and transformer can be used to convert database objects into presentable JSON and not anything else. Is that right?
  3. How do you use a presenter and a transformer for a success response and an error response? By passing exceptions, instead of DB objects to the transformer?
like image 795
Ajeesh Avatar asked Dec 16 '15 09:12

Ajeesh


2 Answers

I had the same exact problem and here is how I used dingo with transformer

Controller:

public function update(Request $request)
{

    $bus = new CommandBus([
        $this->commandHandlerMiddleware
    ]);

    $agency = $bus->handle(
        new UpdateAgencyCommand($request->user()->getId(), $request->route('id'), $request->only('name'))
    );

    return $this->response->item($agency, new AgencyTransformer());
}

Transformer:

class AgencyTransformer extends TransformerAbstract
{
    public function transform(AgencyEntity $agencyEntity)
    {
        return [
            'id' => (int) $agencyEntity->getId(),
            'name' => $agencyEntity->getName(),
        ];
    }
}

and this is how I handle errors:

throw new UpdateResourceFailedException('Could not update agency.', $this->agencyUpdateValidator->errors());
like image 162
Pawel Bieszczad Avatar answered Oct 09 '22 21:10

Pawel Bieszczad


I just now see your similar question here as well. So see my answer on your other question here: https://stackoverflow.com/a/34430595/429719.

From the other question I derived you're using Dingo, so use that as a structured response class. Make sure you're controller extends from Dingo and then you can just return items and collections in a structured way like:

return $this->response->item($user, new UserTransformer);

return $this->response->collection($users, new UserTransformer);

If you want a nice error handling look for the docs here: https://github.com/dingo/api/wiki/Errors-And-Error-Responses

Basically you can throw any of the core exceptions or a few custom Dingo ones. The Dingo layer will catch them and returns a structured JSON response. As per the Dingo docs:

throw new Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException('Nope, no entry today!');

Will generate:

{
    "message": "Nope, no entry today!",
    "status_code": 403
}
like image 35
tomvo Avatar answered Oct 09 '22 20:10

tomvo