laravel-graphql icon indicating copy to clipboard operation
laravel-graphql copied to clipboard

Update to latest version of graphql-php

Open spawnia opened this issue 6 years ago • 1 comments

Hi, i have been using your package for a bit now - it is great, thank you!

I have been having issues with the type coercion of the built-in scalar types of graphql-php. After some investigation, i found that the issue has been fixed in the upstream library.

From version 0.11 going forward, they have added more strict input type coercion for scalars - a feature which i desperately require. Do you have plans to update to a newer version? If so, can i assist with that?

spawnia avatar Apr 25 '18 15:04 spawnia

The issue with the current scalar types is that they cover up errors. For example, the rule to check if an input field is a boolean does not work in most cases:

<?php

namespace App\GraphQL\Types;

use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as BaseType;

class TestType extends BaseType
{
    protected $attributes = [
        'name' => 'Test',
        'description' => 'A type',
    ];
    
    public function fields()
    {
        return [
            'result' => [
                'type' => Type::boolean(),
            ],
        ];
    }
}
<?php

namespace App\GraphQL\Mutations;

use Folklore\GraphQL\Support\Mutation;
use GraphQL;
use GraphQL\Type\Definition\Type;

class TestMutation extends Mutation
{
    public function type()
    {
        return GraphQL::type('Test');
    }
    
    public function args()
    {
        return [
            'input' => [
                'type' => Type::boolean(),
                'rules' => 'boolean'
            ],
        ];
    }
    
    public function resolve($root, $args)
    {
        return ['result' => $args['input']];
    }
}

The behaviour differs depending on how input is passed.

If it is written inline as part of the query, it is validated through the Schema Definition and never even gets to the Laravel Validation.

If it is passed as a variable, the value is coerced in BooleanType->parseValue() and gets converted to a boolean - this leads to some weird results.

Consider the following query:

mutation test($input: Boolean) {
  test(input: $input) {
    result
  }
}

The following shows the current behaviour:

Truthy:

{
  "input": true
}
OR
{
  "input": 1
}
OR
{
  "input": "false"
}
OR
{
  "input": 123
}
OR
{
  "input": -1
}
OR
{
  "input": {
    "foo": "bar"
  }
}
OR
{
  "input": [{}]
}
OR
{
  "input": [false]
}

Output
{
  "data": {
    "test": {
      "result": true
    }
  }
}

Falsy:

{
  "input": false
}
OR
{
  "input": {}
}
OR
{
  "input": "0"
}
OR
{
  "input": []
}

Output
{
  "data": {
    "test": {
      "result": false
    }
  }
}

This passes through to Laravel and gets caught there:

{
  "input": ""
}
OR
{
  "input": null
}

Output:
{
  "data": {
    "test": null
  },
  "errors": [
    {
      "message": "validation",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "validation": {
        "input": [
          "The input field must be true or false."
        ]
      }
    }
  ]
}

For completeness sake, if variables are left blank:

{
  "data": {
    "test": null
  },
  "errors": [
    {
      "message": "Undefined index: input",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

spawnia avatar Apr 26 '18 07:04 spawnia