diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
index 962af71..1da1b34 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
@@ -17,6 +17,13 @@
 abstract class ResourceBase extends PluginBase {
 
   /**
+   * Holds all predefined HTTP methods and their configuration.
+   *
+   * @var array
+   */
+  protected $reuqestMethods;
+
+  /**
    * Provides an array of permissions suitable for hook_permission().
    *
    * Every plugin operation method gets its own user permission. Example:
@@ -29,7 +36,7 @@
   public function permissions() {
     $permissions = array();
     $definition = $this->getDefinition();
-    foreach ($this->requestMethods() as $method) {
+    foreach ($this->requestMethods() as $method => $settings) {
       $lowered_method = strtolower($method);
       // Only expose permissions where the HTTP request method exists on the
       // plugin.
@@ -55,7 +62,7 @@ public function routes() {
     $collection = new RouteCollection();
 
     $methods = $this->requestMethods();
-    foreach ($methods as $method) {
+    foreach ($methods as $method => $settings) {
       // Only expose routes where the HTTP request method exists on the plugin.
       if (method_exists($this, strtolower($method))) {
         $prefix = strtr($this->plugin_id, ':', '/');
@@ -83,22 +90,73 @@ public function routes() {
    * Provides predefined HTTP request methods.
    *
    * Plugins can override this method to provide additional custom request
-   * methods.
+   * methods or to alter the semantics.
+   *
+   * @param string $method
+   *   Optional: a specific request method to return setting information for.
    *
    * @return array
-   *   The list of allowed HTTP request method strings.
+   *   An array with HTTP methods as keys and value arrays with the following
+   *   key/value pairs:
+   *    - success_code: an integer used for the HTTP response code on success.
+   *    - incoming_data: a boolean to indicate that incoming data has to be
+   *      de-serialized.
+   *    - outgoing_data: a boolean to indicate that outgoing data has to be
+   *      serialized.
    */
-  protected function requestMethods() {
-    return drupal_map_assoc(array(
-      'HEAD',
-      'GET',
-      'POST',
-      'PUT',
-      'DELETE',
-      'TRACE',
-      'OPTIONS',
-      'CONNECT',
-      'PATCH',
-    ));
+  public function requestMethods($method = NULL) {
+    if ($this->reuqestMethods == NULL) {
+      $this->reuqestMethods = array(
+        'HEAD' => array(
+          'success_code' => 200,
+          'incoming_data' => FALSE,
+          'outgoing_data' => FALSE,
+        ),
+        'GET' => array(
+          'success_code' => 200,
+          'incoming_data' => FALSE,
+          'outgoing_data' => TRUE,
+        ),
+        'POST' => array(
+          'success_code' => 201,
+          'incoming_data' => TRUE,
+          'outgoing_data' => FALSE,
+        ),
+        'PUT' => array(
+          'success_code' => 200,
+          'incoming_data' => TRUE,
+          'outgoing_data' => FALSE,
+        ),
+        'DELETE' => array(
+          'success_code' => 204,
+          'incoming_data' => FALSE,
+          'outgoing_data' => FALSE,
+        ),
+        'TRACE' => array(
+          'success_code' => 200,
+          'incoming_data' => FALSE,
+          'outgoing_data' => FALSE,
+        ),
+        'OPTIONS' => array(
+          'success_code' => 200,
+          'incoming_data' => FALSE,
+          'outgoing_data' => FALSE,
+        ),
+        'CONNECT'  => array(
+          'success_code' => 200,
+          'incoming_data' => FALSE,
+          'outgoing_data' => FALSE,
+        ),
+        'PATCH'  => array(
+          'success_code' => 200,
+          'incoming_data' => TRUE,
+          'outgoing_data' => FALSE,
+        ),
+      );
+    }
+    if ($method) {
+      return $this->reuqestMethods[$method];
+    }
+    return $this->reuqestMethods;
   }
 }
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/DBLogResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/DBLogResource.php
index afc8d50..71c3d1c 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/DBLogResource.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/DBLogResource.php
@@ -9,15 +9,15 @@
 
 use Drupal\rest\Plugin\ResourceBase;
 use Drupal\Core\Annotation\Plugin;
-use Symfony\Component\HttpFoundation\Response;
+use Drupal\Core\Annotation\Translation;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
  * Provides a resource for database watchdog log entries.
  *
  * @Plugin(
- *  id = "dblog",
- *  label = "Watchdog database log"
+ *   id = "dblog",
+ *   label = @Translation("Watchdog database log")
  * )
  */
 class DBLogResource extends ResourceBase {
@@ -38,8 +38,8 @@ public function routes() {
    *
    * Returns a watchdog log entry for the specified ID.
    *
-   * @return \Symfony\Component\HttpFoundation\Response
-   *   The response object.
+   * @return object
+   *   The databse row loaded as stdClass object.
    *
    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
    */
@@ -53,8 +53,7 @@ public function get($id = NULL) {
       if (empty($result)) {
         throw new NotFoundHttpException('Not Found');
       }
-      // @todo remove hard coded format here.
-      return new Response(drupal_json_encode($result[0]), 200, array('Content-Type' => 'application/json'));
+      return $result[0];
     }
   }
 }
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 3524389..a28ae07 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
@@ -8,6 +8,7 @@
 namespace Drupal\rest\Plugin\rest\resource;
 
 use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\rest\Plugin\ResourceBase;
 use Symfony\Component\HttpFoundation\Response;
@@ -18,21 +19,38 @@
  * Represents entities as resources.
  *
  * @Plugin(
- *  id = "entity",
- *  label = "Entity",
- *  derivative = "Drupal\rest\Plugin\Derivative\EntityDerivative"
+ *   id = "entity",
+ *   label = @Translation("Entity"),
+ *   derivative = "Drupal\rest\Plugin\Derivative\EntityDerivative"
  * )
  */
 class EntityResource extends ResourceBase {
 
   /**
-   * Responds to entity DELETE requests.
+   * Responds to entity GET requests.
    *
    * @param mixed $id
    *   The entity ID.
    *
-   * @return \Symfony\Component\HttpFoundation\Response
-   *   The response object.
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   The loaded entity.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function get($id) {
+    $definition = $this->getDefinition();
+    $entity = entity_load($definition['entity_type'], $id);
+    if ($entity) {
+      return $entity;
+    }
+    throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
+  }
+
+  /**
+   * Responds to entity DELETE requests.
+   *
+   * @param mixed $id
+   *   The entity ID.
    *
    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
    */
@@ -42,13 +60,13 @@ public function delete($id) {
     if ($entity) {
       try {
         $entity->delete();
-        // Delete responses have an empty body.
-        return new Response('', 204);
       }
       catch (EntityStorageException $e) {
         throw new HttpException(500, 'Internal Server Error', $e);
       }
     }
-    throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
+    else {
+      throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
+    }
   }
 }
diff --git a/core/modules/rest/lib/Drupal/rest/RequestHandler.php b/core/modules/rest/lib/Drupal/rest/RequestHandler.php
index 6bea36a..1dbd81a 100644
--- a/core/modules/rest/lib/Drupal/rest/RequestHandler.php
+++ b/core/modules/rest/lib/Drupal/rest/RequestHandler.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\rest;
 
+use Drupal\Core\Entity\EntityNG;
 use Symfony\Component\DependencyInjection\ContainerAware;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
@@ -33,17 +34,41 @@ class RequestHandler extends ContainerAware {
    *   '_plugin' property of route object.
    */
   public function handle($plugin, Request $request, $id = NULL) {
-    $method = strtolower($request->getMethod());
-    if (user_access("restful $method $plugin")) {
+    $method = $request->getMethod();
+    $lower_method = strtolower($method);
+    if (user_access("restful $lower_method $plugin")) {
       $resource = $this->container
         ->get('plugin.manager.rest')
         ->getInstance(array('id' => $plugin));
+      // @todo De-serialization should happen here if the request is supposed
+      // to carry incoming data.
+      $settings = $resource->requestMethods($method);
       try {
-        return $resource->{$method}($id);
+        $data = $resource->{$lower_method}($id);
       }
       catch (HttpException $e) {
         return new Response($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
       }
+      // If the plugin returns response objects itself we pass them through.
+      if ($data instanceof Response) {
+        return $data;
+      }
+      // If there is no response body data to return we can send a response
+      // immediately.
+      if (empty($settings['outgoing_data'])) {
+        return new Response('', $settings['success_code']);
+      }
+      // Otherwise we serialize the data.
+      $serializer = $this->container->get('serializer');
+      // Convert object to array as normalizer does not support
+      // non EntityNG objects.
+      if (is_object($data) && !$data instanceof EntityNG) {
+        $data = (array) $data;
+      }
+      // @todo Replace the format here with something we get from the HTTP
+      //   Accept headers. See http://drupal.org/node/1833440
+      $output = $serializer->serialize($data, 'drupal_jsonld');
+      return new Response($output, $settings['success_code'], array('Content-Type' => 'application/ld+json'));
     }
     return new Response('Access Denied', 403);
   }
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php
index 6bd8e65..66b3457 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('rest', 'dblog');
+  public static $modules = array('jsonld', 'rest', 'dblog');
 
   public static function getInfo() {
     return array(
@@ -32,17 +32,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     // Enable web API for the watchdog resource.
-    $config = config('rest');
-    $config->set('resources', array(
-      'dblog' => 'dblog',
-    ));
-    $config->save();
-
-    // Rebuild routing cache, so that the web API paths are available.
-    drupal_container()->get('router.builder')->rebuild();
-    // Reset the Simpletest permission cache, so that the new resource
-    // permissions get picked up.
-    drupal_static_reset('checkPermissions');
+    $this->enableService('dblog');
   }
 
   /**
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
index 187c386..4c039c2 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
@@ -34,18 +34,7 @@ public static function getInfo() {
    */
   public function testDelete() {
     foreach (entity_get_info() as $entity_type => $info) {
-      // Enable web API for this entity type.
-      $config = config('rest');
-      $config->set('resources', array(
-        'entity:' . $entity_type => 'entity:' . $entity_type,
-      ));
-      $config->save();
-
-      // Rebuild routing cache, so that the web API paths are available.
-      drupal_container()->get('router.builder')->rebuild();
-      // Reset the Simpletest permission cache, so that the new resource
-      // permissions get picked up.
-      drupal_static_reset('checkPermissions');
+      $this->enableService('entity:' . $entity_type);
       // Create a user account that has the required permissions to delete
       // resources via the web API.
       $account = $this->drupalCreateUser(array('restful delete entity:' . $entity_type));
@@ -81,6 +70,7 @@ public function testDelete() {
       $this->assertNotIdentical(FALSE, entity_load($entity_type, $entity->id(), TRUE), 'The ' . $entity_type . ' entity is still in the database.');
     }
     // Try to delete a resource which is not web API enabled.
+    $this->enableService(FALSE);
     $account = $this->drupalCreateUser();
     // Reset cURL here because it is confused from our previously used cURL
     // options.
@@ -88,32 +78,7 @@ public function testDelete() {
     $this->drupalLogin($account);
     $this->httpRequest('entity/user/' . $account->id(), 'DELETE');
     $user = entity_load('user', $account->id(), TRUE);
-    $this->assertEqual($account->id(), $user->id());
+    $this->assertEqual($account->id(), $user->id(), 'User still exists in the database.');
     $this->assertResponse(404);
   }
-
-  /**
-   * Creates entity objects based on their types.
-   *
-   * Required properties differ from entity type to entity type, so we keep a
-   * minimum mapping here.
-   *
-   * @param string $entity_type
-   *   The type of the entity that should be created..
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   The new entity object.
-   */
-  protected function entityCreate($entity_type) {
-    switch ($entity_type) {
-      case 'entity_test':
-        return entity_create('entity_test', array('name' => 'test', 'user_id' => 1));
-      case 'node':
-        return entity_create('node', array('title' => $this->randomString()));
-      case 'user':
-        return entity_create('user', array('name' => $this->randomName()));
-      default:
-        return entity_create($entity_type, array());
-    }
-  }
 }
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 3bc8756..eed04fb 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -31,13 +31,14 @@ protected function httpRequest($url, $method, $body = NULL, $format = 'applicati
       case 'GET':
         // Set query if there are additional GET parameters.
         $options = isset($body) ? array('absolute' => TRUE, 'query' => $body) : array('absolute' => TRUE);
-        return $this->curlExec(array(
+        $response = $this->curlExec(array(
           CURLOPT_HTTPGET => TRUE,
           CURLOPT_URL => url($url, $options),
           CURLOPT_NOBODY => FALSE)
         );
+        break;
       case 'POST':
-        return $this->curlExec(array(
+        $response = $this->curlExec(array(
           CURLOPT_HTTPGET => FALSE,
           CURLOPT_POST => TRUE,
           CURLOPT_POSTFIELDS => $body,
@@ -45,8 +46,9 @@ protected function httpRequest($url, $method, $body = NULL, $format = 'applicati
           CURLOPT_NOBODY => FALSE,
           CURLOPT_HTTPHEADER => array('Content-Type: ' . $format),
         ));
+        break;
       case 'PUT':
-        return $this->curlExec(array(
+        $response = $this->curlExec(array(
           CURLOPT_HTTPGET => FALSE,
           CURLOPT_CUSTOMREQUEST => 'PUT',
           CURLOPT_POSTFIELDS => $body,
@@ -54,13 +56,73 @@ protected function httpRequest($url, $method, $body = NULL, $format = 'applicati
           CURLOPT_NOBODY => FALSE,
           CURLOPT_HTTPHEADER => array('Content-Type: ' . $format),
         ));
+        break;
       case 'DELETE':
-        return $this->curlExec(array(
+        $response = $this->curlExec(array(
           CURLOPT_HTTPGET => FALSE,
           CURLOPT_CUSTOMREQUEST => 'DELETE',
           CURLOPT_URL => url($url, array('absolute' => TRUE)),
           CURLOPT_NOBODY => FALSE,
         ));
+        break;
     }
+
+    $this->verbose($method . ' request to: ' . $url .
+      '<hr />Code: ' . curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE) .
+      '<hr />Response: ' . $response);
+
+    return $response;
+  }
+
+  /**
+   * Creates entity objects based on their types.
+   *
+   * Required properties differ from entity type to entity type, so we keep a
+   * minimum mapping here.
+   *
+   * @param string $entity_type
+   *   The type of the entity that should be created..
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   The new entity object.
+   */
+  protected function entityCreate($entity_type) {
+    switch ($entity_type) {
+      case 'entity_test':
+        return entity_create('entity_test', array('name' => $this->randomName(), 'user_id' => 1));
+      case 'node':
+        return entity_create('node', array('title' => $this->randomString()));
+      case 'user':
+        return entity_create('user', array('name' => $this->randomName()));
+      default:
+        return entity_create($entity_type, array());
+    }
+  }
+
+  /**
+   * Enables the web service interface for a specific entity type.
+   *
+   * @param string|FALSE $resource_type
+   *   The resource type that should get web API enabled or FALSE to disable all
+   *   resource types.
+   */
+  protected function enableService($resource_type) {
+    // Enable web API for this entity type.
+    $config = config('rest');
+    if ($resource_type) {
+      $config->set('resources', array(
+        $resource_type => $resource_type,
+      ));
+    }
+    else {
+      $config->set('resources', array());
+    }
+    $config->save();
+
+    // Rebuild routing cache, so that the web API paths are available.
+    drupal_container()->get('router.builder')->rebuild();
+    // Reset the Simpletest permission cache, so that the new resource
+    // permissions get picked up.
+    drupal_static_reset('checkPermissions');
   }
 }
diff --git a/core/modules/rest/rest.info b/core/modules/rest/rest.info
index 56c650c..c0bf4bd 100644
--- a/core/modules/rest/rest.info
+++ b/core/modules/rest/rest.info
@@ -3,4 +3,6 @@ description = Exposes entities and other resources as RESTful web API
 package = Core
 version = VERSION
 core = 8.x
+; @todo Remove this dependency once hard coding to JSON-LD is gone.
+dependencies[] = jsonld
 configure = admin/config/services/rest
