Warmshowers RESTful Services for Mobile Apps - warmshowers/Warmshowers.org GitHub Wiki
Note that all clients should use the canonical name of the host, www.warmshowers.org, in the URL and also use https. Otherwise the redirect comes back as a 404 error.
- CSRF:
/services/session/token - Log in:
/services/rest/user/login - Log out:
/services/rest/user/logout - Search for users by location:
/services/rest/hosts/by_location - Search for users by keyword:
/services/rest/hosts/by_keyword - Retrieve user object:
/services/rest/user/<uid> - Read feedback:
/user/<uid>/json_recommendations - Create feedback:
/services/rest/node - Send a private message (not replying to existing):
/services/rest/message/send - Reply to privatemsg:
/services/rest/message/reply - Privatemsg unread count:
/services/rest/message/unreadCount - Retrieve all privatemsgs:
/services/rest/message/get - Read privatemsg thread:
/services/rest/message/getThread - Mark privatemsg thread read (or unread):
/services/rest/message/markThreadRead
Following the upgrade to Drupal 7 all authenticated service calls must contain a valid CSRF header - https://www.drupal.org/node/2012982:
Note that Services clients using session authentication now should supply a special X-CSRF-Token header with a token that can be retrieved from http://example.com/services/session/token. This is needed for writing HTTP methods calls (POST, PUT, DELETE).
ALL apps should now request a service token from https://www.warmshowers.org/services/session/token immediately after login and before any further service requests. (Login does not require a token, as there's no session. But even a logout requires a token because it's a session activity.)
GET /services/session/token
Accept: text/plain
To provide a smooth upgrade path from D6 to D7 this request has been included in D6 and responses to both will look the same except that D6 will return a fake token instead. Example response included below.
Status Code: 200 OK
Content-Type: text/plain
Body: KkSi6vREzVqx_M7Hso52z6u_J9rfKspUF7s3kwxYLZc
Apps must now check for a service token as above and include it as an X-CSRF-Token header if one exists:
POST /services/rest/XXXXXXXXXX
X-CSRF-Token: {token_value}
Logs a specified user in and retrieves its profile data on a successful (first) login via this client.
-
URL
/services/rest/user/login
-
Method:
POST -
Headers
-
Accept: application/json(Optional. Otherwise, XML is sent)
-
-
URL Params
None
-
Data Params
to be sent as
x-www-form-urlencodedRequired:
-
username= -
password=
-
-
Success Response:
-
Code:
200 OKResponse: JSON with sessid, session_name, token, and user object.
This information can then be used to authenticate all following requests by adding the following headers:
X-CSRF-Token: <token> Cookie: <session_name>=<sessid>Content: (Example)
JSON:
{ "sessid": "", "session_name": "", "token": "", "user": { "uid": "", "name": "", "theme": "", "signature_format": "", "created": "", // Unix timestamp as a String "access": "", // Unix timestamp as a String "login": 1460103119, // Unix timestamp as an Integer "status": "", "timezone": "", "language": "", "picture": { "fid": "", "uid": "", "filename": "", "uri": "", "filemime": "", "filesize": "", "status": "", "timestamp": "", "url": "" }, "fullname": "", "notcurrentlyavailable": "", "fax_number": "", "mobilephone": "", "workphone": "", "homephone": "", "preferred_notice": "", "maxcyclists": "", "storage": "", "motel": "", "campground": "", "bikeshop": "", "comments": "", "shower": "", "kitchenuse": "", "lawnspace": "", "sag": "", "bed": "", "laundry": "", "food": "", "languagesspoken": "", "URL": "", "becomeavailable": "", "set_unavailable_timestamp": "", "set_available_timestamp": "", "last_unavailability_pester": "", "hide_donation_status": "", "email_opt_out": "", "street": "", "additional": "", "city": "", "province": "", "postal_code": "", "country": "", "latitude": "", "longitude": "", "source": "", "comment_notify_settings": { "uid": "", "node_notify": "", "comment_notify": "" }, "privatemsg_disabled": false, "profile_image_mobile_profile_photo_std": "", "profile_image_profile_picture": "", "profile_image_mobile_photo_456": "", "profile_image_map_infoWindow": "" } }
XML:
<?xml version="1.0" encoding="utf-8"?> <result> <sessid></sessid> <session_name></session_name> <token></token> <user> <uid></uid> <name></name> <theme></theme> <signature_format></signature_format> <created></created> <access></access> <login></login> <status></status> <timezone></timezone> <language></language> <picture> <fid></fid> <uid></uid> <filename></filename> <uri></uri> <filemime></filemime> <filesize></filesize> <status></status> <timestamp></timestamp> <url></url> </picture> <fullname></fullname> <notcurrentlyavailable></notcurrentlyavailable> <fax_number></fax_number> <mobilephone></mobilephone> <workphone></workphone> <homephone></homephone> <preferred_notice></preferred_notice> <maxcyclists></maxcyclists> <storage></storage> <motel></motel> <campground></campground> <bikeshop></bikeshop> <comments></comments> <shower></shower> <kitchenuse></kitchenuse> <lawnspace></lawnspace> <sag></sag> <bed></bed> <laundry></laundry> <food></food> <languagesspoken></languagesspoken> <URL></URL> <becomeavailable></becomeavailable> <set_unavailable_timestamp></set_unavailable_timestamp> <set_available_timestamp></set_available_timestamp> <last_unavailability_pester></last_unavailability_pester> <hide_donation_status></hide_donation_status> <email_opt_out></email_opt_out> <street></street> <additional></additional> <city></city> <province></province> <postal_code></postal_code> <country></country> <latitude></latitude> <longitude></longitude> <source></source> <comment_notify_settings> <uid></uid> <node_notify></node_notify> <comment_notify></comment_notify> </comment_notify_settings> <privatemsg_disabled></privatemsg_disabled> <profile_image_mobile_profile_photo_std></profile_image_mobile_profile_photo_std> <profile_image_profile_picture></profile_image_profile_picture> <profile_image_mobile_photo_456></profile_image_mobile_photo_456> <profile_image_map_infoWindow></profile_image_map_infoWindow> </user> </result>
-
-
Error Response:
-
Code:
401 Unauthorized : Wrong username or password.Content:
JSON:
[ "Wrong username or password." ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>Wrong username or password.</result>
-
Code:
401 Unauthorized : Missing argument usernameContent:
JSON:
[ "Missing required argument username" ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>Missing required argument username</result>
-
Code:
401 Unauthorized : Missing argument passwordContent:
JSON:
[ "Missing required argument password" ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>Missing required argument password</result>
-
Code:
406 NOT ACCEPTABLE : Already logged in as <username>.Content:
JSON:
[ "Already logged in as <username>." ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>Already logged in as <username>.</result>
-
Logs the currently logged in user out.
-
URL
/services/rest/user/logout
-
Method:
POST -
Headers
-
Accept: application/json(Optional. Otherwise, XML is sent) -
Cookie: <session_name>=<session_id>(Retrieved during login) -
X-CSRF-Token: <token>(Also retrieved during login)
-
-
URL Params
None
-
Data Params
None
-
Success Response:
-
Code: 200 OK
Content: (Example)
JSON:
[ true ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>1</result>
-
-
Error Response:
-
Code:
401 Unauthorized : CSRF validation failedContent:
JSON:
[ "CSRF validation failed" ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>CSRF validation failed</result>
-
Code:
406 NOT ACCEPTABLE : User is not logged in.Content:
JSON:
[ "User is not logged in." ]
XML:
<?xml version="1.0" encoding="utf-8"?> <result>User is not logged in.</result>
-
POST /services/rest/hosts/by_location
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Post parameters:
minlat maxlat minlon maxlon centerlat centerlon limit
offset and limit parameters allow paging through the results. The results include a total count.
POST /services/rest/hosts/by_keyword
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Post parameters:
keyword offset limit
GET /services/rest/user/<UID>
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
GET /user/<uid>/json
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
GET /user/<uid>/json_recommendations
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
(Note: I had to do drush vset services_node_save_button_trust_referral_resource_create "Submit" to make this work)
POST /services/rest/node
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Post parameters:
node[type]=trust_referral
node[field_member_i_trust][0][uid][uid]=<username> (NOTE not the uid, the username instead)
node[field_rating][value]=Postive|Neutral|Negative
node[body]=<body of feedback>
node[field_guest_or_host][value]=Guest|Host|Met Traveling|Other
node[field_hosting_date][0][value][year]=<year>
node[field_hosting_date][0][value][month]=<numeric month, 1-12>
POST /services/rest/message/send
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Post parameters:
recipients=comma-delimited set of username(s) [Not UID]
subject=
body=
POST /services/rest/message/reply
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Parameters thread_id= body=
POST /services/rest/message/unreadCount
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
POST /services/rest/message/get
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
POST /services/rest/message/getThread
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Parameters thread_id=
POST /services/rest/message/markThreadRead
Accept: application/json
Cookie: <session_name>=<sessid> (obtained from login)
Parameters thread_id= status=[0|1] (OPTIONAL, defaults to 0==READ. 1 means UNREAD)
** experimental, not in effect yet **
Access inbox: GET /services/rest/message
Access a single message: GET /services/rest/message/MESSAGE_ID
Create a new message thread (if thread_id is empty) or reply to a thread (if thread_id is provided) POST /services/rest/message
with
- body
- recipients (username)
- subject
- thread_id