Last updated September 7, 2013. Created by Mac_Weber on November 27, 2011.
Edited by a_thakur, revagomes, jackbravo, develCuy. Log in to edit this page.

Using services to create a node with required custom fields may be challenging. Most of the problems fall on formatting the data to be sent.

Here are three examples of how to figure out how format the data. The first example is the easiest, it will show how to post a Text field. The second example will use a fivestar field. Finally, the third example will show how to use a node reference field with auto complete widget.

I will send the data in JSON format, but this tutorial can be used for any format your web service accepts.

Tools I will use:

Step-by-step

  1. Figure out how Drupal wants to receive the data structure

  2. Build the data structure

  3. POST the data structure

  4. Verify if it worked

  1. Figure out how Drupal wants to receive the data structure

  2. For all examples, the first step is to figure out how Drupal handles the data object of that node. An easy way to do it is to use add a custom block to the page which has the form used to create the node. Use PHP format and input this code:

    <?php
    dpm
    ($_POST);
    ?>

    This code will output the data object right after you create a new node.

    Then, try it once to see this structured data. You will see something like:
    dpm() example

    The important parts are:

    The Text field
    dpm() of Text field

    The fivestar field
    dpm() of Fivestar field

    The node reference field
    dpm() of Node Reference field

  3. Build the data structure

  4. The Text field is the easiest. You have to build the same structure you see on the dpm():

    {
       "field_review":[
          {
             "value":"The user comments"
          }
       ]
    }
    Compare with the dpm() data:
    Text field dpm()

    If you use http://braincast.nl/samples/jsoneditor/ to build your JSON tree, you can see the path as json['field_review'][0]['value'], which matches the Text field structure on the dpm(). The value "The user comments" is the text value sent for the Text field.

    Note that there is no "0" (zero) in the structure. In this very specific case, it would work. However, in other cases, such as the node review field with auto complete, it may lead errors!

    It works without the zero because JSON already put it on the path as the first index of arrays.

    The structure for the fivestar field is the following:

    {
       "field_fivestar_value":[
          {
             "rating":"100",
             "target":"0"
          }
       ]
    }
    Compare to:
    Fivestar dpm()

    Note again I did not use "0", even knowing it would work. Moreover, in this specific example, I'm not targeting the fivestar rating. In my case, the only allowed values for "rating" were "20", "40", "60", "80", or "100".

    The tricky part is the node reference field, when it is set to use the auto complete widget. You have to query "[nid:xxxx]" to avoid errors such as "found no valid post with that title".

    This field on JSON format looks like:

    {
       "field_establishment":[
          {
             "nid":{
                "nid":"[nid:26686]"
             }
          }
       ]
    }
    Compare to:
    Node reference dpm()
  5. POST the data structure

  6. The first thing you should know before posting is that a node requires a title field. In addition, to create the node, you have to specify the node type you are creating. Then, include this data:

    {
       "title":"Review",
       "type":"establishment_review"
    }

    Now, get everything together:

    {
       "title":"Review",
       "type":"establishment_review",
       "field_establishment":[
          {
             "nid":{
                "nid":"[nid:26686]"
             }
          }
       ],
       "field_fivestar_value":[
          {
             "rating":"20",
             "target":"0"
          }
       ],
       "field_review":[
          {
             "value":"comments about the restaurant"
          }
       ]
    }
    Note that there is no curly brackets ({ nor }) surrounding each field. This is very important, and it will not work if you leave them there.

    Your data is ready to be POSTed.

    Use the firefox add-on Poster to test it:
    Firefox Poster screenshotNote that the data is not indented and I am not using multiple lines to organize the data. This is to avoid errors. It happened once when I copied the code to OneNote, and later pasted again in Poster. The format changed with some extra unwanted spaces and it messed the data. It may lead to false errors!. Again, use a single line of data when using Poster.

    The URL is your Drupal web address + your Services endpoint + requested resource. In this case:
    Drupal address: http://example.com
    Services endpoint: /rest_api
    Requested resource: /node
    Also change the Content Type to application/json

    You should get a response like:

    Poster responseNote the HTTP 200 OK status. It means the web service processed your request.

    If you want the response also in JSON, change the URL to http://example.com/rest_api/node.json

  7. Verify if it worked

  8. A you can see on the response:

    <?xml version="1.0" encoding="utf-8"?>
    <result><nid>5138098</nid><uri>http://example.com/rest_api/node/5138098</uri></result>

    Just put write on your browser address bar: http://example.com/node/5138098. The browser should open your new node.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

