Brian Perry: Extending The Drupal API Client

Planet Drupal - 7. Februar 2024 - 2:00

import RadCallout from '../../../components/rad/RadCallout.astro';

As a result of our Pitch-burgh funding, the current focus of the Drupal API Client is to create a fully featured client for Drupal's JSON:API implementation. Even with that goal, we've focused on making our work extensible for other API formats in the future through the implementation of an ApiClient base class. Functionality that could apply to any API client is added to the base class, while anything specific to JSON:API is added to the JsonApiClient class (which extends ApiClient.)

Recently, we have been working on adding Decoupled Router support to our JSON:API Client. I found this implementation to be a great example of the extensibility of the library, so I wanted elaborate on it in a blog post for those who may want to extend the API Client in the future.

The existing JsonApiClient has the following method to retrieve data for a resource:

await client.getResource('node--article', '3347c400-302d-4f6c-8fcb-3e74beb002c8');

Ideally, users of Decoupled Router could also get an identical response by resolving a path:

await client.getResource('/articles/give-it-a-go-and-grow-your-own-herbs');

To achieve this, we first needed to provide a way to reliably get data from Decoupled Router.

The Decoupled Router Endpoint

With the module enabled, Decoupled Router exposes an endpoint with the following structure:

/router/translate-path?path=<path>

Given a path like /articles/give-it-a-go-and-grow-your-own-herbs the endpoint could provide a response similar to:

{ "resolved": "https://dev-drupal-api-client-poc.pantheonsite.io/en/articles/give-it-a-go-and-grow-your-own-herbs", "isHomePath": false, "entity": { "canonical": "https://dev-drupal-api-client-poc.pantheonsite.io/en/articles/give-it-a-go-and-grow-your-own-herbs", "type": "node", "bundle": "article", "id": "11", "uuid": "3347c400-302d-4f6c-8fcb-3e74beb002c8" }, "label": "Give it a go and grow your own herbs", "jsonapi": { "individual": "https://dev-drupal-api-client-poc.pantheonsite.io/en/jsonapi/node/article/3347c400-302d-4f6c-8fcb-3e74beb002c8", "resourceName": "node--article", "pathPrefix": "jsonapi", "basePath": "/jsonapi", "entryPoint": "https://dev-drupal-api-client-poc.pantheonsite.io/en/jsonapi" }, "meta": { "deprecated": { "jsonapi.pathPrefix": "This property has been deprecated and will be removed in the next version of Decoupled Router. Use basePath instead." } } }

While easy to make sense of, this response technically doesn't follow the JSON:API spec, which prevents us from using our existing JSON:API Client without modification. We could write a small amount of custom code in JsonApiClient to fetch and handle data from this endpoint, but this case is exactly what our ApiClient base class is intended for. With a similarly small amount of code we can extend the ApiClient class to add only what is unique to the Decoupled Router endpoint, while getting access to all of the features of the base class at the same time.

So rather than writing code specific to JsonApiClient, we decided to create a new DecoupledRouterClient class that our JsonApiClient could then make use of.

Extending ApiClient

For the sake of example, a simple Decoupled Router client could look like this:

// DecoupledRouterClient.ts import { ApiClient, type ApiClientOptions, type BaseUrl, } from "@drupal-api-client/api-client"; export class DecoupledRouterClient extends ApiClient { constructor(baseUrl: BaseUrl, options?: ApiClientOptions) { super(baseUrl, options); const { apiPrefix } = options || {}; this.apiPrefix = apiPrefix || "router/translate-path"; } async translatePath(path: string) { const apiUrl = `${this.baseUrl}/${this.apiPrefix}?path=${path}`; const response = await this.fetch(apiUrl); return response.json(); } }

In our constructor, the only modification we need to make is the default value for the API prefix. While the base class doesn't have a default, Decoupled Router uses router/translate-path. Now when instance of DecoupledRouter is created without this option, it will use the default.

We then define a translatePath method that:

  • Takes a path of type string
  • Uses the fetch method provided by the base class to make a request to Decoupled Router
  • Returns a promise with the provided json data

