Tuesday, 11 June 2019

Wrapping JSON response in an abstracted way in PHP / Laravel

I am making a REST API that will return different JSON responses depending on which type of User is making the call.

There is a single endpoint: example.com/api/v1/collect that uses Laravel's API authentication to get the User model with $user = auth()->guard('api')->user();.

Each User will belong to a Type.

If User 1 (type_id 1) makes the call, the response will look like:

{
    "example": 1,
    "success": true,
    "data" : [
        ...
    ]
}

If User 2 (type_id 2) makes the call, the response can be different, depending on the user's type. It could look like:

{
    "example": 2,
    "response" : [
        ...
    ],
    "custom": "string",
    "success": 200
}

The ... is the data that we are sending back (for example a list of Post titles) and it will always be the same, but the "envelope" (or wrapper) around it would be specific to each user (or type of user).

So far, I've found two solutions to wrap that ... in an abstracted way:

Solution 1: Using Laravel Blade

// Api\V1\ApiController.php

$data = $user->posts->pluck('title');

// Each type of user will have a different blade filename
// There could be around a 100 types which will result in a 100 blade files
// The filename is stored in the database
$filename = $user->type->filename; // returns 'customBladeTemplate'

// Return a JSON response after passing the $data to the view
return response()->json([
    view($filename, compact('data'))->render(),
]);

Using a blade file for each type of user allows me to wrap the data like this:

// resources/views/customBladeTemplate.blade.php
// This filename has to match the one in the database column
{
    "example": 1,
    "success": true,
    "data" : [
        {!! $data !!}
    ]
}

That will output a JSON response for the User 1 (example 1)

Solution 2: Using Laravel response macros

// Api\V1\ApiController.php

$data = $user->posts->pluck('title');

// Each type of user will have a different macro name
// There could be around a 100 types which will result in a 100 different macros
// The macro name is stored in the database
$macroName = $user->type->macro_name; // returns 'customMacroName'

return response()->{macroName}($data);

Creating a Macro for each type of user, using the macro name from the DB:

// App\Providers\AppServiceProvider.php

use Illuminate\Http\Response;

public function boot()
{
    Response::macro('customMacroName', function ($data) {
        return Response::json([
            'example' => 2,
            'response' => $data,
            'custom' => 'string',
            'success' => 200,
        ]);
    });
}

That macro will output a JSON response for the User 2 (example 2)


Both options work fine but I am still wondering:

  • Is there another (possibly better) way to do it?
  • Are those two solutions valid or can they be enhanced?
  • Which of those two solutions seem to be better and why?


from Wrapping JSON response in an abstracted way in PHP / Laravel

No comments:

Post a Comment