diff --git a/core/modules/rest/rest.module b/core/modules/rest/rest.module
index c0c6be3..123a553 100644
--- a/core/modules/rest/rest.module
+++ b/core/modules/rest/rest.module
@@ -5,6 +5,7 @@
  * RESTful web services module.
  */
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -40,6 +41,37 @@ function rest_help($route_name, RouteMatchInterface $route_match) {
       $output .= '<dd>' . t('REST support for content items of the Node module is enabled by default, and support for other types of content entities can be enabled. To enable support, you can use a <a href="!config">process based on configuration editing</a> or the contributed <a href="!restui">Rest UI module</a>.', array('!config' => 'https://drupal.org/documentation/modules/rest', '!restui' => 'https://drupal.org/project/restui')) . '</dd>';
       $output .= '<dd>' . t('You will also need to grant anonymous users permission to perform each of the REST operations you want to be available, and set up authentication properly to authorize web requests.') . '</dd>';
       $output .= '</dl>';
+      $output .= '<h3>' . t('API Docs') . '</h3>';
+      $output .= '<p>' . t('The API documentation is viewable on') . ' <a href="/docs/rest/api">/docs/rest/api</a></p>';
       return $output;
   }
 }
+
+
+/**
+ * Implements hook_theme().
+ */
+function rest_theme() {
+   return array(
+      'rest_documentation' => array(
+        'variables' => array('field_description' => NULL, 'methods' => array()),
+        'template' => 'rest-documentation',
+     ),
+    'rest_documentation_section' => array(
+      'variables' => array('method' => NULL, 'headers' => NULL, 'body' => NULL),
+      'template' => 'rest-documentation-section',
+    ),
+    'rest_documentation_endpoints' => array(
+      'variables' => array('endpoints' => NULL),
+      'template' => 'rest-documentation-endpoints',
+    ),
+    'rest_documentation_type' => array(
+      'variables' => array('required' => NULL, 'optional' => NULL),
+      'template' => 'rest-documentation-type',
+    )
+  );
+}
+
+function template_preprocess_rest_documentation($variables) {
+  $variables['field_description'] = String::checkPlain($variables['field_description']);
+}
diff --git a/core/modules/rest/rest.routing.yml b/core/modules/rest/rest.routing.yml
index 843dee9..da1f7a4 100644
--- a/core/modules/rest/rest.routing.yml
+++ b/core/modules/rest/rest.routing.yml
@@ -4,3 +4,9 @@ rest.csrftoken:
     _controller: '\Drupal\rest\RequestHandler::csrfToken'
   requirements:
     _access: 'TRUE'