Using an instance of this class would look something like:

// main.ts import { DecoupledRouterClient } from "./DecoupledRouterClient.ts"; const decoupledRouterClient = new DecoupledRouterClient("https://dev-drupal-api-client-poc.pantheonsite.io"); const translatedPath = await decoupledRouterClient.translatePath( "/articles/give-it-a-go-and-grow-your-own-herbs" );

<RadCallout>Check out this code sandbox for a live version of the example above.</RadCallout>

Taking Advantage of Additional ApiClient Features

With this example we already have a functional client, but quite a bit more is possible using the features of the ApiClient class we extended. For example, We can already make authenticated requests using any of the supported authentication methods:

// main.ts import { DecoupledRouterClient } from "./DecoupledRouterClient.ts"; const decoupledRouterClient = new DecoupledRouterClient("https://dev-drupal-api-client-poc.pantheonsite.io", { authentication: { type: "OAuth", credentials: { clientId: "client-id", clientSecret: "client-secret" } }, }); // API requests will now be authenticated const translatedPath = await decoupledRouterClient.translatePath( "/articles/give-it-a-go-and-grow-your-own-herbs" );

Our example Decoupled Router client could be updated to take advantage of built in caching, logging, or locale support. For example, the following modification would allow us to make use of the defaultLocale option if our Drupal site supports multiple languages:

// DecoupledRouterClient.ts import { ApiClient, type ApiClientOptions, type BaseUrl, } from "@drupal-api-client/api-client"; export class DecoupledRouterClient extends ApiClient { constructor(baseUrl: BaseUrl, options?: ApiClientOptions) { super(baseUrl, options); const { apiPrefix } = options || {}; this.apiPrefix = apiPrefix || "router/translate-path"; } async translatePath(path: string) { // If it exists, incorporate the default locale // into the apiUrl const apiUrlObject = new URL( `${this.defaultLocale ?? ""}/${this.apiPrefix}?path=${path}`, this.baseUrl, ); const apiUrl = apiUrlObject.toString(); const response = await this.fetch(apiUrl); return response.json(); } }

Routing is a common problem, so we've added a fully featured getResourceByPath method to our latest @drupal-api-client/json-api-client release. We've also published the Decoupled Router client as a standalone package for anyone who wants to use it separately.

While the caching functionality of the client can lessen the impact, getResourceByPath still makes multiple API calls for uncached data, which leaves room for improvement. We could optimize this in the future by providing support for the subrequests module. That is yet another client for a type of Drupal API that could use the ApiClient base class as a starting point.

We're closing in on the 1.0 release of @drupal-api-client/json-api-client. If you’re interested in contributing, check out our project page on Drupal.org, and join us in the #api-client channel on Drupal Slack.

BMW 5er Touring: Der erste Kombi mit E-Antrieb von BMW​

heise online Newsticker - 7. Februar 2024 - 1:05

Ab Mai liefert BMW den neuen 5er Touring aus. Der Kombi wird nochmals deutlich größer und ist erstmals auch als Elektroauto zu haben.

Wirecard: Angeklagter Bellenhaus auf freiem Fuß

heise online Newsticker - 6. Februar 2024 - 23:55

Der geständige Wirecard-Manager Oliver Bellenhaus darf im weiteren Prozess ungesiebte Luft atmen. Seine Untersuchungshaft ist unter Auflagen aufgehoben.​

Meta folgt Youtube: Fotorealistische KI-Inhalte sollen gekennzeichnet werden

heise online Newsticker - 6. Februar 2024 - 23:09

Meta Platforms möchte fotorealistische KI-Bilder kennzeichnen, wenn sie gekennzeichnet sind. Videos und Ton aus KI sollen die Uploader selbst kennzeichnen.​

PreviousNext: Adding real-time processing to QueueWorker plugins

Planet Drupal - 6. Februar 2024 - 21:52

