Drupaldelphia 2018: Drupal Unhitched: The CMS in Decoupled Architectures

Drupaldelphia 2018: Drupal Unhitched: The CMS in Decoupled Architectures

D74c365206652832a56fd9ba1fb61d99?s=128

dirtystylus

April 27, 2018
Tweet

Transcript

  1. Drupal Unhitched The CMS in Decoupled Architectures Drupaldelphia 2018 Drupal

    Unhitched / @dirtystylus 1
  2. Hi. Mark Llobrera Technology Director, Bluecadet Philadelphia @dirtystylus @bluecadet Drupal

    Unhitched / @dirtystylus 2
  3. Drupal Unhitched / @dirtystylus 3

  4. Drupal Unhitched / @dirtystylus 4

  5. Drupal Unhitched / @dirtystylus 5

  6. Descriptive, Not Prescriptive I’m not telling you how to do

    this stuff. But I hope all of this helps. Drupal Unhitched / @dirtystylus 6
  7. 3 Things Drupal Unhitched / @dirtystylus 7

  8. 3 Things 1. What is a decoupled CMS? Drupal Unhitched

    / @dirtystylus 7
  9. 3 Things 1. What is a decoupled CMS? 2. Decoupled

    Scenarios Drupal Unhitched / @dirtystylus 7
  10. 3 Things 1. What is a decoupled CMS? 2. Decoupled

    Scenarios 3. Decoupling Drupal Drupal Unhitched / @dirtystylus 7
  11. 1. What is a Decoupled CMS? Drupal Unhitched / @dirtystylus

    8
  12. What is a decoupled CMS? Drupal Unhitched / @dirtystylus 9

  13. What is a decoupled CMS? —An architecture for websites and

    applications where the CMS is not used to render the user- facing site or application. Drupal Unhitched / @dirtystylus 9
  14. Stop me if you’ve heard this one before Drupal Unhitched

    / @dirtystylus 10
  15. Separating CONTENT from PRESENTATION Drupal Unhitched / @dirtystylus 11

  16. 2. Decoupled Scenarios Drupal Unhitched / @dirtystylus 12

  17. CMS (Drupal 8) + Touchscreen Interactive (React) + JS Website

    (React) Drupal Unhitched / @dirtystylus 13
  18. Drupal Unhitched / @dirtystylus 14

  19. Drupal Unhitched / @dirtystylus 15

  20. Drupal Unhitched / @dirtystylus 16

  21. Drupal Unhitched / @dirtystylus 17

  22. Drupal Unhitched / @dirtystylus 18

  23. CMS (Drupal 8) + CMS-rendered Website + Digital Signage (React)

    Drupal Unhitched / @dirtystylus 19
  24. Drupal Unhitched / @dirtystylus 20

  25. Drupal Unhitched / @dirtystylus 21

  26. Drupal Unhitched / @dirtystylus 22

  27. Drupal Unhitched / @dirtystylus 23

  28. CMS + CMS-rendered Website + React components Drupal Unhitched /

    @dirtystylus 24
  29. Drupal Unhitched / @dirtystylus 25

  30. Drupal Unhitched / @dirtystylus 26

  31. CMS + Statically Published React (GatsbyJS) Drupal Unhitched / @dirtystylus

    27
  32. Drupal Unhitched / @dirtystylus 28

  33. Drupal Unhitched / @dirtystylus 29

  34. Drupal Unhitched / @dirtystylus 30

  35. Drupal Unhitched / @dirtystylus 31

  36. CMS (Drupal 7) + CMS-rendered Website + Touch Wall (Cinder/C++)

    + 2 Touchscreen Interactives (AngularJS) + iOS / Android Native Applications Drupal Unhitched / @dirtystylus 32
  37. Drupal Unhitched / @dirtystylus 33

  38. Drupal Unhitched / @dirtystylus 34

  39. Drupal Unhitched / @dirtystylus 35

  40. Drupal Unhitched / @dirtystylus 36

  41. Drupal Unhitched / @dirtystylus 37

  42. Drupal Unhitched / @dirtystylus 38

  43. PROS and CONS Drupal Unhitched / @dirtystylus 39

  44. Pros Drupal Unhitched / @dirtystylus 40

  45. Pros —Back and Front End systems are swappable Drupal Unhitched

    / @dirtystylus 40
  46. Pros —Back and Front End systems are swappable —Teams can

    divide and conquer Drupal Unhitched / @dirtystylus 40
  47. Cons Drupal Unhitched / @dirtystylus 41

  48. Cons —Larger tech stack (Drupal, JS, multiple environments) Drupal Unhitched

    / @dirtystylus 41
  49. Cons —Larger tech stack (Drupal, JS, multiple environments) —Maintenance Drupal

    Unhitched / @dirtystylus 41
  50. Cons —Larger tech stack (Drupal, JS, multiple environments) —Maintenance —For

    websites you lose built-in functionality of CMS: menus/routing/accessibility/SEO Drupal Unhitched / @dirtystylus 41
  51. 3. Decoupling Drupal Drupal Unhitched / @dirtystylus 42

  52. Start with Content Drupal Unhitched / @dirtystylus 43

  53. Start with Content —Getting content ready to travel Drupal Unhitched

    / @dirtystylus 43
  54. Start with Content —Getting content ready to travel —NO Presentation

    specific names NO Drupal Unhitched / @dirtystylus 43
  55. Start with Content —Getting content ready to travel —NO Presentation

    specific names NO —Decouple your mind Drupal Unhitched / @dirtystylus 43
  56. Start with Content —Getting content ready to travel —NO Presentation

    specific names NO —Decouple your mind —Content in many forms/faces Drupal Unhitched / @dirtystylus 43
  57. Two Content Types Drupal Unhitched / @dirtystylus 44

  58. Two Content Types —Author Drupal Unhitched / @dirtystylus 44

  59. Two Content Types —Author —Book Drupal Unhitched / @dirtystylus 44

  60. Author Drupal Unhitched / @dirtystylus 45

  61. Book Drupal Unhitched / @dirtystylus 46

  62. HOW?? Drupal Unhitched / @dirtystylus 47

  63. HOW?? —Core: RESTful Web Services Drupal Unhitched / @dirtystylus 47

  64. HOW?? —Core: RESTful Web Services —Custom Controller Drupal Unhitched /

    @dirtystylus 47
  65. HOW?? —Core: RESTful Web Services —Custom Controller —JSON API Drupal

    Unhitched / @dirtystylus 47
  66. HOW?? —Core: RESTful Web Services —Custom Controller —JSON API —GraphQL

    Drupal Unhitched / @dirtystylus 47
  67. RESTful Web Services Two basic approaches: Drupal Unhitched / @dirtystylus

    48
  68. RESTful Web Services Two basic approaches: —Core RESTful Services Drupal

    Unhitched / @dirtystylus 48
  69. RESTful Web Services Two basic approaches: —Core RESTful Services —REST

    Exports Drupal Unhitched / @dirtystylus 48
  70. Core RESTful Services Drupal Unhitched / @dirtystylus 49

  71. Core RESTful Services —Core REST Module Drupal Unhitched / @dirtystylus

    49
  72. Core RESTful Services —Core REST Module —REST UI Module https://drupal.org/project/restui

    Drupal Unhitched / @dirtystylus 49
  73. Request: /node/1?format=json Drupal Unhitched / @dirtystylus 50

  74. { "nid": [ { "value": 1 } ], "uuid": [

    { "value": "3036ea2d-7502-4c64-8bc6-2e9ee3a0f897" } ], "vid": [ { "value": 1 } ], "langcode": [ { "value": "en" } ], "type": [ { "target_id": "book", "target_type": "node_type", "target_uuid": "a3c32842-68b2-46fd-b70e-d6ed9e71ee2d" } ], "revision_timestamp": [ { "value": "2018-04-23T18:10:59+00:00", "format": "Y-m-d\\TH:i:sP" } ], "revision_uid": [ { "target_id": 1, "target_type": "user", "target_uuid": "a7484c09-d013-402e-b070-46c0d84a7b28", "url": "/user/1" } ], "revision_log": [], "status": [ { "value": true } ], "title": [ { "value": "The Fifth Season" } ], "uid": [ { "target_id": 1, "target_type": "user", "target_uuid": "a7484c09-d013-402e-b070-46c0d84a7b28", "url": "/user/1" } ], "created": [ { "value": "2018-04-23T18:10:29+00:00", "format": "Y-m-d\\TH:i:sP" } ], "changed": [ { "value": "2018-04-23T18:10:59+00:00", "format": "Y-m-d\\TH:i:sP" } ], "promote": [ { "value": true } ], "sticky": [ { "value": false } ], "default_langcode": [ { "value": true } ], "revision_translation_affected": [ { "value": true } ], "path": [ { "alias": null, "pid": null, "langcode": "en" } ], "body": [ { "value": "<p>Part one of the Broken Earth trilogy.</p>\r\n", "format": "basic_html", "processed": "<p>Part one of the Broken Earth trilogy.</p>", "summary": "" } ] } Drupal Unhitched / @dirtystylus 51
  75. { "nid": [ { "value": 1 } ], "type": [

    { "target_id": "book", "target_type": "node_type", "target_uuid": "a3c32842-68b2-46fd-b70e-d6ed9e71ee2d" } ], "title": [ { "value": "The Fifth Season" } ], "body": [ { "value": "<p>Part one of the Broken Earth trilogy.</p>\r\n", "format": "basic_html", "processed": "<p>Part one of the Broken Earth trilogy.</p>", "summary": "" } ] } Drupal Unhitched / @dirtystylus 52
  76. REST Exports Drupal Unhitched / @dirtystylus 53

  77. REST Exports —Views! (! old friend) Drupal Unhitched / @dirtystylus

    53
  78. REST Exports —Views! (! old friend) —“Provide a REST Export”

    checkbox ✅ Drupal Unhitched / @dirtystylus 53
  79. Drupal Unhitched / @dirtystylus 54

  80. Drupal Unhitched / @dirtystylus 55

  81. Drupal Unhitched / @dirtystylus 56

  82. [ { "title": "Kim Stanley Robinson", "body": "<p>Author of the

    <em>Mars</em> trilogy and <em>New York 2140</em>.</p>\r\n", "field_books": [ "2" ] }, { "title": "N. K. Jemisin", "body": "<p>Hugo Award-winning author of the Broken Earth trilogy.</p>\r\n", "field_books": [ "1" ] } ] Drupal Unhitched / @dirtystylus 57
  83. Custom Controller Drupal Unhitched / @dirtystylus 58

  84. Custom Controller Drupal Unhitched / @dirtystylus 59

  85. Custom Controller —Routing (YML) Drupal Unhitched / @dirtystylus 59

  86. Custom Controller —Routing (YML) —Controller Class Drupal Unhitched / @dirtystylus

    59
  87. Routing mann.season: path: 'api/season' defaults: _controller: \Drupal\mann_api\Controller\Season::api methods: [GET] requirements:

    _access: 'TRUE' Drupal Unhitched / @dirtystylus 60
  88. … $a_query = \Drupal::entityQuery('node'); $a_query->condition('status', 1); $a_query->condition('type', 'event'); $entity_ids =

    $a_query->execute(); $events = Node::loadMultiple($entity_ids); foreach ($events as $event) { $item['id'] = (int) $event->nid->value; $date = $event->field_event_date->value; $item['date'] = $date; $item['title'] = $event->title->value; $item['display_title'] = $event->field_display_title->value; $image_data = MediaAssetService::getMediaPathSingle($event, 'field_featured_image'); $item['image'] = urldecode($image_data['image']); $item['image_relative'] = urldecode($image_data['image_relative']); $data[] = $item; } $response = new JsonResponse(['data' => $data]); return $response; … Drupal Unhitched / @dirtystylus 61
  89. JSON API https://www.drupal.org/project/jsonapi Drupal Unhitched / @dirtystylus 62

  90. Out of the box: /jsonapi/node/[Content Type] for example: /jsonapi/node/author Drupal

    Unhitched / @dirtystylus 63
  91. { "data": [ { "type": "node--author", "id": "88223a76-278d-4fc6-9945-0bdb56cc78d3", "attributes": {

    "nid": 2, "body": { "value": "<p>Winner of the Hugo Award.</p>\r\n", "format": "basic_html", "processed": "<p>Winner of the Hugo Award.</p>", "summary": "" }, "field_display_name": { "value": "N. K. Jemisin", "format": "basic_html", "processed": "N. K. Jemisin" } }, "relationships": { "field_books": { "data": [ { "type": "node--book", "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f" } ], }, } ], } Drupal Unhitched / @dirtystylus 64
  92. { "attributes": { "nid": 2, "body": { "value": "<p>Winner of

    the Hugo Award.</p>\r\n", "format": "basic_html", "processed": "\<p>Winner of the Hugo Award.</p>", "summary": "" }, "field_display_name": { "value": "N. K. Jemisin", "format": "basic_html", "processed": "N. K. Jemisin" } }, } Drupal Unhitched / @dirtystylus 65
  93. { "relationships": { "field_books": { "data": [ { "type": "node--book",

    "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f" } ], }, } Drupal Unhitched / @dirtystylus 66
  94. Relationships are complicated /jsonapi/node/[Content Type]?include=[Field Name] for example (we want

    field_books): /jsonapi/node/author?include=field_books Drupal Unhitched / @dirtystylus 67
  95. { "included": [ { "type": "node--book", "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f", "attributes": {

    "nid": 1, "title": "The Fifth Season", "body": { "value": "<p>Part one of the Broken Earth trilogy.</p>\r\n", "format": "basic_html", "processed": "<p>Part one of the Broken Earth trilogy.</p>", "summary": "" } }, } } Drupal Unhitched / @dirtystylus 68
  96. "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f" Drupal Unhitched / @dirtystylus 69

  97. GraphQL https://www.drupal.org/project/graphql Drupal Unhitched / @dirtystylus 70

  98. Installation Note Drupal Unhitched / @dirtystylus 71

  99. Installation Note —Download the module (or use drush dl graphql)

    Drupal Unhitched / @dirtystylus 71
  100. Installation Note —Download the module (or use drush dl graphql)

    —Run composer require webonyx/graphql-php at root level (error otherwise) Drupal Unhitched / @dirtystylus 71
  101. Installation Note —Download the module (or use drush dl graphql)

    —Run composer require webonyx/graphql-php at root level (error otherwise) —Enable the module Drupal Unhitched / @dirtystylus 71
  102. Explorer allows you to test out queries Drupal Unhitched /

    @dirtystylus 72
  103. Drupal Unhitched / @dirtystylus 73

  104. Auto-complete! Drupal Unhitched / @dirtystylus 74

  105. Drupal Unhitched / @dirtystylus 75

  106. Simple Query query { nodeQuery { entities { entityId, entityLabel

    } } } Drupal Unhitched / @dirtystylus 76
  107. { "data": { "nodeQuery": { "entities": [ { "entityId": "1",

    "entityLabel": "The Fifth Season" }, { "entityId": "2", "entityLabel": "New York 2140" }, { "entityId": "3", "entityLabel": "N. K. Jemisin" }, { "entityId": "4", "entityLabel": "Kim Stanley Robinson" } ] } } } Drupal Unhitched / @dirtystylus 77
  108. Node Query w/ Types (Author) query { nodeQuery { entities

    { ...on NodeAuthor { entityId title body { value } fieldDisplayName { value } fieldBooks { entity { entityId title } } } } } } Drupal Unhitched / @dirtystylus 78
  109. References are Easy(ish) fieldBooks { entity { entityId title }

    } Drupal Unhitched / @dirtystylus 79
  110. { "data": { "nodeQuery": { "entities": [ {}, {}, {

    "entityId": "3", "title": "N. K. Jemisin", "body": { "value": "<p>Hugo Award-winning author of the Broken Earth trilogy.</p>\r\n" }, "fieldDisplayName": { "value": "N. K. Jemisin" }, "fieldBooks": [ { "entity": { "entityId": "1", "title": "The Fifth Season" } } ] }, { "entityId": "4", "title": "Kim Stanley Robinson", "body": { "value": "<p>Author of the <em>Mars</em> trilogy and <em>New York 2140</em>.</p>\r\n" }, "fieldDisplayName": { "value": "Kim Stanley Robinson" }, "fieldBooks": [ { "entity": { "entityId": "2", "title": "New York 2140" } } ] } ] } } } Drupal Unhitched / @dirtystylus 80
  111. query { nodeQuery { entities { ...on NodeAuthor { entityId

    title body { value } fieldDisplayName { value } fieldBooks { entity { entityId title } } } ...on NodeBook { entityId title body { value } } } } } Drupal Unhitched / @dirtystylus 81
  112. Filter by Node Type query { nodeQuery (filter: {conditions: [{

    field: "type" value: "author" operator: EQUAL }] } ) { … } } Drupal Unhitched / @dirtystylus 82
  113. query { nodeQuery (filter: {conditions: [{ field: "type" value: "author"

    operator: EQUAL }] } ) { entities { ...on NodeAuthor { entityId title body { value } fieldBooks { entity { title body { value } } } } } } } Drupal Unhitched / @dirtystylus 83
  114. { "data": { "nodeQuery": { "entities": [ { "entityId": "3",

    "title": "N. K. Jemisin", "body": { "value": "<p>Hugo Award-winning author of the Broken Earth trilogy.</p>\r\n" }, "fieldBooks": [ { "entity": { "title": "The Fifth Season", "body": { "value": "<p>Part one of the Broken Earth trilogy.</p>\r\n" } } } ] }, Drupal Unhitched / @dirtystylus 84
  115. Bonus: Communication Drupal Unhitched / @dirtystylus 85

  116. We’ve tried: Drupal Unhitched / @dirtystylus 86

  117. We’ve tried: —Polling for changes (are we there yet?) Drupal

    Unhitched / @dirtystylus 86
  118. We’ve tried: —Polling for changes (are we there yet?) —NodeJS

    (get a server in the middle, maybe Socket I/O) Drupal Unhitched / @dirtystylus 86
  119. Enter Progressive Web Applications Drupal Unhitched / @dirtystylus 87

  120. Enter Progressive Web Applications —CMS to Application communication is a

    use case Drupal Unhitched / @dirtystylus 87
  121. Enter Progressive Web Applications —CMS to Application communication is a

    use case —PWAs have Service Workers and Push Notifications Drupal Unhitched / @dirtystylus 87
  122. Web Push API Drupal Unhitched / @dirtystylus 88

  123. Web Push API —Gives web applications the ability to receive

    messages pushed to them from a server Drupal Unhitched / @dirtystylus 88
  124. Web Push API —Gives web applications the ability to receive

    messages pushed to them from a server —Requires a subscription to be activated, but once allowed, the subscription is saved by the browser Drupal Unhitched / @dirtystylus 88
  125. Web Push API —Gives web applications the ability to receive

    messages pushed to them from a server —Requires a subscription to be activated, but once allowed, the subscription is saved by the browser —You can pass “messages”, but fundamentally you are passing data for your app or website to interpret as you see fit Drupal Unhitched / @dirtystylus 88
  126. Web Push API —Gives web applications the ability to receive

    messages pushed to them from a server —Requires a subscription to be activated, but once allowed, the subscription is saved by the browser —You can pass “messages”, but fundamentally you are passing data for your app or website to interpret as you see fit —Browsers handle pushing the data through Service Workers, so a third party is not required Drupal Unhitched / @dirtystylus 88
  127. Fine Print Drupal Unhitched / @dirtystylus 89

  128. Fine Print —Limited browser support: ✅ Chrome, ✅ Firefox, "

    Safari (coming soon?) Drupal Unhitched / @dirtystylus 89
  129. Fine Print —Limited browser support: ✅ Chrome, ✅ Firefox, "

    Safari (coming soon?) —Spec is considered experimental, so it may change in the future Drupal Unhitched / @dirtystylus 89
  130. Fine Print —Limited browser support: ✅ Chrome, ✅ Firefox, "

    Safari (coming soon?) —Spec is considered experimental, so it may change in the future —Great for kiosks, but in the wild, you can’t guarantee that a user will subscribe Drupal Unhitched / @dirtystylus 89
  131. Fine Print —Limited browser support: ✅ Chrome, ✅ Firefox, "

    Safari (coming soon?) —Spec is considered experimental, so it may change in the future —Great for kiosks, but in the wild, you can’t guarantee that a user will subscribe —Sockets for non-web-based projects (Cinder/C++, Unity) Drupal Unhitched / @dirtystylus 89
  132. Drupal Unhitched / @dirtystylus 90

  133. Where to Next? Drupal Unhitched / @dirtystylus 91

  134. Where to Next? —Two-way communication Drupal Unhitched / @dirtystylus 91

  135. Where to Next? —Two-way communication —Content Authoring via JS Front

    End (WordPress and Drupal) Drupal Unhitched / @dirtystylus 91
  136. Takeaways Drupal Unhitched / @dirtystylus 92

  137. Takeaways —Start with your Content, and make that portable Drupal

    Unhitched / @dirtystylus 92
  138. Takeaways —Start with your Content, and make that portable —There’s

    many different ways to expose your content Drupal Unhitched / @dirtystylus 92
  139. Takeaways —Start with your Content, and make that portable —There’s

    many different ways to expose your content —You can do this! Drupal Unhitched / @dirtystylus 92
  140. We’re hiring. Drupal Unhitched / @dirtystylus 93

  141. THANK YOU. Mark Llobrera Technology Director, Bluecadet Philadelphia @dirtystylus @bluecadet

    Drupal Unhitched / @dirtystylus 94