Interagir avec l'API GraphQL
Interagir avec l'API GraphQLExécuter Gato GraphQL sans WordPress

Exécuter Gato GraphQL sans WordPress

Gato GraphQL a été construit à l'aide de composants PHP autonomes, gérés via Composer, de telle sorte que tous les composants PHP constituant le serveur GraphQL ne dépendent pas de WordPress !

Ainsi, le serveur GraphQL peut s'exécuter comme une application PHP autonome, et vous pouvez l'inclure dans n'importe quelle application PHP, basée sur WordPress ou autre.

Si pour un cas d'utilisation votre application n'a pas besoin d'accéder aux données WordPress, alors, au moins pour ce cas d'utilisation, vous êtes prêt à démarrer.

Cette vidéo illustre un tel cas d'utilisation : interagir avec l'API GitHub, pour télécharger/installer des artefacts depuis GitHub Actions pendant le développement :

Démo Headless WordPress sans Wordpress : exécution d'une requête GraphQL

Dans la vidéo, la requête GraphQL exécute une requête HTTP pour récupérer les derniers plugins Gato GraphQL générés dans GitHub Actions, qui sont téléversés comme artefacts lors de la fusion d'une pull request.

Les URLs des artefacts de la réponse GraphQL sont ensuite injectées dans WP-CLI, afin que les plugins soient automatiquement installés sur un serveur web DEV local, pour lancer les tests.

Dans ce cas d'utilisation, comme aucune donnée WordPress n'est accédée, le serveur GraphQL peut déjà s'exécuter comme une app PHP autonome.

En détail : Exécuter Gato GraphQL comme une app PHP autonome

Voici l'explication détaillée de la vidéo de démonstration.

Nous fournissons la requête GraphQL à exécuter dans le fichier retrieve-github-artifacts.gql.

La requête se connecte à l'API GitHub en récupérant le token d'accès depuis la variable d'environnement GITHUB_ACCESS_TOKEN. Elle génère dynamiquement le chemin complet pour l'endpoint actions/artifacts à partir des variables fournies, puis envoie une requête HTTP contre celui-ci.

À partir de la réponse, elle extrait ensuite la « download URL » de chaque élément d'artefact, et envoie des requêtes HTTP asynchrones contre elles. Depuis l'en-tête Location de chacune de ces « download URLs », on obtient l'URL réelle du fichier téléchargeable.

Enfin, elle affiche toutes les URLs ensemble séparées par un espace, pour faciliter l'injection dans WP-CLI.

# Fichier retrieve-github-artifacts.gql
 
query RetrieveProxyArtifactDownloadURLs(
  $repoOwner: String!
  $repoProject: String!
  $perPage: Int = 1
  $artifactName: String = ""
) {
  githubAccessToken: _env(name: "GITHUB_ACCESS_TOKEN")
    @remove
 
  # Créer l'en-tête d'autorisation à envoyer à GitHub
  authorizationHeader: _sprintf(
    string: "Bearer %s"
    values: [$__githubAccessToken]
  )
    @remove
 
  # Créer l'en-tête d'autorisation à envoyer à GitHub
  githubRequestHeaders: _echo(
    value: [
      { name: "Accept", value: "application/vnd.github+json" }
      { name: "Authorization", value: $__authorizationHeader }
    ]
  )
    @remove
    @export(as: "githubRequestHeaders")
 
  githubAPIEndpoint: _sprintf(
    string: "https://api.github.com/repos/%s/%s/actions/artifacts?per_page=%s&name=%s"
    values: [$repoOwner, $repoProject, $perPage, $artifactName]
  )
 
  # Utiliser le champ de "Send HTTP Request Fields" pour se connecter à GitHub
  gitHubArtifactData: _sendJSONObjectItemHTTPRequest(
    input: {
      url: $__githubAPIEndpoint
      options: { headers: $__githubRequestHeaders }
    }
  )
    @remove
 
  # Extraire finalement l'URL de chaque élément "artifacts"
  gitHubProxyArtifactDownloadURLs: _objectProperty(
    object: $__gitHubArtifactData
    by: { key: "artifacts" }
  )
    @underEachArrayItem(passValueOnwardsAs: "artifactItem")
      @applyField(
        name: "_objectProperty"
        arguments: { object: $artifactItem, by: { key: "archive_download_url" } }
        setResultInResponse: true
      )
    @export(as: "gitHubProxyArtifactDownloadURLs")
}
 
query CreateHTTPRequestInputs
  @depends(on: "RetrieveProxyArtifactDownloadURLs")
{
  httpRequestInputs: _echo(value: $gitHubProxyArtifactDownloadURLs)
    @underEachArrayItem(passValueOnwardsAs: "url")
      @applyField(
        name: "_objectAddEntry"
        arguments: {
          object: {
            options: { headers: $githubRequestHeaders, allowRedirects: null }
          }
          key: "url"
          value: $url
        }
        setResultInResponse: true
      )
    @export(as: "httpRequestInputs")
    @remove
}
 
query RetrieveActualArtifactDownloadURLs
  @depends(on: "CreateHTTPRequestInputs")
{
  _sendHTTPRequests(inputs: $httpRequestInputs) {
    artifactDownloadURL: header(name: "Location")
      @export(as: "artifactDownloadURLs", type: LIST)
  }
}
 