Projects no longer need to rely on unpredictable processing time frames. The SM project can intercept legacy Drupal @QueueWorker items and insert them into the Symfony Messenger message bus, effectively giving existing core and contrib queue workers jobs real-time processing capabilities.

by daniel.phin / 7 February 2024

This post is part 5 in a series about Symfony Messenger.

  1. Introducing Symfony Messenger integrations with Drupal
  2. Symfony Messenger’ message and message handlers, and comparison with @QueueWorker
  3. Real-time: Symfony Messenger’ Consume command and prioritised messages
  4. Automatic message scheduling and replacing hook_cron
  5. Adding real-time processing to QueueWorker plugins
  6. Making Symfony Mailer asynchronous: integration with Symfony Messenger
  7. Displaying notifications when Symfony Messenger messages are processed
  8. Future of Symfony Messenger in Drupal
QueueWorker plugins

@QueueWorker plugin implementations require no modifications, including the method of dispatch, data payload, or the processItem . The data payload must of course be serialisable. Fortunately, most QueueWorker plugins already comply since their data is serialised and stored to the queue table. As always, avoid adding complex objects like Drupal entities to payloads.

Runners

With queue interception, the sm command can be solely relied upon. Legacy runners such as Drupal web cron, request termination cron (automated_cron.module), and Drush queue:run will be rendered inoperable since they will no longer have anything to process. Consider decommissioning legacy runners when deploying queue interception.

Setup

Queue interception is a part of the primary SM module. Adding a single line in settings.php is the only action required to to enabling this feature:

$settings['queue_default'] = \Drupal\sm\QueueInterceptor\SmLegacyQueueFactory::class;

SM module will need to be fully installed before this line is added. Consider wrapping the line in a class_exists(SmLegacyQueueFactory::class) to enable in a single deployment.

Existing per-queue backends

Setup may be more complex if projects are utilising per-queue backends or anything other than the default database backend for queues, such as Redis. In that case, carefully evaluate whether to convert all or specific queues to use Symfony Messenger.

Whether per-queue backends are utilised can be determined by looking for queue_service_ or queue_reliable_service_ prefixed items in settings.php.

Routing

@QueueWorker jobs are converted to \Drupal\sm\QueueInterceptor\SmLegacyDrupalQueueItem messages in the backend. Knowing this class name allows you to configure transport routing. If routing for this message is not explicitly configured, it will naturally fall back to the default transport, or execute synchronously if there is no routing configuration.

Running the jobs

As usual, when a transport is configured, all you need to do is run sm messenger:consume to execute the tasks. The worker will either listen or poll for messages, and execute them in a very short amount of time after they are dispatched, in a dedicated thread. More information on the worker can be found in post 3 of this series.

The next post covers how Drupal emails can be dispatched to messages, so the web thread can execute faster.

Tagged Symfony, Symfony Messenger

Drupal Core News: DrupalCI and all patch testing will be turned off on July 1, 2024

Planet Drupal - 6. Februar 2024 - 21:16

To continue automated testing, projects must convert to GitLab CI and contributors must switch from patches to merge requests by July 1, 2024.

As of July 2023, contributed projects are fully equipped to adopt GitLab CI. In October 2023 we announced that Gitlab CI testing of Drupal core was already five times faster than the legacy DrupalCI system. In our December 2023 maintainer email we announced that our legacy DrupalCI will be retired as soon as July 2024. Now we are announcing further details.

What's happening?

Some DrupalCI features are already turned off

Projects without DrupalCI testing configured cannot add it anymore. Direct access to log output and artifacts on DrupalCI is no longer available. Results are still summarized on the Automated Testing tab of those project's pages.

With the exception of Drupal 7, it is not possible to run tests on patches against Drupal core anymore. Even for Drupal 7, patches need to be sent for testing manually.

Changing DrupalCI schedules ends on April 30, 2024

After April 30, 2024, DrupalCI schedules can not be added or changed, except to remove DrupalCI testing. Tests will keep running with existing configured schedules until removed.

DrupalCI and all patch testing will be turned off on July 1, 2024

