- 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_basiccurl --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!