Drupal

Basic Auth Global

New Drupal Modules - 13 October 2017 - 6:47am

This module alters the Basic Auth service so it can be used globally for routes that do not specify an authentication method. It can be useful on sites that use the Basic Auth module on a site where the web server also implements basic authentication (typically a development environment).

Categories: Drupal

SendPulse Rules

New Drupal Modules - 13 October 2017 - 6:25am

Rules integration for SendPulse module.

Categories: Drupal

User Panels

New Drupal Modules - 13 October 2017 - 6:17am

Allows to add some user page and form elements that is not provided by panels and ctools page manager.

Categories: Drupal

Field Collection Access

New Drupal Modules - 13 October 2017 - 6:15am

Advanced access control for Field Collection items following the design of node access in drupal core.

Categories: Drupal

Valuebound: Extend existing field widgets in Drupal 8 application using annotation plugin

Planet Drupal - 13 October 2017 - 4:55am

Have you ever wondered how the text or email or entity reference field is extended in Drupal 8? Or how to create a custom field/widget/formatter so that it can match with the rest of fields in your Drupal application? This blog will cover everything required to extend existing field widgets in Drupal 8 using annotation plugin. 

Many developers, who recently started working on Drupal 8, may not be aware of an entire process so let’s take a closer look to everything step-by-step. Key comparisons between Drupal 7 and Drupal 8, what is an annotation, why annotation and sample use case from an Inline Entity Form step-by-step. After completing this post, you will be able to extend the field with your own methods/functions without…

Categories: Drupal

Data Import

New Drupal Modules - 13 October 2017 - 3:55am
Categories: Drupal

Nuvole: How to maintain Drush commands for Drush 8 and 9 and Drupal console with the same code base.

Planet Drupal - 13 October 2017 - 1:48am
Config Split treats all the cli the same.

Drupal 8.4 and its upgrade to Symfony 3 has made the compatibility of the global Drush 8 a bit more challenging. Drush 9 works with Drupal 8.4 but it is not stable yet and the format of how third party Drush commands are made has changed significantly.

While Drush 9 comes with a command that helps porting Drush 8 commands you will still end up maintaining very similar code in two places one with calls to drush_confirm('...') and one with $this->io()->confirm('...'). If you decide to also provide your commands for Drupal console you now have three times the burden.

Because we tried to provide the commands for Config Split for both Drush and Drupal console early on we faced this problem already more than a year ago. And now it has paid off because porting the commands to Drush 9 was very quick.

The solution is actually really simple and brings the added benefit of being able to test the business logic of the commands in the absence of Drush or Drupal console. It is all about separating the command discovery from the command logic. Drush 8, 9 and Drupal console all have a bit different ways to discover and invoke commands, but the business logic you want to implement is the same so all we have to do is to extract a common "interface" our custom service can implement and then make the command definitions wrap that and keep things DRY.

The CliService

Config Split defines a config_split.cli service with the class ConfigSplitCliService with all its dependencies injected. It has the methods \Drupal\config_split\ConfigSplitCliService::ioExport and \Drupal\config_split\ConfigSplitCliService::ioImport that implement all the commands logic and delegate the actual importing and exporting to specific methods.

The method signature for both the export and import method are more or less the same: CliService::ioMethod($arguments, $io, callable $t).

  • $arguments: The arguments passed to the command.
  • $io: This is an object that interacts with the command line, in Drush 9 and Drupal console this comes from the Symfony console component, for Drush 8 we created a custom wrapper around drush_confirm and drush_log called ConfigSplitDrush8Io.
  • $t: This is essentially a t function akin to how Drupal translates strings. Because Drupal console translates things differently we had to be a bit creative with that by adding a t method to the command.
Commands wrap the service

The Drush 8 command is essentially:

<?php
function drush_config_split_export($split = NULL) {
  // Make the magic happen.
  \Drupal::service('config_split.cli')->ioExport($split, new ConfigSplitDrush8Io(), 'dt');
}
?>

