AngularJS $resource creating new object instead of updating object - rest

// Set up the $resource
$scope.Users = $resource("http://localhost/users/:id");
// Retrieve the user who has id=1
$scope.user = $scope.Users.get({ id : 1 }); // returns existing user
// Results
{"created_at":"2013-03-03T06:32:30Z","id":1,"name":"testing","updated_at":"2013-03-03T06:32:30Z"}
// Change this user's name
$scope.user.name = "New name";
// Attempt to save the change
$scope.user.$save();
// Results calls POST /users and not PUT /users/1
{"created_at":"2013-03-03T23:25:03Z","id":2,"name":"New name","updated_at":"2013-03-03T23:25:03Z"}
I would expect that this would result in a PUT to /users/1 with the changed attribute. But it's instead POST to /users and it creates a new user (with a new id along with the new name).
Is there something that I'm doing wrong?
AngularJS v1.0.5

you just need to tell the $resource, how he has to bind the route-parameter ":id" with the JSON Object:
$scope.Users = $resource("http://localhost/users/:id",{id:'#id'});
This should work,
regards

thanks for the answer. It worked in the end for me too.
As a side note, I was using .NET WEB API and my entity has an Id property (UPPER CASE "I").
The PUT and DELETE worked only after I used the following:
$scope.Users = $resource("http://localhost/users/:Id",{Id:'#Id'});
Hope it helps.

Related

Google Analytics Reporting API - Get Activity data via Client ID

I am trying to get user activity data via his client id using Google Analytics api. Take a look at the below image:
Now highlighted text is users client id, it could be user id too, and when I trying to get it via Google's playground, I get the correct response and activity data which is required, like:
and this is the response:
which is required and OK.
but I want this data via API, and have searched the web to get it, but nothing helped me.
Here is sample code Google showing i.e.
function getReport($analytics) {
// Replace with your view ID, for example XXXX.
$VIEW_ID = "<REPLACE_WITH_VIEW_ID>";
// Create the DateRange object.
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("7daysAgo");
$dateRange->setEndDate("today");
// Create the Metrics object.
$sessions = new Google_Service_AnalyticsReporting_Metric();
$sessions->setExpression("ga:sessions");
$sessions->setAlias("sessions");
// Create the ReportRequest object.
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges($dateRange);
$request->setMetrics(array($sessions));
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request) );
return $analytics->reports->batchGet( $body );
}
I do found a class for adding user to request i.e.
$user = new Google_Service_AnalyticsReporting_User();
$user->setType("CLIENT_ID");
$user->setUserId("660467279.1539972080");
but this class Google_Service_AnalyticsReporting_ReportRequest which accepts conditions/filters for query does not have such method to accept user object.
How can I achieve this?
You should use this function: $analytics->userActivity->search().
$search = new Google_Service_AnalyticsReporting_SearchUserActivityRequest();
$search->setViewId($VIEW_ID); // Google Analytics View ID
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("7daysAgo");
$dateRange->setEndDate("today");
$search->setDateRange($dateRange);
$user = new Google_Service_AnalyticsReporting_User();
$user->setType("USER_ID"); // or CLIENT_ID if you are not using custom USER ID views
$user->setUserId($user_id); // The actual user's ID as stored in your DB passed to GA
$search->setPageSize(10); // Number of results you want to pull
$search->setUser($user);
return $analytics->userActivity->search($search); // Perform the search query.
Alternatively you can also pass the params to search() like:
$params = [
'metrics' => //Your comma separated desired metrics
'dimmensions' => //Your comma separated custom dimmentions
]
return $analytics->userActivity->search($search, $params);

In a REST API, to GET a resource, should I include the resource ID in the url?