+rest.docs:
+  path: '/docs/rest/api'
+  defaults:
+    _controller: 'Drupal\rest\Controller::docRoot'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/rest/src/Controller.php b/core/modules/rest/src/Controller.php
new file mode 100644
index 0000000..f86acbb
--- /dev/null
+++ b/core/modules/rest/src/Controller.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rest\Controller.
+ */
+
+namespace Drupal\rest;
+
+use Drupal\Core\Entity\Field\Type\Field;
+use Symfony\Component\DependencyInjection\ContainerAware;
+
+class Controller extends ContainerAware {
+
+  // TODO use DiC
+  //      see getRestBundles()
+  //      see getEntityManager()
+
+  /**
+   * Renders the REST documentation.
+   *
+   * This is the start point for exploring the exposed rest entities.
+   *
+   * Only exposed entities are listed.
+   *
+   * @return array
+   */
+  public function docRoot() {
+    $config = \Drupal::config('rest.settings')->get('resources') ?: array();
+
+    $all_bundles = $this->getRestBundles();
+
+    $items = array();
+    foreach ($config as $id => $config) {
+      $item = array();
+      foreach ($config as $method => $settings) {
+        $supported_formats = join(', ', $settings['supported_formats']);
+        $supported_auth = join(", ", $settings['supported_auth']);
+        $item[] = t("Method %method using formats '%supported_formats' with authentication methods '%supported_auth'", array(
+          '%method' => $method,
+          '%supported_auth' => $supported_auth,
+          '%supported_formats' => $supported_formats
+        ));
+      }
+
+      list(, $entity) = explode(":", $id);
+      $bundles = array_keys($all_bundles[$entity]);
+      $doc_refs = array();
+      foreach ($bundles as $bundle) {
+        $doc_refs[] = l($bundle, '/docs/rest/api/types/' . $entity . '/' . $bundle);
+      }
+      $items[] = array(
+        '#theme' => 'item_list',
+        '#title' => t("Resource %entity has documentation for !doc-urls", array(
+          '%entity' => $entity,
+          '!doc-urls' => join(', ', $doc_refs)
+        )),
+        '#items' => $item,
+      );
+    }
+
+    $result = array(
+      '#theme' => 'item_list',
+      '#title' => t('Rest resources'),
+      '#items' => $items,
+    );
+
+    return $result;
+  }
+
+  /**
+   * List all fields for given entity type and bundle.
+   *
+   * @param $entity_type
+   * @param $bundle
+   * @return array
+   */
+  public function type($entity_type, $bundle) {
+    $required = array();
+    $optional = array();
+
+    $fields = $this->getEntityManager()->getFieldDefinitions($entity_type, $bundle);
+
+    /** @var \Drupal\Core\Field\FieldDefinitionInterface $field */
+    foreach ($fields as $id => $field) {
+      $item = l($field->getName(), "rest/relation/$entity_type/$bundle/$id");
+
+      if ($field->isRequired()) {
+        $required[] = $item;
+      }
+      else {
+        $optional[] = $item;
+      }
+    }
+
+    $requiredItems = array(
+      '#theme' => 'item_list',
+      '#title' => "Required fields",
+      '#items' => $required,
+    );
+    $optionalItems = array(
+      '#theme' => 'item_list',
+      '#title' => "Optional fields",
+      '#items' => $optional,
+    );
+
+    $render = array(
+      '#theme' => 'item_list',
+      '#title' => 'Fields for ' . $entity_type . ' / ' . $bundle,
+      '#items' => array($requiredItems, $optionalItems),
+    );
+    return $render;
+  }
+
+  /**
+   * Generate field page.
+   *
+   * @param $entity_type
+   * @param $bundle
+   * @param $field_name
+   * @return mixed
+   */
+  public function relation($entity_type, $bundle, $field_name) {
+    // TODO fix for drupal_set_title
+    // drupal_set_title($field_name);
+
+    /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields */
+    $fields = $this->getEntityManager()->getFieldDefinitions($entity_type, $bundle);
+
+    /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
+    $field_definition = $fields[$field_name];
+
+    // TODO: SA what information is disclosed?
+    //       All settings are exposed
+    // TODO: how to check for field permissions?
+
+    $rows = array();
+    $rows[] = array("Type", $field_definition->getType());
+    $rows[] = array("Description", $field_definition->getDescription());
+    foreach ($field_definition->getSettings() as $key => $value) {
+      $rows[] = array("Settings - $key", print_r($value, TRUE));
+    }
+
+    $result = array(
+      '#theme' => 'table',
+      '#title' => t("Rest resources for !entity_type / !bundle / !field_name", array(
+        '!entity_type' => l($entity_type, ''),
+        '!bundle' => l($bundle, '/docs/rest/api/types/' . $entity_type . '/' . $bundle),
+        '!field_name' => $field_name,
+      )),
+      '#rows' => $rows,
+    );
+    return $result;
+  }
+
+  protected function getRestBundles() {
+    // TODO use DIC
+    $bundles = \Drupal::entityManager()->getAllBundleInfo();
+
+    $config = \Drupal::config('rest.settings')->get('resources');
+
+    // TODO: Change this to only expose info for REST enabled entity types.
+    //       aka filter out all ConfigEntities too.
+
+    return $bundles;
+  }
+
+  protected function getEntityManager() {
+    // TODO use DIC
+    return \Drupal::entityManager();
+  }
+
+}
diff --git a/core/modules/rest/src/Routing/ResourceRoutes.php b/core/modules/rest/src/Routing/ResourceRoutes.php
index 5605048..a0b0ea9 100644
--- a/core/modules/rest/src/Routing/ResourceRoutes.php
+++ b/core/modules/rest/src/Routing/ResourceRoutes.php
@@ -8,17 +8,17 @@
 namespace Drupal\rest\Routing;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Routing\RouteBuildEvent;
 use Drupal\Core\Routing\RouteSubscriberBase;
