Um cliente GraphQL escrito em PHP que fornece classes geradoras de consultas muito simples, mas poderosas, que tornam o processo de interação com um servidor GraphQL muito simples.
Existem três maneiras principais de usar este pacote para gerar suas consultas GraphQL:
Query dinamicamente. É projetado para ser utilizado em casos onde uma consulta está sendo construída de forma dinâmica.Execute o seguinte comando para instalar o pacote usando o compositor:
$ composer require gmostafa/php-graphql-client
Para evitar o incômodo de ter que escrever qualquer consulta e apenas interagir com objetos PHP gerados a partir do seu esquema de API, visite o repositório PHP GraphQL OQM
$ gql = ( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);Esta consulta simples recuperará todas as empresas exibindo seus nomes e números de série.
A consulta fornecida no exemplo anterior é representada na "forma abreviada". A forma abreviada envolve escrever um número reduzido de linhas de código, o que acelera o processo de escrita de consultas. Abaixo está um exemplo do formulário completo para exatamente a mesma consulta escrita no exemplo anterior.
$ gql = ( new Query ())
-> setSelectionSet (
[
( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
)
]
);Como visto no exemplo, a forma abreviada é mais simples de ler e escrever e geralmente é preferida em comparação à forma completa.
O formulário completo não deve ser usado a menos que a consulta não possa ser representada na forma abreviada, que possui apenas um caso, quando queremos executar múltiplas consultas no mesmo objeto.
$ gql = ( new Query ())
-> setSelectionSet (
[
( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
),
( new Query ( ' countries ' ))
-> setSelectionSet (
[
' name ' ,
' code ' ,
]
)
]
);Esta consulta recupera todas as empresas e países exibindo alguns campos de dados para cada um. Basicamente, ele executa duas (ou mais, se necessário) consultas independentes em um envelope de objeto de consulta.
Escrever múltiplas consultas requer escrever o objeto de consulta no formato completo para representar cada consulta como um subcampo no objeto de consulta pai.
$ gql = ( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber ' ,
( new Query ( ' branches ' ))
-> setSelectionSet (
[
' address ' ,
( new Query ( ' contracts ' ))
-> setSelectionSet ([ ' date ' ])
]
)
]
);Esta consulta é mais complexa, recuperando não apenas campos escalares, mas também campos de objetos. Esta consulta retorna todas as empresas, exibindo seus nomes, números de série, e para cada empresa, todas as suas filiais, exibindo o endereço da filial, e para cada endereço, recupera todos os contratos vinculados a este endereço, exibindo suas datas.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' name ' => ' Tech Co. ' , ' first ' => 3 ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);Esta consulta não recupera todas as empresas adicionando argumentos. Esta consulta irá recuperar as 3 primeiras empresas com o nome "Tech Co.", exibindo seus nomes e números de série.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' serialNumbers ' => [ 159 , 260 , 371 ]])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);Esta consulta é um caso especial da consulta de argumentos. Neste exemplo, a consulta irá recuperar apenas as empresas com número de série entre 159, 260 e 371, exibindo o nome e o número de série.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' filter ' => new RawObject ( ' {name_starts_with: "Face"} ' )])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);Esta consulta é outro caso especial da consulta de argumentos. Neste exemplo, estamos definindo um "filtro" de objeto de entrada personalizado com alguns valores para limitar as empresas que estão sendo retornadas. Estamos configurando o filtro "name_starts_with" com valor "Face". Esta consulta irá recuperar apenas as empresas cujos nomes começam com a frase “Face”.
A classe RawObject que está sendo construída é usada para injetar a string na consulta como ela está. Qualquer string inserida no construtor RawObject será colocada na consulta como está, sem qualquer formatação personalizada normalmente feita pela classe de consulta.
$ gql = ( new Query ( ' companies ' ))
-> setVariables (
[
new Variable ( ' name ' , ' String ' , true ),
new Variable ( ' limit ' , ' Int ' , false , 5 )
]
)
-> setArguments ([ ' name ' => ' $name ' , ' first ' => ' $limit ' ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);Esta consulta mostra como as variáveis podem ser usadas neste pacote para permitir solicitações dinâmicas habilitadas pelos padrões GraphQL.
A classe Variable é uma classe imutável que representa uma variável nos padrões GraphQL. Seu construtor recebe 4 argumentos:
$ gql = ( new Query ())
-> setSelectionSet (
[
( new Query ( ' companies ' , ' TechCo ' ))
-> setArguments ([ ' name ' => ' Tech Co. ' ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
),
( new Query ( ' companies ' , ' AnotherTechCo ' ))
-> setArguments ([ ' name ' => ' A.N. Other Tech Co. ' ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
)
]
);Um alias pode ser definido no segundo argumento do construtor Query para ocasiões em que o mesmo objeto precisa ser recuperado diversas vezes com argumentos diferentes.
$ gql = ( new Query ( ' companies ' ))
-> setAlias ( ' CompanyAlias ' )
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);O alias também pode ser definido através do método setter.
Ao consultar um campo que retorna um tipo de interface, talvez seja necessário usar fragmentos embutidos para acessar dados no tipo concreto subjacente.
Este exemplo mostra como gerar fragmentos embutidos usando este pacote:
$ gql = new Query ( ' companies ' );
$ gql -> setSelectionSet (
[
' serialNumber ' ,
' name ' ,
( new InlineFragment ( ' PrivateCompany ' ))
-> setSelectionSet (
[
' boardMembers ' ,
' shareholders ' ,
]
),
]
);A classe QueryBuilder pode ser usada para construir objetos Query dinamicamente, o que pode ser útil em alguns casos. Funciona de forma muito semelhante à classe Query, mas a construção da Query é dividida em etapas.
É assim que o exemplo "Query With Input Object Argument" pode ser criado usando o QueryBuilder:
$ builder = ( new QueryBuilder ( ' companies ' ))
-> setVariable ( ' namePrefix ' , ' String ' , true )
-> setArgument ( ' filter ' , new RawObject ( ' {name_starts_with: $namePrefix} ' ))
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();Tal como acontece com a classe Query, um alias pode ser definido usando o segundo argumento do construtor.
$ builder = ( new QueryBuilder ( ' companies ' , ' CompanyAlias ' ))
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();Ou através do método setter
$ builder = ( new QueryBuilder ( ' companies ' ))
-> setAlias ( ' CompanyAlias ' )
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();Assim como a classe Query, a classe QueryBuilder pode ser escrita em formato completo para permitir a gravação de várias consultas em um objeto construtor de consultas. Abaixo está um exemplo de como o formulário completo pode ser usado com o QueryBuilder:
$ builder = ( new QueryBuilder ())
-> setVariable ( ' namePrefix ' , ' String ' , true )
-> selectField (
( new QueryBuilder ( ' companies ' ))
-> setArgument ( ' filter ' , new RawObject ( ' {name_starts_with: $namePrefix} ' ))
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' )
)
-> selectField (
( new QueryBuilder ( ' company ' ))
-> setArgument ( ' serialNumber ' , 123 )
-> selectField ( ' name ' )
);
$ gql = $ builder -> getQuery (); Esta consulta é uma extensão da consulta do exemplo anterior. Ele retorna todas as empresas começando com um prefixo de nome e retorna a empresa com o serialNumber de valor 123, ambos na mesma resposta.
Um objeto Cliente pode ser facilmente instanciado fornecendo o URL do endpoint GraphQL.
O construtor Client também recebe um array opcional "authorizationHeaders", que pode ser usado para adicionar cabeçalhos de autorização a todas as solicitações enviadas ao servidor GraphQL.
Exemplo:
$ client = new Client (
' http://api.graphql.com ' ,
[ ' Authorization ' => ' Basic xyz ' ]
);O construtor Client também recebe um array opcional "httpOptions", que substitui "authorizationHeaders" e pode ser usado para adicionar opções personalizadas de solicitação do Guzzle HTTP Client.
Exemplo:
$ client = new Client (
' http://api.graphql.com ' ,
[],
[
' connect_timeout ' => 5 ,
' timeout ' => 5 ,
' headers ' => [
' Authorization ' => ' Basic xyz '
'User-Agent' => ' testing/1.0 ' ,
],
' proxy ' => [
' http ' => ' tcp://localhost:8125 ' , // Use this proxy with "http"
' https ' => ' tcp://localhost:9124 ' , // Use this proxy with "https",
' no ' => [ ' .mit.edu ' , ' foo.com ' ] // Don't use a proxy with these
],
' cert ' => [ ' /path/server.pem ' , ' password ' ]
. . .
]
);É possível utilizar seu próprio cliente HTTP pré-configurado que implementa a interface PSR-18.
Exemplo:
$ client = new Client (
' http://api.graphql.com ' ,
[],
[],
$ myHttpClient
);Executando consulta com o cliente GraphQL e obtendo os resultados na estrutura do objeto:
$ results = $ client -> runQuery ( $ gql );
$ results -> getData ()-> companies [ 0 ]-> branches ;Ou obtendo resultados na estrutura do array:
$ results = $ client -> runQuery ( $ gql , true );
$ results -> getData ()[ ' companies ' ][ 1 ][ ' branches ' ][ ' address ' ]; A execução de consultas contendo variáveis requer a passagem de uma matriz associativa que mapeia nomes de variáveis (chaves) para valores de variáveis (valores) para o método runQuery . Aqui está um exemplo:
$ gql = ( new Query ( ' companies ' ))
-> setVariables (
[
new Variable ( ' name ' , ' String ' , true ),
new Variable ( ' limit ' , ' Int ' , false , 5 )
]
)
-> setArguments ([ ' name ' => ' $name ' , ' first ' => ' $limit ' ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
$ variablesArray = [ ' name ' => ' Tech Co. ' , ' first ' => 5 ];
$ results = $ client -> runQuery ( $ gql , true , $ variablesArray );As mutações seguem as mesmas regras das consultas do GraphQL, selecionam campos nos objetos retornados, recebem argumentos e podem ter subcampos.
Aqui está um exemplo de como construir e executar mutações:
$ mutation = ( new Mutation ( ' createCompany ' ))
-> setArguments ([ ' companyObject ' => new RawObject ( ' {name: "Trial Company", employees: 200} ' )])
-> setSelectionSet (
[
' _id ' ,
' name ' ,
' serialNumber ' ,
]
);
$ results = $ client -> runQuery ( $ mutation );As mutações podem ser executadas pelo cliente da mesma forma que as consultas são executadas.
As mutações podem utilizar as variáveis da mesma forma que as consultas. Aqui está um exemplo de como usar as variáveis para passar objetos de entrada para o servidor GraphQL dinamicamente:
$ mutation = ( new Mutation ( ' createCompany ' ))
-> setVariables ([ new Variable ( ' company ' , ' CompanyInputObject ' , true )])
-> setArguments ([ ' companyObject ' => ' $company ' ]);
$ variables = [ ' company ' => [ ' name ' => ' Tech Company ' , ' type ' => ' Testing ' , ' size ' => ' Medium ' ]];
$ client -> runQuery (
$ mutation , true , $ variables
);Estas são a mutação resultante e as variáveis passadas com ela:
mutation( $ company : CompanyInputObject!) {
createCompany (companyObject: $ company )
}
{"company":{"name":"Tech Company", " type " :"Testing", " size " :"Medium"}}GraphQL Pokémon é uma API GraphQL pública muito interessante disponível para recuperar dados de Pokémon. A API está disponível publicamente na web, vamos usá-la para demonstrar os recursos deste cliente.
Link do repositório Github: https://github.com/lucasbento/graphql-pokemon
Link da API: https://graphql-pokemon.now.sh/
Esta consulta recupera as evoluções de qualquer pokémon e seus ataques:
query( $ name : String!) {
pokemon (name: $ name ) {
id
number
name
evolutions {
id
number
name
weight {
minimum
maximum
}
attacks {
fast {
name
type
damage
}
}
}
}
}É assim que esta consulta pode ser escrita usando a classe de consulta e executada usando o cliente:
$ client = new Client (
' https://graphql-pokemon.now.sh/ '
);
$ gql = ( new Query ( ' pokemon ' ))
-> setVariables ([ new Variable ( ' name ' , ' String ' , true )])
-> setArguments ([ ' name ' => ' $name ' ])
-> setSelectionSet (
[
' id ' ,
' number ' ,
' name ' ,
( new Query ( ' evolutions ' ))
-> setSelectionSet (
[
' id ' ,
' number ' ,
' name ' ,
( new Query ( ' attacks ' ))
-> setSelectionSet (
[
( new Query ( ' fast ' ))
-> setSelectionSet (
[
' name ' ,
' type ' ,
' damage ' ,
]
)
]
)
]
)
]
);
try {
$ name = readline ( ' Enter pokemon name: ' );
$ results = $ client -> runQuery ( $ gql , true , [ ' name ' => $ name ]);
}
catch ( QueryError $ exception ) {
print_r ( $ exception -> getErrorDetails ());
exit ;
}
print_r ( $ results -> getData ()[ ' pokemon ' ]);Ou alternativamente, é assim que esta consulta pode ser gerada usando a classe QueryBuilder:
$ client = new Client (
' https://graphql-pokemon.now.sh/ '
);
$ builder = ( new QueryBuilder ( ' pokemon ' ))
-> setVariable ( ' name ' , ' String ' , true )
-> setArgument ( ' name ' , ' $name ' )
-> selectField ( ' id ' )
-> selectField ( ' number ' )
-> selectField ( ' name ' )
-> selectField (
( new QueryBuilder ( ' evolutions ' ))
-> selectField ( ' id ' )
-> selectField ( ' name ' )
-> selectField ( ' number ' )
-> selectField (
( new QueryBuilder ( ' attacks ' ))
-> selectField (
( new QueryBuilder ( ' fast ' ))
-> selectField ( ' name ' )
-> selectField ( ' type ' )
-> selectField ( ' damage ' )
)
)
);
try {
$ name = readline ( ' Enter pokemon name: ' );
$ results = $ client -> runQuery ( $ builder , true , [ ' name ' => $ name ]);
}
catch ( QueryError $ exception ) {
print_r ( $ exception -> getErrorDetails ());
exit ;
}
print_r ( $ results -> getData ()[ ' pokemon ' ]); Embora não seja o objetivo principal deste pacote, ele suporta a execução de consultas de string brutas, assim como qualquer outro cliente usando o método runRawQuery na classe Client . Aqui está um exemplo de como usá-lo:
$ gql = <<<QUERY
query {
pokemon(name: "Pikachu") {
id
number
name
attacks {
special {
name
type
damage
}
}
}
}
QUERY ;
$ results = $ client -> runRawQuery ( $ gql );