I am trying to create an REST API for creating and retrieving files in my database. The tutorial I was following uses the following method to retrive a single file:
$app->get('/file/:file_id', 'authenticate', function($file_id) {
global $user_id;
$response = array();
$db = new DbHandler();
// fetch file
$result = $db->getFile($file_id, $user_id);
if ($result != NULL) {
$response["error"] = false;
$response["id"] = $result["id"];
$response["file"] = $result["fileLocation"];
$response["status"] = $result["status"];
$response["createdAt"] = $result["created_at"];
echoRespnse(200, $response);
} else {
$response["error"] = true;
$response["message"] = "The requested resource doesn't exist";
echoRespnse(404, $response);
}
});
Here they are using the HTTP GET method and are specifying the file ID in the URL, is it OK to do this, safety wise? Would it not be safer to use POST and hide the file ID in the body of the request, or should they not be putting the file ID in a header with the GET request? or is it not something I should be worried about?
In REST post method is used to create a new resource not to get it. Get method is used for fetching the resource and you need to specify the ID to determine particular resource. Passing it via URL is a common practice. You can randomly generate such ID to make it harder to guess.
As Opal said above, the ID is used to identify a resource. If you are unsure have a read of this - http://blog.teamtreehouse.com/the-definitive-guide-to-get-vs-post

How to make a REST delete method with cfhttp

I have never done it before and now when the need arise, things are not working.
I have to send an ID to delete a DB record with RESTful service. Here is the code I am trying:
<cfhttp url="http://127.0.0.1:8500/rest/test/something" method="DELETE" port="8500" result="qryRes1">
<cfhttpparam type="body" value="36"/>
</cfhttp>
and in the REST function
remote any function someName() httpmethod="DELETE"{
var testID = ToString(getHTTPRequestData().content);
//make db call to delete
return testid;
}
The result comes as blank [empty string]. I am not able to retrieve the sent value in function. What I am missing?
Edit: one slightly different but related to CF rest, is it necessary to convert query to an array before sending it back to client? Directly serializing won't solve the purpose same way?
you may want to take a look at deleteUser() in http://www.anujgakhar.com/2012/02/20/using-rest-services-in-coldfusion-10/ as an example of how to support DELETE in REST API style.
remote any function deleteUser(numeric userid restargsource="Path") httpmethod="DELETE" restpath="{userid}"
{
var response = "";
var qry = new Query();
var userQry = "";
qry.setSQl("delete from tbluser where id = :userid");
qry.addParam(name="userid", value="#arguments.userid#", cfsqltype="cf_sql_numeric");
userQry = qry.execute().getPrefix();
if(userQry.recordcount)
{
response = "User Deleted";
} else {
throw(type="Restsample.UserNotFoundError", errorCode='404', detail='User not found');
}
return response;
}
As for the 2nd part of your question, it'd be best to first turn a query into a array of structs first unless you're using CF11 which does it for you. See: http://www.raymondcamden.com/index.cfm/2014/5/8/ColdFusion-11s-new-Struct-format-for-JSON-and-how-to-use-it-in-ColdFusion-10
The default JSON structure for query in CF 8 to 10 were designed for <cfgrid> in ColdFusion on top of Adobe's discontinued Spry framework.

What's the best way to handle a REST API's 'create' response in Backbone.js

