diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php index b582a9f..5f910cb 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php @@ -155,6 +155,11 @@ public function patch($id, EntityInterface $entity) { } // Overwrite the received properties. foreach ($entity->getProperties() as $name => $property) { + // Requests cannot overwrite id or uuid, so skip them. + if (in_array($name, array('id', 'uuid'))) { + continue; + } + if (isset($entity->{$name})) { $original_entity->{$name} = $property; } diff --git a/core/modules/rest/lib/Drupal/rest/RequestHandler.php b/core/modules/rest/lib/Drupal/rest/RequestHandler.php index 30156de..e0d09bc 100644 --- a/core/modules/rest/lib/Drupal/rest/RequestHandler.php +++ b/core/modules/rest/lib/Drupal/rest/RequestHandler.php @@ -75,7 +75,7 @@ public function handle(Request $request, $id = NULL) { } catch (HttpException $e) { $error['error'] = $e->getMessage(); - $format = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)->getRequirement('_format') ?: 'drupal_jsonld'; + $format = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)->getRequirement('_format') ?: 'hal_json'; $content = $serializer->serialize($error, $format); // Add the default content type, but only if the headers from the // exception have not specified it already. @@ -88,9 +88,8 @@ public function handle(Request $request, $id = NULL) { if ($data != NULL) { // All REST routes are restricted to exactly one format, so instead of // parsing it out of the Accept headers again we can simply retrieve the - // format requirement. If there is no format associated just pick Drupal - // JSON-LD. - $format = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)->getRequirement('_format') ?: 'drupal_jsonld'; + // format requirement. If there is no format associated just pick HAL. + $format = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)->getRequirement('_format') ?: 'hal_json'; $output = $serializer->serialize($data, $format); $response->setContent($output); diff --git a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php index d6973e5..e505a07 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php @@ -19,7 +19,7 @@ class CreateTest extends RESTTestBase { * * @var array */ - public static $modules = array('rest', 'entity_test'); + public static $modules = array('hal', 'rest', 'entity_test'); public static function getInfo() { return array( @@ -46,9 +46,9 @@ public function testCreate() { $entity_values = $this->entityValues($entity_type); $entity = entity_create($entity_type, $entity_values); - $serialized = $serializer->serialize($entity, 'drupal_jsonld'); + $serialized = $serializer->serialize($entity, 'hal_json'); // Create the entity over the REST API. - $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/hal+json'); $this->assertResponse(201); // Get the new entity ID from the location header and try to read it from @@ -71,7 +71,7 @@ public function testCreate() { $loaded_entity->delete(); // Try to send invalid data that cannot be correctly deserialized. - $this->httpRequest('entity/' . $entity_type, 'POST', 'kaboom!', 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type, 'POST', 'kaboom!', 'application/hal+json'); $this->assertResponse(400); // Try to create an entity without the CSRF token. @@ -82,21 +82,21 @@ public function testCreate() { CURLOPT_POSTFIELDS => $serialized, CURLOPT_URL => url('entity/' . $entity_type, array('absolute' => TRUE)), CURLOPT_NOBODY => FALSE, - CURLOPT_HTTPHEADER => array('Content-Type: application/vnd.drupal.ld+json'), + CURLOPT_HTTPHEADER => array('Content-Type: application/hal+json'), )); $this->assertResponse(403); $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); // Try to create an entity without proper permissions. $this->drupalLogout(); - $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/hal+json'); $this->assertResponse(403); $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); // Try to create a resource which is not REST API enabled. $this->enableService(FALSE); $this->drupalLogin($account); - $this->httpRequest('entity/entity_test', 'POST', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/entity_test', 'POST', $serialized, 'application/hal+json'); $this->assertResponse(404); $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php index 9be9896..f5910a3 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php @@ -19,7 +19,7 @@ class DBLogTest extends RESTTestBase { * * @var array */ - public static $modules = array('jsonld', 'rest', 'dblog'); + public static $modules = array('hal', 'rest', 'dblog'); public static function getInfo() { return array( @@ -50,16 +50,16 @@ public function testWatchdog() { $account = $this->drupalCreateUser(array('restful get dblog')); $this->drupalLogin($account); - $response = $this->httpRequest("dblog/$id", 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest("dblog/$id", 'GET', NULL, 'application/hal+json'); $this->assertResponse(200); - $this->assertHeader('content-type', 'application/vnd.drupal.ld+json'); + $this->assertHeader('content-type', 'application/hal+json'); $log = drupal_json_decode($response); $this->assertEqual($log['wid'], $id, 'Log ID is correct.'); $this->assertEqual($log['type'], 'rest_test', 'Type of log message is correct.'); $this->assertEqual($log['message'], 'Test message', 'Log message text is correct.'); // Request an unknown log entry. - $response = $this->httpRequest("dblog/9999", 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest("dblog/9999", 'GET', NULL, 'application/hal+json'); $this->assertResponse(404); $decoded = drupal_json_decode($response); $this->assertEqual($decoded['error'], 'Log entry with ID 9999 was not found', 'Response message is correct.'); diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php index 2bed8ba..7667365 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php @@ -19,7 +19,7 @@ class DeleteTest extends RESTTestBase { * * @var array */ - public static $modules = array('rest', 'entity_test'); + public static $modules = array('hal', 'rest', 'entity_test'); public static function getInfo() { return array( diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php index 6cbfbd8..9a62b1e 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php @@ -26,7 +26,7 @@ * @param string $format * The MIME type of the transmitted content. */ - protected function httpRequest($url, $method, $body = NULL, $format = 'application/ld+json') { + protected function httpRequest($url, $method, $body = NULL, $format = 'application/hal+json') { if (!in_array($method, array('GET', 'HEAD', 'OPTIONS', 'TRACE'))) { // GET the CSRF token first for writing requests. $token = $this->drupalGet('rest/session/token'); @@ -159,7 +159,7 @@ protected function entityValues($entity_type) { * @param string $method * The HTTP method to enable, e.g. GET, POST etc. * @param string $format - * (Optional) The serialization format, e.g. jsonld. + * (Optional) The serialization format, e.g. hal_json. */ protected function enableService($resource_type, $method = 'GET', $format = NULL) { // Enable REST API for this entity type. diff --git a/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php b/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php index e157a2d..2b77bbd 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php @@ -19,7 +19,7 @@ class ReadTest extends RESTTestBase { * * @var array */ - public static $modules = array('jsonld', 'rest', 'entity_test'); + public static $modules = array('hal', 'rest', 'entity_test'); public static function getInfo() { return array( @@ -48,34 +48,34 @@ public function testRead() { $entity = $this->entityCreate($entity_type); $entity->save(); // Read it over the REST API. - $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/hal+json'); $this->assertResponse('200', 'HTTP response code is correct.'); - $this->assertHeader('content-type', 'application/vnd.drupal.ld+json'); + $this->assertHeader('content-type', 'application/hal+json'); $data = drupal_json_decode($response); // Only assert one example property here, other properties should be // checked in serialization tests. - $this->assertEqual($data['uuid'][LANGUAGE_DEFAULT][0]['value'], $entity->uuid(), 'Entity UUID is correct'); + $this->assertEqual($data['uuid'][0]['value'], $entity->uuid(), 'Entity UUID is correct'); // Try to read the entity with an unsupported mime format. $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/wrongformat'); $this->assertResponse(415); // Try to read an entity that does not exist. - $response = $this->httpRequest('entity/' . $entity_type . '/9999', 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest('entity/' . $entity_type . '/9999', 'GET', NULL, 'application/hal+json'); $this->assertResponse(404); $decoded = drupal_json_decode($response); $this->assertEqual($decoded['error'], 'Entity with ID 9999 not found', 'Response message is correct.'); // Try to read an entity without proper permissions. $this->drupalLogout(); - $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/hal+json'); $this->assertResponse(403); $this->assertNull(drupal_json_decode($response), 'No valid JSON found.'); } // Try to read a resource which is not REST API enabled. $account = $this->drupalCreateUser(); $this->drupalLogin($account); - $response = $this->httpRequest('entity/user/' . $account->id(), 'GET', NULL, 'application/vnd.drupal.ld+json'); + $response = $this->httpRequest('entity/user/' . $account->id(), 'GET', NULL, 'application/hal+json'); $this->assertResponse(404); $this->assertNull(drupal_json_decode($response), 'No valid JSON found.'); } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php index c920514..1cf36d3 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php @@ -19,7 +19,7 @@ class UpdateTest extends RESTTestBase { * * @var array */ - public static $modules = array('rest', 'entity_test'); + public static $modules = array('hal', 'rest', 'entity_test'); public static function getInfo() { return array( @@ -51,12 +51,10 @@ public function testPatchUpdate() { // Create a second stub entity for overwriting a field. $patch_values['field_test_text'] = array(0 => array('value' => $this->randomString())); $patch_entity = entity_create($entity_type, $patch_values); - // We don't want to overwrite the UUID. - unset($patch_entity->uuid); - $serialized = $serializer->serialize($patch_entity, 'drupal_jsonld'); + $serialized = $serializer->serialize($patch_entity, 'hal_json'); // Update the entity over the REST API. - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/hal+json'); $this->assertResponse(204); // Re-load updated entity from the database. @@ -64,12 +62,12 @@ public function testPatchUpdate() { $this->assertEqual($entity->field_test_text->value, $patch_entity->field_test_text->value, 'Field was successfully updated.'); // Try to empty a field. - $normalized = $serializer->normalize($patch_entity, 'drupal_jsonld'); + $normalized = $serializer->normalize($patch_entity, 'hal_json'); $normalized['field_test_text'] = array(); - $serialized = $serializer->encode($normalized, 'jsonld'); + $serialized = $serializer->encode($normalized, 'hal_json'); // Update the entity over the REST API. - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/hal+json'); $this->assertResponse(204); // Re-load updated entity from the database. @@ -77,20 +75,20 @@ public function testPatchUpdate() { $this->assertNull($entity->field_test_text->value, 'Test field has been cleared.'); // Try to update a non-existing entity with ID 9999. - $this->httpRequest('entity/' . $entity_type . '/9999', 'PATCH', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/9999', 'PATCH', $serialized, 'application/hal+json'); $this->assertResponse(404); $loaded_entity = entity_load($entity_type, 9999, TRUE); $this->assertFalse($loaded_entity, 'Entity 9999 was not created.'); // Try to update an entity without proper permissions. $this->drupalLogout(); - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/hal+json'); $this->assertResponse(403); // Try to update a resource which is not REST API enabled. $this->enableService(FALSE); $this->drupalLogin($account); - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/hal+json'); $this->assertResponse(404); } @@ -120,9 +118,9 @@ public function testPutUpdate() { $update_entity->uuid->value = $entity->uuid(); $update_entity->id->value = $entity->id(); - $serialized = $serializer->serialize($update_entity, 'drupal_jsonld'); + $serialized = $serializer->serialize($update_entity, 'hal_json'); // Update the entity over the REST API. - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/hal+json'); $this->assertResponse(204); // Re-load the updated entity from the database. @@ -138,8 +136,8 @@ public function testPutUpdate() { // Try to delete a property. unset($update_entity->field_test_text); - $serialized = $serializer->serialize($update_entity, 'drupal_jsonld'); - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json'); + $serialized = $serializer->serialize($update_entity, 'hal_json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/hal+json'); $this->assertResponse(204); // Re-load the updated entity from the database. @@ -147,20 +145,20 @@ public function testPutUpdate() { $this->assertTrue($entity->field_test_text->isEmpty(), 'Property has been deleted.'); // Try to create an entity with ID 9999. - $this->httpRequest('entity/' . $entity_type . '/9999', 'PUT', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/9999', 'PUT', $serialized, 'application/hal+json'); $this->assertResponse(404); $loaded_entity = entity_load($entity_type, 9999, TRUE); $this->assertFalse($loaded_entity, 'Entity 9999 was not created.'); // Try to update an entity without proper permissions. $this->drupalLogout(); - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/hal+json'); $this->assertResponse(403); // Try to update a resource which is not REST API enabled. $this->enableService(FALSE); $this->drupalLogin($account); - $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json'); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/hal+json'); $this->assertResponse(404); } } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/Views/StyleSerializerTest.php b/core/modules/rest/lib/Drupal/rest/Tests/Views/StyleSerializerTest.php index 4aeaaa7..c38db82 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/Views/StyleSerializerTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/Views/StyleSerializerTest.php @@ -25,7 +25,7 @@ class StyleSerializerTest extends PluginTestBase { * * @var array */ - public static $modules = array('views_ui', 'entity_test', 'jsonld', 'rest_test_views'); + public static $modules = array('views_ui', 'entity_test', 'hal', 'rest_test_views'); /** * Views used by this test. @@ -127,13 +127,9 @@ public function testSerializerResponses() { $this->assertIdentical($actual_json, $expected, 'The expected JSON output was found.'); - $expected = $serializer->serialize($entities, 'jsonld'); - $actual_json = $this->drupalGet('test/serialize/entity', array(), array('Accept: application/ld+json')); - $this->assertIdentical($actual_json, $expected, 'The expected JSONLD output was found.'); - - $expected = $serializer->serialize($entities, 'drupal_jsonld'); - $actual_json = $this->drupalGet('test/serialize/entity', array(), array('Accept: application/vnd.drupal.ld+json')); - $this->assertIdentical($actual_json, $expected, 'The expected JSONLD output was found.'); + $expected = $serializer->serialize($entities, 'hal_json'); + $actual_json = $this->drupalGet('test/serialize/entity', array(), array('Accept: application/hal+json')); + $this->assertIdentical($actual_json, $expected, 'The expected HAL output was found.'); } /** diff --git a/core/modules/rest/rest.info.yml b/core/modules/rest/rest.info.yml index e67ea21..1ac5015 100644 --- a/core/modules/rest/rest.info.yml +++ b/core/modules/rest/rest.info.yml @@ -4,7 +4,5 @@ package: Core version: VERSION core: 8.x dependencies: - # @todo Remove this dependency once hard coding to JSON-LD is gone. - - jsonld - serialization configure: admin/config/services/rest diff --git a/core/modules/rest/rest.module b/core/modules/rest/rest.module index 233db32..43b32f4 100644 --- a/core/modules/rest/rest.module +++ b/core/modules/rest/rest.module @@ -69,7 +69,7 @@ function rest_help($path, $arg) { $output .= '

' . t('Example uses') . '

'; $output .= '
'; $output .= '
' . t('An HTTP GET request can be used to get a node') . '
'; - $output .= '
curl -H "Accept: application/vnd.drupal.ld+json" --include --request GET --cookie ' . session_name() . '=' . session_id() . ' ' . url('entity/node/5', array('absolute' => TRUE)) . '
'; + $output .= '
curl -H "Accept: application/hal+json" --include --request GET --cookie ' . session_name() . '=' . session_id() . ' ' . url('entity/node/5', array('absolute' => TRUE)) . '
'; $output .= '
' . t('An HTTP DELETE request can be used to delete a node') . '
'; $output .= '
curl --include --request DELETE --cookie ' . session_name() . '=' . session_id() . ' ' . url('entity/node/5', array('absolute' => TRUE)) . '
'; $output .= '
';