How do I use DTOs to consume a REST API in PHP? - php

I have an API to consume for a service that provides finance quotations on used cars. My app is written in PHP and I have Guzzle 5 added via Composer.
I have used other APIs previously that have take XML or just an Array of POST parameters to send, but this one is more complex.
This API uses DTO objects and the documentation says this:
relies heavily on DTOs to carry data between client and server. The following
sections detail the DTOs. Each web service will serialise and transfer them in their own
formats/methods. It is the responsibility of the client application to correctly construct requests and
parse responses. It is suggested that object serialization and deserialization be used for easier usage.
So I have no idea how to achieve this with Guzzle. Some of the enumeration types are things such as "RequestAssetMotorVehicle". Would you use StdClass or Arrays doing this in PHP? Or classes? How would I serialise it?
Guzzle Docs

Without the API's documentation this is difficult to express. But I'll try. We'll use a generic JSON based REST API
DTO standards are usually per company and sometimes per application. In short: A DTO is a serialized object.
Let's say this is a POST request ( we're creating a new user)
{
'name':'john',
'foo':'bar',
'site':'stackoverflow.com'
}
That JSON is a DTO. Now let's do a GET
{
'error':false,
'results':2,
'data': [{'name':'john','foo':'bar','site':'stackoverflow.com'},
{'name':'mark','foo':'bar','site':'notstackoverflow.com'}]
}
the array of 'data' is an array of DTO.
So what the dox are telling you is that you need to familiarize your application with the API by creating a layer for that data to pass through to be formed into objects on your side and the same layer should take an object and turn it into a DTO. In some cases you can just handle the responses from API's with simple code, however in a situation were the GET request would return more than 10 results you are going to want to parse it with some class. Essentially creating an ORM for DTOs.
As far as guzzle goes: set the body to what ever the results of pushing the data through the layer.
public function createUserWithSomeApi()
{
$g= new \Guzzle\Client();
$response = $g->post('http://api.some.place/v1/users', [
'body' => (new strangeApiDtoParser)->prepare($new_user_data)
]);
return ApiDtoParser::fromDTO($response->getBody());
}
And receive
public function getUsersFromSomeApi()
{
$g= new \Guzzle\Client();
$response = $g->get('http://api.some.place/v1/users', [
'query' => ['foo' => 'bar']
]);
return ApiDtoParser::fromDTO($response->getBody());
}
Now your parser:
class ApiDtoParser
{
public static function fromDto($raw)
{
$returnArray=[];
$decoded =json_decode($data,true);
foreach($decoded as $one){
$obj = new DtoObj;
foreach ($one as $key => $value) {
$meth = "set". ucfirst(strtolower($key));
$obj->{$meth}($var);
}
$returnArray[]=$obj;
}
return $returnArray;
}
}
Judging by the context of you excerpt, You will need to create a request based parser though

Related

Include simple fields based on context in Fractal

I am using the Fractal library to transform a Book object into JSON by using a simple transformer:
class BookTransformer extends \League\Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'name' => $book->getName()
// ...
];
}
}
And I am performing the transformation as follows.
$book = new Book('My Awesome Book');
$resource = new \League\Fractal\Resource\Item($book, new BookTransformer());
$fractal = new \League\Fractal\Manager();
$fractal->setSerializer(new \League\Fractal\Serializer\ArraySerializer());
$json = $fractal->createData($resource)->toJson();
This works great. However, I have certain fields on my Book object that should not always be included, because this depends on the context the transformation is done in. In my particular use case, the JSON returned to AJAX requests from my public website should not include sensitive information, while this should be the case when the data is requested from an admin backend.
So, let's say that a book has a topSecretValue field, which is a string. This field should not be included in one transformation, but should be included in another. I took a look at transformer includes, and played around with it, but this only works with resources. In my case, I need to somehow include different fields (not resources) for different contexts. I have been digging around and could not find anything in the Fractal library that could help me, but maybe I am missing something?
I came up with a working solution, but it is not the prettiest the world has ever seen. By having a BaseBookTransformer that transforms fields that should always be included, I can extend this transformer to add fields for other contexts, e.g. AdminBookTransformer or TopSecretValueBookTransformer, something like the below.
class AdminBookTransformer extends BookTransformer
{
public function transform(Book $book)
{
$arr = parent::transform($book);
$arr['author'] = $book->getTopSecretValue();
return $arr;
}
}
This works fine, although it is not as "clean" as using includes (if it were possible), because I have to actually use a different transformer.
So the question is: is there anything in Fractal that enables me to accomplish this in a simpler/cleaner way, or is there a better way to do it, be it the Fractal way or not?

