Запуск Gato GraphQL без WordPress
Gato GraphQL построен с использованием автономных PHP-компонентов, управляемых через Composer, таким образом, что все PHP-компоненты, составляющие GraphQL-сервер, не зависят от WordPress!
Таким образом, GraphQL-сервер может работать как автономное PHP-приложение, и вы можете включить его в любое PHP-приложение — основанное на WordPress или на чём-либо другом.
Если для некоторых сценариев использования ваше приложение не нуждается в доступе к данным WordPress, то, по крайней мере для этих сценариев, вы уже готовы к работе.
В этом видео демонстрируется один из таких сценариев: взаимодействие с API GitHub для загрузки/установки артефактов из GitHub Actions в процессе разработки:
В видео GraphQL query выполняет HTTP-запрос для получения последних плагинов Gato GraphQL, сгенерированных в GitHub Actions и загруженных в качестве артефактов при слиянии pull request.
Затем URL-адреса артефактов из ответа GraphQL передаются в WP-CLI, чтобы плагины автоматически устанавливались на локальном DEV-веб-сервере для запуска тестов.
В этом сценарии, поскольку доступ к данным WordPress не осуществляется вовсе, GraphQL-сервер уже может работать как автономное PHP-приложение.
Подробно: запуск Gato GraphQL как автономного PHP-приложения
Вот подробное описание демонстрационного видео.
Мы предоставляем GraphQL query для выполнения в файле retrieve-github-artifacts.gql.
Query подключается к API GitHub, получая токен доступа из переменной окружения GITHUB_ACCESS_TOKEN. Она динамически формирует полный путь к конечной точке actions/artifacts из предоставленных переменных, а затем отправляет HTTP-запрос к ней.
Из ответа извлекается «download URL» каждого элемента артефакта, после чего к ним отправляются асинхронные HTTP-запросы. Из заголовка Location каждого из этих «download URL» мы получаем фактический URL загружаемого файла.
Наконец, все URL выводятся вместе, разделённые пробелом, что удобно для передачи в WP-CLI.
# 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: " "
)
}PHP-логика непосредственно загружает код из плагина Gato GraphQL и из бандла «Power Extensions» (необходимого для отправки HTTP-запросов и другой функциональности).
Как автономное PHP-приложение, мы должны явно указать, какие модули инициализируются, и предоставить любую нестандартную конфигурацию.
Например, мы сообщаем модулю SendHTTPRequests, что он может подключаться к https://api.github.com/repos, а модулю EnvironmentFields — что он может обращаться к переменной окружения GITHUB_ACCESS_TOKEN.
Обратите внимание, что схема GraphQL генерируется при первом выполнении GraphQL query и кэшируется на диск. Таким образом, начиная со второго раза, ни один из кодов для вычисления схемы не выполняется, что делает работу быстрее.
Наконец, автономное приложение инициализирует GraphQL-сервер, выполняет query против него и выводит ответ.
<?php
// File retrieve-github-artifacts.php
declare(strict_types=1);
use GraphQLByPoP\GraphQLServer\Server\StandaloneGraphQLServer;
use PoP\Root\Container\ContainerCacheConfiguration;
// Load the GraphQL server via the standalone PHP components
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql/vendor/scoper-autoload.php');
// Load the PRO extensions via the standalone PHP components
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql-power-extensions-bundle/vendor/scoper-autoload.php');
// Modules required in the 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,
];
// Configure the 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',
],
],
];
// Cache the schema to disk, to speed-up execution from the 2nd time onwards
$containerCacheConfiguration = new ContainerCacheConfiguration('MyGraphQLServer', true, 'retrieve-github-artifacts', __DIR__ . '/tmp');
// Initialize the server
$graphQLServer = new StandaloneGraphQLServer($moduleClasses, $moduleClassConfiguration, [], [], $containerCacheConfiguration);
/**
* GraphQL query to execute, stored in its own .gql file
*
* @var string
*/
$query = file_get_contents(__DIR__ . '/retrieve-github-artifacts.gql');
// GraphQL variables
$variables = [
'repoOwner' => 'GatoGraphQL',
'repoProject' => 'GatoGraphQL',
'perPage' => 3
];
// Execute the query
$response = $graphQLServer->execute(
$query,
$variables,
);
// Print the response
echo $response->getContent();Для выполнения GraphQL query запускаем в терминале (используя jq для форматированного вывода JSON):
php retrieve-github-artifacts.php | jqНаконец, чтобы извлечь URL артефактов из ответа GraphQL и передать их в WP-CLI, выполняем:
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