using vuejs in front of drupal 8
TRANSCRIPT
Hello, i’m Bri(an)• Twitter: @brian_ward • Drupal: drupal.org/u/briward • Website: briward.com
2 @brian_ward
“But we already have a theme-layer in Drupal?”
6 @brian_wardBut we already have a theme-layer in Drupal?
Remember, you don’t have to make it fully headless
@brian_wardBut we already have a theme-layer in Drupal? 7
benefits?• Flexibility. • Decoupled architecture. • (easily) Upgradable/changeable front-end. • Dedicated/Focused teams. • Happy front-end developers.
9 @brian_wardBut we already have a theme-layer in Drupal?
What are the
RESTful Web ServicesRESTful Web Services exposes entities and
other resources as a RESTful web API.
Required
11 @brian_wardSo what do we get out of the box?
SerializationSerialization module provides a service for (de)serializing data to/from formats such as
JSON and XML
Required
12 @brian_wardSo what do we get out of the box?
HALSerializes entities using Hypertext
Application Language (HAL)
Optional
13 @brian_wardSo what do we get out of the box?
RESTUIProvides a user interface for managing REST
resources.
Recommended
14 @brian_wardSo what do we get out of the box?
16 @brian_ward3 ways to create a REST API with D8
Using the core RestResources
Using View REST exports
Create custom REST resources
Option #1
Option #2
Option #3
Using the core REST resources
/node/{node} /entity/block/{block} /comment/{comment} /entity/comment_type/{comment_type}
@brian_ward17
Option #1
Using the core REST resources
Pros & Cons
@brian_ward20
✓ Straight out of the box. ✓ Requires almost no setup. ✓ No custom code necessary.
- Exposes system information. - Absolutely no flexibility. - Lacks ability to version. - Unable to limit output.
Using the core REST resources
Using views REST exportViews is now in core and also comes bundled with REST
support out of the box.
21 @brian_ward
Option #2
Using views REST export
23 @brian_ward
Pros & Cons✓ Straight out of the box. ✓ Familiar to developers. ✓ Manageable within the UI.
- Returns data with incorrect types. - More flexibility, but still limited in
various areas. - Authentication issues.
Using views REST export
Creating custom REST resourcesOption #3 (recommended)
Being object-oriented by nature, D8 allows us to extend the base ResourceBase class and create our own custom resources. This
would be my recommendation.
24 @brian_wardCreating custom rest resources
/** * Provides a resource to get articles by UUID. * * @RestResource( * id = "articles", * label = @Translation("Articles (v1.0)"), * uri_paths = { * "canonical" = "/api/v1.0/articles/{uuid}" * } * ) */ class ArticleBundleResource extends ResourceBase { }
25Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
public function getArticle($uuid) { $entity = \Drupal::entityManager()->getStorage(‘node') ->loadByProperties([ 'uuid' => $uuid, 'type' => 'article' ]); return reset($entity);
}
26Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
public function get($uuid = NULL) { if (Uuid::isValid($uuid)) { $entity = $this->getArticle($uuid); return new ResourceResponse($this->transform($entity)); } else { return new ResourceResponse([ ‘http_code’ => 400, ‘error' => 100, 'message' => 'The UUID supplied is invalid.' ], 400); } }
27Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
private function transform($entity) { return [ 'id' => (int) $entity->nid[0]->value, 'title' => (string) $entity->title[0]->value, 'published' => (bool) $entity->published[0]->value, ];}
28Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
Pros & Cons✓ Provides most flexibility. ✓ Transformable output. ✓ Easier to manage versions.
- Requires reasonable programming knowledge.
@brian_ward29Creating custom rest resources
HATEOASAPI Theory
HATEOAS is a constraint of the REST application architecture. In a nutshell, it is providing information on how to navigate the site's REST resources dynamically by including hypermedia links with
the responses.
30 @brian_wardHATEOAS
Content negotiationTo put it simply, this is the mechanism for determining what
content-type the data will be returned in.
31 @brian_wardHATEOAS
Content negotiation
32 @brian_wardHATEOAS
?_format=jsonBasically, this is the mechanism for determining what content-type
the data will be returned in. Ideally, we would want to use an “accept” header.
Hypermedia controls
34
Provide links to related endpoints so users of your api can easily find their way around your data.
@brian_wardHATEOAS
private function transform($entity) { return [ 'links' => [ [ 'rel' => 'self', 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value ] ] ];}
35Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
'links' => [ [ 'rel' => 'self', 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value ], [ 'rel' => ‘article.comments’, 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value.'/comments' ] ]
Plugin/Rest/Resource/ArticleBundleResource.php 36 @brian_ward
Versioning
38 @brian_ward
As Phil Sturgeon says “There are many wrong ways to version your API”. Don’t get too caught up about this.
@brian_ward40
Now that we have created our API, we can play around with it on the front-end.
Now we’re ready
Introducing Vue.jsVue.js is a MVVM JavaScript library for building modern web
interfaces. It provides data-reactive components with a simple and flexible API.
@brian_ward41Introducing Vue.js
Top trending JS framework on Github.
@brian_wardIntroducing Vue.js 42
First stable version released earlier this month.
Evan You is also a core developer on the MeteorJS project & previously a Google employee.
Has awesome documentation.
Viewnew Vue({ el: '#app' })
Each Vue instance is associated with a DOM element (el).
44 @brian_wardIntroducing Vue.js
ViewModel
45 @brian_ward
new Vue({ /* options */ })
• An object that syncs the Model and the View. • Every Vue instance is a ViewModel.
Introducing Vue.js
Modelnew Vue({ data: {} })
An object that is used as data inside a Vue instance will become reactive (Vue instances that are observing our objects
will be notified of the changes).
@brian_ward46Introducing Vue.js
var MyComponent = Vue.extend({})
Components
47 @brian_ward
Components are simply a convenient way to structure and organise our applications.
Optional
Introducing Vue.js
Browserify & Vueifyrequire('./app.vue')
48 @brian_ward
Browserify lets you require('modules') in the browser by bundling up all of your dependencies.
Optional
Introducing Vue.js
this.$http.get(url, callback)
VueResource
Using the official Vue-Resource plugin, we can request and store our Drupal content as data objects.
Recommended
49 @brian_wardIntroducing Vue.js
router.on(url, callback)
Director
A tiny and isomorphic URL router for JavaScript
Recommended
50 @brian_wardIntroducing Vue.js
Great, let’s see that in action!Firstly we will need to create our package.json, HTML &
bootstrap JS files. From there we’ll load in our components and interact with our API.
@brian_ward53Introducing Vue.js
{ "main": "./src/app.js", "scripts": { "watch": "watchify -v -t vueify -e ./src/app.js -o build/build.js" }, "devDependencies": { "vueify": "^1.1.5", "watchify": "^3.3.1" }, "dependencies": { "director": "^1.2.8", "vue": "^0.12.9", "vue-resource": "^0.1.11" } }
package.json 54 @brian_ward
<!DOCTYPE html> <html> <head> <meta charset=“utf-8"></head> <body> <div id="app"></div> <!-- Load our build script --> <script src="build/build.js"></script> </body> </html>
55index.html @brian_ward
/** * Boot up the Vue instance with the VueResource plugin. */ var Vue = require(‘vue')Vue.use(require(‘vue-resource’))
var app = new Vue(require('./app.vue'))
56start.js @brian_ward
/** * Wire up the router. */ var Router = require('director').Router var router = new Router() router.on(‘/articles/:uuid’, function (uuid) { app.view = 'article-view' app.params.uuid = uuid }) router.init('/')
57start.js @brian_ward
<template> <component is="{{ view }}" class="view" params="{{ params }}" v-transition transition-mode="out-in"> </component> </template>
58app.vue @brian_ward
<script> module.exports = { el: '#app', data: { view: '', params: { uuid: '' } }, components: { 'article-view': require('./views/article-view.vue') } } </script>
59app.vue @brian_ward
<template> <div class="post full"> <article class="post-content"> <h1 v-text="article.title"></h1> <div v-html="article.body"></div> </article> </div> </template>
60article-view.vue @brian_ward
61
<template> <div class="post full"> <article class="post-content"> <h1>{{ article.title }}</h1> <div>{{{ article.body }}}</div> </article> </div> </template>
@brian_wardarticle-view.vue
<script> module.exports = { props: ['params'], data: function () { return { article: {} } }, ready: function() { var url = '/api/v1.0/articles/' + uuid + '?_format=json'; this.$http.get(url, function (article) { this.$set('article', article) }) } } </script>
62 @brian_wardarticle-view.vue
And that’s it.By using Drupal 8 and Vue.js we’re able to create a beautiful,
maintainable and de-coupled application.
https://github.com/briward/examples
63 @brian_ward
Useful links
65 @brian_ward
• http://vuejs.org • https://en.wikipedia.org/wiki/Model_View_ViewModel • http://browserify.org • https://github.com/vuejs/vueify • http://vuejs.org/guide/components.html • http://www.w3.org/TR/components-intro • http://drupal.org/project/restui • ...how-to-enable-cors-requests-against-drupal-8/ • Phil Sturgeon’s book “Build APIs you won’t hate”.