No DrupalCI tests will be executed after this date. It will also no longer be possible to run tests on any patches on Drupal.org on any project. Existing test results will be kept for six months.

All results from DrupalCI tests will be removed on January 1, 2025

This is the end of DrupalCI data retention. No testing results will be available beyond January 1, 2025.

What to do about it? Most projects can start GitLab CI testing with a provided template .gitlab-ci.yml

Using GitLab CI for testing may seem intimidating at first but the Drupal Association engineering team and a number of community volunteers have spent a lot of time to make it as easy as possible for you to adopt GitLab CI for testing.

There is a preconfigured .gitlab-ci.yml template that will set up everything you need to test your project. This template has several useful features, including a variables file that will be automatically updated by the Drupal Association, to make sure you’re always testing against the currently supported versions of Drupal.

Most project maintainers won’t have to make any changes to the template, just commit the template to your project and your testing should work right away!

Set up GitLab CI for your drupal.org project today.

Contributors must use merge requests on all projects to get automated testing after July 1, 2024

GitLab CI, like almost all modern CI systems, is designed to test merge requests. If you have ever contributed to a project on GitHub, you pretty much already know how it works. The advantage of Drupal.org merge requests is that they are collaborative by default, so you and fellow contributors can work in the same fork.

Read the best practices for contributing through merge requests.

TechStage | Top 10: Die besten Smartphones bis 300 Euro – Motorola und Xiaomi vor Samsung

heise online Newsticker - 6. Februar 2024 - 21:00

Mehr als ein Einsteiger-Smartphone sollte das neue Mobilgerät schon können, aber gleichzeitig nicht viel kosten? TechStage zeigt die besten Handys bis 300 Euro.

Vodafone: "Beträchtliche" Auswirkungen durch Ende des Nebenkostenprivilegs

heise online Newsticker - 6. Februar 2024 - 20:07

Während Vodafone in Deutschland den Negativtrend beim Service-Umsatz stoppen konnte, droht mit dem Ende​ des Nebenkostenprivilegs ein weiterer Umsatzverlust.

Elektrisches Downsizing-SUV zwischen Dacia Spring und Citroën ë-C3 von Hyundai?

heise online Newsticker - 6. Februar 2024 - 19:35

Zwischen Dacia Spring und Citroën ë-C3: Hyundai will Elektro-Kleinstwagen mit rund 200 km Reichweite ab "Ende 2024" unter 20.000 Euro in Deutschland anbieten.​

ImageX: Drupal Calendar Creation Unleashed: Useful Modules And A Step-by-Step Walkthrough

Planet Drupal - 6. Februar 2024 - 19:31

Authored by: Nadiia Nykolaichuk.

One of the earliest known calendars was created by ancient Egyptians, who used hieroglyphics and carvings to represent the months, days, and important events. Today, visually appealing and user-friendly calendars are easily created on websites, all thanks to powerful CMSs like Drupal. We’ll share some modules in Drupal that are available for calendar creation and management, and carefully walk you through the key steps of building a calendar. 

Arbeitsmarkt: Admins und Security-Experten wieder mehr gefragt​

heise online Newsticker - 6. Februar 2024 - 19:30

Die Zahl der Jobausschreibungen für ITler ist Ende 2023 laut Personalvermittler Hays wieder angestiegen. Unter anderem für Admins gab es wieder mehr Auswahl.

KI: Bundesregierung warnt vor Überwachungsdruck am Arbeitsplatz

heise online Newsticker - 6. Februar 2024 - 19:22

Künstliche Intelligenz kann laut Regierung zu Eingriffen in das Recht auf informationelle Selbstbestimmung Beschäftigter und zu einer Abwertung von Jobs führen.

BSI: Nationales IT-Lagezentrum soll Cybersicherheit "substanziell erhöhen"​

heise online Newsticker - 6. Februar 2024 - 18:49

Zehn BSI-Experten sollen die Cybersicherheitslage für Deutschland rund um die Uhr im Blick behalten. Die Polizei mahnt, föderale Doppelarbeit zu vermeiden.​

