Un client GraphQL écrit en PHP qui fournit des classes génératrices de requêtes très simples, mais puissantes, qui rendent le processus d'interaction avec un serveur GraphQL très simple.
Il existe 3 manières principales d'utiliser ce package pour générer vos requêtes GraphQL :
Query
. Sa conception est destinée à être utilisée dans les cas où une requête est créée de manière dynamique.Exécutez la commande suivante pour installer le package à l'aide de composer :
$ composer require gmostafa/php-graphql-client
Pour éviter d'avoir à écrire des requêtes et simplement interagir avec les objets PHP générés à partir de votre schéma API, visitez le référentiel PHP GraphQL OQM.
$ gql = ( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
Cette simple requête récupérera toutes les entreprises affichant leurs noms et numéros de série.
La requête fournie dans l'exemple précédent est représentée sous la forme « abrégée ». La forme abrégée implique l'écriture d'un nombre réduit de lignes de code, ce qui accélère le processus d'écriture des requêtes. Vous trouverez ci-dessous un exemple du formulaire complet pour exactement la même requête écrite dans l’exemple précédent.
$ gql = ( new Query ())
-> setSelectionSet (
[
( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
)
]
);
Comme le montre l'exemple, la forme abrégée est plus simple à lire et à écrire, il est généralement préférable de l'utiliser par rapport à la forme complète.
La forme complète ne doit pas être utilisée à moins que la requête ne puisse être représentée sous la forme abrégée, qui n'a qu'un seul cas, lorsque nous voulons exécuter plusieurs requêtes dans le même objet.
$ gql = ( new Query ())
-> setSelectionSet (
[
( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
),
( new Query ( ' countries ' ))
-> setSelectionSet (
[
' name ' ,
' code ' ,
]
)
]
);
Cette requête récupère toutes les entreprises et tous les pays affichant certains champs de données pour chacun. Il exécute essentiellement deux (ou plus si nécessaire) requêtes indépendantes dans une seule enveloppe d'objet de requête.
L'écriture de plusieurs requêtes nécessite d'écrire l'objet de requête sous sa forme complète pour représenter chaque requête sous forme de sous-champ sous l'objet de requête parent.
$ gql = ( new Query ( ' companies ' ))
-> setSelectionSet (
[
' name ' ,
' serialNumber ' ,
( new Query ( ' branches ' ))
-> setSelectionSet (
[
' address ' ,
( new Query ( ' contracts ' ))
-> setSelectionSet ([ ' date ' ])
]
)
]
);
Cette requête est plus complexe, récupérant non seulement les champs scalaires, mais également les champs d'objet. Cette requête renvoie toutes les sociétés, en affichant leurs noms, numéros de série, et pour chaque société, toutes ses succursales, en affichant l'adresse de la succursale, et pour chaque adresse, elle récupère tous les contrats liés à cette adresse, en affichant leurs dates.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' name ' => ' Tech Co. ' , ' first ' => 3 ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
Cette requête ne récupère pas toutes les sociétés en ajoutant des arguments. Cette requête récupérera les 3 premières sociétés portant le nom « Tech Co. », en affichant leurs noms et numéros de série.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' serialNumbers ' => [ 159 , 260 , 371 ]])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
Cette requête est un cas particulier de la requête arguments. Dans cet exemple, la requête récupérera uniquement les sociétés dont le numéro de série est compris entre 159, 260 et 371, en affichant le nom et le numéro de série.
$ gql = ( new Query ( ' companies ' ))
-> setArguments ([ ' filter ' => new RawObject ( ' {name_starts_with: "Face"} ' )])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
Cette requête est un autre cas particulier de la requête d'arguments. Dans cet exemple, nous définissons un « filtre » d’objet d’entrée personnalisé avec certaines valeurs pour limiter les sociétés renvoyées. Nous définissons le filtre "name_starts_with" avec la valeur "Face". Cette requête récupérera uniquement les entreprises dont les noms commencent par l'expression « Face ».
La classe RawObject en cours de construction est utilisée pour injecter la chaîne dans la requête telle quelle. Quelle que soit la chaîne entrée dans le constructeur RawObject, elle sera placée dans la requête telle quelle, sans aucun formatage personnalisé normalement effectué par la classe de requête.
$ gql = ( new Query ( ' companies ' ))
-> setVariables (
[
new Variable ( ' name ' , ' String ' , true ),
new Variable ( ' limit ' , ' Int ' , false , 5 )
]
)
-> setArguments ([ ' name ' => ' $name ' , ' first ' => ' $limit ' ])
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
Cette requête montre comment les variables peuvent être utilisées dans ce package pour autoriser les requêtes dynamiques activées par les normes GraphQL.
La classe Variable est une classe immuable qui représente une variable dans les standards GraphQL. Son constructeur reçoit 4 arguments :
$ 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 '
]
)
]
);
Un alias peut être défini dans le deuxième argument du constructeur Query pour les occasions où le même objet doit être récupéré plusieurs fois avec des arguments différents.
$ gql = ( new Query ( ' companies ' ))
-> setAlias ( ' CompanyAlias ' )
-> setSelectionSet (
[
' name ' ,
' serialNumber '
]
);
L'alias peut également être défini via la méthode setter.
Lors de l'interrogation d'un champ qui renvoie un type d'interface, vous devrez peut-être utiliser des fragments en ligne pour accéder aux données sur le type concret sous-jacent.
Cet exemple montre comment générer des fragments en ligne à l'aide de ce package :
$ gql = new Query ( ' companies ' );
$ gql -> setSelectionSet (
[
' serialNumber ' ,
' name ' ,
( new InlineFragment ( ' PrivateCompany ' ))
-> setSelectionSet (
[
' boardMembers ' ,
' shareholders ' ,
]
),
]
);
La classe QueryBuilder peut être utilisée pour construire des objets Query de manière dynamique, ce qui peut être utile dans certains cas. Son fonctionnement est très similaire à celui de la classe Query, mais la création de la requête est divisée en étapes.
C'est ainsi que l'exemple « Requête avec argument d'objet d'entrée » peut être créé à l'aide de QueryBuilder :
$ builder = ( new QueryBuilder ( ' companies ' ))
-> setVariable ( ' namePrefix ' , ' String ' , true )
-> setArgument ( ' filter ' , new RawObject ( ' {name_starts_with: $namePrefix} ' ))
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();
Comme pour la classe Query, un alias peut être défini à l'aide du deuxième argument du constructeur.
$ builder = ( new QueryBuilder ( ' companies ' , ' CompanyAlias ' ))
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();
Ou via la méthode setter
$ builder = ( new QueryBuilder ( ' companies ' ))
-> setAlias ( ' CompanyAlias ' )
-> selectField ( ' name ' )
-> selectField ( ' serialNumber ' );
$ gql = $ builder -> getQuery ();
Tout comme la classe Query, la classe QueryBuilder peut être écrite sous sa forme complète pour permettre l'écriture de plusieurs requêtes sous un seul objet générateur de requêtes. Vous trouverez ci-dessous un exemple de la façon dont le formulaire complet peut être utilisé avec 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 ();
Cette requête est une extension de la requête de l'exemple précédent. Il renvoie toutes les sociétés commençant par un préfixe de nom et renvoie la société avec le serialNumber
de valeur 123, les deux dans la même réponse.
Un objet client peut facilement être instancié en fournissant l'URL du point de terminaison GraphQL.
Le constructeur Client reçoit également un tableau facultatif « authorizationHeaders », qui peut être utilisé pour ajouter des en-têtes d'autorisation à toutes les requêtes envoyées au serveur GraphQL.
Exemple:
$ client = new Client (
' http://api.graphql.com ' ,
[ ' Authorization ' => ' Basic xyz ' ]
);
Le constructeur Client reçoit également un tableau facultatif "httpOptions", qui remplace les "authorizationHeaders" et peut être utilisé pour ajouter des options de requête personnalisées du client HTTP Guzzle.
Exemple:
$ 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 ' ]
. . .
]
);
Il est possible d'utiliser votre propre client HTTP préconfiguré qui implémente l'interface PSR-18.
Exemple:
$ client = new Client (
' http://api.graphql.com ' ,
[],
[],
$ myHttpClient
);
Exécuter une requête avec le client GraphQL et obtenir les résultats dans la structure de l'objet :
$ results = $ client -> runQuery ( $ gql );
$ results -> getData ()-> companies [ 0 ]-> branches ;
Ou obtenir des résultats dans la structure d'un tableau :
$ results = $ client -> runQuery ( $ gql , true );
$ results -> getData ()[ ' companies ' ][ 1 ][ ' branches ' ][ ' address ' ];
L'exécution de requêtes contenant des variables nécessite de transmettre un tableau associatif qui mappe les noms de variables (clés) aux valeurs de variables (valeurs) à la méthode runQuery
. Voici un exemple :
$ 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 );
Les mutations suivent les mêmes règles de requêtes dans GraphQL, elles sélectionnent des champs sur les objets renvoyés, reçoivent des arguments et peuvent avoir des sous-champs.
Voici un exemple d’exemple sur la façon de construire et d’exécuter des mutations :
$ mutation = ( new Mutation ( ' createCompany ' ))
-> setArguments ([ ' companyObject ' => new RawObject ( ' {name: "Trial Company", employees: 200} ' )])
-> setSelectionSet (
[
' _id ' ,
' name ' ,
' serialNumber ' ,
]
);
$ results = $ client -> runQuery ( $ mutation );
Les mutations peuvent être exécutées par le client de la même manière que les requêtes.
Les mutations peuvent utiliser les variables de la même manière que les requêtes. Voici un exemple sur la façon d'utiliser les variables pour transmettre dynamiquement des objets d'entrée au serveur GraphQL :
$ 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
);
Voici la mutation résultante et les variables transmises avec :
mutation( $ company : CompanyInputObject!) {
createCompany (companyObject: $ company )
}
{"company":{"name":"Tech Company", " type " :"Testing", " size " :"Medium"}}
GraphQL Pokemon est une API GraphQL publique très intéressante disponible pour récupérer des données Pokemon. L'API est disponible publiquement sur le Web, nous l'utiliserons pour démontrer les capacités de ce client.
Lien du dépôt Github : https://github.com/lucasbento/graphql-pokemon
Lien API : https://graphql-pokemon.now.sh/
Cette requête récupère les évolutions de n'importe quel Pokémon et leurs attaques :
query( $ name : String!) {
pokemon (name: $ name ) {
id
number
name
evolutions {
id
number
name
weight {
minimum
maximum
}
attacks {
fast {
name
type
damage
}
}
}
}
}
C'est ainsi que cette requête peut être écrite à l'aide de la classe query et exécutée à l'aide du client :
$ 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 bien, voici comment cette requête peut être générée à l'aide de la 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 ' ]);
Bien que ce ne soit pas l'objectif principal de ce package, il prend en charge l'exécution de requêtes de chaîne brute, comme tout autre client utilisant la méthode runRawQuery
dans la classe Client
. Voici un exemple d'utilisation :
$ gql = <<<QUERY
query {
pokemon(name: "Pikachu") {
id
number
name
attacks {
special {
name
type
damage
}
}
}
}
QUERY ;
$ results = $ client -> runRawQuery ( $ gql );