Fill models with Web Services - php

Having a basic example of a REST endpoint which returns a User json object, how would we fill our Model having that we get the data from a Web Service instead of a DB?
My approach is to have a very very basic 'SDK' with independent Classes with my data representation and access data methods, and in every method I make a call to the API with Guzzle to actually perform the action.
The problem is that I'm losing all the power that Eloquent provides.
Is there any recommended approach to do this in Laravel? Non Laravel approachs will do too.

I'd recommend to use a combination of cache and collections.
First you'll collect the web service results to a collection that you will then cache.
Something like this :
$users = Cache::remember('users', $minutes, function() use ($guzzle) {
$apiUsers = $guzzle->get('api/users'); // Get the API response as json
return collect(json_decode($apiUsers));
});
Using collections you'll have access to almost all of the Eloquent features (because it returns Collection as well. So you might do things like $user = $users->where('email', 'you#email.com')->first();
Then if you want to make it more like an "SDK", you can create a package that has classes and methods that makes it easier to get and use your API.

The problem is that I'm losing all the power that Eloquent provides.
That's not the only problem here. Your approach will be quite ineffective if you are planing to call remote API on each page display and the overall performance will greatly suffer from such approach. What you can do instead is to have your API data cached in local DB, so your models can use Eloquent to get them from with all the benefits.

Related

MVC + REST + nested resources + single page app

I'm a novice, but struggling hard to implement this interactive application I'm working on "the right way" or at least a good way in terms of scalability, maintainability, modularity, development speed and tool independence. That's why I chose the REST design guides and a framework which implements MVC.
However I can't get my head around where to put what in the following situation and any input or reading material from a more experienced developer in this techniques would be greatly appreciated :
I'm developing a single page web app which creates a resource that has several nested resources within. In the create methods and alike, I need to call the create methods from the nested resources. Right now every GET request is responded with a JSON, which the front end then parses, shows and add dynamically to the page accordingly. The question is : where should this create and store methods from nested resources be, in the controller or in the model?
Currently, my approach is : since the controller function is to handle user input, interact with model and return the view accordingly, the nested store methods are in the model since they're not created independently, their create methods are in the controller since they're requested from ajax calls, but this isn't nested, and so on. I'm worried that this is too mixed up and not general.
Am I ok ? Am I mixed up? I don't wanna make a mess for my coworkers to understand. Theory becomes tricky when applied..
I'm gonna have a go at this. I am myself still learning about this as well, so if any information is wrong, please correct me.
In terms of scalability, you should always be able to create any model independently, even though at this point it appears not strictly necessary. The REST paradigm stands for exactly this: Each model (a.k.a. resource) has its own (sub)set of CRUD endpoints, which a client application can use to perform any action, on any composition of data (compositions in which elementary entities are mostly the models you specify).
Furthermore, a model should be concerned with its own data only, and that data is typically found in a single table (in the case of relational datastores). In many cases models specify facilities to read related resources, so that this data can be included when requested. That might look like the line below, and the response is ideally fully compliant with the JSON API specification:
GET //api/my-resources/1?include=related-resource
However, a model should never create (POST), update (PUT) or delete (DELETE) these relations, not at all without explicit instructions to do so.
If you have a procedure where a model and its nested models (I assume related models) are to be created in a single go, an extra endpoint can be created for this action. You'd have to come up with a sensible name for that set of resources, and use that throughout your application's HTTP/support layer.For instance, for creation of such a set, the request might be:
POST //api/sensible-name { your: 'data' }
Keep the { your: 'data' }
part as close to a typical JSON API format as possible, preferably fully compliant. Then, in your back-end (I suppose Laravel, inn your case) you'd want to create a factory implementation that might be called <SensibleName>Factory that takes care of figuring out how to map the posted data to different models, and how their relations should be specified. Under the hood, this factory just uses the model classes' creation facilities to get you where you want to go.
When you would instead automate this process in your model it would be impossible to create the resources independently.
When you would instead automate this process in any single-resource controller that would be non-compliant with the REST paradigm.
With the factory pattern, you explicitly use that class to perform the higher level action, and none of the above concerns apply, not speaking about whether this approach is in accordance with REST at all.
The key takeaway is that the exact same result must still be achievable by performing multiple requests to single-resource endpoints, and your additional /api/sensible-name endpoint just substitutes for the need to call to those multiple endpoints, for the purpose of convenience, when you DO want to create multiple records in a single go.
Note that my statement has little to do with what endpoints to create to fetch nested resources. This SO question has some pretty good conversation as to what is acceptable, and how your specific needs might relate to that.
In the end, it's all about what works for you and your application, and REST and the like are just philosophies that propose to you an approach for similar needs in general web development as well as possible.

REST api - Updating table with POST from view

