Dingo API remove "data" envelope
Asked Answered
H

3

12

is it there an easy way to remove the "data" envelope from the Dingo API response.

When I use this Transformer to transform user models:

class UserTransformer extends EloquentModelTransformer
{

    /**
     * List of resources possible to include
     *
     * @var array
     */
    protected $availableIncludes = [
        'roles'
    ];

    protected $defaultIncludes = [
        'roles'
    ];

    public function transform($model)
    {
        if(! $model instanceof User)
            throw new InvalidArgumentException($model);

        return [
            'id' => $model->id,
            'name' => $model->name,
            'email' => $model->email
        ];
    }

    /**
     * Include Roles
     *
     * @param User $user
     * @return \League\Fractal\Resource\Item
     */
    public function includeRoles(User $user)
    {
        $roles = $user->roles;

        return $this->collection($roles, new RoleTransformer());
    }

I get this response:

{
data : [
      "id": 102,
      "name": "Simo",
      "email": "[email protected]",
      "roles": {
        "data": [
          {
            "id": 1    
            "name": "admin"
          }
        ]
      }
    }
]
}

I read some articles about RESTful APIs and a lot of them stated that such enveloped responses arent very modern (You should use the HTTP Header instead).

How can I disable this behaviour at least for the includes?

Thank you

Harriot answered 31/10, 2015 at 17:46 Comment(2)
I am not sure but you could use this github.com/dingo/api/wiki/Responses#morphing-and-morphed-events and morph your response before sending but yes, definitely is not an easy way.Tuning
Go to repository, search for what you are asking in ticket section ("remove data") etc.. make your own ticket.. That's what you do when something is on github. btw: +1 from me; just my 2 pennies.Delanos
S
14

For those who fall on this later and as I had really hard time to make it, I'd like to share how I made it working in my API :

1) Create a Custom Serializer, NoDataArraySerializer.php :

namespace App\Api\V1\Serializers;

use League\Fractal\Serializer\ArraySerializer;

class NoDataArraySerializer extends ArraySerializer
{
    /**
     * Serialize a collection.
     */
    public function collection($resourceKey, array $data)
    {
        return ($resourceKey) ? [ $resourceKey => $data ] : $data;
    }

    /**
     * Serialize an item.
     */
    public function item($resourceKey, array $data)
    {
        return ($resourceKey) ? [ $resourceKey => $data ] : $data;
    }
}

2) Set new the Serializer. In bootstrap/app.php, add :

$app['Dingo\Api\Transformer\Factory']->setAdapter(function ($app) {
    $fractal = new League\Fractal\Manager;
    $fractal->setSerializer(new App\Api\V1\Serializers\NoDataArraySerializer);
    return new Dingo\Api\Transformer\Adapter\Fractal($fractal);
});

That's it.

Now, in your UserController (for instance), you can use it like this :

namespace App\Api\V1\Controllers;

use App\Api\V1\Models\User;
use App\Api\V1\Transformers\UserTransformer;

class UserController extends Controller
{
    public function index()
    {
        $items = User::all();

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

And the response will look like :

[
    {
        "user_id": 1,
        ...
    },
    {
        "user_id": 2,
        ...
    }
]

Or, I you want to add an enveloppe, you just need to set the resource key in the Controller. Replace :

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

by

return $this->response->collection($items, new UserTransformer(), ['key' => 'users']);

And the response will look like :

{
    "users": [
        {
            "user_id": 1,
            ...
        },
        {
            "user_id": 2,
            ...
        }
    ]
}
Simonne answered 24/2, 2016 at 13:8 Comment(5)
Well I tried something like: return $this->response->collection(Post::all(), new PostTransformer, ['key' => 'posts']); and I don't have this key? :(Moot
What errors do you have? Have you set the custom Serializer?Simonne
What version of Lumen/Dingo API are you using?Simonne
Did exactly this in laravel 5.4 it seems not to work, Target [Dingo\Api\Contract\Transformer\Adapter] is not instantiable is the error i getBandur
The right place is NOT bootstrap/app.php; but boot method of AppServiceProvider or any other providerKary
T
4

One addition to the solution of YouHieng. The preferred way to register the NoDataArraySerializer in Laravel 5.3 and above is to write a custom ServiceProvider and add the logic into the boot() method and not the bootstrap/app.php file.

For Example:

php artisan make:provider DingoSerializerProvider

Then:

public function boot(){
    $this->app['Dingo\Api\Transformer\Factory']->setAdapter(function ($app) {
        $fractal = new League\Fractal\Manager;
        $fractal->setSerializer(new App\Http\Serializers\NoDataArraySerializer());
        return new Dingo\Api\Transformer\Adapter\Fractal($fractal);
    });
}
Tapdance answered 28/7, 2017 at 20:20 Comment(0)
S
3

Have a look to http://fractal.thephpleague.com/serializers/#arrayserializer. They explain exactly what to do when

Sometimes people want to remove that 'data' namespace for items

Soberminded answered 19/1, 2016 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.