For Drush 9 we can use dependency injection and the Drush 9 command becomes essentially:

<?php
class ConfigSplitCommands extends DrushCommands {
  public function splitExport($split = NULL) {
    $this->cliService->ioExport($split, $this->io(), 'dt');
  }
}
?>

And very similar the Drupal console command:

<?php
class ExportCommand extends SplitCommandBase {
  protected function execute(InputInterface $input, OutputInterface $output) {
    $this->setupIo($input, $output);
    // Make the magic happen.
    $this->cliService->ioExport($input->getOption('split'), $this->getIo(), [$this, 't']);
  }
}
?> Testing

The ConfigSplitCliServiceTest is a KernelTest which asserts that the export works as expected by exporting to a virtual file system. The test coverage is not 100% (patches welcome) but the most important aspects for the complete and conditional splitting (blacklist/graylist) is thoroughly tested. There are no limitations on what or how you can test your CliService since it is self contained in your module and does not depend on Drush or the Drupal console. For example one could write a unit test with a mocked $io object that asserts that the messages printed to the cli are correct.

Tags: Drupal 8Drupal PlanetDrush
Categories: Drupal

InternetDevels: More profits & less effort with Drupal multisite functionality

Planet Drupal - 13 October 2017 - 1:27am

Here is another recipe for success. You can have a whole team of websites playing for you, and they don’t have to be created from scratch or managed separately. The secret lies in Drupal’s well-developed multisite functionality. Thanks to this, Drupal will not only let you leave your competitors behind, but also multiply this effect by many times.

Read more
Categories: Drupal

Appnovation Technologies: A Homeowner's Guide to Drupal Security

Planet Drupal - 13 October 2017 - 12:00am
A Homeowner's Guide to Drupal Security Working in our Managed Services department, we handle many Drupal 7 and 8 sites - all of which have one thing in common. Despite their different requirements, designs and content - they all need security updates applying and are all in need of some care and attention when it comes to securing them. If a Drupal site was a house: Securi...
Categories: Drupal

Views Reset

New Drupal Modules - 12 October 2017 - 11:55pm

Helps to add simple Reset button in views exposed forms.

Default views comes with reset button that will be standard HTML submit buttons. It will take bit more time to load the view when clicked as it will go through Drupal form submission process. However we just want to get the view loaded without any filtering applied or with just default filter. So, this module helps us to load that view without gong through complex form submission.

Categories: Drupal

Email scheduler

New Drupal Modules - 12 October 2017 - 9:10pm

# Email scheduler version 1.0 #

This modules allows the configure of email notifications based on user roles.

### How do I get this set up? ###

* Install and enable the module as normal
* Select the type that you need to config to send emails (/admin/config/email_scheduler)
* Go to user(/admin/people) or role (/admin/people/permissions/roles) to configure the settings

### Completed ###

Categories: Drupal

Content Access Booster

New Drupal Modules - 12 October 2017 - 12:31pm
Abstract