I'm new to RESTful web services and still figuring out the design/architecture aspect coupled with MVC pattern. I am using Codeigniter framework to implement MVC.
I had a pretty simple question. I am using using form data to update a table in my database. I have written an api that will do this:
http://www.example.com/api/resource/tablename/?param1=info1...
Typical api. What I wanted to know was, in the MVC pattern should I be using cURL in my VIEW to POST data and update my table with the form data or should I still be send the POST data to my controller and make the api call from the controller to update the table.
To me it seems arbitrary at this point as both will accomplish the same thing but what is the standard practice? Is it okay to directly communicate with you api from the VIEW to update your db table??
Is it okay to directly communicate with you api from the VIEW to
update your db table??
Yes, it is...in fact that is pretty much what you should do in this case! Send your data directly to the API. Your API should do all data validation and return an error message (in a standardized format like JSON, XML etc) if any data validation fails OR perform whatever action it needs to do with the POSTed data. A great benefit in doing so would be that your API can be used by any caller and would be a complete ecosystem by itself.
Without knowing more about your intended applications I can say this:
Typically you want to try and keep any processing logic (PHP) out of your views if possible. The whole point of the controller is to handle transaction operations from your model and then pass it to your view. So if you are using an API to gather some data from a service that is intended to be used/manipulated in your view then the logical location for that would be in the controller.
The MVC pattern isn't a hard and fast law of X goes in Y and Y goes in Z. It is a pattern that makes it easy to extend and abstract your data gathering, processing logic, and visual layouts.
Technically depending on the application and how you planned to use it you could create a model for the API so that it could be used in multiple controllers without the need to re-write it.

Best way to implement an external API in Laravel 5?

I'm currently working on a project that requires me to call an external API via HTTP to get some data in the form of JSON. This data will be saved to a database pattern defined with the Eloquent ORM. This API requires authentication (by token) and then accepts calls with GET, POST is not needed. The parameters are added to the URL (e.g. ?origin=LHR&destination=GHA).
I'm trying to find a Laravel way to access such data easily - just writing a basic class that has a function with all parameters doesn't seem right. I'd much rather have some sort of query builder, but for the URL. I looked at repositories, but that seems to be geared towards database calls.
To sum up: is there any good "Laravel way" to call an external API?
I've dene something like this just few days ago;
My solution was to define array GET params. F.a.
get-some-stuff?where[foo]=bar&with[relation]&with[otherRelation]
Then you can get the params via Input::get() and go through them with an foreach.
F.a.
foreach(Input::get() as $method => $value) { ...
In the foreach you could decide what to do based on $method

Cakephp + HttpSocket component + Restful API

Recently I am coding a small web page with CakePHP. The most of my models represent data that has to be collected through an external API with the HttpSocket component which provides CakePHP 2.x.
This is the main reason I include the following method in AppModel.php
public function get ($url, $options = array()) {
$options += $this->default;
$url .= 'api_key=' . $options['api_key'];
$hs = new HttpSocket();
return $hs->get($url);
}
I want to implement some measures to control the number of times CakePHP call the API, because it has limitations (100 request per minute and 1000 per hour, for example)
What is the best way to accomplish this?
I thought about store data related to the request in a new table but I am not sure if I can do queries from AppModel.php
Thank you
I would create a new table like api_call_log and increment the count. You can simply get a model instance in your AppModel:
$ApiCallLog = ClassRegistry::init('ApiCallLog')
$ApiCallLog->log();
Put your logic for the count into the model method and pass arguments as you need, not sure what else you might need.
Instead of putting it in AppModel a behavior might be a better place and you can implement additional methods there as well as your code grows and attach it only to models that need it.
An alternative that is very likely less resource hungry than using a SQL DB is to use a Redis cache. So use Cache::read() and Cache::write() to get the actual count and increment it. This is very likely the better alternative if you get A LOT requests to the API. You might get collisions using a SQL DB if you don't lock the tables during the counting and incrementing operation. I never had this case but I would not count on that it won't happen.
Additional note: get() is a very generic name, I would rename it to httpGet(). Names that are not specific can be pretty confusing, especially if there are methods of the same name in other classes around.

Using load('relation') with caching

I know you can cache a query by appending ->remember($minutes).
However, this doesn't work when using loading on an existing Eloquent result. This is because load doesn't return a querybuilder but directly executes it.
Say you want to load the friends of a user:
$user=Auth::user();
$user->load('friends'); // How to cache these results ?
How can I cache these ?
You can't using this code on its own. You do have two options, though:
1) Wrap your code in a wrapper somewhere (essentially abstracting away this call), which does a cache check first, and runs these queries if the cached item does not exist or is expired.
2) Extend the Auth library, specifically its EloquentUserProvider class, and modify the query performed by the retrieveById() method.
You can see one method of abstracting methods and caching in Chris Fidao's Implementing Laravel. The accompanying book is handy!
You have to convert User object into QueryBuilder to get access to ->remember() method
Try
User::with('friends')->where('id', Auth::user()->id)->remember()->first();

Categories