Hello. I was wondering if you have successfully POSTed an Image Field via Services 3 (I'm using Drupal 6)? - Format is JSON

I have followed your tutorial with great success, but cannot for the life of me, POST a node with an Image Field...

Thanks in advance for any advice. I surely need it.

- Jason

Hi,

designbymind, did you figure out how to post a node with an image field? I can't for the life of me figure it out.

Hope you're well and taking care of yourself.

Evelyn

Below my code for uploading images to imagefield through the services. This is a external PHP-script, which can be run on external server (without Drupal).

In server resources you should check next resources: file.create, node.create, user.login.

This code makes 3 steps:

  1. authorize user test_user. This user should have permissions to create node type "test" (you can change node type) and upload files.
  2. Upload image file and store fid of this file.
  3. Create a new node and attach uploaded image to imagefield with name field_main_image.

<?php
// node data
$filename = '/absolute/path/to/image.jpg';
$title = 'A node created with services 3.x and REST server';
$body = '<p>Body lorem ipsum</p>';
$tags = 'TEST_TAG, TEST_TAG2';
$type = 'test'; // node type
$vid = 2; // vid of vocabulary marked as "Tags"
$services_url = 'http://example.com/your-rest-server-endpoint';
/*
* Server REST - user.login
*/
// REST Server URL for auth
$request_url = $services_url . '/user/login';
// User data
$user_data = array(
 
'username' => 'test_user',
 
'password' => 'password',
);
$user_data = http_build_query($user_data);
// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json')); // Accept JSON response
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_POSTFIELDS, $user_data); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// Check if login was successful
if ($http_code == 200) {
 
// Convert json response as array
 
$logged_user = json_decode($response);
}
else {
 
// Get error msg
 
$http_message = curl_error($curl);
  die(
'Auth error ' . $http_message);
}
// Define cookie session
$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;
/*
* Server REST - file.create
*/
if(!file_exists($filename)) {
  die(
'File not exists');
}
if(!
is_readable($filename)) {
  die(
'File not readable');
}
// file
$file = array(
 
'filesize' => filesize($filename),
 
'filename' => basename($filename),
 
'file' => base64_encode(file_get_contents($filename)),
 
'uid' => $logged_user->user->uid,
);
$file = http_build_query($file);
// REST Server URL for file upload
$request_url = $services_url . '/file';
// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_POSTFIELDS, $file); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// Check if login was successful
if ($http_code == 200) {
 
// Convert json response as array
 
$file_data = json_decode($response);
}
else {
 
// Get error msg
 
$http_message = curl_error($curl);
  die(
'Sending file error<br>' . $http_message . "\n<br>");
}
// file id (nessesary for node)
$fid = $file_data->fid;
/*
* Server REST - node.create
*/
// REST Server URL
$request_url = $services_url . '/node';
// Node data
$node_data = array(
 
'title' => $title,
 
'type' => $type,
 
'body' => $body,
 
'taxonomy[tags][' . $vid . ']' => $tags,
 
'field_main_image[]' => array('fid' => $fid, 'list' => 1, 'data' => NULL),
);
$node_data = http_build_query($node_data);
// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json')); // Accept JSON response
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// Check if login was successful
if ($http_code == 200) {
 
// Convert json response as array
 
$node = json_decode($response);
}
else {
 
// Get error msg
 
$http_message = curl_error($curl);
  die(
'Getting data error<br>' . $http_message . "\n<br>");
}
print_r($node);
?>

Have you ever had any success with this method for updating a node.

It works for me to create, but if I follow the same method for adding new files to my node on update, they will only be created (added to file_managed) but not connected to the node. But if I update title or description on an existing file it will be updated. It seems like you only can specify fid for the files when creating, not updating. It will skip those files.

