• Stars
    star
    113
  • Rank 301,923 (Top 7 %)
  • Language
    PHP
  • License
    Other
  • Created almost 7 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

PHP Client for GraphQL

PHP GraphQL Client

Latest Version Software License Build Status Total Downloads Average time to resolve an issue Percentage of issues still open

PHP Client for GraphQL

Main features

  • Client with Oauth2 Support
  • Easy query/mutation execution
  • Simple array results for mutation and queries
  • Powerful object results for mutation and queries
    • Filter results
    • Manipulate results precisely and bulk
    • Transform query results in mutations

Installation

Via composer:

composer require softonic/graphql-client

Documentation

Instantiate a client

You can instantiate a simple client or with Oauth2 support.

Simple Client:

<?php
$client = \Softonic\GraphQL\ClientBuilder::build('https://your-domain/graphql');

OAuth2 provider:

<?php

$options = [
    'clientId'     => 'myclient',
    'clientSecret' => 'mysecret',
];

$provider = new Softonic\OAuth2\Client\Provider\Softonic($options);

$config = ['grant_type' => 'client_credentials', 'scope' => 'myscope'];

$cache = new \Symfony\Component\Cache\Adapter\FilesystemAdapter();

$client = \Softonic\GraphQL\ClientBuilder::buildWithOAuth2Provider(
    'https://your-domain/graphql',
    $provider,
    $config,
    $cache
);

Using the GraphQL Client

You can use the client to execute queries and mutations and get the results.

<?php

/**
 * Query Example
 */
$query = <<<'QUERY'
query GetFooBar($idFoo: String, $idBar: String) {
  foo(id: $idFoo) {
    id_foo
    bar (id: $idBar) {
      id_bar
    }
  }
}
QUERY;

$variables = [
    'idFoo' => 'foo',
    'idBar' => 'bar',
];

/** @var \Softonic\GraphQL\Client $client */
$response = $client->query($query, $variables);

if($response->hasErrors()) {
    // Returns an array with all the errors found.
    $response->getErrors();
}
else {
    // Returns an array with all the data returned by the GraphQL server.
    $response->getData();
}

/**
 * Mutation Example
 */
$mutation = <<<'MUTATION'
mutation ($foo: ObjectInput!){
  CreateObjectMutation (object: $foo) {
    status
  }
}
MUTATION;
$variables = [
    'foo' => [
        'id_foo' => 'foo', 
        'bar' => [
            'id_bar' => 'bar'
        ]
    ]
];

/** @var \Softonic\GraphQL\Client $client */
$response = $client->query($mutation, $variables);

if($response->hasErrors()) {
    // Returns an array with all the errors found.
    $response->getErrors();
}
else {
    // Returns an array with all the data returned by the GraphQL server.
    $response->getData();
}

In the previous examples, the client is used to execute queries and mutations. The response object is used to get the results in array format.

This can be convenient for simple use cases, but it is not recommended for complex results or when you need to use that output to generate mutations. For this reason, the client provides another output called data objects. Those objects allow you to get the results in a more convenient format, allowing you to generate mutations, apply filters, etc.

How to use a data object and transform it to a mutation query

The query result can be obtained as an object which will provide facilities to convert it to a mutation and modify the data easily. At the end, the mutation object will be able to be used as the variables of the mutation query in the GraphQL client.

First we execute a "read" query and obtain the result as an object compound of Items and Collections.

$response = $client->query($query, $variables);

$data = $response->getDataObject();

/**
 * $data = new QueryItem([
 *      'id_book'   => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *      'id_author' => 1234,
 *      'genre'     => 'adventure',
 *      'chapters'  => new QueryCollection([
 *          new QueryItem([
 *              'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *              'id_chapter' => 1,
 *              'name'       => 'Chapter One',
 *              'pov'        => 'first person',
 *              'pages'      => new QueryCollection([]),
 *          ]),
 *          new QueryItem([
 *              'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *              'id_chapter' => 2,
 *              'name'       => 'Chapter two',
 *              'pov'        => 'third person',
 *              'pages'      => new QueryCollection([
 *                  new QueryItem([
 *                      'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter'        => 2,
 *                      'id_page'           => 1,
 *                      'has_illustrations' => false,
 *                  ]),
 *                  new QueryItem([
 *                      'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter'        => 2,
 *                      'id_page'           => 2,
 *                      'has_illustrations' => false,
 *                  ]),
 *              ]),
 *          ]),
 *      ]),
 *  ]);
 */

