Mit der GraphQL API interagieren
Mit der GraphQL API interagierenGato GraphQL ohne WordPress ausführen

Gato GraphQL ohne WordPress ausführen

Gato GraphQL wurde mit eigenständigen PHP-Komponenten erstellt, die über Composer verwaltet werden, sodass alle PHP-Komponenten, die den GraphQL-Server ausmachen, nicht von WordPress abhängig sind!

Daher kann der GraphQL-Server als eigenständige PHP-Anwendung ausgeführt werden, und du kannst ihn in jede PHP-Anwendung einbinden, die auf WordPress oder irgendetwas anderem basiert.

Wenn deine Anwendung für einen bestimmten Anwendungsfall nicht auf WordPress-Daten zugreifen muss, bist du zumindest für diesen Anwendungsfall bereit loszulegen.

Dieses Video zeigt einen solchen Anwendungsfall: Interaktion mit der GitHub-API, um Artefakte aus GitHub Actions während der Entwicklung herunterzuladen/zu installieren:

Demo Headless WordPress ohne WordPress: Ausführung einer GraphQL-query

Im Video führt die GraphQL-query eine HTTP-Anfrage aus, um die neuesten Gato GraphQL-Plugins abzurufen, die in GitHub Actions generiert wurden und beim Mergen eines Pull Requests als Artefakte hochgeladen werden.

Die URLs der Artefakte aus der GraphQL-Antwort werden dann in WP-CLI injiziert, damit die Plugins automatisch auf einem lokalen DEV-Webserver installiert werden, um Tests auszuführen.

In diesem Anwendungsfall, da überhaupt keine WordPress-Daten abgerufen werden, kann der GraphQL-Server bereits als eigenständige PHP-App ausgeführt werden.

Im Detail: Gato GraphQL als eigenständige PHP-App ausführen

Hier ist die detaillierte Erklärung des Demo-Videos.

Wir stellen die auszuführende GraphQL-query in der Datei retrieve-github-artifacts.gql bereit.

Die query verbindet sich mit der GitHub-API, indem sie das Zugriffstoken aus der Umgebungsvariable GITHUB_ACCESS_TOKEN holt. Sie generiert dynamisch den vollständigen Pfad für den actions/artifacts-Endpunkt aus den bereitgestellten Variablen und sendet dann eine HTTP-Anfrage dagegen.

Aus der Antwort extrahiert sie dann die „Download-URL" aus jedem Artefakt-Element und sendet asynchrone HTTP-Anfragen dagegen. Aus dem Location-Header jeder dieser „Download-URLs" erhalten wir die tatsächliche URL der herunterladbaren Datei.

Schließlich gibt sie alle URLs zusammen, durch ein Leerzeichen getrennt, aus, um die Injektion in WP-CLI zu erleichtern.

# File retrieve-github-artifacts.gql
 
query RetrieveProxyArtifactDownloadURLs(
  $repoOwner: String!
  $repoProject: String!
  $perPage: Int = 1
  $artifactName: String = ""
) {
  githubAccessToken: _env(name: "GITHUB_ACCESS_TOKEN")
    @remove
 
  # Create the authorization header to send to GitHub
  authorizationHeader: _sprintf(
    string: "Bearer %s"
    values: [$__githubAccessToken]
  )
    @remove
 
  # Create the authorization header to send to 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]
  )
 
  # Use the field from "Send HTTP Request Fields" to connect to GitHub
  gitHubArtifactData: _sendJSONObjectItemHTTPRequest(
    input: {
      url: $__githubAPIEndpoint
      options: { headers: $__githubRequestHeaders }
    }
  )
    @remove
 
  # Finally just extract the URL from within each "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: " "
  )
}

Die PHP-Logik lädt den Code direkt aus dem Gato GraphQL-Plugin und aus dem „Power Extensions"-Bundle (benötigt zum Senden von HTTP-Anfragen und anderen Funktionalitäten).

Als eigenständige PHP-App müssen wir explizit angeben, welche Module initialisiert werden, und eine von der Standardkonfiguration abweichende Konfiguration bereitstellen.

Beispielsweise weisen wir das Modul SendHTTPRequests an, die Verbindung zu https://api.github.com/repos zu erlauben, und das Modul EnvironmentFields, den Zugriff auf die Umgebungsvariable GITHUB_ACCESS_TOKEN zu erlauben.

Beachte, dass das GraphQL-Schema beim ersten Ausführen der GraphQL-query generiert und auf der Festplatte zwischengespeichert wird. Auf diese Weise wird ab dem 2. Mal kein Code zur Berechnung des Schemas mehr ausgeführt, was die Ausführung schneller macht.

Schließlich initialisiert die eigenständige App den GraphQL-Server, führt die query dagegen aus und gibt die Antwort aus.

<?php
// File retrieve-github-artifacts.php
 
declare(strict_types=1);
 
use GraphQLByPoP\GraphQLServer\Server\StandaloneGraphQLServer;
use PoP\Root\Container\ContainerCacheConfiguration;
 
// Lade den GraphQL-Server über die eigenständigen PHP-Komponenten
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql/vendor/scoper-autoload.php');
 
// Lade die PRO-Erweiterungen über die eigenständigen PHP-Komponenten
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql-power-extensions-bundle/vendor/scoper-autoload.php');
 
// In der GraphQL-query benötigte Module
$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,
];
 
// Konfiguriere die Module
$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',
    ],
  ],
];
 
// Schema auf der Festplatte zwischenspeichern, um die Ausführung ab dem 2. Mal zu beschleunigen
$containerCacheConfiguration = new ContainerCacheConfiguration('MyGraphQLServer', true, 'retrieve-github-artifacts', __DIR__ . '/tmp');
 
// Server initialisieren
$graphQLServer = new StandaloneGraphQLServer($moduleClasses, $moduleClassConfiguration, [], [], $containerCacheConfiguration);
 
/**
 * Auszuführende GraphQL-query, in einer eigenen .gql-Datei gespeichert
 *
 * @var string
 */
$query = file_get_contents(__DIR__ . '/retrieve-github-artifacts.gql');
 
// GraphQL-Variablen
$variables = [
  'repoOwner' => 'GatoGraphQL',
  'repoProject' => 'GatoGraphQL',
  'perPage' => 3
];
 
// Query ausführen
$response = $graphQLServer->execute(
  $query,
  $variables,
);
 
// Antwort ausgeben
echo $response->getContent();

Um die GraphQL-query auszuführen, starten wir im Terminal (mit jq zum lesbaren Ausgeben des JSON):

php retrieve-github-artifacts.php | jq

Schließlich führen wir folgendes aus, um die Artefakt-URLs aus der GraphQL-Antwort zu extrahieren und in WP-CLI zu injizieren:

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