Pour les besoins d'une de mes formations, j'ai dû mettre en place un drupal 8 découplé.

CORS (Cross-origin resource sharing)

Le « partage de ressources entre origines multiples » (Cross-Origin Resource Sharing, CORS) est désactivé par défaut dans drupal 8.

Pour régler cela : 2 actions :

  • sur le serveur apache 
    • sudo a2enmod headers
    • Dans le fichier de conf d'apache (/etc/apache2/sites-available/mysite.conf :
<VirtualHost *:80>
    ServerAdmin admin@example.com
    ServerName local.d8-json.my
    DocumentRoot /home/yvan/dev/d8-json/web
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<Directory /home/yvan/dev/d8-json/web>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
        Header set Access-Control-Allow-Origin "*"
</Directory>

Puis 

sudo a2dissite d8-json.conf
sudo systemctl reload apache2
sudo a2ensite d8-json.conf
sudo systemctl reload apache2
  • dans le fichier web/sites/default/services.yml :

cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token', 'authorization', 'content-type', 'accept', 'origin', 'x-requested-with']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['POST', 'GET', 'OPTIONS', 'DELETE', 'PUT', 'PATCH']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: false

Le front-office sera fait uniquement en js et css et le back office est drupal 8.

Côté Drupal

  • activer les modules  du coeur dans la catégorie "Web Services"

    • HAL

    • HTTP Basic Authentification
    • RESTful Web Services
    • Serialization
  • le module contrib
    • REST UI
  • Créer un module custom Ex : test_rest dans lequel j'ai créé
    • le fichier test_rest.info.yml :
name: test_rest
description: 'Test rest
package: Coopernet
type: module
version: 1.0
core: 8.x
dependencies:
  - drupal:node
  - drupal:path
  - drupal:text
  • le fichier web/modules/custom/test_rest/src/Plugin/rest/resource/ListArticles.php
<?php
namespace Drupal\test_rest\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
/**
 * Provides a Demo Resource
 *
 * @RestResource(
 *   id = "list_articles",
 *   label = @Translation("Articles Resource"),
 *   uri_paths = {
 *     "canonical" = "/test_rest/list_articles"
 *   }
 * )
 */
class ListCartes extends ResourceBase {
  /**
   * Responds to entity GET requests.
   * @return \Drupal\rest\ResourceResponse
   */
  public function get() {
    $response = ['message' => 'Liste des articles bientôt !!!'];
    return new ResourceResponse($response);
  }
}
  • puis activer le point d'entrée (endpoint) de la ressource, en l'occurence "Articles Resource" dans l'interface de REST UI (/admin/config/services/rest) en donnant tous les droits nécessaires
  • enfin, faire appel à ce point d'entrée vial js :
(function() {
  console.log("Hello");
  // création de la requête
  const req = new XMLHttpRequest();

  function enCours(event) {
    // On teste directement le status de notre instance de XMLHttpRequest
    if (this.status === 200) {
      // Tout baigne, voici le contenu de la réponse
      console.log("Contenu", this.responseText);
    } else {
      // On y est pas encore, voici le statut actuel
      console.log("Statut actuel", this.status, this.statusText);
    }
  }

  req.onload = enCours;

  // ouverture de la requête
  //req.open("GET", "/node/3?_format=hal_json", true);
  req.open("GET", "/memo/list_cartes?_format=json", true);
  // en complément
  req.setRequestHeader("Content-Type", "application/hal+json");
  // envoi de la requête
  req.send(null);
})();
  • Par défaut le super utilisateur est autorisé à obtenir des données via tous les points d'entrée (endpoint) mais si vous souhaitez donner l'accès à d'autres utilisateurs, il faudra vous rendre sur l'interface classique des droits de drupal et gérer chaque accès (rubrique "RESTful Web Services")

Problèmes rencontrés 

Status 422

Failed to load resource: the server responded with a status of 422 (Unprocessable Entity)
rest/type/node/article does not correspond to an entity on this site 

Solution : vider les caches : drush cr source : https://www.drupal.org/project/restui/issues/2599364

error 404 -  No route found for "POST ... 

Dans le cas d'une requête post, attention à ajouter une deuxième ligne concernant uri_paths :

uri_paths = {
 *     "canonical" = "/foolzz_rest_api/profile/{uid}",
 *     "https://www.drupal.org/link-relations/create" = "/foolzz_rest_api/profile/{uid}"
 *   }