Boost large websites using content_access (eventually combined with other access modules like node access node reference or node access user reference

Categories: Drupal

Database

New Drupal Modules - 12 October 2017 - 12:06pm
Categories: Drupal

Menu Formatter

New Drupal Modules - 12 October 2017 - 11:13am

-- SUMMARY --

If you would like to render a menu in an entity reference field, this is the module for you!

-- REQUIREMENTS --

You must have the menu_ui and entity_reference core modules installed.

-- INSTALLATION --

* Install as usual as per http://drupal.org/node/895232.

-- USAGE --

Categories: Drupal

Texas Creative: Drupal and Wordpress and Joomla, Oh My!

Planet Drupal - 12 October 2017 - 9:32am

Not all CMS are created equal. Before building your next website, here are a few tips on why your CMS choice matters. (Plot twist: as told by an Account Manager.)

Read More
Categories: Drupal

Amazon Elastic Transcoder

New Drupal Modules - 12 October 2017 - 8:09am

A video transcoder for the video module. This project allows drupal 7 website operators to transcode video using Amazon Elastic Transcoding services on the AWS cloud. Services utilized include S3, SNS, and Elastic Transcoder.

Dependencies:

  • Video (2.x)
  • Amazon S3 (2.x-dev)
  • Amazon S3 CORS (optional w/ patches provided below)

Several patches are required to achieve full feature coverage. Issues will be listed below.

Categories: Drupal

Yet Another Blog Archive

New Drupal Modules - 12 October 2017 - 7:46am

Module provides "Archive Block" as blogger.com for core blog module.

Categories: Drupal

Noticeboard

New Drupal Modules - 12 October 2017 - 7:21am

A virtual notice board.
Used to provide users information about time-sensitive things across the site.

Categories: Drupal

Vardot: SEO Checklist Before Launching Your Drupal Website

Planet Drupal - 12 October 2017 - 7:11am
SEO Checklist Before Launching Your Drupal Website Dmitrii Susloparov Thu, 10/12/2017 - 17:11

Search Engine Optimization (SEO) might not be the first thing you think of when designing a new website, but building an optimized framework from the start will help you drive traffic to your site and keep it there. With our Drupal SEO-checklist in hand you can build an excellent website that draws customers from launch day. Briefly speaking, here is a bullet list of what to check before the launch day. Below we’ll speak about each point in more detail.

 

  • Check that all web pages have unique titles using the Page Title module

  • Check if XML Sitemap and Google News Sitemap are configured properly

  • Check if Redirect module is enabled and configured

  • Check if Global Redirect module is enabled and configured

  • Check that .htaccess redirect to site with/without www

  • Check that the homepage title includes a slogan, and is descriptive for the function of the site

  • Check if Meta Tags is filled with descriptive information

  • Check that OG tags are filled correctly and with descriptive information.

  • Check if site's information appears well when shared on Facebook

  • Check if Path aliases patterns are meaningful

  • Check if Google Analytics is enabled and configured

  • Check if Page Title module is enabled and configured

  • Check if Google News Sitemap is enabled and configured

  • Check if Site verification is enabled and configured

  • Check if Search 404 module is enabled and configured

 

Drupal SEO: 12 Things that Will Improve Your Site's Ranking Check that all web pages have unique titles...

...and make sure to write them correctly. All of your pages should be easily identifiable to the end user. Not only should they have unique titles, they should have meaningful titles. Having multiple pages with the same titles (like “Get in touch”, “Contact us” and “Make a booking”) will simply confuse your end users and search engine crawlers.

 

Not only do good page titles help customers who are already on your site, but they help with social sharing, and picking your site out of search engine results. Titles are the first element that any user will see, whether they come directly to your site, find it in a search engine, or see it shared on social media.

 

Writing good titles is extremely important, and having keywords in your title that match a user's search greatly improves the chances of them clicking on your page.

 

Ensuring all your pages have a unique name will help users navigate, boost your SEO ratings, and increase the chances that someone will type the right keywords into a search engine to bring them to your site.

 

You can set up unique page titles much easier if you install the Drupal Page Title module.

10 Drupal Modules that Will Boost Your Website’s SEO

 

 

Check if XML Sitemap and Google News Sitemap are configured properly

The XML Sitemap module creates a robot friendly map of your site that Google and other search engines can crawl to categorise your website. There are a few settings you can alter for your site at admin/config/search/xmlsitemap and you can view the sitemap from http://yoursite.com/sitemap.xml.

 

You should configure XML Sitemap early in your site build for the best effect, but you can also alter the settings later on if needed.

 

Google News Sitemap offers a similar but different service that creates a Google specific map - as suggested in the name. These two modules work nicely side by side to make your site easy for search engines to crawl and index.

 

Please note that if your site contains AMPs, there is no need to create sitemaps for them. The rel=amphtml link is enough for Google to pick up on the accelerated mobile page version, which means you can easily gain traffic from Top Stories carousels and mobile search. Creating AMP on your Drupal site became easy with our step-by-step guide.

 

 

Check if Redirect module is enabled and configured

Redirect is a handy module for making sure users always make it to your site. It uses case-insensitive matching to help catch broken links with redirects and tracks how often users are hitting those redirects. You can use redirects to capture any broken links, set up promotional links, or simply capture typos users are entering when trying to access your site.

 

Check if Global Redirect module is enabled and configured

If you’re using Drupal 8 you can skip this one because the functionality has been rolled into the redirect module. Otherwise install Global Redirect to work in tandem with Redirect to catch any broken links. Global Redirect will test all links with and without a trailing slash, ensure links are case-insensitive and if a link is truly broken it will return a user to your home page, rather than an ugly 404 page that decrease the position of your site in SERPs.

Check that .htaccess redirects to site with/without www

Some users attempting to visit your site will navigate to www.yoursite.com, while others will simply type yoursite.com. By setting up your site to handle either request you can be sure you won’t miss any visitors.

 

 

Check that the homepage title includes a headline, logo and primary image and is descriptive for the function of the site

The headline as well as the slogan represent who you are as a business. Make your first impression a good one as this will also be visible on search engines. This is a good opportunity to stack your website with SEO friendly keywords, but don’t go overboard and sacrifice your image for it - keyword stuffing may not only decrease the trust index of your site, but also its conversion rates.

Ensure Metatags are filled with descriptive information

Writing SEO-optimized metatags is highly important, because they remain one of the top on-page ranking factors. Make sure to install the Metatag module on your site to have an easy, user friendly interface for updating metadata. With the module installed you can easily populate metadata with keywords, page descriptions, and more.

 

SEO tips for your Drupal site

 

The Metatag module will also give you extra control over how your site appears when shared on Twitter or Facebook.

Check that OG tags are filled correctly and with descriptive information.

OG tags are metatags specifically designed to ensure your site communicates nicely with Facebook. By setting these tags correctly you will be able to control exactly how your site appears on Facebook, including what images and what taglines are used.

Check if site's information appears well when shared on Facebook and Twitter

After configuring the metatag module and OG tags, pop over to Facebook and make sure that your site shares the way you would like it too. It’s important to test this out now before users start sharing your site around.

 

Similarly try tweeting a couple of your pages to see how well your Twitter Cards come through. If you don’t want to show your site to your audience until you are sure it is set up properly, you can check Twitter Cards using the Card Validator.

 

For more information on configuring Twitter cards, check out the Twitter user guides.

 

Check if Path aliases patterns are meaningful

By default Drupal will set your URLs to node/123 - while this works great for the database back end, it doesn’t work well for your end users, or for search engines.

 

You can use the Pathauto module to create rules and patterns for your URLs that will significantly cut down on your maintenance times and simplify your site navigation.

Check if Google Analytics is enabled and configured

While having Google Analytics configured won’t improve your SEO, it will give you all the data you need to understand where your users are coming from and how they behave once they hit your site.

 

Installing the Google Analytics module makes setting up and configuring Google Analytics a breeze.

Check if Site verification is enabled and configured

The Site verification module makes it easy to check the boxes that tell search engines that your site is truly yours. Having your site verified will improved how search engines crawl your site, and for Google will allow you to access private search data. With site verification you will receive better data and better search engine rankings for just a few minutes work.

 

Check if Search 404 module is enabled and configured

The Search 404 module is a saving grace for reducing your bounce rate, your SEO and improving your customer experience. Instead of your users finding an ‘Error: Page not Found” in place of the content they were hoping for, they will be offered a search of your site based on the URL string. For example if “www.yoursite.com/great-seo-tips” doesn’t exist, users this module will automatically search your site for ‘Great SEO tips” and show the users the results.

 

 

Bottom line

While SEO may seem like a tricky subject to wrap your head around, the basics are easy with the right modules and the right guidance. Drupal is a great content management system for building search engine optimized websites.

 

With our SEO checklist you can get off on the right foot, and here at Vardot we love educating our customers to build top quality websites. If you’re looking for even more ways to improve your sites SEO, have a look at SEO articles in our blog or get in touch with us.

Categories: Drupal

Lullabot: Incredible Decoupled Performance with Subrequests

Planet Drupal - 12 October 2017 - 6:52am

In my previous post, Modern Decoupling is More Performant, we discussed how saving HTTP round-trips has a very positive impact on performance. In particular, we demonstrated how the JSON API module could help your application by returning multiple entities in a single request. Doing so eliminates the need for making an individual request per entity. However, this is only possible when fetching entities, not when writing data and only if those entities are related to the entry point (a particular entity or collection).

Sometimes you can solve this problem by writing a custom resource in the back-end every time, but that can lead to many custom resources, which impacts maintainability and is tiresome. If your API is public and you don’t have prior knowledge of what the consumers are going to do with it, it’s not even possible to write these custom endpoints.

The Subrequests module completes that idea by allowing ANY set of requests to be aggregated together. It can aggregate them even when one of them depends on a previous response. The module works with any request, it's not limited to REST or any other constraint. For simplicity, all the examples here will make requests to JSON API.

Why Do We Need It?

The main concept of the Subrequests module is that instead of sending multiple requests to your Drupal instance we will only send a single request. In this master request, we will provide the information about the requests we need to make in a JSON document. We call this document blueprint.

A blueprint is a JSON document containing the instructions for Drupal to make all those requests in our name. The blueprint document contains a list of subrequest objects. Each subrequest object contains the information about a single request being aggregated in the blueprint.

Imagine that our consumer application has a decoupled editorial interface. This editorial interface contains a form to create an article. As part of the editorial experience, we want the form to create the article and a set of tags in the Drupal back-end.

Without using Subrequests, the consumer application should execute the following requests when the form is submitted:

  • Query Drupal to find the UUID for the tags vocabulary.
  • Query Drupal to find the UUID of the user, based on the username present in the editorial app.
  • Create the first tag in the form using the vocabulary UUID.
  • Create the second tag in the form using the vocabulary UUID.
  • Create the article in the form using the user UUID and the newly created tags.

We can query for the user and the vocabulary in parallel. Once that is done, and using the information in the vocabulary response, we can create the tag entities. Once those are created, we can finally create the article. In total, we would be making five requests at three sequential levels. And, this is not even a complex example!

undefined

A JavaScript pseudo-code for the form submission handler could look like:

console.log('Article creation started…'); Promise.all([ httpRequest('GET', 'https://cms.contentacms.io/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags'), httpRequest('GET', 'https://cms.contentacms.io/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin'), ]) .then(res => { const [vocab, user] = res; return Promise.all([ Promise.resolve(user), httpRequest('POST', 'https://cms.contentacms.io/api/tags', bodyForTag1, headers), httpRequest('POST', 'https://cms.contentacms.io/api/tags', bodyForTag2, headers), ]) }) .then(res => { const [user, tag1, tag2] = res; const body = buildBodyForArticle(formData, user, tag1, tag2); return httpRequest('POST', 'https://cms.contentacms.io/api/articles', body, headers); }) .then(() => { console.log('Article creation finished!'); }); Using Subrequests

Our goal is to have JavaScript pseudo-code that looks like:

console.log('Article creation started…'); const blueprint = buildBlueprint(formData); httpRequest('POST', 'https://cms.contentacms.io/api/subrequests?_format=json', blueprint, headers) .then(() => { console.log('Article creation finished!'); });

We've reduced our application code to a single POST request that contains a blueprint in the request body. We have reduced the problem to the blueprint creation. That is a big improvement in the developer experience of consumer applications.

undefined Parallel Requests

In our current task we need to perform two initial HTTP requests that can be run in parallel:

  • Query Drupal to find the UUID for the tags vocabulary.
  • Query Drupal to find the UUID of the user based on the username in the editorial app.

That translates to the following blueprint:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": ["Accept": "application/vnd.application+json"] }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": ["Accept": "application/vnd.application+json"] } ]

