Error message

Deprecated function: implode(): Passing glue string after array is deprecated. Swap the parameters in drupal_get_feeds() (line 394 of /home1/tylerfra/public_html/includes/common.inc).

Drupal Services Examples

Category: 

jDrupal: Be sure to check out jDrupal for an easy to use JavaScript Library to communicate with Drupal Services.

This document describes how to read/write entities to/from Drupal using the Services module. It also covers how to handle session authentication. Let's get started...

Installation and Setup

  1. Download the Services Module
  2. Enable It
  3. Drink Dr. Pepper

Now to create a service, we'll start with the basics... go to Structure -> Services -> Add, and enter some stuff like this:

Namemy_services
Endpoint titleMy Services
ServerREST
Path to endpointmy_endpoint

Ignore the other fields for now. Click 'Save' to, you guessed it, save your new service.

Next up, we need to enable some Resources for our Service. Go to Site Structure -> Services -> List, then click 'Edit Resources' next to your Service.

Check the boxes next to each resource that you'd like to enable, save, then flush all of Drupal's caches.

Examples

Each example below includes the HTTP method (GET, POST, PUT, or DELETE) and an example URL to use. When using POST or PUT, you must send along some data, and that example data will be listed on the line after the http method and url. If there is a special Content-Type header to use, it will be mentioned after the data, otherwise just use application/json.

C.R.U.D.I. = Create, Retrieve, Update, Delete, Index

X-CSRF-Token

For all POST, PUT and DELETE requests (except for user login), you must attach a token to the header of your request. The name of the header to use is:

X-CSRF-Token

The value of the token can be retrieved here:

http://localhost/drupal-7?q=services/session/token

Content-Type

Unless otherwise noted, the Content-Type header of your request should be set to:

application/json

Session Authentication

GET: http://localhost/drupal-7/?q=services/session/token

POST: http://localhost/drupal-7/?q=my_endpoint/system/connect.json

POST: http://localhost/drupal-7/?q=my_endpoint/user/login.json
username=w5TmhqOvWF&password=4mBj5tYQu8
application/x-www-form-urlencoded
    
POST: http://localhost/drupal-7/?q=my_endpoint/user/logout.json

POST: http://localhost/drupal-7/?q=my_endpoint/user/register.json
{"name":"yFzqH7dNEv","mail":"kT3miidPAx@example.com","pass":"MSQ4JvRhZh","pass2":"MSQ4JvRhZh"}
application/x-www-form-urlencoded

User C.R.U.D.I.

POST: http://localhost/drupal-7/?q=my_endpoint/user.json
{"name":"LSAwug2XxL","mail":"soRkkjZisJ@example.com","pass":"iPpNcwnEqW","pass2":"iPpNcwnEqW"}

GET: http://localhost/drupal-7/?q=my_endpoint/user/52.json

PUT: http://localhost/drupal-7/?q=my_endpoint/user/52.json
{"uid":"52","mail":"8dGyPlGSrB@example.com","current_pass":"iPpNcwnEqW"}

DELETE: http://localhost/drupal-7/?q=my_endpoint/user/52.json

GET: http://localhost/drupal-7/?q=my_endpoint/user.json

Node C.R.U.D.I.

POST: http://localhost/drupal-7/?q=my_endpoint/node.json
{"type":"article","title":"BEVVtDcZmL","language":"und"}

GET: http://localhost/drupal-7/?q=my_endpoint/node/125.json

PUT: http://localhost/drupal-7/?q=my_endpoint/node/125.json
{"node":{"nid":"125","title":"KHrkDnudKR","language":"und"}}

DELETE: http://localhost/drupal-7/?q=my_endpoint/node/125.json

GET: http://localhost/drupal-7/?q=my_endpoint/node.json

Comment C.R.U.D.I.

POST: http://localhost/drupal-7/?q=my_endpoint/comment.json
{"subject":"S5KeJTVFED","comment_body":{"und":[{"value":"gSXNfHPxgf"}]},"nid":"126"}

