I'm working on an Ember.js app. I have an update function, part of an ObjectController.
The function should save my updated model, however when I call save(); it sends a POST request not a PUT request. (Tested in Chrome.)
Why would that happen? How can I make sure a PUT request is sent for updates?
Here is my code:
customer = this.get('model');
customer.set('name', 'New name');
customer.save();
For extra reference, when I log the "dirtyType" with console.log( customer.get('dirtyType') ); it says "updated".
Any help very much appreciated!
UPDATE
I've adjusted the sample code above to make it clearer, I am NOT creating a new model and wanting to use PUT. I have an existing model that I need to update.
I'm not sure if your workaround is correct in the land of PUT vs POST.
TL;DR PUT should define the resource (by Request-URI), but we don't do that during creation, so we shouldn't be using a POST. Override the create/save if you need this for your server, instead of hacking the isNew property, which may come back to bite you.
Put
9.6 PUT
The PUT method requests that the enclosed entity be stored under the
supplied Request-URI. If the Request-URI refers to an already
existing resource, the enclosed entity SHOULD be considered as a
modified version of the one residing on the origin server. If the
Request-URI does not point to an existing resource, and that URI is
capable of being defined as a new resource by the requesting user
agent, the origin server can create the resource with that URI. If a
new resource is created, the origin server MUST inform the user agent
via the 201 (Created) response. If an existing resource is modified,
either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
to indicate successful completion of the request. If the resource
could not be created or modified with the Request-URI, an appropriate
error response SHOULD be given that reflects the nature of the
problem. The recipient of the entity MUST NOT ignore any Content-*
(e.g. Content-Range) headers that it does not understand or implement
and MUST return a 501 (Not Implemented) response in such cases.
If the request passes through a cache and the Request-URI identifies
one or more currently cached entities, those entries SHOULD be
treated as stale. Responses to this method are not cacheable.
The fundamental difference between the POST and PUT requests is
reflected in the different meaning of the Request-URI. The URI in a
POST request identifies the resource that will handle the enclosed
entity. That resource might be a data-accepting process, a gateway to
some other protocol, or a separate entity that accepts annotations.
In contrast, the URI in a PUT request identifies the entity enclosed
with the request -- the user agent knows what URI is intended and the
server MUST NOT attempt to apply the request to some other resource.
If the server desires that the request be applied to a different URI,
Custom Adapter
App.ApplicationAdapter = DS.RESTAdapter.extend({
createRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record, { includeId: true });
//return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });
return this.ajax(this.buildURL(type.typeKey), "PUT", { data: data });
},
updateRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record);
var id = get(record, 'id');
// you could do the same here, but it's even more incorrect
return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data });
},
});
http://www.ietf.org/rfc/rfc2616.txt
Thank you for all of your help guys, however I have found the issue and it is ridiculously silly.
The API I have been using had a new flag "is_new" and that had been added to the model and was overwriting the "isNew" property.
Causing Ember (and me) to get very confused.
I've tweaked the API and all is good in the world!
If the model was created with createRecord, and thus has isNew == true and you call save() the expected behavior is POST. Once the record has been persisted, and it is changed, and thus isDirty == true but isNew == false then the save() will be a PUT.
This is described in the Models Guide.
Related
I have a model that contains a FileField which may not be blank. When creating tests for this model, I've run into the problem that I get errors when testing with PUT, while the exact same thing works when doing a POST.
As views I'm simply using generics.ListCreateAPIView for the POST destination and generics.RetrieveUpdateDestroyAPIView for the PUT destination, both work normally when using the API in browser.
The payload for the POST and PUT is created as follows:
uploaded_file = SimpleUploadedFile('TestCode4.c', "Testcode", content_type='text/plain')
self.valid_payload = {
'name': 'TestValid',
'test_file': uploaded_file
}
Then the working POST test looks as follows:
client = Client()
response = client.post(
reverse('code-list'),
self.valid_payload,
format='json'
)
And the PUT:
client = Client()
response = client.put(
reverse('code-detail', kwargs={'pk': 1}),
self.valid_payload,
format='json'
)
The POST returns 204 and creates a new object, while the PUT returns 415 with the following error:
{u'detail': u'Unsupported media type "application/octet-stream" in request.'}
I am unsure what is going wrong here, it seems that both the post and put are passing the SimpleUploadedFile data in the same way, though with put it somehow becomes an octet stream.
I figured out the problem Django's django.test.Client class does not support the 'PUT' method. Instead the REST framework provides the class rest_framework.test.APIClient, which does support PUT (and PATCH, etc).
The client.put() function now needs to be filled in a little differently (I was unable to get it to work with SimpleUploadedFile) as explained here: https://fodra.github.io/2017/05/31/testing-django-rest-api-with-image-field.html
I am new developer and i have not much knowledge on http service. so i was finding the difference between PUT and POST. i read this one https://forums.asp.net/t/2100831.aspx?WebApi+what+is+difference+between+PUT+and+POST
below things not clear specially what is idempotent?
i found one guy said - The PUT method is defined to be idempotent ( ie : have the same result over subsequent calls ). PUT would always update the same resource and return 200 status code.
But POST would create a new resource and return 201 status code.
anyone would mind to explain why PUT is considered as idempotent. thanks
From a pure RESTful point of view PUT is considered idempotent because it does not matter how many times you make the same request, the result will be the same.
However, this being said, don't forget that the object you are trying to update might have its state changed between these identical PUT requests so the response you get might not actually be the same.
This does not mean that if you fire 100 PUT requests only one goes through though like in a previous response.
One more thing, just to be clear, POST is used to create new resources and typically returns the unique identifier of the created resource.
PUT is used to update resources and typically returns the entire updated resource so you can see what changes have been made to it.
There have been many discussions on what data should each of these accept, my personal view is that POST takes the fields required create the resource, no ID, while PUT takes the fields take will be updated and if the ID is part of the URL then it can be omitted again
for example, let's say you issue a PUT request to an endpoint like this:
api/users/1
where 1 is the id you need to identify this user, then your method could look like this:
[HttpPut]
public UserClass Put(int id, UserClass user)
{}
in this case your UserClass does not need the id as you already have it from the URL.
Hope all of this makes sense, I find the use of "idempotent" in a RESTful context quite confusing!
Let's say you want to update an User object so you call the PutUser method this way
$.ajax({
url: "yourUrl/PutUser/1",
type: 'PUT',
data: "firstName: fName, lastName: lName",
success: function(data) {
alert('User Updated.');
}
});
And your PutUser method looks like this
[HttpPut]
public dynamic PutUser(int id, UserClass user)
{}
In this case if you make the Ajax PUT request using the same parameters 1, 2..5 or N times the result will be identical, that is what idempotent means.
On the other hand if you have this
$.ajax({
url: "yourUrl/PostUser",
type: 'POST',
data: "firstName: fName, lastName: lName",
success: function(data) {
alert('User Updated.');
}
});
And your PostUser method looks like this
[HttpPost]
public dynamic PostUser(UserClass user)
{}
And call the PostUser method with the same parameters N times, you will Post N identical users and that could mean for example in 100 identical rows in your database, so all your calls will be processed.
I am trying to learn Angular2
and I am trying to create a simple blog with authentication.
this here is my add a new post method:
[Authorize]
// POST: api/Post
public PostModel Post([FromBody]PostViewModel model)
{
var post = new PostModel
{
Body = model.Body,
Title = model.Title,
AuthorId = IdentityExtensions.GetUserId(User.Identity),
};
var res = blogRepo.AddPost(post);
return res;
}
everything works fine, but IdentityExtension.GetUserId() do not return the most current logged in user but the first user since the app started.
basically I am looking for a way to make sure that the current user logs out on the server as well as on the client (the client side is just a simple removal of the localStorage.removeItem("jwt");)
also there is a good chance that what I am doing is totally wrong, but I can't access the ApplicationUserManager in this controller.
ok I have found the problem, although I haven't managed to solve it yet but I will update this when i do, and I am writing this as an answer since the problem is totally different from what I asked and thought to be.
the problem is related to sending the authentication hints as Thierry Templier suggested. I have a file that exports headers like this:
export const authHeaders = new Headers();
authHeaders.append('Accept', 'application/json');
authHeaders.append('Content-Type', 'application/json');
authHeaders.append('Authorization', 'Bearer ' + localStorage.getItem('jwt'));
And I Import this header where ever I need it. but I am not sure why it always sends a cached value (i.e the first value stored on the client and it has nothing to do with the server side as my question implies).
to solve this issue I just have to make sure the latest access-token stored on localstorage is sent to the server.
EDIT: for now I am constructing the headings in the constructor.
I am using Parse for my backend and want to search for existing friend requests and update those instead of creating new ones (if there is already an existing one).
I thought I figured out how to do it but when I submit new friend requests they get created as new objects instead of updating the old one, even though I found an existing request.
Here is the code I am using:
Parse.Cloud.beforeSave("FriendRequest", function(request, response) {
//search for an existing friend request with the same "from" and "to"
var query = new Parse.Query("FriendRequest");
query.equalTo("from", request.object.get("from"))
.equalTo("to", request.object.get("to"));
query.find({
success: function(results) {
if(results.length > 0)
{
var result = results[0];
//the new request id is undefined as expected
console.log("request id: " + request.object.id);
//the result id is valid for an object in the db as expected
console.log("result id: " + results[0].id);
//set the id of the request to the id of the existing db object
request.object.id = results[0].id;
//the valid id is now in the request object id
console.log("request id: " + request.object.id);
//after response.success, the database shows a new entry
//with a different id
//instead of updating the existing entry
response.success();
}
}
});
});
There isn't a lot going on here. The query does come back successful with the correct entry in the database. I can confirm that I get the correct objectId for the existing item in the database. Any thoughts or ideas are appreciated!
You can't manually set the objectId of an object.
If you want beforeSave to NOT create a new object (which is what you're about to do when beforeSave is called), you need to manually update the existing object and then respond with a failure. If you respond with response.success(), the object will be saved normally.
In your code, you don't seem to make any changes to the existing object. All you really need to do is to return response.error (https://parse.com/docs/cloud_code_guide#functions-onsave)
Of course, you should also handle this in your code somehow. Either by alerting the user, or handling it silently.
However; why does your code attempt to save a new friend request if one already exist? Your app should know that one exists and disable the friend request button or whatever the UI offers.
I have created a Spring MVC web app.
The app makes a few calls to the controller. These calls are close/open/end game.
I make these calls using Ajax, so I can handle a response on the top of the page.
ajaxPost = function (url, action, id, onSuccess, onError) {
$.ajax({
type: "POST",
url: url + "?" + action + "=" + id,
success: function(response) {
if(onSuccess !== null) {
onSuccess(response);
}
},
error: function(e) {
if(onError !== null) {
onError(e);
}
}
});
};
The question I have is that I'm using 'POST' for the Ajax request, is that correct, or should it be 'PUT'?
My controller has a default URL, and I'm using the param attribute to decide which method to call, as I have many buttons on the page.
#RequestMapping(params = "open", method = RequestMethod.POST)
#RequestMapping(params = "close", method = RequestMethod.POST)
It doesn't sit well with me that I'm using 'POST' for these calls. Maybe it should be 'PUT'...
Any suggestions? Does it matter?
It depends on what your request should do. So there's no general rule that you should use one over the other, they have different use cases.
POST for creating a record.
PUT for updating an existing record (or putting a record at a specified location/id).
See this wikipedia article for the definitions.
One thing to note is that PUT should be idempotent, doing the same PUT request multiple times should ideally produce the same result as doing a single PUT request. However, POST is not idempotent, so doing several POST requests should (or will) create multiple new records.
So after having read this you should check what your method does, and select the corresponding request method.
Both PUT and POST may create a new record; PUT may also update/change an existing record.
The difference between POST and PUT is that PUT is expected to address the record with it's ID, so that the server knows what ID to use when creating (or updating) the record, while POST expects the server to generate an ID for the record and return it to the client after the record has been created.
Thus, a POST is addressed to the resource as a collection: POST /resource, while PUT is addressed to a single item in the collection: PUT /resource/1
Use POST. Always use POST, unless you're absolutely rock-solid certain that PUT is properly supported by your hosting system.