For each subrequest, we can observe that we are providing four keys:

  • requestId A string used to identify the subrequest. This is an arbitrary value generated by the consumer application.
  • action Identifies the action being performed. A "view" action will generate a GET request. A "create" action will generate a POST request, etc.
  • uri The URL where the subrequest will be sent .
  • headers An object containing the headers specific for this subrequest.

The response to this blueprint (after adjusting the permissions in Drupal to view users and vocabularies) will return the response to both subrequests:

{ "vocabulary": { "headers": { "content-id": ["<vocabulary>"], "status": [200] }, "body": "{\"data\":[{\"type\":\"vocabularies\",\"id\":\"47ce8895-0df6-44a4-af43-9ef3b2a924dd\",\"attributes\":{\"status\":true,\"dependencies\":{\"module\":[\"recipes_magazin\"]},\"_core\":\"HJlsFfKP4PFHK1ub6QCSNFmzAnGiBG7tnx53eLK1lnE\",\"name\":\"Tags\",\"vid\":\"tags\",\"description\":\"Use tags to group articles on similar topics into categories.\",\"hierarchy\":0,\"weight\":0},\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/vocabularies\\/47ce8895-0df6-44a4-af43-9ef3b2a924dd\"}}],\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/vocabularies?filter%5Bvid-filter%5D%5Bcondition%5D%5Bpath%5D=vid\\u0026filter%5Bvid-filter%5D%5Bcondition%5D%5Bvalue%5D=tags\"}}" }, "user": { "headers": { "content-id": ["<user>"], "status": [200] }, "body": "{\"data\":[{\"type\":\"users\",\"id\":\"a0b7af80-e319-4271-899f-f151d3fbfc8e\",\"attributes\":{\"internalId\":1,\"name\":\"admin\",\"mail\":\"admin@example.com\",\"timezone\":\"Europe\\/Madrid\",\"isActive\":true,\"createdAt\":\"2017-09-15T15:47:26+0200\",\"updatedAt\":\"2017-09-15T20:06:15+0200\",\"access\":1505565434,\"lastLogin\":\"2017-09-15T20:06:07+0200\"},\"relationships\":{\"roles\":{\"data\":[]}},\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/users\\/a0b7af80-e319-4271-899f-f151d3fbfc8e\"}}],\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/users?filter%5Badmin%5D%5Bcondition%5D%5Bpath%5D=name\\u0026filter%5Badmin%5D%5Bcondition%5D%5Bvalue%5D=admin\"}}" } }

