Laravel response macro
Tags: laravel
Published: 2021-08-13 18:44:04

In this article I will talk about one of my favorite feature when using Laravel framework. Yes, It's a response macro.

I will share you what it is and how we can use this feature to make our response more simpler and reusable.

Let's start it out!

## What is response macro?
Response macro is a custom response that you can re-use in your routes or controllers.

When building a REST API, commonly you will use `response()` helper to send data back to the user.

You also use some variants of `response()` helper when you want to tell that the requested data is not found.

For example you will use these similar syntax to handle your REST API.
```php
// Syntax when sending response with HTTP no content
return response()->json(null, 204);

// Syntax when sending response with HTTP not found
return response()->json(['message' => 'post not found'], 404);

// Syntax when sending response with HTTP created
return response()->json(['message' => 'register success'], 201);
```
Now, imagine. What if we can transform those response into simpler form but has same functionality?.
```php
// Syntax when sending response with HTTP no content
return response()->noContent();

// Syntax when sending response with HTTP not found
return response()->notFound('post not found');

// Syntax when sending response with HTTP created
return response()->created('register success');
```
It's cool right? even those syntax tells us explicitly what actual action of those response send to the user.

## How to add response macro?
Basically, we just extend the basic features of Laravel `Response` object by registering our custom response inside `App\Providers\AppServiceProvider`.

Open file `app/Providers/AppServiceProvider.php` and use `Illuminate\Support\Facades\Response` (Response facade). To register the custom response use `Response::macro()` inside the `boot` method.

`Response::macro()` has two parameters. The custom response name and the implementation. Let's add one of the previous custom responses above.

```php
<?php

namespace App\Providers;

use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Response::macro('notFound', function ($message) {
            return Response::make(compact('message'), HTTP_NOT_FOUND);
        });
    }
}
```

## How to use response macro?
If you have added the response macro, you can use it inside routes or controllers. For example you have a `PostController.php` with method `show` inside it.
```php
<?php

public function show(int $id)
{
    $post = Post::find($id);

    if (is_null($post)) {
        $message = sprintf('Post with id %d not found', $id);

        return response()->notFound($message);
    }

    return new PostResource($post);
}
```

## Bonus
Response macro is not about adding simple custom response only. You can use response macro as a transform layer (or service) to add micro functionality.

For example you can add response macro to convert markdown to HTML.
```php
<?php

public function boot()
{
    Response::macro('markdown', function ($raw) {
        // fake markdown converter library
        $md = new Markdown();

        return Response::make(['data' => $md->toHTML($raw)], HTTP_OK);
    });
}
```

Use it inside your controller.
```php
<?php

public function render(int $id)
{
    $post = Post::find($id);

    if (is_null($post)) {
        $message = sprintf('Post with id %d not found', $id);

        return response()->notFound($message);
    }

    return response()->markdown($post->body);
}
```

**NOTE**:
When you use response macro as a transform layer, always remember to never put business logic inside it such a validation, database operations, etc.

<a href="https://www.buymeacoffee.com/thexdev"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a macbook&emoji=💻&slug=thexdev&button_colour=FFDD00&font_colour=000000&font_family=Poppins&outline_colour=000000&coffee_colour=ffffff"></a>