We can also filter the results in order to work with fewer data later. The filter method returns a new object with the filtered results, so you need to reassign the object to the original one, if you want to modify it.

$data->chapters = $data->chapters->filter(['pov' => 'third person']);

/**
 * $data = new QueryItem([
 *      'id_book'   => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *      'id_author' => 1234,
 *      'genre'     => 'adventure',
 *      'chapters'  => new QueryCollection([
 *          new QueryItem([
 *              'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *              'id_chapter' => 2,
 *              'name'       => 'Chapter two',
 *              'pov'        => 'third person',
 *              'pages'      => new QueryCollection([
 *                  new QueryItem([
 *                      'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter'        => 2,
 *                      'id_page'           => 1,
 *                      'has_illustrations' => false,
 *                  ]),
 *                  new QueryItem([
 *                      'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter'        => 2,
 *                      'id_page'           => 2,
 *                      'has_illustrations' => false,
 *                  ]),
 *              ]),
 *          ]),
 *      ]),
 *  ]);
 */

Then we can generate the mutation variables object from the previous query results. This is build using a mutation config. The config for each type has the following parameters:

  • linksTo: the location in the query result object where the data can be obtained for that type. If not present, it means it's a level that has no data from the source.
  • type: mutation object type (Item or Collection).
  • children: if the mutation has a key which value is another mutation type.