In the (simplified) response above we can see that for each subrequest, we have one key in the response object. That key is the same as our requestId in the blueprint. Each one of the subresponses contains the information about the response headers and the response body. Note how the response body is an escaped JSON object.

This blueprint is not sufficient to create an article with two tags, but it's a great start. Let's build on top of that to create the tags and the article.

Dependent Requests

The next task we need to execute is the creation of the two tag entities:

  • Create the first tag in the form using the vocabulary UUID.
  • Create the second tag in the form using the vocabulary UUID.

To do this, we will need to expand the blueprint. However, we don't know the vocabulary UUID at the time we are writing the blueprint. What we do know is that the vocabulary UUID will be in the subresponse to the vocabulary subrequest. In particular, we can find the UUID in data[0].id.

We will use that information to create a blueprint that can create tags. Since we don't know the actual value of the vocabulary UUID, we will use a replacement token. At some point, during the blueprint processing by Drupal, the token will be resolved to the actual UUID value.

Replacement Tokens

We can use replacement tokens anywhere in the body or the URI of our subrequests. For those to be resolved, a token needs to be formatted in the following way:

{{<requestId>.<"body"|"headers">@<json-path-expression>}}

In particular, the replacement token for our vocabulary UUID will be:

{{vocabulary.body@$.data[0].id}}

