Hiding API fields dynamically — Laravel 5.5

September 26th 2017

I recently saw a question on Laravel Brasil community that turned out to be a lot more interesting than it looks. Imagine you have a UsersResource with the following implementation:

For some reason you might want to reuse that resource class on another endpoint, but hide the email field. This article is an approach on how to achieve that.

If you have no idea what API Resources are, check out my previous articles on this subject.

1- Setting up the project

The interesting stuff start at section 3.

composer create-project --prefer-dist laravel/laravel api-fields
cd api-fields
touch database/database.sqlite

Edit your .env file to remove database settings and use SQLite

DB_CONNECTION=sqlite

Continue setting up the project

php artisan migrate
php artisan make:resource UsersResource
php artisan make:resource --collection UsersResourceCollection
php artisan make:controller UsersController
php artisan tinker
factory(App\User::class)->times(20)->create();
quit

2- The Routes

Make sure to create a route in the api.php file.

Route::apiResource('/users', 'UsersController');

3- The Controller

The Controller represents the desired goal. In this example let’s suppose in the listing we only want the name of all users whereas in the show we want to hide only the email address.

In order to achieve this, we need both our UsersResourceCollection and our UsersResource to know how to handle the hide call.

4- The UsersResource Class

Let’s start with the show method. The UsersResource::make will return an object of UsersResource. As such, we should expose a method hide that stores the desired keys to be removed from the response.

Done! At this point we should be able to access http://api.dev/api/users/1 and se a response without the id field.

{
"data": {
"name": "Mr. Frederik Morar",
"email": "darryl.wilkinson@example.org"
}
}

5- The UsersResourceCollection Class

For a collection of items to work on the index method, we need to perform a few changes:

  • (1) Make sure UsersResource::collection returns an instance of UsersResourceCollection
  • (2) Expose the hide method on UsersResourceCollection
  • (3) Pass through the hidden fields to UsersResource

For (1), we just need to override the collection method on UsersResource

For (2) and (3) we need to change the UsersResourceCollection file. Let’s expose the hide method and process the collection with the hidden fields.

And that’s it! Now if we call http://api.dev/api/users we can see a response without id and email fields like the UsersController specified.

{
"data": [{
"name": "Mr. Frederik Morar"
}, {
"name": "Angel Daniel"
}, {
"name": "Brianne Mueller"
}],
"links": {
"first": "http://lab.php71/api-fields-2/public/api/users?page=1",
"last": "http://lab.php71/api-fields-2/public/api/users?page=7",
"prev": null,
"next": "http://lab.php71/api-fields-2/public/api/users?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 7,
"path": "http://api-fields.lab.php71/api/users",
"per_page": 3,
"to": 3,
"total": 20
}
}

6- Conclusion

The goal was to make the Resource class a little flexible by allowing it to hide some fields that another endpoint may expose. An actual example of this implementation would be a /users endpoint not including the avatar attribute, but when requesting a specific user via /users/99 we may desire to include the avatar in the response.

I wouldn’t recommend reusing API Resources too much as it may easily increase the complexity of a layer that is suppose to be simple. With that said, hiding some specific fields between requests of list and specific record does seem a reasonable request on the account of the simplicity of the implementation.

7- What’s Next

On a next article, I’ll try to extract the hide method into a trait and make it reusable throughout all of the API Resources. Follow me on Medium to stay tuned!

More by Marco Aurélio Deleu

More Related Stories