+use Drupal\Core\Routing\RoutingEvents;
 use Drupal\rest\Plugin\Type\ResourcePluginManager;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Subscriber for REST-style routes.
  */
-class ResourceRoutes extends RouteSubscriberBase{
+class ResourceRoutes extends RouteSubscriberBase {
 
   /**
    * The plugin manager for REST plugins.
@@ -66,7 +66,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $method = $route->getRequirement('_method');
         // Only expose routes where the method is enabled in the configuration.
         if ($method && isset($enabled_methods[$method])) {
-          $route->setRequirement('_access_rest_csrf',  'TRUE');
+          $route->setRequirement('_access_rest_csrf', 'TRUE');
 
           // Check that authentication providers are defined.
           if (empty($enabled_methods[$method]['supported_auth']) || !is_array($enabled_methods[$method]['supported_auth'])) {
@@ -97,4 +97,86 @@ protected function alterRoutes(RouteCollection $collection) {
     }
   }
 
+  /**
+   * Generate relational routes.
+   *
+   * TODO: why do we generate routes for relations?
+   *
+   * @param RouteBuildEvent $event
+   */
+  public function relationRoutes(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+
+    // TODO: why filter out the non relation ones? Ie field_image is exposed through _links to ie HAL browser.
+    $link_field_types = array(
+      'entity_reference',
+      'taxonomy_term_reference',
+    );
+    $fieldMap = \Drupal::entityManager()->getFieldMap();
+
+    foreach ($fieldMap as $entity_type => $fields) {
+      foreach ($fields as $field_name => $field) {
+        // FIXME
+        //if (in_array($field['type'], $link_field_types)) {
+          foreach ($field['bundles'] as $bundle) {
+            // TODO why use relation in link. This should be in */api/* path
+            $route = new Route("/rest/relation/$entity_type/$bundle/$field_name", array(
+              '_content' => 'Drupal\rest\Controller::relation',
+              'entity_type' => $entity_type,
+              'bundle' => $bundle,
+              'field_name' => $field_name,
+            ), array(
+              '_method' => 'GET',
+              '_access' => 'TRUE',
+            ));
+            $collection->add("rest.relation.$entity_type.$bundle.$field_name", $route);
+          }
+        //}
+      }
+    }
+  }
+
+  /**
+   * Add all supported EntityTypes to the routes.
+   *
+   * @param RouteBuildEvent $event
+   */
+  public function typeRoutes(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+
+    foreach ($this->getRestBundles() as $entity_type => $bundles) {
+      foreach ($bundles as $bundle_name => $bundle) {
+        $route = new Route("/docs/rest/api/types/$entity_type/$bundle_name", array(
+          '_content' => 'Drupal\rest\Controller::type',
+          'entity_type' => $entity_type,
+          'bundle' => $bundle_name,
+        ), array(
+          '_method' => 'GET',
+          '_access' => 'TRUE',
+        ));
+        $collection->add("rest.type.$entity_type.$bundle_name", $route);
+      }
+    }
+  }
+
+  protected function getRestBundles() {
+    $bundles = \Drupal::entityManager()->getAllBundleInfo();
+
+    // TODO: Change this to only expose info for REST enabled entity types.
+    // TODO: filter out all ConfigEntities
+
+    return $bundles;
+  }
+
+  /**
+   * Implements EventSubscriberInterface::getSubscribedEvents().
+   */
+  static function getSubscribedEvents() {
+    $events = parent::getSubscribedEvents();
+
+    $events[RoutingEvents::DYNAMIC][] = array('relationRoutes');
+    $events[RoutingEvents::DYNAMIC][] = array('typeRoutes');
+    return $events;
+  }
+
 }