GET: http://localhost/drupal-7/?q=my_endpoint/comment/30.json

PUT: http://localhost/drupal-7/?q=my_endpoint/comment/30.json
{"subject":"wULr64gdpj","comment_body":{"und":[{"value":"YhmemEQ4Cy"}]},"cid":"30"}

DELETE: http://localhost/drupal-7/?q=my_endpoint/comment/30.json

GET: http://localhost/drupal-7/?q=my_endpoint/comment.json&parameters[cid]=30

Taxonomy Vocabulary C.R.U.D.I.

POST: http://localhost/drupal-7/?q=my_endpoint/taxonomy_vocabulary.json
{"name":"WkSTeYfABe","description":"RQoHVs22yZ","machine_name":"wksteyfabe"}

GET: http://localhost/drupal-7/?q=my_endpoint/taxonomy_vocabulary/16.json

PUT: http://localhost/drupal-7/?q=my_endpoint/taxonomy_vocabulary/16.json
{"vid":"16","name":"gSXktVuVty","machine_name":"wksteyfabe"}

DELETE: http://localhost/drupal-7/?q=my_endpoint/taxonomy_vocabulary/16.json

GET: http://localhost/drupal-7/?q=my_endpoint/taxonomy_vocabulary.json&parameters[name]=WkSTeYfABe

Taxonomy Term C.R.U.D.I.

POST: http://localhost/drupal-7/?q=my_endpoint/taxonomy_term.json
{"vid":"17","name":"V8m22sqRBO"}

GET: http://localhost/drupal-7/?q=my_endpoint/taxonomy_term/13.json

PUT: http://localhost/drupal-7/?q=my_endpoint/taxonomy_term/13.json
{"vid":"17","tid":"13","name":"C5Kjy2WOxK"}

DELETE: http://localhost/drupal-7/?q=my_endpoint/taxonomy_term/13.json

GET: http://localhost/drupal-7/?q=my_endpoint/taxonomy_term.json&parameters[vid]=17&parameters[name]=V8m22sqRBO

Comments

Thanks for sharing this. It really helped me a lot understand how to start developing a mobile app and integrate it with drupal.

Ok. I don't understand the part of: system->connect. I don't have the access. Please, send me a e-mail.

tyler's picture

Hi Eduardo, Please check out the system->connect explanation in this article for more information about the system connect service resource.

Basically, when you make a call to system connect, it returns to you information about the user that made the call (user id, session id, etc).

Hi Tyler can you explaine the Server part a little bit more in detail? Do you use the REST Module or something else?

tyler's picture

Hello Felix,

Please refer to this post for a much more detailed explanation on how to get Services up and running:

http://www.tylerfrankenstein.com/code/android-app-with-drupal-7-services...

It was really helpful to me. Can you add some more examples of webservices which shows the selected fields in the database tables.

Thanks a lot.

tyler's picture

Hi Pritam, I'm not sure what you mean by 'shows selected fields in the database tables'. You may want to check out the Views Datasource (Views JSON) module, or you can write your own service for the Services module.

Hey, 

I followed your tutorials about rest & drupal, and I implemented the same logic in the Intel XDK/(appmobi earlier).  thank you, that was very helpfull. now I have some questions if you dont mind :)  :-

- this is for sure not the safest way to send the user's password.  I tried using https instead of http, but the android webview does not allow secured requests, so I have to write a plugin to use the HttpsURLConnection  class for that.  but before doing that, I was woundering if you have any other Ideas for making the login secured.

- how do you manage the user recognition cookies/sessions ? , I read somewhere that you should save the session-id & send it with each request, I´m not looking for the code, just for the logic.

greetings :)

tyler's picture

Hi akka,

I agree that this may not be the safest way to send the user's password, but that is how the User Login resource from the Services module works, so I stick with that and hope for the best. Using https is probably a bonus for security.

At this time, I don't have much experience with native Android development, so I am not qualified to speak about webview and HttpsURLConnection, sorry.

