Styles



Styles

0 0


presentation-headless-drupal


On Github amitaibu / presentation-headless-drupal

Styles

Select transitionsNone - Default

/**
 * Get matching tags.
 *
 * @param query
 *   The query string.
 */
$scope.tagsQuery = function (query) {
  var url = DrupalSettings.getBasePath() + 'api/v1/tags';
  var terms = {results: []};

  var lowerCaseTerm = query.term.toLowerCase();
  if (angular.isDefined($scope.tagsQueryCache[lowerCaseTerm])) {
    // Add caching.
    terms.results = $scope.tagsQueryCache[lowerCaseTerm];
    query.callback(terms);
    return;
  }

  $http.get(url, {
    params: {
      string: query.term
    }
  }).success(function(data) {

Mercury project

The pre-Pantheon days

Version 1

// Check if user has access.
function restful_get_access($object, $type)
{
    if ( entity_access ($type,$object) ) {
        return true;
    } else {
        return false;
    }
}
Code should be like Hiku pop.

Version 2

/**
 * Check if user has access.
 */
function restful_get_access($object, $type) {
  if (entity_access($type, $object)) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

Version 3

/**
 * Check if user has access.
 */
function restful_get_access($object, $type) {
  if (entity_access($type, $object)) {
    return TRUE;
  }
  return FALSE;
}

Version 4

/**
 * Check if user has access.
 */
function restful_get_access($object, $type) {
  return entity_access($type, $object);
}

Version 5

/**
 * Check if user has access.
 */
function restful_get_access($object, $type) {
  // ...
}

Version 6

/**
 * Check if user has access to a given entity.
 *
 * @param string $entity_type
 *   The entity type.
 * @param \Entity $entity
 *   The entity object.
 * @param stdClass $account
 *   (optional) The user object to perform the check on. If empty, Defaults to
 *   the current user.
 *
 * @return bool
 *   TRUE if the user has access to the entity, otherwise FALSE.
 */
function restful_get_access($entity_type, $entity, $account = NULL) {
  // ...
}
Implementation details

Version 7

/**
 * Check if user has access to a given entity.
 *
 * @param string $entity_type
 *   The entity type.
 * @param \Entity $entity
 *   The entity object.
 * @param stdClass $account
 *   (optional) The user object to perform the check on. If empty, Defaults to
 *   the current user.
 *
 * @return bool
 *   TRUE if the user has access to the entity, otherwise FALSE.
 */
function restful_get_access($entity_type, $entity, $account = NULL) {
  return entity_access($entity_type, $entity, $account);
}

Headless Drupal

Aesthetic Code

and some other burning issues

Josh Koenig - Pantheon(@outlandishjosh)
Amitai Burstein - Gizra (@amitaibu)

It must be the past because

  • You write Plain CSS
  • Your first solution to the problem is Views
  • You think you can do it all with just plain Drupal

2015: Headless Drupal

No longer monolithic Drupal. Front end advanced quickly.

Rest

https://example.com/node/1

RestWs

https://example.com/node/1.json
{
  body: {
    value: "<p>This is the body</p> ",
    format: "filtered_html"
  },
  field_tags: [ ],
  nid: "1",
  vid: "1",
  is_new: false,
  type: "article",
  title: "A new article",
  language: "und",
  status: "1",
  promote: "1",
  sticky: "0",
  revision: null,
}

GitHub on Rest

https://github.com/symfony/symfony2.json
{
  nid: "1",
  vid: "1",
  is_new: false,
  title: "Symfony2",
  type: "repository",
  field_user_ref: 100,
  language: "fr",
  // ...
}

RESTful

This module achieves a practical RESTful for Drupal following best practices.

RESTful

https://example.com/api/articles/1
{
  data: [
    {
      id: "1",
      label: "A new article",
      self: "https://example.com/api/v2.0/articles/1"
    }
  ],
  self: {
    title: "Self",
    href: "https://example.com/api/v2.0/articles/1"
  }
}
Expose bundles, Versionable API, Clean output

RESTful

https://example.com/api/v1.5/articles/1
{
  data: [
    {
      id: "1",
      label: "A new article",
      self: "https://example.com/api/v1.5/articles/1",
      text: "<p>This is the body</p> ",
      user: {
        id: "1",
        label: "admin",
        self: "https://example.com/api/v1.0/users/1",
        mail: "admin@example.com"
      }
    }
  ],
  self: {
    title: "Self",
    href: "https://example.com/api/v1.5/articles/1"
  }
}

RESTful

https://example.com/api/v1.5/articles/1
class RestfulExampleArticlesResource__1_5 extends RestfulEntityBaseNode {

  /**
   * Overrides RestfulEntityBaseNode::publicFieldsInfo().
   */
  public function publicFieldsInfo() {
    $public_fields = parent::publicFieldsInfo();

    $public_fields['text'] = array(
      'property' => 'field_text_area',
      'sub_property' => 'value',
    );

    $public_fields['user'] = array(
      'property' => 'author',
      'resource' => array(
        // The bundle of the entity.
        'user' => array(
          // The name of the resource to map to.
          'name' => 'users',
          // Determines if the entire resource should appear, or only the ID.
          'full_view' => TRUE,
        ),
      ),
    );


    return $public_fields;
  }
}

GET

// Get the RESTful handler.
$handler = restful_get_restful_handler('articles', 1, 5);

// Get a list of articles.
$result = $handler->get(); // https://example.com/api/v1.5/articles

// Sort list DESC.
$request = array(
  'sort' => array(
    'id' => 'DESC',
  ),
);
$result = $handler->get('', $request); // https://example.com/api/v1.5/articles/1?sort=-id

// Get article with ID 1.
$result = $handler->get(1); // https://example.com/api/v1.5/articles/1

POST, PATCH, PUT, DELETE

// Get the RESTful handler.
$handler = restful_get_restful_handler('articles', 1, 5);

// Create a new "article" resource.
$request = array('label' => 'My new article');
$result = $handler->post('', $request);

// Update just the label.
$request = array('label' => 'Edited label');
$handler->patch($result['id'], $request);

// Delete.
$handler->delete($result['id']);

Features

  • Authentication
  • Rate Limit
  • Render Cache
  • Data Providers (Entity, DB, CTools plugins)

Discovery

GET: https://example.com/api
{
  data: [
    {
      label: "Articles",
      description: "Export the article content type with "cookie" authentication.",
      name: "articles__2_0",
      resource: "articles",
      major_version: 2,
      minor_version: 0,
      self: "https://example.com/api/v2.0/articles"
    },
    {
      label: "Login",
      description: "Login a user and return a JSON along with the authentication cookie..",
      // ...
      self: "https://example.com/api/login"
    },
    {
      label: "File upload",
      description: "A file upload wrapped with RESTful.",
      // ...
      self: "https://example.com/api/file-upload"
    },
    {
      label: "CSRF token",
      description: "Export the CSRF token unique for each user.",
      // ...
      self: "https://example.com/api/session/token"
    },
  ],
  count: 10,
  self: {
    title: "Self",
    href: "https://example.com/api"
    }
  }
}

Discovery

OPTIONS: https://example.com/api/articles
{
  label: {
    info: {
      label: "Label",
      description: "The label of the resource."
    },
    data: {
      type: "string",
      read_only: false,
      cardinality: 1,
      required: false
    },
    form_element: {
      type: "texfield",
      default_value: "",
      placeholder: "",
      size: 255,
      allowed_values: null
    }
  }
}
Auto discovery apps that can crawl the backend. Quick post.

Features

  • Authentication
  • Rate Limit
  • Render Cache
  • Data Providers (Entity, DB, CTools plugins)
  • Formatters

Simple JSON

https://example.com/api/articles/1
{
  data: [
    {
      id: "1",
      label: "A new article",
      self: "https://example.com/api/v2.0/articles/1"
    }
  ],
  self: {
    title: "Self",
    href: "https://example.com/api/v2.0/articles/1"
  }
}

HAL+JSON

https://example.com/api/articles/1 Create your own formatter to fit existing apps
{
  hal:articles: [
    {
      id: "1",
      label: "A new article",
      _links: {
        self: {
          href: "https://example.com/api/v2.0/articles/1"
        }
      }
    }
  ],
  _links: {
    self: {
      title: "Self",
      href: "https://example.com/api/v2.0/articles/1"
    },
    curies: {
      name: "hal",
      href: "https://example.com/docs/rels/{rel}",
      templated: true
    }
  }
}

Features

  • Authentication
  • Rate Limit
  • Render Cache
  • Data Providers (Entity, DB, CTools plugins)
  • Formatters
  • Tests

Lots of tests ...

... executed every commit

https://github.com/Gizra/restful

Lets talk about tests

Lets imagine everyone actually wrote tests

Behat

Scenario: Validate a user can login to the site and see the homepage.
Given I visit "/user/login"
 # Fill the username and password input fields, and click submit
 When I fill "username" with "foo"
  And I fill "password" with "bar"
  And I press "Login"
 Then I should get a "200" HTTP response

Behat, Human readable

Scenario: Validate a user can login to the site and see the homepage.
Given I login with an "authenticated" user
 When I go to the homepage
 Then I should have access

Machine

Scenario: Validate a user has access to an article.
Given I login with an "authenticated" user
 When I go to "node/1"
 Then I should have access

Human

Scenario: Validate a user has access to an article.
Given I login with an "authenticated" user
 When I go to the content "My first article"
 Then I should have access
/**
 * @When /^I go to the content "([^"]*)"$/
 */
public function iGoToTheContent($title) {
  $query = new entityFieldQuery();
  $result = $query
    ->entityCondition('entity_type', 'node')
    ->propertyCondition('title', $title)
    ->propertyCondition('status', NODE_PUBLISHED)
    ->range(0, 1)
    ->execute();

  if (empty($result['node'])) {
    $params = array('@title' => $title);
    throw new Exception(format_string("Node @title not found.", $params));
  }

  $nid = key($result['node']);
  return new Given('I go to "node/' . $nid. '"');
}
Hedley

Clear Communication

Separate the wheat from the chaff

The same way you imagine the clean UI; Your code is the UI. Define the user. Keep it clear for all the "user" stack.