Executar Gato GraphQL sem WordPress
O Gato GraphQL foi construído utilizando componentes PHP autônomos, gerenciados via Composer, de tal forma que todos os componentes PHP que compõem o servidor GraphQL não dependem do WordPress!
Dessa forma, o servidor GraphQL pode ser executado como uma aplicação PHP autônoma, e você pode incluí-lo em qualquer aplicação PHP, baseada em WordPress ou em qualquer outra tecnologia.
Se para algum caso de uso sua aplicação não precisar acessar dados do WordPress, então, pelo menos para esse caso de uso, você já está pronto para começar.
Este vídeo demonstra um caso de uso assim: interagir com a API do GitHub, para baixar/instalar artefatos do GitHub Actions durante o desenvolvimento:
No vídeo, a query GraphQL executa uma requisição HTTP para buscar os últimos plugins do Gato GraphQL gerados no GitHub Actions, que são enviados como artefatos ao fazer o merge de um pull request.
Os URLs dos artefatos da resposta GraphQL são então injetados no WP-CLI, para que os plugins sejam instalados automaticamente em um servidor web DEV local, para executar os testes.
Neste caso de uso, como nenhum dado do WordPress é acessado, o servidor GraphQL já pode ser executado como uma app PHP autônoma.
Em detalhes: Executar Gato GraphQL como uma app PHP autônoma
Aqui está a explicação detalhada do vídeo demonstrativo.
Fornecemos a query GraphQL a ser executada no arquivo retrieve-github-artifacts.gql.
A query se conecta à API do GitHub obtendo o token de acesso da variável de ambiente GITHUB_ACCESS_TOKEN. Ela gera dinamicamente o caminho completo para o endpoint actions/artifacts a partir das variáveis fornecidas, e então envia uma requisição HTTP contra ele.
Da resposta, extrai então a "download URL" de cada item de artefato, e envia requisições HTTP assíncronas contra elas. Do cabeçalho Location de cada um desses "download URLs", obtemos o URL real do arquivo baixável.
Por fim, imprime todos os URLs juntos separados por um espaço, para facilitar a injeção no 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
# Cria o cabeçalho de autorização para enviar ao GitHub
authorizationHeader: _sprintf(
string: "Bearer %s"
values: [$__githubAccessToken]
)
@remove
# Cria o cabeçalho de autorização para enviar ao 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]
)
# Usa o campo de "Send HTTP Request Fields" para se conectar ao GitHub
gitHubArtifactData: _sendJSONObjectItemHTTPRequest(
input: {
url: $__githubAPIEndpoint
options: { headers: $__githubRequestHeaders }
}
)
@remove
# Por fim, extrai o URL de cada item "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: " "
)
}A lógica PHP carrega diretamente o código do plugin Gato GraphQL, e do bundle "Power Extensions" (necessário para enviar requisições HTTP, e outras funcionalidades).
Como uma app PHP autônoma, devemos indicar explicitamente quais módulos são inicializados, e fornecer qualquer configuração não padrão.
Por exemplo, indicamos ao módulo SendHTTPRequests para permitir a conexão com https://api.github.com/repos, e ao módulo EnvironmentFields para permitir o acesso à variável de ambiente GITHUB_ACCESS_TOKEN.
Observe que o schema GraphQL é gerado na primeira vez que a query GraphQL é executada, e armazenado em cache no disco. Dessa forma, a partir da 2ª vez em diante, nenhum código para calcular o schema é executado, tornando a execução mais rápida.
Por fim, a app autônoma inicializa o servidor GraphQL, executa a query contra ele, e imprime a resposta.
<?php
// File retrieve-github-artifacts.php
declare(strict_types=1);
use GraphQLByPoP\GraphQLServer\Server\StandaloneGraphQLServer;
use PoP\Root\Container\ContainerCacheConfiguration;
// Carrega o servidor GraphQL via os componentes PHP autônomos
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql/vendor/scoper-autoload.php');
// Carrega as extensões PRO via os componentes PHP autônomos
require_once (__DIR__ . '/wordpress/wp-content/plugins/gatographql-power-extensions-bundle/vendor/scoper-autoload.php');
// Módulos necessários na query 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,
];
// Configura os módulos
$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',
],
],
];
// Armazena o schema em cache no disco, para acelerar a execução a partir da 2ª vez
$containerCacheConfiguration = new ContainerCacheConfiguration('MyGraphQLServer', true, 'retrieve-github-artifacts', __DIR__ . '/tmp');
// Inicializa o servidor
$graphQLServer = new StandaloneGraphQLServer($moduleClasses, $moduleClassConfiguration, [], [], $containerCacheConfiguration);
/**
* Query GraphQL a ser executada, armazenada em seu próprio arquivo .gql
*
* @var string
*/
$query = file_get_contents(__DIR__ . '/retrieve-github-artifacts.gql');
// Variáveis GraphQL
$variables = [
'repoOwner' => 'GatoGraphQL',
'repoProject' => 'GatoGraphQL',
'perPage' => 3
];
// Executa a query
$response = $graphQLServer->execute(
$query,
$variables,
);
// Imprime a resposta
echo $response->getContent();Para executar a query GraphQL, rodamos no terminal (usando jq para imprimir o JSON de forma legível):
php retrieve-github-artifacts.php | jqPor fim, para extrair os URLs dos artefatos da resposta GraphQL e injetá-los no WP-CLI, executamos:
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