When building an API it is common for people to just grab stuff from the database and pass it to json_encode()
. The problem with this approach is that it can quickly lead to inconsistent output - for example when a database table schema changes.
A data transformer acts as the middle-man between the data fetched and what is output to ensure consistency. Think of it as a view layer for your data. Below is a transformer class and example that you can extend to write your own transformers.
<?php
abstract class Transformer
{
/**
* @var mixed
*/
protected $data;
/**
* Constructor.
*
* @param mixed $data
*/
public function __construct($data)
{
$this->setData($data);
}
/**
* Set the data.
*
* @param mixed $data
*/
public function setData($data)
{
$this->data = $data;
}
/**
* Get the data.
*
* @return mixed
*/
public function getData()
{
return $this->data;
}
/**
* Transform the data into an array.
*
* @return array
*/
abstract public function transform();
/**
* Return the transformed data as a JSON string.
*
* @param int $options
*
* @return string
*/
public function json($options = 0)
{
$data = json_encode($this->transform(), $options);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \InvalidArgumentException(json_last_error_msg());
}
return $data;
}
}
Now let's create a specific transformer for outputting a user's data.
<?php
class UserTransformer extends Transformer
{
/**
* {@inheritdoc}
*/
public function transform()
{
$data = $this->getData();
return [
'userID' => (int) $data['id'],
'userName' => $data['first_name'].' '.$data['last_name'],
'userCreated' => date('Y-m-d H:i:s', $data['created']),
];
}
}
And finally we call the user transformer from our controller, passing in the user's data and outputting as JSON.
<?php
class UserController
{
/**
* An example controller that find's a user and outputs JSON
*/
public function find($id)
{
$data = $this->user->find($id); // this might come from a database somewhere
$transform = new UserTransformer($data);
header('Content-Type: application/json');
echo $transform->json();
}
}
Response method
If you use Laravel or Lumen an extra method that I use in my Transformer class is response
:
<?php
/**
* Return the transformed data as a JSON response.
*
* @param int $status
* @param array $headers
* @param int $options
*
* @return \Illuminate\Http\JsonResponse
*/
public function response($status = 200, array $headers = [], $options = 0)
{
return response()->json($this->transform(), $status, $headers, $options);
}
Then in my controller I can just return $transform->response(201);
to get a JSON response with a 201 status code for example.