Here is the array for the PUT.

[field_files] => Array
(
  [und] => Array
  (
    [0] => Array
      (
        [fid] => 185
        [display] => 1
        [title] => My name
        [description] =>
      )
    [1] => Array
      (
        [fid] => 186
        [display] => 1
        [title] =>
        [description] => My description
      )
  )
)

Use the files resource to get the json obj of the file. endpoint/file/185.json
Then use it to update the node. node.field_files[und][0] = jsonObj;

Nice script but I was coming to madness because file was uploaded but not attached to node.
Till I eventually realize it would be better to replace :

curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));

by :

curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded','Accept: application/json'));

So we can decode the json response and get the fid (else it is null).

I hope it will be usefull

Yann

Thank you for your sample.

But how do you do for private files ?

Isnt there a simpler way than this. To clean up a node for a node.create for the services? Right now I'm looking into doing a "prepare for service" function to automatically clean $node object for posting. I think it's strange that there isnt one in Drupal/Services already?

I am having a lot of trouble populating a simple field through the method you have outlined here. I have created a content type called basic_content which has a field called text with machine name field_text which is a text field with a Text field widget. Now I can create instances of this content type with the method you have outlined but the Text field never gets populated. Here is my json string:

{
   "title":"online submission",
   "type":"basic_content",
   "field_text":[
      {
         "value":"Some Text"
      }
   ]
}

Any idea why this might not work?

Thanks for your awesome tutorial!

Try something like