I'm using backbone.js to interact with a REST API that, when posting to it to create a new resource, responds with a status of 201, a 'Location' header pointing to the resource's URI, but an empty body.
When I create a new model at the moment, its successful, but the local representation of the model only contains the properties I explicitly set, not any of the properties that would be set on the server (created_date, etc.)
From what I understand, Backbone would update its representation of the model with data in the body, if there were any. But, since there isn't, it doesn't.
So, clearly, I need to use the location in the Location header to update the model, but what's the best way to do this.
My current mindset is that I would have to parse the url from the header, split out the id, set the id for the model, then tell the model to fetch().
This seems really messy. Is there a cleaner way to do it?
I have some influence over the API. Is the best solution to try to get the API author to return the new model as the body of the response (keeping the 201 and the location header as well)?
Thanks!
Sounds like you will have to do a little customization.
Perhaps override the parse method and url method of your model class inherited from
Backbone.Model.
The inherited functions are:
url : function() {
var base = getUrl(this.collection);
if (this.isNew()) return base;
return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + this.id;
},
parse : function(resp) {
return resp;
},
and you could try something like:
parse: function(resp, xhr) {
this._url = xhr.getResponseHeader('location')
return resp
}
url: function() {
return this._url
}
Yes, backbone.js really wants the result of a save (be it PUT or POST) to be a parseable body which can be used to update the model. If, as you say, you have influence over the API, you should see if you can arrange for the content body to contain the resource attributes.
As you point out, its makes little sense to make a second over-the-wire call to fully materialize the model.
It may be that a status code of 200 is more appropriate. Purists may believe that a 201 status code implies only a location is returned and not the entity. Clearly, that doesn't make sense in this case.
With Backbone 0.9.9, I couldn't get the accepted answer to work. The signature of the parse function seems to have changed in an older version, and the xhr object is no longer available in the function signature.
This is an example of what I did, to make it work with Backbone v0.9.9 and jQuery 1.8.3 (using a Deferred Object/Promise), relying on the jqXHR object returned by Backbone.Model.save() :
window.CompanyView = Backbone.View.extend({
// ... omitted other functions...
// Invoked on a form submit
createCompany: function(event) {
event.preventDefault();
// Store a reference to the model for use in the promise
var model = this.model;
// Backbone.Model.save returns a jqXHR object
var xhr = model.save();
xhr.done(function(resp, status, xhr) {
if (!model.get("id") && status == "success" && xhr.status == 201) {
var location = xhr.getResponseHeader("location");
if (location) {
// The REST API sends back a Location header of format http://foo/rest/companys/id
// Split and obtain the last fragment
var fragments = location.split("/");
var id = fragments[fragments.length - 1];
// Set the id attribute of the Backbone model. This also updates the id property
model.set("id", id);
app.navigate('companys/' + model.id, {trigger: true});
}
}
});
}
});
I did not use the success callback that could be specified in the options hash provided to the Backbone.Model.save function, since that callback is invoked before the XHR response is received. That is, it is pointless to store a reference to the jqXHR object and use it in the success callback, since the jqXHR would not contain any response headers (yet) when the callback is invoked.
Another other to solve this would be to write a custom Backbone.sync implementation, but I didn't prefer this approach.

Zend Framework: Checking if route exists from code

in zend framework, is there anyway i can check if a route exists from code?
example
say the following routes/urls are valid (point to controller/action)
/users
/users/1 // /users?id=1
/users/page/1 /users?page=1
/users/tagged/tagname/page/1 /users?tagged=1&page=1
if the user tries to goto /users/nonexistantpage it should fail. soemthing to check if the user request the url, will it fail, but on the code level.
I believe you're looking for the match() method for the Zend router. See if that helps.
It's kinda old question, but I guess this is what you are looking for:
foreach(Zend_Controller_Front::getInstance()->getRouter()->getRoutes() as $route)
{
$route->match($uri);
}
For those using Zend Framework 2, this is very simple.
Let say we want to check if an URI matches against registered router and redirect the user if this is different from the current url.
$goto = 'http://www.mysite.tld/admin';
$request = $this->getRequest();
$request->setUri($goto);
if ($routeToBeMatched = $this->getServiceLocator()->get('Router')->match($request)) {
$currentRouteMatchName = $this->getEvent()->getRouteMatch()->getMatchedRouteName();
if ($routeToBeMatched->getMatchedRouteName() != $currentRouteMatchName) {
return $this->redirect()->toRoute($goto);
}
}
If you use rewrite router (Zend_Controller_Router_Rewrite), it has a method hasRoute($route_name)
Then if you want to check if route exists anywhere in your application you can check it like that:
Zend_Controller_Front::getInstance()->getRouter()->hasRoute("my_route");