I have created a basic API using Laravel and am currently building the front end with Angular. Something I am struggling to decide on is how / where to cross reference data in the form of id's with their actual value.
A task object is currently returned from the API as the following:
{
"id":1,
"task_owner":7,
"client":2,
"campaign":17,
"created_by":1,
"title":"Finalise agenda for Call.",
"notes":null,
"viewed":0,
"priority":1,
"start_date":"2016-08-10",
"end_date":"2016-08-11",
"sub_tasks":[
{
"id":1,
"title":"my first subtask"
}
]
}
When displaying the task - I obviously want to show actual values, not ID's, for client, campaign, created_by etc. But I also need the id's to update those tables later, and for filters (ie show only tasks where client_id = 2).
So should I cross reference and send back these bits of data and include as part of my task object - or should I pull all user, client and campaign data in separate API calls first, and then cross reference on the front end?
The Eloquent framework is a powerful tool when querying. I would use the with() function to include whatever you want to include.
Task::with('task_owner', 'campaign', 'created_by')->get();
This is requiring of course that the relationships is correctly set up in the Task model
Related
For a RESTful API, consider a model schema as follows:
MyCoolObject {
field_a
field_b
field_c
}
Is it better to create one update endpoint to update one or many fields on the model (PUT)? Or create one endpoint per field that would only update that one field (PATCH)?
Heuristic: how do you GET the information from your API?
Typically if you get the information a single resource with all of the information included in its representation...
GET /my-cool-object
Then you should also edit that information using the same resource
PUT /my-cool-object
PATCH /my-cool-object
POST /my-cool-object
In cases where you get the information from multiple resources (presumably via links)
GET /my-cool-object
GET /my-cool-object/a
GET /my-cool-object/b
GET /my-cool-object/c
Then you would normally edit the information in its own resource
PUT /my-cool-object/a
PATCH /my-cool-object/a
POST /my-cool-object/a
This seems like a common situation so I've been searching for a question like this but I can't find it. I have built a RESTful Web API in ASP.NET. I have two related tables: Photos and PhotoGroups. The Photos table has a PhotoGroupID column that relates to the same column in PhotoGroups. In my AngularJS Single Page Application I have retrieved data from both tables using the standard RESTful queries. I am displaying a page with the Photos listed in a grid layout and one of the columns is the PhotoGroupID, numbers like 1, 2, 3, and 4. So how can I display the names of those groups instead of those numbers by joining the two queries in a RESTful fashion? I know how to add a new method in the Web API that gives me that joined data, but that doesn't seem natural in a RESTful sense. What is the common way to do this on the client side in AngularJS? Is there some kind of filter that joins the two tables, or some special syntax to bind a column to the PhotoGroup name column? I'm going to run into many cases like that when displaying information from related tables in the future and I want to do this the right way.
I started to solve this problem by adding a new method to my Web API that joined the Photos and PhotoGroups tables, but I quickly realized that I would be returning a collection of anonymous objects. To resolve that would require declaring a new class that contained the columns I wanted to return. That seems like it's getting much more complicated than the beauty and simplicity of REST.
So I pondered the alternatives in AngularJS and decided that I could write a custom filter that would convert the PhotoGroupID into a GroupName using the PhotoGroups JSON array that I already had in the controller scope. The code that implemented that solution is shown below. It's a little messy, but not very and it keeps the Web API nice and simple.
in Filter.js:
angular.module('PhotoFilters', []).filter('groupName', function ()
{
return function (input, scope)
{
var groupName = "Not Found";
angular.forEach(scope.PhotoGroups, function (group)
{
if (group.PhotoGroupID == input)
{
groupName = group.GroupName;
}
});
return groupName;
};
});
in my HTML table:
<td>{{ x.PhotoGroupID | groupName:this }}</td>
I am working on a CakePHP3 application that will be used to display information about which products our suppliers are currently offering.
** Different Vendors provide their product lists in different ways, CSV, JSON, or by way of a web scrape **
I have 2 models that I have created:
Vendors - This references a specific Vendor that we use.
VendorProducts - This references all the products that all of our vendors offer.
I would like to be able to call something like:
$vendor->getAvailableProducts()
and have it either get the CSV and parse it, grab the JSON, or scrape the suppliers website and use this to populate the VendorProducts table in the database with products from this supplier.
I understand the idea behind Fat Models and Skinny Controllers, however I'm having a bit of difficulty implementing this feature.
I would like to provide the following functionality.
The Vendor's getAvailableProducts() function can be called via the web interface AND/OR a cakephp shell script that could be run in a cron job.
As some functionality (like scraping the website) takes a considerable amount of time, I would like to be able to see the progress of this function in the view,
eg: X/Y Products Updated from {Supplier}.
This can be broken down into the following questions:
1. Which file should my "getAvailableProducts()" function go in?
2. As each $vendor has a unique updateProducts() function, how would the correct function be called from $vendor->getAvailableProducts()
// something like this?
public function getAvailableProducts() {
if($vendor->name == "SupplierA") {
getProductsFromSupplierA();
}
if($vendor->name == "SupplierB") {
getProductsFromSupplierB();
}
..., etc.
}
3. How can the progress of this function be returned to a View?
Don't use table classes for that create a new namespace within the model layer or in the app itself:
src/Vendor
src/Model/Vendor
Have a factory that constructs and returns you the Vendor classes:
$vendorA = VendorFactory::get('SupplierA');
$vendorB = VendorFactory::get('SupplierB');
Each vendor class must implement a method fetchProducts(), use an interface or an abstract base class for that.
The method should return a normalized array that can be used to turn the products in entities:
$this->newEntities(VendorFactory::get('SupplierA')->fetchProducts());
You'll have a hard time determining the progress if there is no way to know the total amount of records. Which is likely when you scrape the website. Same issue applies when the API doesn't tell you the total amount of records per JSON data set. If you're able to get that total count somehow you can do this:
$this->newEntities(VendorFactory::get('SupplierA')->fetchProducts([
'limit' => 50,
'offset' => 0
]);
And implement pagination for the vendor which you can then use to run over all the records in a while() loop in chunks of X records. If you trigger that via shell you can create a "job" for that and update the progress after each chunk. There are multiple existing solutions for this kind of task already out there. Finally use Comet or Websockets to get the status updated on your website. Or the old way: Trigger an AJAX request every X seconds to check the status.
There is a lot more that could be said, but this is actually already a very broad question, there is very likely not enough detail to cover all cases. Also it might be possible (I'm pretty sure) there are different ways to solve this.
I am writing an app which will send orders to a remote server. I have a lot of the logic done now for setting up new orders. Items are added to a cart, cart totals are created and I am now ready to hit the server endpoint. At the moment, the REST API (which is being built by a separate team) needs me to:
Send a new order request and receive a new order number
Loop through my cart sending each item individually to the new order endpoint
Send the order totals
Send the payment options and amounts
Return the final data as a receipt to the customer
I currently have
- A cart collection which contains item models
- A totals model
I am not looking for code particularly but could someone outline a method to send the data to the server. I'm trying to figure how to use collections and API URI endpoints to do this but don't have any precedent to follow. Would it be natural in a Marionette/Backbone app to use direct POST requests to the server using defferds and promises or is there a better approach?
I would appreciate any pointers in the right direction,
Generally you wouldn't/shouldn't need to use direct POST requests when interacting with a REST API. Backbone models and collections are designed to interact with an API following this model out of the box.
If you define a collection as so:
var Items = Backbone.Collection.Extend({ url: '/items' });
var myItems = new Items();
myItems.fetch();
then when you call 'fetch' on the collection a GET request will be issued to your specified URL which will populate the collection with the models returned. You can add models to this collection which will fire the appropriate requests to the endpoint. eg. a POST. the default mappings are below for the above collection:
create -> POST '/items'
read -> GET '/items[/id]'
update -> PUT '/items/id'
delete -> DELETE '/items/id'
A lot of this is overridable and configurable so that you can fit into the API that your building against.
I'm just getting my head around BackboneJS, but one of the (many) things I'm still struggling with is how exactly the Models Sync up and relate to the serverside DB records.
For example, I have a Model "Dvd", now I change an attribute on the "Dvd" Model, the Name for example, and then I call save(), how exactly does the server side know what DB record to update? Does Backbone hold the DB row ID or something else?
Yes, typically you will set up your Backbone models so that they have database row IDs for any objects you're working with. When one of them is brand new on the client side and not yet saved to the server, it will either have a default or no ID, which doesn't matter since the server will be assigning the ID if and when the initial save transaction succeeds.
Upon saving or updating a model item, Backbone expects the server to reply with some JSON that includes any attributes that have changed since the save or update request was made. In the response to the initial save request, the server informs the client of a newly saved item's row ID (and you can also send along any other information you might need to pass to the client at the same time).
By default, the 'id' attribute of a model object is assumed to be its unique identifier, but backbone lets you change this if you're using a different identifier for the primary key. Just give your model an idAttribute parameter (see the docs for Backbone.Model.extend()) to do that.
Meanwhile, either the urlRoot parameter or a url function can be given to your models to characterize the urls that should be used to send the various ajax requests to the server for a given model.