This document discusses decoupling a Drupal backend from a React frontend using JSONAPI. It provides an overview of the technology stack including Express, React, Redux and Drupal with JSONAPI. It discusses reasons for the decoupled approach including performance improvements. It also covers editorial workflows, structured vs unstructured content, and implementing a content preview feature between the decoupled systems.
5. Things we’re about to discuss…
• Reasons to take on a decoupled project – or not
• Structured data!
• How the technology works
• Editorial modes
• Performance
• Bonus content: the problem of preview
7. Why build one website,
when two can do the same job?
Wait no, reverse that…
8. • Distribution of data to other platforms becomes
possible
• Over time, lightweight design changes are possible
without a total rebuild
• Performance turned out to be the killer app for
Edutopia
Why decoupled?
13. JSONAPI 101: What’s a JSONAPI?
• Contributed module for Drupal
• Renders pretty much any entity as JSON data
• /jsonapi/node/article/{UUID}
• /jsonapi/{entity}/{bundle}/{UUID}
• Also allows:
• lists of content
• filters by field
• inclusion of other content via entity reference
• Respects permissions in Drupal
14. What makes a good API?
Your API needs
structured content
18. Receive API
request and
look up data
Normalize,
and render
JSONAPI response
Handle API
Response Save data to state
Render!
Express
Redux/React
Drupal
Receive request
Parse request and
dispatch API call
19. Routing URLs from React to Drupal
Page Request: https://www.edutopia.org/article/when-rubric-isnt-enough
URL slug (): article/when-rubric-isnt-enough
API request: /jsonapi/node/article?filter[field_url_slug][value]=article/when-rubric-
isnt-enough
20. Handle API
Response Save data to state
Render!
Drupal
Redux/React
Express
Receive API
request and
look up data
Normalize,
and render
JSONAPI response
Receive request
Parse request and
dispatch API call
27. Redux/React
Express
Drupal
Receive request
Parse request and
dispatch API call
Stock JSONAPI
endpoint
Normalize,
and render
JSONAPI response
Handle API
Response Save data to state
Render!
Quit trying so
hard and just ask
Drupal what it is.
Custom
resolver
endpoint
28. Outcome of hacking JSONAPI and React:
• Performance was fine
• The system worked great
• We introduced finicky maintenance issues due to non-standard ways
of using React/Redux.
• Doing things in the wrong order has a cost – but the business need
was met.
37. CMS Implementation
• media module for images, video and documents
• entity embed + inline entity form
• hidden entity ref fields that stored the media entities
referenced in the body field
• alterations to media browser modals for field
overrides
• ckeditor customizations for specific cases
44. Performance!
• Code splitting reduced JS bundle sizes by ~40%
• Lazy-load of images and related content in articles improved load
times by nearly a second.
• Preloading content allows for sub-second response times within the
site.
• Sparse fieldsets
45. More JSONAPI: Sparse fieldsets
• Normally, relationships and includes load the WHOLE
related entity
• You can specify the data payload only contain what
you want, by listing those fields in your request.
46. Example: fields[bundle--type]={comma separated list of
fields}
/jsonapi/node/landing_page?_format=api_json&filter[field_url_slug][valu
e]=videos&include=related_content&fields[node--article]=
uuid,id,nid,title,field_cover_media,field_cover_media_display,field_sum
mary,field_eyebrow,field_url_slug,field_video,field_video_still,field_autho
rs,field_intro
More JSONAPI: Sparse fieldsets
47. Sparse fieldsets reduced the size of
API payloads by 60% or more
- as much as 90% in some cases.
48. • Two websites is definitely twice the work
• You’ll have to reinvent the wheel sometimes
• Everything is harder
• But you gain the capacity for multichannel publishing
• And you might have the fastest site on the block
Takeaways…
50. Preview: Content Moderation + JSONAPI
• These two very fine modules don’t talk to each other
• We made an endpoint that serves revisions through JSONAPI
• JSONAPI respects permissions, so we can secure this out of the box.
• Hacked revisions tab and node views to render links to the preview
front-end
51.
52. Preview: front-end considerations
• Separate web host for previews
• Same codebase, different config
• Routing of preview URLs triggers API request to the Preview endpoint
• Authentication support between front-end and Drupal
• Preview mode on the front-end is configurable, so that previews can’t
be rendered on prod
Editor's Notes
Tech vs. Business stakeholders?
Interested newcomers?
Explored React, Angular or similar JS frameworks?
How many of you have built decoupled projects?
50 or so ‘bots across N. America and Europe
Fully distributed
Work for government, finance, and media companies doing large-scale digital publishing
Syfy.com, NYU School of medicine.
Tech vs. Business stakeholders?
Interested newcomers?
Explored React, Angular or similar JS frameworks?
How many of you have built decoupled projects?
Thanks for that background – So what are we going to do today?
Our discovery process @lullabot always asks this… because decoupled isn’t for everyone.
reinventing the wheel … error handling, logging, authentication, preview
retool your development team…
At least twice the effort guaranteed
So what’s the upside?
If you’re not looking to do multichannel publishing,
don’t have extreme performance needs
Or a wish to burn lots of money on bleeding edge tech
Then you don’t need a decoupled site. Yet.
One of these days, ‘fast’ will be normal.
publishes practical content for teachers, improve quality of education
D7 site – 10-15 years of content
Originally D6, migrated to D7, headed for D8
Lullabot engaged to do a discovery, come up with a future plan for Edutopia.
Sally is one of our lullabot API/JS experts, and was on the discovery team.
JavaScript Modernization Initiative…
Multiple article content types,
Design system and social…
After all the discussion, to build a new Edutopia.org using a decoupled D8/React architecture
Talk front-end, then back-end,
Now, a word about JSONAPI…
Run the list…
This makes an API work out of the box…
But you have to be serving up high-quality data for any of this to matter…
If you can’t break your data down into discrete bits, you’re not going to have a successful decoupled experience. Content modeling is super important, all the way down to what you allow in the body field.
HTML lacks the necessary structure for use in a decoupled project. It’s essentially one long string of text, which you have to render to the screen all at once.
In this example, we don’t have much freedom to alter or remix the data, cause it’s all been rendered to markup already.
Content modeling and structuring your data is essential. But…
We can take each bit of data here and mix them up anyway we want in our React components.
JSONAPI handles this for us in Drupal – except when we might bury important data inside other fields
Talk through request lifecycle…
Among the many problems you have to solve, there has to be some planning about the URLs your front-end will handle.
This is commonly called routing. When you receive a request, how do you know what data to call from the API?
The URL fragment shown above (/article/* ) is passed through. The Front-end has to inspect and figure out what api call to make. This is called routing.
JSONAPI module provides entity/bundle endpoints for pretty much anything in the Drupal CMS – nodes, terms, users, custom entity types.
Talk through request lifecycle…
Among the many problems you have to solve, there has to be some planning about the URLs your front-end will handle.
This is commonly called routing. When you receive a request, how do you know what data to call from the API?
Two of the pieces that sit behind a page on Edutopia.org are the API data we called from Drupal…
And the component (template) in react that we shove that data into…
You’ll note that all our data is sitting under that attributes key, in name-value pairs…
Talk through request lifecycle…
Among the many problems you have to solve, there has to be some planning about the URLs your front-end will handle.
This is commonly called routing. When you receive a request, how do you know what data to call from the API?
The URL fragment shown above (/article/* ) is passed through. The Front-end has to inspect and figure out what api call to make. This is called routing.
JSONAPI module provides entity/bundle endpoints for pretty much anything in the Drupal CMS – nodes, terms, users, custom entity types.
That URL slug gave us enough of a clue that we could call the data and it would render, like this:
So what’s behind this rendered page?
Talk through request lifecycle…
Among the many problems you have to solve, there has to be some planning about the URLs your front-end will handle.
This is commonly called routing. When you receive a request, how do you know what data to call from the API?
Our routing example from earlier was straightforward, but it’s not the whole story.
Real websites have years of urls to handle – they change format over time, have to be kept up for SEO or social media reasons…
Edutopia wanted to keep that haystack of URLs. This meant an url slugs like article/* might not really point to articles, and we can’t establish clear rules.
Solution: add api endpoint that takes a url, looks it up, and then pipes it through the JSONAPI stack to render whatever JSON response is needed.
Front-end then has to have logic to parse the type of response and hand off to the right rendering components. (get better words here)
So we couldn’t expect the front-end to know anything certain about the url slugs that were being requested.
So eventually we gave up and asked Drupal
Instead of the stock jsonapi endpoint, we wrote a ‘resolver’ that looked up content by url alias
Then we returned that data using the JSONAPI layer, and react had to make sense of it and do the right thing to render it.
This added complexity, and we can’t recommend doing this… but it was performant, and allowed us to satisfy the requirement.
Tour of the home page
Node form for landing page –
Editors don’t always like this structured data stuff.
Too many fields, not enough visual feedback
Abstraction is great for software, but hard for humans.
For trained users who know what to expect… this works great.
For users who just want to get the work done…
Edutoipa needed more freedom to embed things into the body.
Video: editing process
But you said the body field was bad!
Remember this slide? Yeah – you can’t make good choices on the front end if you’re already rendering markup from Drupal.
Solution in Drupal: Media entities + entity embed + customizations to entity browser
Hidden entity-ref field was important – cause it won’t show in the API unless it’s in a field.
Here’s what it looked like:
Yikes. This is that drupal entity, embedded in the body of the article.
Data attributes keep things structured…
But you have to extract that out of the body the hard way.
Yikes. This is that drupal entity, embedded in the body of the article.
Data attributes keep things structured…
But you have to extract that out of the body the hard way.
Our RichText component in React has to scan the body and break it into chunks (PITA, fragile)
Chunks get rendered through React components as needed.
And the editors loved it.
Images render markup through react components, based on API data.
The Editors can do their thing, and embed media into their articles, and everyone is happy…
Except for the front-enders. They cry. It’s fincky regular expressions for days.
But when they’re done, it’s great.
Let’s switch gears and talk about performance…
It’s troublesome to juggle these early in the dev process, when your content model is still in flux. But when it’s stable, and before you’re really in the front-end dev game, start using them.
Also useful to clearly document page components and their related fields, so you can easily refer back and keep things clean.
Problem: Authoring content in Drupal doesn't leave you with a sense of what the content will really look like when rendered.
Back-end solution: Custom endpoint taking revision IDs, look up revision, render through JSONAPI stack,
Front-end solution: set up additional host using end to serve revisions, with config to enable previews, basic auth token being passed, auth to preview system.
To take it back to our example for the Edutopia homepage, here’s what the related content would look like:
The actual JSONAPI response is a little messy – the component entity consists of some metadata and then a list of UUIDs, which are references to data objects elsewhere in the data.
Our code works through all that and stores it in Redux, which triggers the render of the corresponding React component.
The actual JSONAPI response is messy – the component entity consists of some metadata and then a list of UUIDs, which are references to data objects elsewhere in the data.
Our code has to work through all that and store it in Redux, which triggers the render of the corresponding React component.
EOL implementations - 3+ article-style content types -
New design system
engagement and SEO increasingly affected by performance
Decoupled or not?