First of all, thanks so much for Services. It's really amazing how much you can do with it!

I understand your standpoint about providing core functionality without modification, but this is one place I have to disagree completely with that stance. When I create taxonomy term, I get a simple 1 or 2 or 0 back. It's not even encoded in JSON! This just seems really inconsistent with what everything else returns for successful creation (such as a file, comment, node, user, etc).

I am on a project right now where iPhones are creating taxonomy terms and then adding them to new nodes. I don't understand, without writing a custom service, how the iPhones are supposed to get the new TID of the term they just created to include in the new nodes they are about to create.

I'm too tired to write the patch now, but it would be a simple one-line fix:
taxonomy_save_term($term);
return $term->tid;

instead of:
return taxonomy_save_term($term);

Curious to hear feedback!

Comments

kylebrowning’s picture

Version: 6.x-3.1 » 7.x-3.x-dev

I think this is doable, but it needs to wait till #1436366: Ability to version a resource lands because we cant change what gets returns as it might break peoples clients.

You however can alter the callback and then make it point to your own function.

MD3’s picture

Great! Just thought I would share my final code for future reference:

function _taxonomy_term_resource_create($term) {
  // Validate vid is not blank.
  if (!$term['vid']) {
    return services_error(t('There is no vid, please enter 1 in required field "vid".'), 404);
  }
  // Validate name is not blank.
  if (!$term['name']) {
    return services_error(t('There is no name, please enter a name in required field "name".'), 404);
  }
  // Adds backwards compatability with regression fixed in #1083242
  $term = _services_arg_value($term, 'term');

  if(taxonomy_save_term($term) == 1) {
    return array("tid" => $term['tid']);
  } else {
    return services_error(t('Unable to create new taxonomy term. Please contact administrator'), 404);
  }
}

I'll try to keep an eye out for the resource versioning so I can submit a timely patch!

ygerasimov’s picture

The time for the patch is now. @MD3 will you take care about it?

MD3’s picture

ygerasimov: would this weekend be fast enough?

ygerasimov’s picture

@MD3 sure, take your time

MD3’s picture

Status: Active » Needs review
StatusFileSize
new0 bytes
new0 bytes

Finally had some time to submit a patch! This should be tested by the community, but I am using it on a production server right now.

Any suggestions on the services_error() ?

MD3’s picture

Thanks to @xjm had to relearn my git skills. Here's the patches.

Status: Needs review » Needs work

The last submitted patch, Services-6.x-3.x-Return_TID-1539138-7.patch, failed testing.

MD3’s picture

So it looks like we need to update the automated tests to take in account that I am returning the TID now instead of 0, 1, or 2. Should I just submit a new patch that updates the .test as well?

kylebrowning’s picture

No, update the tests in this patch.

kylebrowning’s picture

Also I believe i said this before but you need to be using the version resource #1436366: Ability to version a resource

ygerasimov’s picture

Kyle could you please clarify your point about version resource? What needs to be added?

#6 patches are 0 bytes.

kylebrowning’s picture

It needs to look more like this, adhering to proper update hooks so that OLD API's do not break. I left the else out but you get the idea.


function _taxonomy_term_resource_create_update_1_1() {
  $new_settings = array(
    'callback' => '_taxonomy_term_resource_create_1_1',
  );
  return $new_settings;
}

function _taxonomy_term_resource_create_1_1($term) {
  // Adds backwards compatability with regression fixed in #1083242
  $term = _services_arg_value($term, 'term');

  $term = (object)$term;
  if (taxonomy_term_save($term) == 1) {
    return array("tid" => $term->tid);
  }
}
ygerasimov’s picture

Kyle, can we not do in this way? I understand that it will be convenient to use versions for changes in our standard resources. But making new version for such kind small changes will lead us to big number of versions and it will mess everyone. I would suggest not to use versions in standard resources at all until the changes are really significant.

kylebrowning’s picture

