- Base Format
- HTTP Verbs
- URI
- Media Type (aka MIME type)
Get Portland map data
Add a new road
{ "name": "Larry Garfield", "role": { "name": "Initiative Owner", "project": "WSSCI" }, "vested": true }
<contributor> <name>Larry Garfield</name> <role> <name>Initiative Owner</name> <project>WSCCI</project> </role> <vested>true</vested> </contributor>
Reserved properties: _links and _embedded
All resources may have one or more *_url properties linking to other resources.
Operation | HTTP request method | path |
---|---|---|
Create | POST | /entity/node |
Read | GET | /entity/node/1 |
Update | PATCH | /entity/node/1 |
Delete | DELETE | /entity/node/1 |
We try to fix the paths to /node/1 at the code sprint on Friday!
drush si --account-name=klausi --account-pass=secret \ --site-name=drupal-8.localhost
drush en rest hal basic_auth--yes
cp sites/default/files/config_SNJe.../active/* \ sites/default/files/config_SNJe.../staging/
resources: 'entity:node': # We just enable the node resource alone. GET: # Enable HTTP GET requests. supported_formats: - hal_json # Only the HAL format is enabled. supported_auth: - http_basic # Only HTTP Basic auth is enabled.
drush cc all # UI: /admin/config/development/performance
drush role-add-perm anonymous 'restful get entity:node'
curl -H "Accept: application/hal+json" --request GET \ http://drupal-8.localhost/entity/node/1
$ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => 'http://drupal-8.localhost/entity/node/1', CURLOPT_HTTPHEADER => array('Accept: application/hal+json'), CURLOPT_RETURNTRANSFER => TRUE, )); $response = json_decode(curl_exec($ch)); print_r($response);
use Guzzle\Http\Client; $client = new Client('http://drupal-8.localhost'); // If in a Drupal environment use the HTTP client service. $client = Drupal::httpClient()->setBaseUrl('http://drupal-8.localhost'); $request = $client->get('entity/node/1'); $request->addHeader('Accept', 'application/hal+json'); $response = $request->send()->json(); print_r($response);
{ "nid": [ { "value": "1" } ], "uuid": [ { "value": "f11b6d96-5709-4779-815c-9266f79b21c7" } ], "vid": [ { "value": "1" } ], "type": [ { "value": "page" } ], "langcode": [ { "value": "en" } ], "title": [ { "value": "Rest" } ], "_embedded": { "http://localhost/d8ser/rest/relation/node/page/uid": [ { "_links": { "self": { "href": "http://localhost/d8ser/user/1" }, "type": { "href": "http://localhost/d8ser/rest/type/user/user" } } } ], "http://localhost/d8ser/rest/relation/node/page/revision_uid": [ { "_links": { "self": { "href": "http://localhost/d8ser/user/1" }, "type": { "href": "http://localhost/d8ser/rest/type/user/user" } } } ] }, "status": [ { "value": "1" } ], "created": [ { "value": "1372512896" } ], "changed": [ { "value": "1372512901" } ], "comment": [ { "value": "1" } ], "promote": [ { "value": "0" } ], "sticky": [ { "value": "0" } ], "tnid": [ { "value": "0" } ], "translate": [ { "value": "0" } ], "revision_timestamp": [ { "value": "1372512901" } ], "log": [ { "value": "" } ] }
resources: 'entity:node': GET: supported_formats: - hal_json supported_auth: - http_basic POST: supported_formats: - hal_json supported_auth: - http_basic
curl --include --request POST --user klausi:secret \ --header 'Content-type: application/hal+json' \ http://drupal-8.localhost/entity/node --data-binary \ '{"_links":{"type":{"href":"http://drupal-8.localhost/rest/type/node/page"}}, \ "title":[{"value":"test title"}]}'
$node = array( '_links' => array( 'type' => array( 'href' => 'http://drupal-8.localhost/rest/type/node/page' ) ), 'title' => array(0 => array('value' => 'New node title')), ); $data = json_encode($node); $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => 'http://drupal-8.localhost/entity/node', CURLOPT_HTTPHEADER => array('Content-type: application/hal+json'), CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => $data, CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => 'klausi:secret', )); curl_exec($ch);
$node = array( '_links' => array( 'type' => array( 'href' => 'http://drupal-8.localhost/rest/type/node/page' ) ), 'title' => array(0 => array('value' => 'New node title')), ); $data = json_encode($node); $client->post('entity/node', array( 'Content-type' => 'application/hal+json', ), $data) // Username and password for HTTP Basic Authentication. ->setAuth('klausi', 'secret') ->send();
GET http://example.com/dblog/1
/** * @Plugin(id = "dblog") */ class DBLogResource extends ResourceBase { public function get($id = NULL) { if ($id) { $record = db_query("SELECT * FROM {watchdog} WHERE wid = :wid", array(':wid' => $id)) ->fetchAssoc(); if (!empty($record)) { return new ResourceResponse($record); } }}}
GET http://example.com/dblog/1
/**
* @Plugin(id = "dblog")
*/
class DBLogResource extends ResourceBase {
public function get($id = NULL) {
if ($id) {
$record = db_query("SELECT * FROM {watchdog} WHERE wid = :wid",
array(':wid' => $id))
->fetchAssoc();
if (!empty($record)) {
return new ResourceResponse($record);
}
}}}
GET http://example.com/dblog/1
/**
* @Plugin(id = "dblog")
*/
class DBLogResource extends ResourceBase {
public function get($id = NULL) {
if ($id) {
$record = db_query("SELECT * FROM {watchdog} WHERE wid = :wid",
array(':wid' => $id))
->fetchAssoc();
if (!empty($record)) {
return new ResourceResponse($record);
}
}}}
GET http://example.com/dblog/1
/** * @Plugin(id = "dblog") */ class DBLogResource extends ResourceBase { public function get($id = NULL) { if ($id) { $record = db_query("SELECT * FROM {watchdog} WHERE wid = :wid", array(':wid' => $id)) ->fetchAssoc(); if (!empty($record)) { return new ResourceResponse($record); } }}}
GET http://example.com/dblog/1 Accept: application/hal+json
{ "wid": "1", "uid": "0", "type": "system", "message": "%module module installed.", "variables": "a:1:{s:7:\"%module\";s:5:\"dblog\";}", "severity": "6", "link": "", "location": "http://drupal-8.localhost/core/install.php?langcode=en&profile=standard&id=1&op=do_nojs&op=do", "referer": "http://drupal-8.localhost/core/install.php?langcode=en&profile=standard&op=start&id=1", "hostname": "127.0.0.1", "timestamp": "1367615996" }
GET http://example.com/dblog/1 Accept: application/xml
<?xml version="1.0"?> <response> <wid>1</wid> <uid>0</uid> <type>system</type> <message>%module module installed.</message> <variables>a:1:{s:7:"%module";s:5:"dblog";}</variables> <severity>6</severity> <link></link> <location> <![CDATA[http://drupal-8.localhost/core/install.php?langcode=en&profile=standard&id=1&op=do_nojs&op=do]]> </location> <referer> <![CDATA[http://drupal-8.localhost/core/install.php?langcode=en&profile=standard&op=start&id=1]]> </referer> <hostname>127.0.0.1</hostname> <timestamp>1367615996</timestamp> </response>
$serializer->serialize($object, $format, $context)
{ ... "field_image": 5, ... }
{ ... "field_image": "files/foo.png", ... }
$object is instance of Drupal\image\Type\ImageItem $format is 'json'
GET /doctors/slots HTTP/1.1 Accept: application/hal+json Host: med.org
HTTP/1.1 200 OK Content-Type: application/hal+json
{ ... "_embedded": { "http://med.org/rels/open-slots": [ { "_links": { "self": { "href": "/slots/97" }, "http://med.org/rels/book": { "href": "/slots/97" } } "id": 97, "doctor": "Dr. Doe", "start": 2013-05-23T16:00:00, "end": 2013-05-23T16:50:00 }, ... ] } }
POST /slots/97 HTTP/1.1 Content-Type: application/hal+json
{ "_links": { "http://med.org/rels/patient": { "href": "/patients/linclark" } } }
HTTP/1.1 201 Created Location: http://.../slots/97/appointment
{ "_links": { "self": { "href": "/slots/97/appointment" }, "http://med.org/rels/patient": { "href": "/patients/linclark" }, "http://med.org/rels/cancel": { "href": "/slots/97/appointment" } ... } }
it allows the server to change its URI scheme without breaking clients
it helps client developers explore the protocol
$cancel_url = $base . '/slots/' . $appt['id'] . '/appointment';Using link relations:
$cancel_url = $appt['http://med.org/rels/cancel']['uri'];
Locate this session at http://prague2013.drupal.org/schedule
Click the "Take the survey" link
Thank you!