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.
The interesting stuff start at section 3.
composer create-project --prefer-dist laravel/laravel api-fieldscd api-fieldstouch database/database.sqlite
Edit your .env
file to remove database settings and use SQLite
DB_CONNECTION=sqlite
Continue setting up the project
php artisan migratephp artisan make:resource UsersResourcephp artisan make:resource --collection UsersResourceCollectionphp artisan make:controller UsersControllerphp artisan tinkerfactory(App\User::class)->times(20)->create();quit
Make sure to create a route in the api.php
file.
Route::apiResource('/users', 'UsersController');
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.
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": "[email protected]"}}
For a collection of items to work on the index
method, we need to perform a few changes:
UsersResource::collection
returns an instance of UsersResourceCollection
hide
method on UsersResourceCollection
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}}
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.
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!