Giter VIP home page Giter VIP logo

graphql-client's Introduction

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

This package allows you to use thephpleague/oauth2-client adapters for authentication, so the endpoint depends on the adapter that you are using. The adapter could be custom or provided by the library as official or third party.

This is an example using a custom 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.

graphql-client's People

Contributors

arnaudbagnis avatar bkonetzny avatar challgren avatar duxthefux avatar joskfg avatar jsandersuk avatar lotykun avatar rccrdpccl avatar voskobovich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-client's Issues

Question: The proper way to modify the query with PHP variables?

This is a question, not an issue. I read the documentation, but didn't find an answer for this one. What would be to suggested method for modifying the query with php variables.
Here's an example (which won't work):

$my_additional_parameters = 'extra_foo1
  extra_foo2 {
    more_foo_a
    more_foo_b
  }';

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

I can use mutations?

I need execution this code:

mutation($input: OBT_MOTIVOS_VIAJEEntry!) {
  createOBT_MOTIVO_VIAJE(input: $input) {
    NOMBRE_TIPO_MOTIVO,
    DESCRIPCION_TIPO_MOTIVO
  }
}

Variables:

{
  "input": {
    "NOMBRE_TIPO_MOTIVO": "mutPE",
    "DESCRIPCION_TIPO_MOTIVO": "mutPE",
    "DIRECCION_IP": "localhost"
  }
}
   

Is possible?

How to use token

I send the url but sending the token shows me an error.

Network Error.Client error: `POST http://srvprodweb.kkkka.com:3000/graphql` resulted in a `400 Bad Request` response:
{"errors":[{"message":"Context creation failed: Authentication token is invalid, please log in","extensions":{"code":"UN (truncated...)

My code is this:

$options = [
			'Authorization' => 'Bearer eyJhbGciOiJIUzIpkjlkjljlkjljlkjlkjlklkjlkj1YW5AZW1haWwuY29tIiwiaWQiOiIyNmIzZWQyZC1hYTQzLTQ4YWQtYWQ0My0yNDc4YTQ4MGE4M2IiLCJpYXQiOjE1NTk5Mjk5NDZ9.c6p-yu1jRJ7KJoyj4fBoj_9l_Xz_Y3HBX8D_5tITCns',
		];
		

		$client = \Softonic\GraphQL\ClientBuilder::build('http://srvprodweb.kkkka.com:3000/graphql',$options);

How to use token?

Guzzlehttp/guzzle version conflict, required ^6.3, installed ^7.2

Good day!

I have a problem trying to install the library, it marks a conflict with the composer.json since I have installed version 7.2

Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires softonic/graphql-client ^1.2 -> satisfiable by softonic/graphql-client[1.2.0].
- softonic/graphql-client 1.2.0 requires guzzlehttp/guzzle ^6.3 -> found guzzlehttp/guzzle[6.3.0, ..., 6.5.x-dev] but it conflicts with your root composer.json require (^7.2).
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Don't send empty variables

So I'm working with an experimental GraphQL server and I'm doing a simple request with no variables. The request however fails because variables is empty when it should not be sent at all.

Provider Class missing

Hello, I pulled the project down using composer and copy/pasted the getting started code from the documentation, however I am getting the following error:

Fatal error: Uncaught Error: Class 'Softonic\OAuth2\Client\Provider\Softonic' not found

(I am using the composer autoloader to include the files, and other libraries from composer are functioning as expected)

When trying to execute this line:
$provider = new Softonic\OAuth2\Client\Provider\Softonic($options);

Please let me know what the fix for this may be,
Thanks!

TypeError: Softonic\GraphQL\DataObjectBuilder::build(): Argument #1 ($data) must be of type array, null given

softonic/graphql-client                    2.2.0              Softonic GraphQL client
TypeError: Softonic\GraphQL\DataObjectBuilder::build(): Argument #1 ($data) must be of type array, null given, called in /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php on line 45 and defined in /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php:36

Stack trace:

#0 /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php(45): Softonic\GraphQL\DataObjectBuilder->build(NULL, Array)
#1 /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php(54): Softonic\GraphQL\DataObjectBuilder->build(Array, Array)
#2 /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php(45): Softonic\GraphQL\DataObjectBuilder->build(Array, Array)
#3 /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php(54): Softonic\GraphQL\DataObjectBuilder->build(Array, Array)
#4 /var/www/html/vendor/softonic/graphql-client/src/DataObjectBuilder.php(28): Softonic\GraphQL\DataObjectBuilder->build(Array, Array)
#5 /var/www/html/vendor/softonic/graphql-client/src/ResponseBuilder.php(49): Softonic\GraphQL\DataObjectBuilder->buildQuery(Array)
#6 /var/www/html/vendor/softonic/graphql-client/src/ResponseBuilder.php(20): Softonic\GraphQL\ResponseBuilder->getNormalizedResponse('{"data":{"query...')
#7 /var/www/html/vendor/softonic/graphql-client/src/Client.php(65): Softonic\GraphQL\ResponseBuilder->build(Object(GuzzleHttp\Psr7\Response))
#8 /var/www/html/vendor/softonic/graphql-client/src/Client.php(33): Softonic\GraphQL\Client->executeQuery('query Edits($in...', Array)

Part of response to reproduce:

"images":[{"uuid":"1234567890","url":"url"},null],

Hotfix:
image

Symfony 6 support

Basically, https://packagist.org/packages/softonic/guzzle-oauth2-middleware needs to be upgraded and psr/cache set to ^1|^2|^3 or maybe drop 1 and go with ^2|^3

Then this library needs a bump, and I guess it will be installable.

composer require softonic/graphql-client

Using version ^1.3 for softonic/graphql-client
./composer.json has been updated
Running composer update softonic/graphql-client
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

Problem 1
- softonic/guzzle-oauth2-middleware[1.1.0, ..., 1.3] require psr/cache ^1.0 -> found psr/cache[1.0.0, 1.0.1] but the package is fixed to 3.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- softonic/graphql-client 1.3.0 requires softonic/guzzle-oauth2-middleware ^1.1 -> satisfiable by softonic/guzzle-oauth2-middleware[1.1.0, ..., 1.3].
- Root composer.json requires softonic/graphql-client ^1.3 -> satisfiable by softonic/graphql-client[1.3.0].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require softonic/graphql-client:*" to figure out if any version is installable, or "composer require softonic/graphql-client:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Where to provide headers?

I am using this example To instantiate a client without OAuth2, but here i want to send headers what is the way?

Receiving this error: resulted in a 415 Unsupported Media Type response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.