Creating Drupal 7 nodes with PHP via the restws API

Drupal 8 has a built-in REST API that allows programmatical access to all the entities on a site. Similar functionality has been implemented for Drupal 7, in the RESTful Web Services (restws) module.

In project I’m working on, in preparation for upgrading a site to Drupal 8, we were looking into options for creating “D8 ready APIs for a D7 site”. The idea is to implement any new integrations (and to re-implement old ones) so that when we upgrade our Drupal from 7 to 8, the integrated systems won’t even notice it. I checked out the restws module as a potential option for that.

It turns out that the APIs are not identical: The URLs are different (“/node/” vs. “/entity/node/”) and the structure for the data that needs to be sent is different as well ({"type":"page","title":"test title"} vs. {"_links":{"type":{"href":"http://drupal-8.localhost/rest/type/node/page"}}, "title":[{"value":"test title"}]}). As such, restws isn’t going to work for us.

But, since I went through the trouble of adapting aalamaki’s test code to do some testing of my own, I decided to post the code here, as I couldn’t find a good example of creating nodes by doing POST requests against the restws API:

// Example code: Creating Drupal 7 nodes by POSTing from cURL in PHP:

$site = "";
$user = "someusername";
$pass = "theusersassword";
$crl = curl_init();
curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($crl, CURLOPT_USERAGENT, 'PHP script');
curl_setopt($crl, CURLOPT_COOKIEJAR, "/tmp/cookie.txt");
curl_setopt($crl, CURLOPT_COOKIEFILE, '/tmp/cookie.txt');

// Login
curl_setopt($crl, CURLOPT_URL,"http://" . $site . "/user/login");
curl_setopt($crl, CURLOPT_POST, TRUE);
curl_setopt($crl, CURLOPT_POSTFIELDS, "name=" . $user . "&pass=" . $pass . "&form_id=user_login");
curl_setopt($crl, CURLOPT_COOKIE, session_name() . '=' . session_id());
$ret = new stdClass;
$ret->response = curl_exec($crl);
$ret->error = curl_error($crl);
$ret->info = curl_getinfo($crl);

// Get RESTWS token.
curl_setopt($crl, CURLOPT_HTTPGET, TRUE);
curl_setopt($crl, CURLOPT_URL, 'http://' . $site . '/restws/session/token');
$ret = new stdClass;
$ret->response = curl_exec($crl);
$ret->error = curl_error($crl);
$ret->info = curl_getinfo($crl);
$token = $ret->response;

// Do the API call to create the node. Places tagged with "UPDATING" relate to updating existing nodes instead of creating new ones.
$data = json_encode(array(
'type' => 'article', // UPDATING: Don't try to set the "type" for existing nodes.
'title' => 'It is a new article, created by ' . $user . ' at ' . date('c'),

// UPDATING: Use PUT instead of POST when updating a node
curl_setopt($crl, CURLOPT_POST, TRUE);
//curl_setopt($crl, CURLOPT_POST, FALSE);
//curl_setopt($crl, CURLOPT_CUSTOMREQUEST, "PUT");

// UPDATING: Add the node id when updating a node
//curl_setopt($crl, CURLOPT_URL, 'http://' . $site . '/node/1');
curl_setopt($crl, CURLOPT_URL, 'http://' . $site . '/node');

curl_setopt($crl, CURLOPT_HTTPGET, FALSE);
curl_setopt($crl, CURLOPT_POSTFIELDS, $data);
curl_setopt($crl, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'X-CSRF-Token: ' . $token));
$ret = new stdClass;
$ret->response = curl_exec($crl);
$ret->error = curl_error($crl);
$ret->info = curl_getinfo($crl);

curl_close ($crl);


  1. Hello,

    I followed your post but with the same code I always get a 403 Forbidden for response.
    I use a login who begin with restws (restws_api_cms).

    Thank you.

    1. The first thing that comes to mind is if the user account in question has the permission to create the node type you’re trying to create? In addition to that, there may be separate permissions for using the restws API (I can’t remember, as it’s been a while).

      I’m almost certain your problem can be solved just by setting the correct roles and permissions for your user in the Drupal admin UI.

Leave a comment

Your email address will not be published. Required fields are marked *