As for user recognition (cookies/session), that is managed by using the System Connect resource from the Services module. Once you are logged in, each subsequent Service Resource call will use Drupal's session management, so you don't need to pass along any session variables.

I personally use PhoneGap for all of my app development.

ok thank you.

but how do you manage it, when the user closes the app and starts it again. do they need to login again ? how do you manage that ? I read somewhere that you one should login with the sessionid , but I'm still not sure about this and how to manage it.

tyler's picture

You won't need to manage it at all. When your app opens again, make a call to System Connect and Drupal will determine if there is a valid session or not for that device. If the System Connect returns a user id not equal to zero, then it thinks you are still logged in, if not, you will be an anonymous user. You won't need the session id at all.

Thanks for this tutorial, it helped me a lot. Still, I could not manage to login until I found out that one has to set the following header also, which might be a consequence of updated processes. It's worth mentioning this in your setup steps.

Name     Value
Cookie   [session_name]=[sessid]

You'll be finding the values for session_name and sessid in the response on your login.

Cheers, u.

Hello Tyler,

Is it possible to export the content type (title, field name and value) to json or XML with the module services?

Thanks to help.

Thanks Taylor.

Hello tyler,

Thanks for your tuto.

I follow your tuto http://www.tylerfrankenstein.com/code/android-app-with-drupal-7-services-phonegap-and-jquery-mobile but the url "http://localhost/test/system/connect.json"  not work. I have a error "link broken". I don't understand I configured the service correctly like you but not work. 

Need your help please.

Thanks.

tyler's picture

First verify the service is set up correctly by POSTing to it with FireFox poster. Then use 10.0.2.2 in place of localhost when testing in an Android emulator. If you're testing directly to your mobile device, then your drupal site needs to be on the Internet, because your device most likely cannot access your localhost. 

I use addon "console rest" with chrome and I test the url in POST with content-type : application/x-www-form-urlencoded but it not work. 

I try with Firefox but it's the same thing.

 

 

tyler's picture

Make sure you are not logged into your Drupal site in your browser when attempting to contact the System Connect. That's the only other thing I can think of. Please feel free to stop by IRC for more in depth support.

Yes I'am logged out in my drupal site but not work.

I have the error 406.

Error to the addon "REST Console" in chrome:

  1. Status Code: 406
  2. Date: Wed, 24 Jul 2013 19:55:29 GMT
  3. Content-Encoding: gzip
  4. Last-Modified: Wed, 24 Jul 2013 19:55:29 +0000
  5. Server: Apache/2.2.16 (Debian)
  6. X-Powered-By: PHP/5.3.3-7+squeeze15
  7. ETag: "1374695729"
  8. Vary: Accept-Encoding
  9. Content-Type: text/html
  10. Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0
  11. Connection: Keep-Alive
  12. Content-Length: 20
  13. Keep-Alive: timeout=15, max=89
  14. X-Drupal-Cache: MISS
  15. Expires: Sun, 19 Nov 1978 05:00:00 GMT
tyler's picture

It sounds like 'session authentication' is not enabled. It is a checkbox under your service resource settings. There are other troubleshooting techniques available here: https://drupal.org/node/2015065

I have enable the "session authentification" when I create the service. I read your article but is not resovle my problem.

For the Module you activate juste the module "Service" and  "REST Server"? no the "Oauth Authentification" ?

Sorry for my questions but it is a important project  for my school.

tyler's picture

You need to also activate Service Resources, for example:

  • System Connect
  • User Login
  • User Logout
  • etc

yes I have enable System Connect, Login, Logout etc but not work.

There's another way to do this? (another module or other)

At firts let me tell you that your article is so great , it really healp me alot , but I want to know how to use this features in a drupal commerce site , I' ve downloaded commerce services module which allows to activate, product, cart an order , that are display in services resources section.However I don't how to use it in a url like your example I hope you can help me.

 

tyler's picture

Hi Carlos, this is something that I am still trying to learn as well. I've been working on a few tools to make this easier:

I still have very little knowledge about Commerce Services. The #drupal-commerce channel on IRC is a good place to chat with the experts. 