What this replacement says is:

  1. Use the subresponse for the vocabulary subrequest.
  2. Take the body from that subresponse.
  3. Extract the string under data[0].id, by executing the JSON Path expression $.data[0].id. You can execute any JSON Path expression as long as it returns a string. JSON Path is a very powerful way to extract data from an arbitrary JSON object, in our case the body in subresponse to the vocabulary subrequest.

This is what our blueprint looks like after adding the subrequests to create the tag entities. Note the presence of the replacement tokens:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": {"Accept": "application/vnd.api+json"} }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": {"Accept": "application/vnd.api+json"} }, { "action": "create", "requestId": "tags-1", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My First Tag\"},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "tags-2", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My Second Tag\",\"description\":null},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] } ]

Note that to use a replacement token in a subrequest, we need to add a dependency on the subresponse that contains the information. That's why we added the waitFor key in our tag subrequests.

Finishing the Blueprint undefined

Using the same principles that we used for the tags we can add the subrequest for:

  • Create the article in the form using the user UUID and the newly created tags.

That will leave our completed blueprint as:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": {"Accept": "application/vnd.api+json"} }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": {"Accept": "application/vnd.api+json"} }, { "action": "create", "requestId": "tags-1", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My First Tag\"},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "tags-2", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My Second Tag\",\"description\":null},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "article", "headers": {"Content-Type": "application/vnd.api+json"}, "body": "{\"data\":{\"type\":\"articles\",\"attributes\":{\"body\":\"Custom value\",\"default_langcode\":\"1\",\"langcode\":\"en\",\"promote\":\"1\",\"status\":\"1\",\"sticky\":\"0\",\"title\":\"Article Created via Subrequests!\"},\"relationships\":{\"tags\":{\"data\":[{\"id\":\"{{tags-1.body@$.data.id}}\",\"type\":\"tags\"},{\"id\":\"{{tags-2.body@$.data.id}}\",\"type\":\"tags\"}]},\"type\":{\"data\":{\"id\":\"article\",\"type\":\"contentTypes\"}},\"owner\":{\"data\":{\"id\":\"{{user.body@$.data[0].id}}\",\"type\":\"users\"}}}}}", "uri": "/api/articles", "waitFor": ["user", "tags-1", "tags-2"] } ] More Powerful Replacements

