Custom API responses with Laravel Macros
Did you find yourself trying to create a custom API response to use it in your controllers, but in a way that you won’t repeat yourself?
If you are wondering why should I do something like that? In my case, it was to make things easier for the front-end side.
There is an excellent idea that laravel uses, and it is based on the Macroable trait. Many great articles explain well what’s going on under the hood out there, but here we will use the Response Macros to create custom responses. For the error responses, the goal is to get the following JSON response:
"status": 422,
"code": "Failed",
"errors": [
"validation.min.name"
]
And for the success responses, the following:
"status": 201,
"code": "Created",
"data": {
"id": 126,
"name": "David",
"surname": "Williams",
"created": 1619822879,
"updated": 1619822879
}
Step 1: Override validation messages
The first step is to create our own Form Request and, for each rule, provide our own message.
Step 2: Create the macros
Great. In the next step, as the documentation already mentioned, we are going to create our own Service Provider and create our macros.
php artisan make:provider ApiResponseServiceProvider
Step 3: Use the macro
Now we can use that macro in our Controller to manipulate the response based on our need, and we are done, Voilà.
try { ... }
catch (Exception $e){
return response()->error(422, 'Failed', $FlattenMessages);
} $clients = Client::get();return response()->success(201, 'OK', compact('clients'));
Let’s think about it. In our next controller, we will try and catch possible errors, and we will flatten the error messages. As a result, we repeat ourselves. Is there a way to avoid that?
Step 4: The Middleware
My idea was to use a middleware only on API routes and manipulate the JSON responses. That middleware will identify what kind of response we need to return based on the different response statuses.
php artisan make:middleware CustomApiResponse
The macros will change a little bit to be JSON responses specific.
$response->json()->macro(...)
Step 5: DRY Controllers
Finally, we can clean our controllers a let the middleware do the job.
You may see the GitHub repo too for more details. I would love to hear your thoughts.