Hi Tyler,firs of all thanks for your tutorial about drupal services with phonegap.Currently i'm using drupal 7.29,services 3.5,phonegap 3.1,jquery 1.9.1,jquery mobile 1.3.2 . I cannot login by using the following script.Would you help me to point where is the problem ?Thanks a lot.

<a href="http://pastebin.com/VwuYmfqy">login.js</a>

<a href="http://pastebin.com/faR9CXD1">dashboard.js</a>

<a href="http://pastebin.com/kZn33Yg2">index.html</a>

 

tyler's picture

I'm guessing the problem is in the login.js file. I don't think you need to retrieve the CSRF token before calling the User Login service resource. From my understanding, the CSRF token is only needed for authenticated users. So anonymous users making the login call don't need to pass along the token.

Be sure to check out DrupalGap, it takes care of login for you ;)

At this point DrupalGap is only designed to work with PhoneGap 2.9.0

Stop by #drupal-drupalgap on IRC to chat futher.

Thanks a lot tyler.I'll check it out.

Hi Tyler, I have used your tutorial at http://tylerfrankenstein.com/code/android-app-with-drupal-7-services-pho... to develop an application that creates nodes for a mapping site, thanks for the awesome work. Im having issues now using the node creation script to push dates and a digit(unique id) to a drupal site. The code im using to create the node is below and im currently testing everything in chromium browser:

http://pastebin.com/YC6A2FFP

The site has specified ISO date format and it is marked as required. The error in the chromium console is 406 (Not Acceptable: An illegal choice has been detected. Please contact the site administrator. A valid date is required for Date Visited. There are no entities matching "13975").

tyler's picture

Hi David,

I had some troubles populating a date field via Services as well. Here is what I found a few weeks ago:

Other than that, it sounds like there literally isn't an entity with an ID of 13975, please verify that exists.

Also, be sure to check out DrupalGap if you're using D7, it will make your life much easier! ;)

Hello thank you for this great tutorial.
I put a web service in drupal. Then I create a client symfoy2. The CRUD works very well.
In addition I add an action in my resource, but if I test it sends nothing.

tyler's picture

Are you using Drupal 8?

Hello, no Drupal 7.

Hey,

I started development in drupal for about two months.

What i need is i have a form at a server and whole logic of saving and processing there.

Now i need that form on a different domain and i need to fetch that webpage.Getting stuck in it as i am a newbie.Can you help me in achieving this or can guide me giving suitable explanation.

tyler's picture

Take a stop by the Drupal channels on IRC for personalized support from the community

Hi Tyler,

Its actually very helpful. have you worked on the new release of services module 3.7.. I am not able to understand the logout functionality of it. its  showing some CSRF invalide code error. I have checked for session authentication as well 

tyler's picture

Check out  user_logout() in jDrupal to see how User Logout works.

HI tyler.

Its actually very helpful.But I'm having issues now using user login and connect

 i use poster with my request : 

url : http://localhost/homeShop/?q=service/user/login 

My response status : 401 unauthorized  CSRF validation failed

How to fix error ? 

please help me

thanks in advance!

tyler's picture

Try logging out of your Drupal site in Firefox, before using Poster.

Hi Tyler ,

Thank you great help.

I've created 3 resources (all with CRUDI operations) now in a one of my cutom resources (this resource contain : create, update and a "specific" index(that show a list of items with a condition)) now i need to add another index (for other reasons)

 

My question : can i create a resource with multiple indexes in the CRUD operations ? (indexes are differents)

 

Thank you Tyler

hi


PUT /my_endpoint/taxonomy_term/42.json

 

   I am pretty sure that when updating a taxonomy term there are two required fields

1. vid

2. name

vid could be determined from current vid

but, it could be possible that we want to change a tid from one taxonomy vocabulary to another

so, it is o.k. to consider vid a required field

 

but. name shouldn't be a required field when updating

¿don't you think so?

 

thanks for your answer

tyler's picture

The name is required in Drupal, therefore it's required via Services.

comment create/update resource needs to be updated as after services module update to be like (for the request body)

 