Imagine that instead of creating an article for a single user, we wanted to create an article for each one of the users on the site. We cannot write a simple blueprint, like the one above, since we don't know how many users there are in the Drupal site. Hence, we cannot write an article creation subrequest for each user.

To solve this problem we can tweak the user subrequest, so instead of returning a single user it returns all the users in the site:

[ … { "requestId": "user", "action": "view", "uri": "/api/users", "headers": {"Accept": "application/vnd.api+json"} }, … ]

Then in our replacement tokens, we can write a JSON Path expression that will return a list of user UUIDs, instead of a single string. Subrequests will accept JSON Path expressions that return either strings or an array of strings for the replacement tokens.

In our article creation subrequest we will need to change {{user.body@$.data[0].id}} by {{user.body@$.data[*].id}}. The Subrequests module will create a duplicate of the article subrequest for each replacement item. In our case this will have the effect of having a copy of the article creation subrequest per each available user in the user subresponse.

The Final Response

The modified blueprint that generates one article per user will have a response like:

undefined

We can see how a single subrequest can generate n subresponses, and we can use each one of those to generate n other subresponses, etc. This highlights how powerful this technique is. In addition, we have seen that we can combine different type of operations. In our example, we mixed GET and POST in a single blueprint (to get the vocabulary and create the new tags).

Conclusion

Sub requests is a great way to fetch or write many resources in a single HTTP request. This allows us to improve performance significantly while maintaining almost the same flexibility that custom code provides.

Further Your Understanding

If you want to know more about the blueprint format you can read the specification. The Subrequests module comes with a JSON schema that you can use to validate your blueprint. You can find the schema here.

The hero image was downloaded from Frankenphotos and use without modifications with a CC BY 3.0 license.

Categories: Drupal

Pages

Subscribe to As If Productions aggregator - Drupal