Consistent REST API Response in Laravel+Dingo
Asked Answered
O

4

10

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?
Oblast answered 16/12, 2015 at 9:38 Comment(0)
C
1

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());
Colcannon answered 18/12, 2015 at 16:38 Comment(0)
P
1

I just now see your similar question here as well. So see my answer on your other question here: https://mcmap.net/q/1169091/-transformer-usage-on-laravel-dingo-api.

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
}
Philanthropic answered 23/12, 2015 at 7:34 Comment(1)
return $this->response->item($user, new UserTransformer); is not actually tranforming my responses. There is no error or anything being shown in it. Im just getting the plain json without any transformations.Oblast
A
0

You can try use,[Midresapi]: https://github.com/oktorino/midresapi. this will return consistens success or failled response, work in laravel 7 & 8 , Handling validation response, handling 500 response:

$users=\App\User::latest()->limit(2)->get();

return response($users);
#or
return fractal()
        ->collection($users)
        ->transformWith(new \App\Transformers\UserTransformer)
        ->toArray();

Response :

{
"status_code": 200,
"success": true,
"message": "ok",
"data": [
    {
        "username": "dany",
        "email": "[email protected]"
    },
    {
        "username": "scc-client-5150",
        "email": "[email protected]"
    }
  ]
}
Abjure answered 15/2, 2021 at 5:5 Comment(0)
L
-1

Fractal is fully documented here: http://fractal.thephpleague.com/ There is an excellent book that I regularly read from the Phil Sturgeon https://leanpub.com/build-apis-you-wont-hate You can find most of the books code available in github https://github.com/philsturgeon/build-apis-you-wont-hate. You can find really nice examples of Fractal in there.

  1. I would create an Api Controller and extend it from my Controllers.In there there should be all the respond functions (respondWithError, respondWithArray etc.)
  2. Tranformers are transforming objects in a consistent json format so that all your endpoints return the same thing for each entity.

  3. Dont really have an answer on this

  4. There are enough examples in Fractal documentation.
Laryngotomy answered 16/12, 2015 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.