query PrintSpaceSeparatedArtifactDownloadURLs
  @depends(on: "RetrieveActualArtifactDownloadURLs")
{
  spaceSeparatedArtifactDownloadURLs: _arrayJoin(
    array: $artifactDownloadURLs
    separator: " "
  )
}

La logique PHP charge directement le code du plugin Gato GraphQL, et du bundle « Power Extensions » (nécessaire pour envoyer des requêtes HTTP, et d'autres fonctionnalités).

En tant qu'app PHP autonome, nous devons indiquer explicitement quels modules sont initialisés, et fournir toute configuration non par défaut.

Par exemple, nous indiquons au module SendHTTPRequests d'autoriser la connexion à https://api.github.com/repos, et au module EnvironmentFields d'autoriser l'accès à la variable d'environnement GITHUB_ACCESS_TOKEN.

Notez que le schéma GraphQL est généré la première fois que la requête GraphQL est exécutée, et mis en cache sur disque. Ainsi, à partir de la 2ème fois, aucun code de calcul du schéma n'est exécuté, ce qui accélère l'exécution.

Enfin, l'app autonome initialise le serveur GraphQL, exécute la requête contre celui-ci, et affiche la réponse.

<?php
// Fichier retrieve-github-artifacts.php
 
declare(strict_types=1);
 
use GraphQLByPoP\GraphQLServer\Server\StandaloneGraphQLServer;
use PoP\Root\Container\ContainerCacheConfiguration;
 
// Charger le serveur GraphQL via les composants PHP autonomes
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql/vendor/scoper-autoload.php');
 
// Charger les extensions PRO via les composants PHP autonomes
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql-power-extensions-bundle/vendor/scoper-autoload.php');
 
// Modules requis dans la requête GraphQL
$moduleClasses = [
  \PoPSchema\EnvironmentFields\Module::class,
  \PoPSchema\FunctionFields\Module::class,
  \GraphQLByPoP\ExportDirective\Module::class,
  \GraphQLByPoP\DependsOnOperationsDirective\Module::class,
  \GraphQLByPoP\RemoveDirective\Module::class,
  \PoPSchema\ApplyFieldDirective\Module::class,
  \PoPSchema\SendHTTPRequests\Module::class,
  \PoPSchema\ConditionalMetaDirectives\Module::class,
  \PoPSchema\DataIterationMetaDirectives\Module::class,
];
 
// Configurer les modules
$moduleClassConfiguration = [
  \PoP\GraphQLParser\Module::class => [
    \PoP\GraphQLParser\Environment::ENABLE_MULTIPLE_QUERY_EXECUTION => true,
    \PoP\GraphQLParser\Environment::USE_LAST_OPERATION_IN_DOCUMENT_FOR_MULTIPLE_QUERY_EXECUTION_WHEN_OPERATION_NAME_NOT_PROVIDED => true,
    \PoP\GraphQLParser\Environment::ENABLE_RESOLVED_FIELD_VARIABLE_REFERENCES => true,
    \PoP\GraphQLParser\Environment::ENABLE_COMPOSABLE_DIRECTIVES => true,
  ],
  \PoPSchema\SendHTTPRequests\Module::class => [
    \PoPSchema\SendHTTPRequests\Environment::SEND_HTTP_REQUEST_URL_ENTRIES => [
      '#https://api.github.com/repos/(.*)#',
    ],
  ],
  \PoPSchema\EnvironmentFields\Module::class => [
    \PoPSchema\EnvironmentFields\Environment::ENVIRONMENT_VARIABLE_OR_PHP_CONSTANT_ENTRIES => [
      'GITHUB_ACCESS_TOKEN',
    ],
  ],
];
 
// Mettre en cache le schéma sur disque, pour accélérer l'exécution à partir de la 2ème fois
$containerCacheConfiguration = new ContainerCacheConfiguration('MyGraphQLServer', true, 'retrieve-github-artifacts', __DIR__ . '/tmp');
 
// Initialiser le serveur
$graphQLServer = new StandaloneGraphQLServer($moduleClasses, $moduleClassConfiguration, [], [], $containerCacheConfiguration);
 
/**
 * Requête GraphQL à exécuter, stockée dans son propre fichier .gql
 *
 * @var string
 */
$query = file_get_contents(__DIR__ . '/retrieve-github-artifacts.gql');
 
// Variables GraphQL
$variables = [
  'repoOwner' => 'GatoGraphQL',
  'repoProject' => 'GatoGraphQL',
  'perPage' => 3
];
 
// Exécuter la requête
$response = $graphQLServer->execute(
  $query,
  $variables,
);
 
// Afficher la réponse
echo $response->getContent();

Pour exécuter la requête GraphQL, on lance dans le terminal (en utilisant jq pour afficher joliment le JSON) :

php retrieve-github-artifacts.php | jq

Enfin, pour extraire les URLs des artefacts de la réponse GraphQL et les injecter dans WP-CLI, on exécute :

GITHUB_ARTIFACT_URLS=$(php retrieve-github-artifacts.php \
  | grep -E -o '"spaceSeparatedArtifactDownloadURLs\":"(.*)"' \
  | cut -d':' -f2- | cut -d'"' -f2- | rev | cut -d'"' -f2- | rev \
  | sed 's/\\\//\//g')
wp plugin install ${GITHUB_ARTIFACT_URLS} --force --activate