They work just like hook_update_N so i think its ok. Besides in a 4.x branch we can remove the updates and make them standard.

If we do not use versions then peoples clients will break as its changing what is returned from a method call. The only way around that is to add a parameter which I dont really like the idea of, do you?

ygerasimov’s picture

I don't like idea of parameter. Well for this particular case I wouldn't go for new version as this is so minor change. But you are welcome to add it. Would be nice example for other modules to see how new versions work.

kylebrowning’s picture

Its not about how minor it is. Apps right now are expecting 1,2 or 0.

We CANNOT under any circumstances change that as you could crash a feature in someones app, or a website communicating to another site or whatever anyone might be using this endpoint for.

I pretty much wrote the code for it in
#13 it just needs to be put into a patch.

marcingy’s picture

So I would not see core services itself use versioning. Why you may ask, it makes code more difficult to maintain and it makes multiple versions of a method exist in reality. What I would say actually needs to happens is as follows

* Create a new 7.3.x releae which includes versioning, this will allow people to override services as they need
* Create a new 7.4.x branch which is used to clean up returns from services and starts to define 'standards' for returns.

kylebrowning’s picture

Status: Needs work » Closed (won't fix)

Wont fix in 3.x but ive added it as a list of things to do for 4.x

tyler.frankenstein’s picture

Status: Closed (won't fix) » Needs review

With 7.x-3.3 of the Services module, I am able to call the Taxonomy Term Create Resource with only a vid, and it will create an empty term in that vocabulary. I think this is because the call to $term->name = trim($term->name); in taxonomy_term_save returns an empty string for the term name.

When this empty term is created, I receive a response of 1, which indicates SAVED_NEW (which is technically true, but it is a term without a name).

After reading the comments above, I understand it is important to maintain the 0, 1 or 2 return value. But it seems like 0 would never be returned. Please correct me if I'm wrong, but I haven't been able to have the Taxonomy Term Create Service Resource return a 0, ever. (If this is indeed a bug, maybe it deserves its own issue?)

To maintain backwards compatibility, would this be acceptable to return a 0 correctly?

function _taxonomy_term_resource_create($term) {
  // Adds backwards compatability with regression fixed in #1083242
  $term = _services_arg_value($term, 'term');

  $term = (object)$term;
  if (!isset($term->name) || $term->name == '') {
    return 0;
  }
  return taxonomy_term_save($term);
}

If that is code change is OK, I'd be happy to make a patch for it.

Can we also have the vid validated, and if it doesn't validate, return a zero (instead of throwing a 500 error)?

Thank you Services team for your awesome module!

MD3’s picture

EDIT:I realized this needed a better explanation.

When I filed this bug, I was using Drupal 6.24 or 6.25 with Services 6.x-3.0 or 6.x-3.1 and a database that was functional, at best (0 and 'Male', 1 and 'Female' in the same column).

I would suggest that for the default version of taxonomy resource, we leave this alone as Kyle has expressed before. It's really bad to break the current API and could have a lot of consequences for a lot of people.

As for what the new versioned resource returns, we should just imitate /node on every aspect possible (headers, body, etc).

jhedstrom’s picture

StatusFileSize
new845 bytes

Realizing this is for 4.x, here's a patch in the meantime for people using 3.x. Fixes a fatal error in #7 which called a non-existent method.

ygerasimov’s picture

Status: Needs review » Needs work

I propose here to create new version of taxonomy resource that will be based on drupal_form_submit() like node resource instead of saving term via api. This will add all needed validations like empty term name, required variables etc.

kylebrowning’s picture

Issue summary: View changes
Status: Needs work » Closed (won't fix)

Cleaning issue queue. If someone wishes to work on this, let me know by reopening this ticket.

logicp’s picture

Does anyone else have any interest in this? It would be nice to not have to do an additional services call simply to retrieve the newly created TIDs, but I understand the need to maintain the expected functionality that the module has provided thus far. Are there any proposed alternatives? Perhaps an additional resource to be added to the Services Taxonomy API arsenal?

hubobbb’s picture

StatusFileSize
new4.02 KB

Thank you #22 the patches's author. it works well .
Now I give mycode for anyone who want to reference。
I added UPDATE and DELETE function ,witch return tid. Hope can help you .
and also I give ajax case here .
Version : 7.x-3.17 , download the zip file,unzip it .dir ../modules/services/resources/taxonomy_resource.inc
JS code :
var vid=4;//taxonomy_vocabulary vid
//get token
$.ajax({
url: '/service/cytaxonomy/user/token',//this is my service url ,define yours in services
type: 'POST',
dataType: 'json',
error: function onErroru(data){
console.log("user connect cytaxonomy user fail");
},
success: function (data) {
usertoken=data.token;
//cases here :
//updateterm(103,"name","description",5,89,usertoken);
//deleteterm(106,usertoken);
}
});

//term api fn begin

//get term tree
function gettermtree(parent,usertoken){
var updatedata='vid='+vid+'&parent='+parent;
$.ajax({
url: '/service/cytaxonomy/taxonomy_vocabulary/getTree',
type: 'POST',
dataType: 'json',
data: updatedata,
error: function onError(data){
console.log("update taxonomy_vocabulary getTree fail:"+vid);
},
beforeSend: function (request) {
request.setRequestHeader('X-CSRF-Token', usertoken);
},
success: function (data){
console.log(data);
console.log(JSON.stringify(data));
}
});
}
//get tid infos
function getterm(tid){
$.ajax({
url: '/service/cytaxonomy/taxonomy_term/'+tid,
type: 'GET',
dataType: 'json',
error: function onErroru(data){
/* $("#newslisttips").find(".alert").attr("class","alert alert-danger");
$(".newslisttips-content").html("you have offline 。");*/
console.log("user connect get fail");
},
success: function (data) {
console.log(data);
}
});
}
//add new term
function addterm(name,description,weight,parent,usertoken){
var updatedata='term[vid]='+vid+'&term[name]=' + name +'&term[description]='+description+'&term[weight]='+weight+'&term[parent]='+parent;
$.ajax({
url: '/service/cytaxonomy/taxonomy_term',
type: 'POST',
dataType: 'json',
data: updatedata,
error: function onError(data){
console.log("update taxonomy_term fail:"+tid);
},
beforeSend: function (request) {
request.setRequestHeader('X-CSRF-Token', usertoken);
},
success: function (data){
console.log(data);
console.log("added result:"+JSON.stringify(data));
}
});
}
//update term
function updateterm(tid,name,description,weight,parent,usertoken){
var updatedata='term[vid]='+vid+'&term[name]=' + name +'&term[description]='+description +'&term[weight]='+weight+'&term[parent]='+parent;
$.ajax({
url: '/service/cytaxonomy/taxonomy_term/'+tid,
type: 'PUT',
dataType: 'json',
data: updatedata,
error: function onError(data){
console.log("update taxonomy_term fail:"+tid);
},
beforeSend: function (request) {
request.setRequestHeader('X-CSRF-Token', usertoken);
},
success: function (data){
console.log(JSON.stringify(data));
}
});
}
//delelte term
function deleteterm(tid,usertoken){
$.ajax({
url: '/service/cytaxonomy/taxonomy_term/'+tid,
type: 'DELETE',
dataType: 'json',
error: function onError(data){
console.log("DELETE taxonomy_term fail:"+tid);
},
beforeSend: function (request) {
request.setRequestHeader('X-CSRF-Token', usertoken);
},
success: function (data){
console.log("DELETE:"+JSON.stringify(data));
}
});
}
//term api fn end

tyler.frankenstein’s picture

@adventurist I'd be open to some type of query string, e.g. load_term=true being present in the POST URL to indicate a request to fully load the term upon creation.