Zend Framework: Transforming post data before reaching Resource

I have a Zend Framework 2 project using Apigility, and I want to be able to send an array of objects via POST to create multiple entities at once. However, ZF/Rest/Resource automatically converts arrays to objects when making a POST. To make the logic a bit cleaner, I would like to convert the data array to an object of my liking (putting the array into a key such as 'storage') before it reaches the Resource.
// ZF\Rest\RestController
public function create($data) //$data is an array
{
$events = $this->getEventManager();
$events->trigger('create.pre', $this, array('data' => $data));
try {
// I want to convert $data to an object by this point
$entity = $this->getResource()->create($data);
} catch (\Exception $e) {
return new ApiProblem($this->getHttpStatusCodeFromException($e), $e);
}
I thought there must be a way to hook into the create.pre event to do this. I've attached a method which gets the Request from the Event, and gets, converts, and sets the Content of the Request, but my debugger says the Resource is still receiving the original array. I've also tried $event->setParam('data', $object), and this didn't work either. (I assume because the parameters are an array and not passed by reference.) Am I going about this the wrong way, or is this not possible?

Laravel: Transform JSON response data

Currently, I am returning data like so (basic example):
public function index()
{
return User::all();
}
However, I want to wrap my responses with some extra meta data, so that they look something like:
{
'success': true,
'data': {
... // Normal response
}
}
The success value would be something as simple as statusCode == 200.
I've read about using response macros, response factories, after middlewares, the Fractal library etc
Ideally it will work with all responses, e.g. returning Eloquent Models and Collections, as well as with Response::json($data).
What is the best / right way, at the time of Laravel 5.2, to achieve this?
Thanks.
If you're developing a API for Laravel, I'd recommend checking out Dingo. It is one of the most useful package for developing APIs. Dingo uses Fractal to transform the responses. In your application to add such metadata, you could use Transformers in Dingo. There are also a lot of events that you can listen to and modify your data. In your particular example, ResponseWasMorphed would be one of the event that you would listen to.
If you want to continue with your project without adding external package, you can override the response() method in your BaseController which could check and add the needed.
public function response($data, $status)
{
//calculate parameter based on $status
$success = ...
return response(array_merge($data, ['success' => $success]));
}
You can use the fractal package for that. Then you can run the response through a transformer and get the proper response. Here's the package for that. https://packagist.org/packages/league/fractal

Instantiate an stdClass object from json schema specification in PHP

I have a set of JSON requests that I must send to a RESTFul API in order to get some response objects, you know, the usual thing for a webapp, however these API request objects are properly documented with a json schema specification for each, so I would like to load those schema files and create stdClass object instances based on that info automagically.
Is there some way to do this with a library or something in PHP? (don't want to reinvent the wheel)
Thanks!
Edit: Have a look at this schema file which contains an example of what I want to load and build object instances from.
Disclaimer: I do know json_encode / json_decode which is not what I'm looking for. Using that I'd need to traverse through the returned schema object and then create another object/array based on the schema read, which is not what I want.
I don't think there's a built-in way of doing this, but it should be relatively trivial to implement:
function createObj( $json ) {
$obj_schema = json_decode($json, true);
$new_obj = new StdClass;
foreach($obj_schema['properties'] as $property) {
$new_obj->{$property} = null;
}
return $new_obj;
}

PHP MVC - Convert JSON to Model data

So essentially I find myself writing a bunch of boiler plate code that takes info from a JSON encoded string and puts that data into the models used in my MVC web app. Is there an accepted method of doing this? Should every model have an associative array to model object converter? Should there be a utility class I write to do this? Basically, I am just trying to remove that code from my controllers to slim them down and I am new to PHP MVC. I am using Kohana 3.2 if that is of any relevance to the question.
EDIT:
I was asked to clarify. I receive data in string format that is JSON encoded (from a web service of my own writing - Java /w Jersey). So essentially, the models in my web app are not pulling their information from a database, but rather from a web service. Since the web service returns everything in JSON format, I find myself writing code that deals with that issue. The other way around, I can tell the GSON google code to convert JSON to a particular Java object. There does not seem to be a one liner way to do this in PHP. I am not talking about the stdClass object, but a model.
Your model must implement simple interface with method fromArray($array)
public function fromArray(array $array)
{
foreach($array as $property => $value) {
if(property_exists($this, $property) {
$this->$property = $value;
}
}
}
Kohana's models (ORM calss) only works with databse records. If you'd like to use Kohana you'll have to write new module based in ORM module. This module can have the actually do same things with model (load, save) but it's gona work with you input data.

Categories