KI-Update kompakt: Google Gemini, Microsoft, Taylor Swift, Roblox

heise online Newsticker - 6. Februar 2024 - 18:44

Das "KI-Update" liefert werktäglich eine Zusammenfassung der wichtigsten KI-Entwicklungen.

TechStage | Priwatt Pribasic Duo im Test: Balkonkraftwerk mit Top-Panels und 860 Wp

heise online Newsticker - 6. Februar 2024 - 18:36

Das Balkonkraftwerk Pribasic Duo von Priwatt erzeugt dank bifazialer Solarpanels bis 860 Wp und kann 800 Watt ins heimische Stromnetz abgeben. Wie sich die zweiseitigen Photovoltaikmodule in der Praxis schlagen, zeigt unser Test.

Verräterisches Social-Media-Posting: Mutmaßlicher Erpresser vor Gericht

heise online Newsticker - 6. Februar 2024 - 18:08

Eine selbst fotografierte Hand schlägt eine Brücke zwischen einem virtuellen Verdächtigen und einer realen Person. Die muss sich jetzt vor Gericht verantworten.

Bluesky ist jetzt für alle offen

heise online Newsticker - 6. Februar 2024 - 17:35

Wer an dem Microblogging-Dienst teilnehmen will, benötigt nun keine Einladung mehr.

DrupalEasy: Why you should care about using settings.local.php

Planet Drupal - 6. Februar 2024 - 17:14

Teaching folks why a settings.local.php file is an important part of setting up a personal development environment is so important to us here at DrupalEasy that it is a foundational part of both of our long-form Drupal training courses.

While preparing for an upcoming podcast mini-series I've been invited to participate in with the Talking Drupal folks, I'll be mentoring someone who is looking to re-enter the Drupal development scene after missing out on Drupal's transition from its pre-Symfony days. One of the tasks I have outlined for this person is to set up a settings.local.php file. When I went to find a good resource for the "why" and the "how", I came up empty. I couldn't find a single, up-to-date resource that conveyed what I feel is important.

So, that's what this blog post is all about. 

Why use settings.local.php?

Using a settings.local.php is all about configuring your local development environment for a project to be as useful to you, the developer, as possible. Default settings in this file do things like force all errors to the screen and disabling some of the (but not all) Drupal caches.

This file also pulls in the sites/development.services.yml file which contains some useful service class parameters and overrides - again, things that are useful for local development.

Setting up a settings.local.php literally takes less than two minutes, and when I see a Drupal developer struggling to figure out a white-screen-of-death error on their local environment, I can't help but ????

In addition to adding Drupal's core-dev dependencies and the Devel module, enabling the settings.local.php file is literally one of the first things I do when setting up a new site.

How do I enable the settings.local.php?

I'm so glad you asked.

Step 1

Copy sites/example.settings.local.php to sites/default/settings.local.php. Use a user interface (like the MacOS Finder) or the command line - it doesn't matter.

cp web/sites/example.settings.local.php web/sites/default/settings.local.phpStep 2

Uncomment the conditional include for settings.local.php in your sites/default/settings.php file - it looks like this:

# if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { # include $app_root . '/' . $site_path . '/settings.local.php'; # }

Uncommented, it looks like this:

if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { include $app_root . '/' . $site_path . '/settings.local.php'; }Step 3

There is no step 3. This blog post is complete. 
 

Kernfusion: Bayern macht sich auf den Weg

heise online Newsticker - 6. Februar 2024 - 16:57

Einen Masterplan für den Weg hin zur Kernfusion hat die bayerische Regierung seit knapp einem halben Jahr. Nun fängt sie an, ihn umzusetzen.

Chinesische Chips: SMIC hat nicht genügend 7-Nanometer-Kapazität für Huawei

heise online Newsticker - 6. Februar 2024 - 16:48

Baidu soll bereits fortschrittliche KI-Beschleuniger von Huawei erhalten haben. Sie sind eine Alternative zu Nvidias China-Version H20.