$mutationConfig = [
    'book' => [
        'linksTo'  => '.',
        'type'     => MutationItem::class,
        'children' => [
            'chapters'  => [
                'type'     => MutationItem::class,
                'children' => [
                    'upsert' => [
                        'linksTo'  => '.chapters',
                        'type'     => MutationCollection::class,
                        'children' => [
                            'pages' => [
                                'type'     => MutationItem::class,
                                'children' => [
                                    'upsert' => [
                                        'linksTo'  => '.chapters.pages',
                                        'type'     => MutationCollection::class,
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],   
];

$mutation = Mutation::build($mutationConfig, $data);

/**
 * $mutation = new MutationItem([
 *     'book' => new MutationItem([
 *          'id_book'   => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *          'id_author' => 1234,
 *          'genre'     => 'adventure',
 *          'chapters'  => new MutationItem([
 *              'upsert' => new MutationCollection([
 *                  new MutationItem([
 *                      'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter' => 1,
 *                      'name'       => 'Chapter One',
 *                      'pov'        => 'first person',
 *                      'pages'      => new MutationItem([
 *                          'upsert' => new MutationCollection([]),
 *                      ]),
 *                  ]),
 *                  new MutationItem([
 *                      'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                      'id_chapter' => 2,
 *                      'name'       => 'Chapter two',
 *                      'pov'        => 'third person',
 *                      'pages'      => new MutationItem([
 *                         'upsert' => new MutationCollection([
 *                              new MutationItem([
 *                                  'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                  'id_chapter'        => 2,
 *                                  'id_page'           => 1,
 *                                  'has_illustrations' => false,
 *                              ]),
 *                              new MutationItem([
 *                                  'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                  'id_chapter'        => 2,
 *                                  'id_page'           => 2,
 *                                  'has_illustrations' => false,
 *                              ]),
 *                          ]),
 *                      ]),
 *                  ]),
 *              ]),
 *          ]),
 *      ]),
 *  ]);
 */

Now we can modify the mutation data using the following methods:

  • add(): Adds an Item to a Collection.
  • set(): Updates some values of an Item. It also works on Collections, updating all its Items.
  • filter(): Filters the Items of a Collection.
  • count(): Counts the Items of a Collection.
  • isEmpty(): Check if a Collection is empty.
  • has(): Checks whether an Item has an argument or not. Works on Collections too. Dot notation is also allowed.
  • hasItem(): Checks whether a Collection has an Item with the provided data or not.
  • remove(): Removes an Item from a Collection.
  • __unset(): Removes a property from an Item or from all the Items of a Collection.
$mutation->book->chapters->upsert->filter(['id_chapter' => 2])->pages->upsert->add([
    'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
    'id_chapter'        => 2,
    'id_page'           => 3,
    'has_illustrations' => false,
]);

$mutation->book->chapters->upsert->pages->upsert->filter([
    'id_chapter' => 2,
    'id_page'    => 2,
])->set(['has_illustrations' => true]);

$itemToRemove = new MutationItem([
    'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
    'id_chapter'        => 2,
    'id_page'           => 1,
    'has_illustrations' => false,
]);
$mutation->book->chapters->upsert->files->upsert->remove($itemToRemove);

unset($mutation->book->chapters->upsert->pov);

/**
 * $mutation = new MutationItem([
 *     'book' => new MutationItem([
 *         'id_book'   => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *         'id_author' => 1234,
 *         'genre'     => 'adventure',
 *         'chapters'  => new MutationItem([
 *             'upsert' => new MutationCollection([
 *                 new MutationItem([
 *                     'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                     'id_chapter' => 1,
 *                     'name'       => 'Chapter One',
 *                      'pages'      => new MutationItem([
 *                          'upsert' => new MutationCollection([]),
 *                      ]),
 *                 ]),
 *                 new MutationItem([
 *                     'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                     'id_chapter' => 2,
 *                     'name'       => 'Chapter two',
 *                     'pages'      => new MutationItem([
 *                         'upsert' => new MutationCollection([
 *                             new MutationItem([
 *                                 'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                 'id_chapter'        => 2,
 *                                 'id_page'           => 2,
 *                                 'has_illustrations' => true,
 *                             ]),
 *                             new MutationItem([
 *                                 'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                 'id_chapter'        => 2,
 *                                 'id_page'           => 3,
 *                                 'has_illustrations' => false,
 *                             ]),
 *                         ]),
 *                     ]),
 *                 ]),
 *             ]),
 *         ]),
 *     ]),
 * ]);
 */

Finally, the modified mutation data can be passed to the GraphQL client to execute the mutation. When the query is executed, the mutation variables are encoded using json_encode(). This modifies the mutation data just returning the items changed and its parents.

$mutationQuery = <<<'QUERY'
mutation ($book: BookInput!){
  ReplaceBook (book: $book) {
    status
  }
}
QUERY;

$client->mutate($mutationQuery, $mutation);

So the final variables sent to the query would be:

/**
 * $mutation = [
 *     'book' => [
 *         'id_book'   => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *         'id_author' => 1234,
 *         'genre'     => 'adventure',
 *         'chapters'  => [
 *             'upsert' => [
 *                 [
 *                     'id_book'    => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                     'id_chapter' => 2,
 *                     'name'       => 'Chapter two',
 *                     'pages'      => [
 *                         'upsert' => [
 *                             [
 *                                 'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                 'id_chapter'        => 2,
 *                                 'id_page'           => 2,
 *                                 'has_illustrations' => true,
 *                             ],
 *                             [
 *                                 'id_book'           => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d',
 *                                 'id_chapter'        => 2,
 *                                 'id_page'           => 3,
 *                                 'has_illustrations' => false,
 *                             ],
 *                         ],
 *                     ],
 *                 ],
 *             ],
 *         ],
 *     ],
 * ];
 */

NOTE 2: The example has been done for a root Item "book", but it also works for a Collection as root object.

Testing

softonic/graphql-client has a PHPUnit test suite, and a coding style compliance test suite using PHP CS Fixer.

To run the tests, run the following command from the project folder.

$ make tests

To open a terminal in the dev environment:

$ make debug

License

The Apache 2.0 license. Please see LICENSE for more information.

More Repositories

1

axios-retry

Axios plugin that intercepts failed requests and retries them whenever possible
TypeScript
1,795
star
2

laravel-intelligent-scraper

Service to scrape a web page easily without knowing their HTML structure.
PHP
85
star
3

kubewatch

Kubernetes API event watcher
Go
32
star
4

portainer-endpoint

Docker image to auto register all the swarm nodes in portainer
Shell
29
star
5

rate-limit-operator

Rate Limit operator for Envoy Proxy
Go
24
star
6

KillerBees

Stress test tool for web projects. Use Amazon's computing cloud to simulate high concurrency by running parallel requests from many machines
PHP
21
star
7

docker-system-prune

Docker system prune automatically
Dockerfile
20
star
8

node-policy-webhook

K8s webhook handling profiles for tolerations, nodeSelector and nodeAffinity
Go
17
star
9

laravel-middleware-request-id

PHP
15
star
10

nunjucks-include-with

Nunjucks extension that allows send data to include template.
JavaScript
13
star
11

swarm-backup-restore

Shell
11
star
12

varnish-chart

Helm chart for Varnish Cache
VCL
9
star
13

guzzle-oauth2-middleware

This package provides middleware for guzzle for handling OAuth2 token negotiation and renewal on expiry transparently.
PHP
9
star
14

axios-logger

Axios plugin to log all requests and responses
JavaScript
8
star
15

laravel-psr15-bridge

PHP
8
star
16

instamaterial

Java
8
star
17

go-ratelimit-chart

Helm chart for https://github.com/envoyproxy/ratelimit
Mustache
7
star
18

laravel-request-content-decompress-middleware

Laravel request content decompress middleware
PHP
7
star
19

mysql-backup-chart

Helm Chart for automatic mysql backups to object storage
Mustache
6
star
20

helm-workshop

Helm workshop
Smarty
4
star
21

laravel-request-accept-json-middleware

Laravel middleware to add Accept application/json header to requests
PHP
4
star
22

docker-traefik

Traefik instance with self-healing based on HEALTHCHECK command
Dockerfile
4
star
23

homing-pigeon

Write messages reveived from input interface to output interface
Go
4
star
24

guzzle-proxy-middleware

This package allows you to use a proxy transparently in guzzle.
PHP
4
star
25

puppet-puppetmaster

puppetmaster with autosign setup
Puppet
3
star
26

jaxer

PHP Engine Rule to rule them all
PHP
3
star
27

openapi-validation-formats-extension

This library adds some format validation for OpenAPI validation middleware package.
PHP
3
star
28

guzzle-request-content-compress-middleware

This middleware adds the ability to automatically compress the content of a request
PHP
3
star
29

varnish

Varnish docker image
Dockerfile
3
star
30

knative-serving-chart

Helm Chart for https://github.com/knative/serving
HTML
3
star
31

marko-hot-reload

Watch changes in Marko templates in a directory and notify Marko to hot reload them
JavaScript
3
star
32

hapi-axios-errors

Hapi plugin to convert unhandled axios errors into boom errors
JavaScript
3
star
33

make-cacheable

Decorates functions to make them cacheable with Catbox
JavaScript
3
star
34

docker-registry-s3

Provides a way to configure S3 as a backend in runtime.
Shell
3
star
35

helm-octopus

Helm plugin to reference value files packaged in dependency charts
Go
3
star
36

kubencrypt

Easy letsencrypt on kubernetes
Go
3
star
37

laravel-amqp-consumer

Laravel package to handle the consumption of AMQP messages
PHP
3
star
38

docker-node-prune

Docker image for remove unnecessary files from node_modules (.md, .ts, ...)
Shell
3
star
39

deploy-marathon-bluegreen

This is a container with all dependencies to perform a bluegreen deployment
Python
2
star
40

slacksend

Send messages to slack
Shell
2
star
41

gcp-quota-exporter-helm-chart

GCP Quota exporter Helm Chart
Mustache
2
star
42

promisefallback

Receives an array of functions, values or promises and returns a promise that resolves with the first of them that resolves.
JavaScript
2
star
43

laravel-transactional-event-publisher

PHP
2
star
44

oauth2-provider

Softonic OAuth2 provider
PHP
2
star
45

ci-version

CLI program to determine new versions in CI projects
JavaScript
1
star
46

hp-passthrough

Dummy middleware for homing pigeon
Go
1
star
47

freeradius

Dockerized FreeRADIUS
Shell
1
star
48

argocd-helm-secrets

ArgoCD image with helm-secrets plugin
Dockerfile
1
star
49

nginx-vts

Nginx Docker image with access log in JSON format
Dockerfile
1
star
50

mysql-backup

Backup mysql to aws s3
Shell
1
star
51

homing-pigeon-chart

Helm chart for Homing Pigeon
Smarty
1
star
52

cache-blister-dependencies

Uses a configuration to cache all the specified services in a container
JavaScript
1
star
53

laravel-collection-extended

Additional collection methods
PHP
1
star
54

docker-elk

This is a containerized Elk server to extract all logs from docker containers for having Logging system centralized based in official repositories.
Shell
1
star
55

hapi-newrelic

Hapi plugin that allows to define custom transaction names for routes in New Relic.
JavaScript
1
star
56

sdk_catalog-api

SDK for Catalog API
PHP
1
star
57

nodejs_meetup

Open an issue to submit a talk
1
star
58

docker-secret-mounter

Mounts the specified secrets in a predefined folder that should be mounted as a volume
Shell
1
star
59

laravel-database-migrate-test-listener

Laravel database migrate test listener
PHP
1
star
60

ip-blocker

Daemon running in k8s that can block ideally IPs reading from a datasource and writing to a cloud firewall
Go
1
star
61

terraformer

Terraform templating
Shell
1
star
62

pagespeed-exporter-chart

Helm chart for Prometheus pagespeed exporter
Smarty
1
star