Interactie met de GraphQL API
Interactie met de GraphQL APIGato GraphQL uitvoeren zonder WordPress

Gato GraphQL uitvoeren zonder WordPress

Gato GraphQL is gebouwd met zelfstandige PHP-componenten, beheerd via Composer, op een zodanige manier dat alle PHP-componenten die de GraphQL-server vormen niet afhankelijk zijn van WordPress!

Daardoor kan de GraphQL-server draaien als een zelfstandige PHP-applicatie en kun je hem opnemen in elke PHP-applicatie, gebaseerd op WordPress of wat dan ook.

Als je voor een bepaalde use case geen toegang tot WordPress-gegevens nodig hebt, ben je voor die use case al klaar om te starten.

Deze video demonstreert zo'n use case: communiceren met de GitHub API om artefacten van GitHub Actions te downloaden/installeren tijdens de ontwikkeling:

Demo van headless WordPress zonder WordPress: een GraphQL-query uitvoeren

In de video voert de GraphQL-query een HTTP-verzoek uit om de nieuwste Gato GraphQL-plugins op te halen die zijn gegenereerd in GitHub Actions, en die als artefacten worden geüpload bij het samenvoegen van een pull request.

De URL's van de artefacten uit het GraphQL-antwoord worden vervolgens doorgegeven aan WP-CLI, zodat de plugins automatisch worden geïnstalleerd op een lokale DEV-webserver om tests uit te voeren.

In deze use case, waarbij er helemaal geen toegang is tot WordPress-gegevens, kan de GraphQL-server al draaien als een zelfstandige PHP-app.

In detail: Gato GraphQL uitvoeren als een zelfstandige PHP-app

Hieronder volgt de gedetailleerde uitleg van de demovideo.

We geven de uit te voeren GraphQL-query op in het bestand retrieve-github-artifacts.gql.

De query verbindt met de GitHub API door het toegangstoken op te halen uit de omgevingsvariabele GITHUB_ACCESS_TOKEN. Het genereert dynamisch het volledige pad naar het actions/artifacts-eindpunt op basis van de opgegeven variabelen en stuurt daar vervolgens een HTTP-verzoek naartoe.

Uit het antwoord extraheert het de "download URL" uit elk artefact-item en stuurt asynchrone HTTP-verzoeken naar die adressen. Uit de Location-header van elk van deze "download URL's" verkrijgen we de werkelijke URL van het downloadbare bestand.

Ten slotte worden alle URL's samengevoegd, gescheiden door een spatie, om ze gemakkelijk in WP-CLI te kunnen invoegen.

# File retrieve-github-artifacts.gql
 
query RetrieveProxyArtifactDownloadURLs(
  $repoOwner: String!
  $repoProject: String!
  $perPage: Int = 1
  $artifactName: String = ""
) {
  githubAccessToken: _env(name: "GITHUB_ACCESS_TOKEN")
    @remove
 
  # Maakt de autorisatieheader aan om naar GitHub te sturen
  authorizationHeader: _sprintf(
    string: "Bearer %s"
    values: [$__githubAccessToken]
  )
    @remove
 
  # Maakt de autorisatieheader aan om naar GitHub te sturen
  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]
  )
 
  # Gebruikt het veld uit "Send HTTP Request Fields" om verbinding te maken met GitHub
  gitHubArtifactData: _sendJSONObjectItemHTTPRequest(
    input: {
      url: $__githubAPIEndpoint
      options: { headers: $__githubRequestHeaders }
    }
  )
    @remove
 
  # Extraheert ten slotte de URL uit elk "artifacts"-item
  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: " "
  )
}

De PHP-logica laadt de code rechtstreeks uit de Gato GraphQL-plugin en uit de "Power Extensions"-bundel (nodig voor het versturen van HTTP-verzoeken en andere functionaliteit).

Als zelfstandige PHP-app moeten we expliciet aangeven welke modules worden geïnitialiseerd en eventuele niet-standaard configuratie opgeven.

We vertellen de module SendHTTPRequests bijvoorbeeld dat verbindingen met https://api.github.com/repos zijn toegestaan, en de module EnvironmentFields dat toegang tot de omgevingsvariabele GITHUB_ACCESS_TOKEN is toegestaan.

Merk op dat het GraphQL-schema de eerste keer dat de GraphQL-query wordt uitgevoerd wordt gegenereerd en op schijf wordt gecachet. Hierdoor wordt vanaf de 2e keer geen code meer uitgevoerd om het schema te berekenen, waardoor de uitvoering sneller gaat.

Ten slotte initialiseert de zelfstandige app de GraphQL-server, voert de query daartegen uit en drukt het antwoord af.

<?php
// File retrieve-github-artifacts.php
 
declare(strict_types=1);
 
use GraphQLByPoP\GraphQLServer\Server\StandaloneGraphQLServer;
use PoP\Root\Container\ContainerCacheConfiguration;
 
// Laadt de GraphQL-server via de zelfstandige PHP-componenten
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql/vendor/scoper-autoload.php');
 
// Laadt de PRO-extensies via de zelfstandige PHP-componenten
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql-power-extensions-bundle/vendor/scoper-autoload.php');
 
// Modules die vereist zijn in de GraphQL-query
$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,
];
 
// Configureert de 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',
    ],
  ],
];
 
// Slaat het schema op in de schijfcache om de uitvoering vanaf de 2e keer te versnellen
$containerCacheConfiguration = new ContainerCacheConfiguration('MyGraphQLServer', true, 'retrieve-github-artifacts', __DIR__ . '/tmp');
 
// Initialiseert de server
$graphQLServer = new StandaloneGraphQLServer($moduleClasses, $moduleClassConfiguration, [], [], $containerCacheConfiguration);
 
/**
 * Uit te voeren GraphQL-query, opgeslagen in een eigen .gql-bestand
 *
 * @var string
 */
$query = file_get_contents(__DIR__ . '/retrieve-github-artifacts.gql');
 
// GraphQL-variabelen
$variables = [
  'repoOwner' => 'GatoGraphQL',
  'repoProject' => 'GatoGraphQL',
  'perPage' => 3
];
 
// Voert de query uit
$response = $graphQLServer->execute(
  $query,
  $variables,
);
 
// Drukt het antwoord af
echo $response->getContent();

Om de GraphQL-query uit te voeren, draaien we het volgende in de terminal (met jq voor een nette JSON-opmaak):

php retrieve-github-artifacts.php | jq

Ten slotte, om de artefact-URL's uit het GraphQL-antwoord te extraheren en in WP-CLI te injecteren, draaien we:

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