Fran García-Linares
fran.garcia@amazeelabs.com
Fran García-Linares, Drupal web developer
fjgarlin@gmail.com
https://www.drupal.org/u/fjgarlin
...linkedin, github, slides.com, strava → fjgarlin
Intro (5 min)
GraphQL (5 min)
GraphQL and Twig (20 min)
Steps to decoupling from here (5 min)
Q & A (5 min)
GraphQL?
GraphQL vs SQL
It usually appears next to
- JSON-API
- Decoupled build
- Apollo
- React, VueJS...
- Twig??
composer require drupal/graphql_twig
[drupal8-composer]$ composer require drupal/graphql_twig
Using version ^1.0@beta for drupal/graphql_twig
./composer.json has been updated
> DrupalProject\composer\ScriptHandler::checkComposerVersion
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
- Installing webonyx/graphql-php (v0.12.6): Loading from cache
- Installing drupal/graphql (3.0.0-rc3): Loading from cache
- Installing drupal/graphql_twig (1.0.0-beta11): Loading from cache
Writing lock file
Generating autoload files
> DrupalProject\composer\ScriptHandler::createRequiredFiles
drush -y en graphql_twig graphql_core
# development.services.yml
parameters:
twig.config:
debug: true
First template: node.html.twig
{#graphql
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
}
}
#}
<h5>
{{ "Title brought via GraphQL" | t }}:
<em>{{ graphql.node.title }}</em>
</h5>
<hr>
{# rest of file... #}
on hover...
on click...
First template: node.html.twig
Bring additional variables not available in the template.
# node.html.twig.gql
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
}
nodes:nodeQuery {
count
}
}
{# node.html.twig #}
<h5>
{{ "Title brought via GraphQL" | t}}:
<em>{{ graphql.node.title }}</em>
</h5>
<h6>
{{ "Pages on the site" | t}}:
{{ graphql.nodes.count }}
</h6>
<hr>
{# rest of file... #}
Problem: Bring total number of nodes on site and show on every node page
Classic Drupal Solutions:
// Get node count for site.
public function nodeCountState() {
$query = \Drupal::entityQuery('node')->condition('status', \Drupal\node\NodeInterface::PUBLISHED);
$result = $query->count()->execute();
return $result;
}
Problem: Bring total number of nodes on site and show on every node page
{#graphql
query() {
nodes:nodeQuery {
count
}
}
#}
...
{{ "Count" | t }}: {{ graphql.nodes.count }}
...
GraphQL + twig solution:
Problem: ... and languages available
{#graphql
query() {
languages:availableLanguages {
name
}
}
#}
...
<ul>
{% for language in graphql.languages %}
<li>{{ language.name }}</li>
{% endfor %}
</ul>
...
GraphQL + twig solution:
Problem: ... and all the previous and a count and list of users...
* It uses Drupal permissions so the data is curated
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
}
nodes:nodeQuery {
count
}
languages:availableLanguages {
id
name
}
users:userQuery {
count
list:entities {
name:entityLabel
}
}
}
GraphQL + twig solution:
and...
Recap soft decoupling
1. Take .twig file
2. Change twig logic for React / Vue logic
import React from "react";
import { render } from "react-dom";
import { ApolloClient, gql, ApolloProvider, Query } from "react-apollo";
const client = new ApolloClient({ uri: "https://drupal.url/graphql" });
const graphql_query = gql`
query {
user:userById(id: "1") {
label:entityLabel
}
}
`;
const App = () => (
<ApolloProvider client={client}>
<Query query={graphql_query}>
{({ loading, error, data }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error </div>;
return <div>{data.user.label}</div>;
}}
</Query>
</ApolloProvider>
);
render(App, document.getElementById("root"));
{#graphql
query($user: String!) {
user:userById(id: $user) {
label:entityLabel
}
}
#}
<div>
{{ graphql.data.user.label }}
</div>
removing app code >>>
1. Take .twig file
2. Change twig logic for React / Vue logic
{#graphql
query($user: String!) {
user:userById(id: $user) {
label:entityLabel
}
}
#}
<div>
{{ graphql.data.user.label }}
</div>
// imports, graphql endpoint...
const graphql_query = gql`
query {
user:userById(id: "1") {
label:entityLabel
}
}
`;
// app stuff...
<Query query={graphql_query}>
{({ loading, error, data }) => {
return <div>{data.user.label}</div>;
}}
</Query>
// app stuff...