{"subject":"S5KeJTVFED","comment_body":"gSXNfHPxgf","nid":"60"}

works for services 7.x-3.12 .

 

If I'm logging into a services endpoint over HTTPS, and I send

username=w5TmhqOvWF&password=4mBj5tYQu8

in plain text in the body of the request, like your example says, is that going to be safe?

I might need to edit customer data in Drupal Commerce, and I don't want hackers getting hold of the REST user's credentials

tyler's picture

Over https is safe.

I can't assign a node to a taxonomy with Services.  I've tried sending the "tid" value and the "name" value to the endpoint for the specific node, but neither one works.  The node's field remains blank.

 

tyler's picture

It depends on what type of field you are using, i.e. taxonomy term reference field, or an entity reference field, and then it depends on what widget you are using for that field's configuration. I personally only use entity reference fields now when referencing taxonomy terms, and no longer use a taxonomy term reference field (provided by core). From there, just Google for "Drupal 7 Services Entity Reference Field" or "Drupal 7 Services Taxonomy Term Reference Field" and you should find responses from myself and others talking about the various formats to use depending on the widget you have selected for your field instance.

Optionally check out the services_entity project on d.o, that module makes it much easier to POST the straight JSON representation of an entity without having to worry about the nuances of the Services module in regards to it being built on top of the Drupal Forms API.

That worked like a charm, but now I need to reassign the categories on thousands of nodes, and then rewrite my views to use the "entity reference" as the required relationship.

But another problem has come up:  Do you know if there's any way to get a drupal commerce product to be assigned to a product display with Services?

tyler's picture

You can use a Batch script to process thousands of entities are re-assign values to your new field: http://tylerfrankenstein.com/code/drupal-batch-example

For Commerce Services, checkout this project: https://www.drupal.org/project/commerce_services

It's not very well maintained, I've got a few patches in the queue that are yet to be reviewed, but have used them in the past for clients.

This can be done with rules.

1.) Add a new field to your Product Display. For my project, I used "Item Number."

2.) Add a new field to your Commerce Product variations For my project, I used "Parent Item."

3.) Add new commerce product variations, and make sure to set a Parent Item that matches the Item Number you'll use in the Product Display.

4.) Set up a rule to run on the event "After updating existing content of type Product Display," or "After saving new content of type Product Display." Depending on your workflow needs, you may want the run to run after both events.

5.) Add any conditions you need to restrict the rule, so that it only runs based on your workflow needs.

6.) Add an action "Fetch Entity by Property."

7.) Set the entity type to "Commerce Products," and then set the Property to "Parent Item." Set the Value data selector to "node:field-item-number." Remove the number from "Limit Result Count" so that ALL your product variations that have the right "Parent Item" setting get used.

8.) Add a loop to your rule. Set the List data selector to "entity-fetched." It won't matter how many entities get fetched, the loop will handle all of them.

9.) Add "Add an item to a list" to the LOOP in the rule. Set the List data selector to "node:field-item-type," or whatever your Product Reference field is called. Set the Item to add data selector to "list-item." Set "enforce uniqueness" to "True." Set "Insert Position" to whatever your workflow needs are.

10.) Save the rule.

Always add your commerce products FIRST. Once you're finished adding them (you can add them in REST API also), then you can add your corresponding product display. If it works, your new product display will automatically contain your new commerce products.

If this does NOT work:

1.) Go to "Structure > Content Types > Product Display" and pick "Manage Fields."

2.) Change the Widget for your "Product reference" field to "Autocomplete text field."

3.) Save your product display content type.

I tested this method, and it worked. A product display t-shirt with sizes running "S," "M," "L," "XL," "2X," and "3X" had lost its commerce products due to a glitch I made when updating products via REST API. I used my item as a guinea pig and edited the "Body" field of the Product Display.

When the product display finished saving, I looked at it in my storefront, and the "Add to Cart" button had reappeared with my sizing options the way I needed them to appear.

 

Thank by your answer. I need login with email. Any Idea ??