<?php
{
  
"title":"online submission",
  
"type":"basic_content",
  
"field_text": {
     
"und":[
        {
"value":"Some text"}
     ]
   }
}
// Object with encode
$node= new stdClass;
$node->title = "online submission";
$node->type = "basic_content",
$node->field_text = array('und' =>array(array('value' => 'Some text'));
json_enode($node);
?>

I was stuck with a similar issue, and found it very useful to put the following debugging code at the end of node.modules' node_submit()-function (line 1005 in v. 7.15):

<?php
 
/* debug code start*/
 
$test = drupal_json_encode($_POST);
 
dpm($test);
 
/*debug code end*/
 
return $node;
?>

Now make a new node of the content type you are working with and (if you're logged in and have the devel module installed) you should get more or less correctly formatted json data. This is the only way I figured out how to get json data that would get saved in my fields when posted with the Firefox Poster plugin.

See my issue here for more details

Following the example for node references using the auto complete widget, I could finally save reference to other nodes. Now, imagine the oposite, I want to remove a reference, what should be the format for that? I tried just remove it from the JSON object but actually it don change anything.

For example, this is the current data:

{"und":[{"nid":"[nid:431]"},{"nid":"[nid:561]"},{"nid":"[nid:563]"}]}

An this is a simple change

{"und":[{"nid":"[nid:431]"},{"nid":"[nid:561]"}]}

But if I execute the PUT with this data, I keep the same old value. Any one know how to fix that?

Here is a Date CCK in D6.

"field_datecckfield":[
  {
    "value":{
      "date":"2010-01-27"
    }
  }
],

Hi all,
I'm trying to node.create objects of a certain content type to a XML-RPC server.
Because I do not know what custom fields are attached to the content type i am using a node.retrieve to load an existing object of that content type as a template. I then strip the object of nid, created etc.

My idea was that now I have a new object, with all custom fields attached, ready to be posted to the XML-RPC server. Unfortunaly the server doesn't save the new node due to field errors.

I compared the POST data (see Step 1 in this tutorial) with the 'Called arguments array' the server received ... and they differ.

Example 'POST data':

[field_vacature_provincie] => Array
(
  [und] => 237
)

Example 'Called argument array':

[field_vacature_provincie] => Array
(
  [und] => Array
  (
    [0] => Array
    (
      [tid] => 237
    )
  )
)

Some other custom fields are accepted and some not.
Does anyone have an idea how to get my template node object into the right format?

Hi everyone,
I'm having a hard time trying to figure out how to turn off a boolean field.
Something similar happens with taxonomy terms and the check-box widget, selecting items is not a problem but if I want to update the node and deselect all of the items nothing happens.

Does anybody knows how to achieve this?

Damián Farina

Did you ever manage to do this? I'm having the same problem at the moment.

I cant seem to get my node create working, I have the end point set up for node create, and nodes are being created the 5 start value is not getting set.

Here is my array:

// Node data
$node_data = array(
  'uid'  => 1,
  'title' => 'awesome',
  'type' => 'rating',
  'body' => array(
    'und' => array(
      'value' => 'awesome game guys!',
    ),
  ),
  'field_fsrating' => array(
'und' => array(array(
'value' => 100,
'target' => 0,
)
)
),
);

I have also tried:

// Node data
$node_data = array(
  'uid'  => 1,
  'title' => 'awesome',
  'type' => 'rating',
  'body' => array(
    'und' => array(
      'value' => 'awesome game guys!',
    ),
  ),
  'field_fsrating' => array(
'und' => array(
'value' => 100,
'target' => 0,
)
),
);

with out much luck, the debug log for services doesnt really help it shows the data getting called and passed but when viewing the node or looking in devel nothing is assigned to field_fsraiting

any ideas?

ahhh, got caught with usually doing value = some int, with five star it needs to be this, after re-reading this post..

so it should look like :

// Node data
$node_data = array(
  'uid'  => 1,
  'title' => 'awesome',
  'type' => 'rating',
  'body' => array(
    'und' => array(
      'value' => 'awesome game guys!',
    ),
  ),
  'field_fsrating' => array(
'und' => array(array(
'rating' => 100,
)
)
),
);

Hi,
i have a problem inserting/modifying a simple List(text) field.
When i call a node via Services i have a structure like this

"field_type": {
        "und": [{
            "value": "field_value"
        }]
    }

but if I try to insert with the same structure i have back this error
{
    "form_errors": {
        "field_type][und": "An illegal choice has been detected. Please contact the site administrator."
    }
}

How can i insert this field?

The structure for getting and inserting information may be different. You my even have just get or just insert for some information.

DO NOT follow the same Services structure to post and get. Try using the Devel module to see how your node is created using the UI. There you will see an more accurate structure.

To figure out how Drupal expects your data to be inserted, read again the first step "Figure out how Drupal wants to receive the data structure"

I read 'Figure out how Drupal wants to receive the data structure' but i don't understand why this insert don't work.

I have this dsm() output:
Structure image
so this code should be right:

"field_type": {
        "und": [{
            "value": "Office"
        }]
    }

PROBLEM SOLVED!

I don't know why but this code works.

"field_type": {
        "und": {
            "value": "Office"
        }
    }

I also do not know why this works, but removing the bracket allows the value to be submitted to Drupal select form fields using Services successfully.

Thanks!

Did anybody manage to POST/PUT entity reference fields?
I tried a lot of variations, and according to the data scheme it should be "field_reference":{"und":[{"target_id":12}]} (?), but nothing worked.

Ok, I figured it out:

My entity reference field widget was "autocomplete tagging". I switched it to "select box", now if i provide data like "field_reference": [ entity_id_1, entity_id_2 ...] it simply works.
My REST-API depends now on field widgets configured for the frontend ... not a thing of beauty.

Regarding entity reference..Totally dependent on the widget used.

For Autocomplete ;

"field_reference": {
"und":[{
"target_id":"Anything (69)"
}]
}

The title of the node is required but it appears any string will do. I suspect the nid is ripped out with a regex call.

For checkboxes it reads "field_reference": { 1:1, 2:2, ... ,nid:nid} and for select box "field_reference": [1,2,3 ... nid].

This is how you format something for the geo location field:

"field_location":{"und":[{"address":{"field":"Lund, Sweden"},"lat":"55.7046601","lng":"13.191007300000024"}]}

In Drupal 7, each field's data is grouped by the language, so the array structure need to look like the following:

'field_ip_address' => array('und' => array(array('value' => '1.2.3.4')))

Based on http://drupal.stackexchange.com/questions/3207/simple-rest-request-to-cr...

Hi!
I created a block with the content given above, but the $_POST array is empty all the time.

    ... (Array, 0 elements)
Called from modules/php/php.module(80) : eval()'d code, line 2

Where exactly do I have to put the block? It is in the header region of every content type now. No matter what kind of node i create, the array will be empty. :(

Thanks for any hints or help.

Hi I try to set poster to test the creation of node.
Firstly the custom block with the code

<?php
dpm
($_POST);
?>

returns an empty array. So I see the properties of fields from devel tab of my content type entry.

See our structure at http://www.easytechservers.gr/temp/drupal-devel-services-date-bug.png

I can set simple textfileds data and create the node from poster except a date filed of my content type. See out json structure here.

{
   "title":"test reserv from poster",
   "type":"reservation",
   "field_email":[
      {
         "value":"t@0.com"
      }
   ],
"field_phone":[
      {
         "value":"690000000"
      }
   ],
"field_date_2":[
      {
         "value":"2013-12-25 00:00:00"
      }
   ]
}

I'm very confused how the structure of fields must be to works the post. What happens with nested array and dictionaries of a general structure and how we have to construct the json? Please some more useful explanation about the construction of json in general.

Thanks.

Part solution
I found this structure of date json that works

"field_date_2":{
      "und":[{
        "value":{"date":"12/25/2013"}
            }]}
}

But I could not set the date in format 25/12/2013 only 12/25/2013.
And in general I could not find instructions for construction of json for services module.

Checking the option "Display redirection page" in the Devel settings solved the problem for me

Hi,

I have field collection "field_collection_images" with two fields: field_collection_image (it's node reference) and field_collection_image_comment field (usual textarea field).

And I need that this field collection will be created through services. But when I pass params, a node is created, but field collection values are empty.

I create next params in the request:

$data = array('node[type]' => "test", 'node[title]'=>'test', 'node[uid]' => 1, 'node[language]' => 'und', 'node[body][und][0][value]' => 'test test', 'node[field_collection_images][und][0][value]' => "[nid:1]");

OR

$data = array('node[type]' => "test", 'node[title]'=>'test', 'node[uid]' => 1, 'node[language]' => 'und', 'node[body][und][0][value]' => 'test test', 'node[field_collection_image][und][0][nid]' => 1);

Could someone help me - how the params should be formed ?

Regards,
Max.

user can pass value in poster using this format.

Name Value
field_field_date[und][0][value][date] 1 Jan 2014
field_field_date[und][0][value][time] 11:45am
field_field_date[und][0][value2][date] 3 Jan 2014
field_field_date[und][0][value2][time] 11:45pm
field_field_date[und][0][show_todate] 1
field_field_date[und][0][all_day] 0

I have a system that more or less follows the "upload file, save file id, create node and add file id" pattern described earlier by Romka. Everything was working great until I updated Drupal from 7.24 to 7.26.

I'm not using JSON, my post body looks like this:
field_sales_contact[und][0]=3&type=sales_lead&title=Manuel%20Uptonloader&field_business_card[und][0][fid]=151

I started down this path after some messages started showing up in Drupal's logs:

Notice: Undefined offset: 0 in file_field_widget_form() (line 526 of /Applications/XAMPP/xamppfiles/htdocs/<my site>/html/modules/file/file.field.inc).
Notice: Undefined offset: 0 in image_field_widget_form() (line 358 of /Applications/XAMPP/xamppfiles/htdocs/<my site>/html/modules/image/image.field.inc).

I'm not ready to point fingers at a particular file or update yet, but I thought I'd start sharing some of my troubles.

I report the same error Undefined offset: 0 with json. The node has been created but hasn't a file attached. I think there is a bug or same kind of hole in documentation.
Can someone document how actually create a node that has a file field with the current version of drupal and the current version of the services module?

Thanks

Brennino

Is there someone that could help with this error please? I have also check the documentation here http://drupanium.org/api but seems outdated for services 3.5+

In that documentation, I have tried the procedure showed here http://drupanium.org/api/82 but without success, same error.
I believe there is also an approach using the resource node/file_attach but isn't present in the documentation at drupanium.

I need help for attach a file to a node field and I believe there was someone else in my same situation.

Thanks