GithubHelp home page GithubHelp logo

folkloreinc / laravel-graphql Goto Github PK

View Code? Open in Web Editor NEW
1.8K 59.0 233.0 539 KB

Facebook GraphQL for Laravel 5. It supports Relay, eloquent models, validation and GraphiQL.

PHP 99.41% Shell 0.59%
graphql laravel relay php

laravel-graphql's People

Contributors

adamroyle avatar alnutile avatar c3riz88 avatar cppcho avatar dimitri-koenig avatar dmongeau avatar eazyserver avatar foobarquaxx avatar gotrecillo avatar hailwood avatar inxilpro avatar kevinasher avatar kevinvdburgt avatar ktogo avatar larswolff avatar medz avatar mohammad-fouladgar avatar n1ru4l avatar pelletiermaxime avatar petecoop avatar rafaelfess avatar rafaelrenanpacheco avatar roemerb avatar satchinjoshi avatar sonarsoftware avatar spamoom avatar stefanjanssen95 avatar travisobregon avatar trihatmaja avatar withinboredom 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  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

laravel-graphql's Issues

Unit Tests

This package looks really promising @dmongeau, I'd love to use it in production but the lack of tests scares me. Is it on the road map to add tests to the package?

how to send request in graphql

I'm following the readme to setup my first graphql API, but I come across some issues.

according to https://github.com/Folkloreatelier/laravel-graphql#creating-a-query , this should return a response when invoking http://homestead.app/graphql?query=query+FetchUsers{users{id,email}} but I my lumen 5.3.2 project it just returned a 404 not found.

noticing that in routes.php#L64 there is no router for get requests, So I suggest whether change the readme file that use a post request, like:

curl 'http://homestead.app/graphql/' --data 'query=query+FetchUsers{users{id,email}}'

or add

$router->get(preg_replace($schemaParameterPattern, '', $queryRoute), array(
        'as' => 'graphql.query',
        'uses' => $queryController
));

in routes.php

Eager loading relationships

When resolving a query is it possible to get the list of types requests in order to eager load Eloquent relationships?

Infinite Loop With Lists and Relations

Hi, I've encountered an issue that results in an infinite loop and a segmentation fault with trying to use lists to definite simple relationships versus a Relay connection. Is there something I'm doing incorrectly for this situation or is this an issue? I could use a connection though in this use case there at most are 1-2 related objects so a connection is overkill and a list would be more appropriate.

I have a SessionType which has a list of payments for the one-to-many relationship. In relayFields() I'm returning this for payments:

'payments' => [
'type' => Type::listOf(GraphQL::type('payment')),
'description' => 'Payments for session',
'resolve' => function (Session $session) {
return $session->payments;
}
],
In my PaymentType I then have the inverse:

'session' => [
'type' => GraphQL::type('session'),
'description' => 'Session that payment is connected to',
'resolve' => function (Payment $payment) {
return $payment->session;
}
],
This results in an infinite loop since it is trying to create the PaymentType while trying to create the SessionType which then repeats the process resulting in a loop

@davidstoker

Eager Loading Constraints w/ Arguments

Is there currently a way to get the arguments of a relationship in the resolve function? With the following (using the instructions in the README) I can determine if I need to eager load a relationship in the parent's resolve:

class CustomersQuery extends Query
{
    //...
    public function resolve($root, $args, ResolveInfo $info)
    {
        $customers = Customer::query();
        $fields = $info->getFieldSelection(3);

        foreach ($fields as $field => $keys) {
            if ($field == 'orders') {
                // Can I get the arguments for orders here so I can put 
                // a constraint on the relationship? For Example:
                // $customers->with(['orders' => function ($q) use ($args) {
                //     $q->take($args['orders.limit']);
                // }]);
                $customers->with('orders');
            }
        }

        return $customers->take($args['limit'])->get();
    }
}

And with my type definition I can add arguments and grab them in the field's resolve function:

class CustomerType extends GraphQLType
{
    public function fields()
    {
        $orderType = new OrderType;

        return [
            // ...
            'orders' => [
                'type' => Type::listOf($orderType->toType()),
                'description' => 'Customer orders.',
                'args' => [
                    'limit' => [
                        'name' => 'limit',
                        'type' => Type::nonNull(Type::int())
                    ]
                ],
                'resolve' => function ($customer, $args) {
                    return $customer->orders()->take($args['limit'])->get();
                }
            ]
        ];
    }
}

However, at that point I've already pull all related records from the DB. Is there a way to get the arguments in the parent's resolve function?

Btw, this package has made working with GraphQL an absolute joy!

Error on adding arguments to query

In the example given if i add a argument like

query FetchUsers
{
  users(id : "1")
   {
     email
   }
}

I'm getting error

     Exception in Utils.php line 155:
     User Error: expected iterable, but did not find one.

in Utils.php line 155

at Utils::invariant(false, 'User Error: expected iterable, but did not find one.') in Executor.php line 562

at Executor::completeValue(object(ExecutionContext), object(ListOfType), object(ArrayObject), 
object(ResolveInfo), object(User)) in Executor.php line 497

at Executor::completeValueCatchingError(object(ExecutionContext), object(ListOfType), object(ArrayObject), object(ResolveInfo), object(User)) in Executor.php line 474

at Executor::resolveField(object(ExecutionContext), object(ObjectType), array(null), object(ArrayObject), 'users', array()) in Executor.php line 205

at Executor::executeFieldsSerially(object(ExecutionContext), object(ObjectType), array(null), object(ArrayObject)) in Executor.php line 224

at Executor::executeFields(object(ExecutionContext), object(ObjectType), array(null), object(ArrayObject)) in Executor.php line 152

at Executor::executeOperation(object(ExecutionContext), object(OperationDefinition), null) in Executor.php line 94

at Executor::execute(object(Schema), object(Document), null, null, null) in GraphQL.php line 29

at GraphQL::execute(object(Schema), 'query Fs{users(id : "1"){id ,email}}', null, null) in GraphQL.php line 78

at GraphQL->query('query Fs{users(id : "1"){id ,email}}', null) in routes.php line 39

at GraphQLServiceProvider->{closure}(object(Request))

If i query without argument it is working fine!

Implementation of the "Node Interface" Relay specification

Like @chrissm79, I am too trying to implement the Relay specifications set out for a GraphQL server. The Relay Global Object Identification Specification states the following:

The server must provide an interface called Node. That interface must include exactly one field, called id that returns a nonโ€null ID.

This id should be a globally unique identifier for this object, and given just this id, the server should be able to refetch the object.

Here is my attempt to implement it:
NodeInterface.php

<?php namespace App\GraphQL\Types;

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

class NodeInterface extends GraphQLType
{
    protected $attributes = [
        'name' => 'Node',
        'description' => 'Node Interface'
    ];

    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::id()),
                'description' => 'Id of the node'
            ]
        ];
    }
}

graphql.php

    ...
    'schema' => [
        'query' => [
            'node' => App\GraphQL\Queries\NodeQuery::class,
            'users' => App\GraphQL\Queries\UsersQuery::class,
        ],
    ],
    ...
    'types' => [
        'node' => App\GraphQL\Types\NodeInterface::class,
        'user' => App\GraphQL\Types\UserType::class
    ]
    ...

NodeQuery.php
This, I suppose, is the place where the base64 encoded global id gets decoded into i.e. id+type information in your Laravel app using a helper function like decodeGlobalIdField($args['globalId']). How can I access the globalId if I need it outside of the resolve() function? Do I need it outside of it? What do I return in the type() function?

<?php namespace App\GraphQL\Queries;

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

class NodeQuery extends Query {

    protected $attributes = [
        'name' => 'node'
    ];

    public function type()
    {
        return GraphQL::type('node');
    }

    public function args()
    {
        return [

        ];
    }

    public function resolve($root, $args)
    {

    }

}

Any hints and tips are helpful!
At the end of the day I try to rebuild the following introspection query:

{
  __type(name: "Node") {
    name
    kind
    fields {
      name
      type {
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}

... that shall lead to the following output:

{
  "__type": {
    "name": "Node",
    "kind": "INTERFACE",
    "fields": [
      {
        "name": "id",
        "type": {
          "kind": "NON_NULL",
          "ofType": {
            "name": "ID",
            "kind": "SCALAR"
          }
        }
      }
    ]
  }
}

So far, I am making the following introspection query:

{
  __type(name: "Node"){
    name
    description
    kind
  }
}

... for which I am yielding

{
  "data": {
    "__type": {
      "name": "Node",
      "description": "Node Interface",
      "kind": "OBJECT"
    }
  }
}

If I'd had to cut my question short, what do I have to do for "kind" to return "INTERFACE" instead of "OBJECT"?

Rules on custom fields

This is more of an suggestion, but I have a custom field that requires arguments and I'd like to use the built-in validation. It only took me a few minutes to realize that a Mutation is nothing more than of Field that has rules applied. I simply switched my Field to extend a Mutation instead and everything works fine, but I'm wondering if that logic could be placed in the Field and still have the Mutation type extend it just for naming purposes.

Alternatively, maybe the logic could be put into a trait which mutations use and the user can choose to add the trait to have validation run on a custom field's arguments (something like ShouldBeValidated).

Thanks!

HTTP status codes

Is there any way to set the HTTP status code from the resolve() method? I know GraphQL can return "partial success", but it'd be nice to be able to take advantage of the tool that HTTP provides us ๐Ÿ˜€

GraphQL not found

I am getting the following error

Class 'GraphQL' not found in /Users/jakedavies/dev/Zeus/app/GraphQL/Query/AdsQuery.php on line 19

Using the following query class, set up the same way as the example is.

<?php

namespace App\GraphQL\Query;

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

use App\Ad;

class AdsQuery extends Query {

    protected $attributes = [
      'name' => 'Ads query'
    ];

    public function type()
    {
        return Type::listOf(GraphQL::type('ad'));
    }

    public function args()
    {
        return [
          'id' => ['name' => 'id', 'type' => Type::string()],
          'name' => ['name' => 'name', 'type' => Type::string()]
        ];
    }

    public function resolve($root, $args)
    {
        if(isset($args['id']))
        {
            return Ad::find($args['id']);
        }
        else
        {
            return Ad::all();
        }
    }

}

Where is GraphQL loaded?

Custom field return type null

When asking GraphQL to build the schema of a type, custom field using Type::listof(. . .) return a null type

Request :

{  
  __type(name: "User") { 
    name 
    fields { 
      name 
      type { 
        name 
      } 
    } 
  } 
}

Reponse :

{
  "data":{
    "__type":{
      "name": "User",
      "fields":[
        {"name": "followings", "type":{"name": null }},
      ]
    }
  }
}

Status codes for error handling

I like how the graph-php and this package catch errors during the query and places the message in the payload. It does not however preserve the response status code set or $code attribute in the error object.

Any chance this can be done?

withCount

Hi,

I'm trying to access Eloquents withCount to get the count of a relation as a property which works fine when it's in the first level of the query, but in the second level it always returns null.

Can you help me why this happens?

For example:

query clubs(slug:"adagio"){
  id,
  name,
  likes_count, // returns the count of the likes
  events {
    likes_count, // returns null
    name
  }
}

Thanks

error-message: Cannot query field users on Query

Thank you for your work on this package. I am very excited to use.

I am sorry to make an issue but I'm just learning relay (as most are atm) and I followed your instructions on the readme exactly however I get the following error message when visiting my .../graphql?query=query+FetchUsers{users{id,email}} .

{ "errors": [ { "message": "Cannot query field users on Query", "locations": [ { "line": 1, "column": 18 } ] } ] }

Error message isn't very helpful to me and I'm not sure where to look to dig deeper. I'm on Ubuntu 15.04, Laravel 5.* using Homestead VM.

Shared "context" between mutations?

Is there any way to share $root between mutations? Something like:
https://github.com/webonyx/graphql-php/blob/master/tests/Executor/MutationsTest.php#L68-L85

Since mutations are executed serially in the order given, I'm trying to achieve something like the following (source article):

mutation something {
  loginWithToken(token: "6e37a03e-9ee4-42fd-912d-3f67d2d0d852"),
  do_stuff(greeting: "Hello", name: "Tom"),
  do_more_stuff(submarine_color: "Yellow")
}

Where the user is authenticated in the first mutation, and stays "available" for all subsequent ones.

I tried this idea and $root seems to be null inside my mutation's resolve() method!

Any tips are appreciated, thanks for reading ๐Ÿ˜

Using fragments

Is using fragments available ??
Any example of doing that ?

JSON value

Hey,

I wanna know how I can give back a string as an actual json object and not as an escaped string from a table's column? Is there a way to achieve this?

Query variables

I think there is a problem with the way $args is fetched in the resolve function. When i set the variable like this:

query getNews($offset: Int = 0, $limit: Int = 3) {
  news(offset: $offset, limit: $limit) {
    id,
    headline,
    article,
    total_news_count,
    date,
    slug,
    author {
      username
    }
  }
}

I get the correct response. 3 articles with the correct offset. But when i do it this way:

query getNews($offset: Int, $limit: Int) {
  news(offset: $offset, limit: $limit) {
    id,
    headline,
    article,
    total_news_count,
    date,
    slug,
    author {
      username
    }
  }
}

and set the variables with Angular2 the server doesn't set the appropriate $args columns. The variables are sent to the server

image

Here is my NewsQuery

<?php
namespace App\GraphQL\Query;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;
use App\News;

class NewsQuery extends Query {

    protected $attributes = [
        'name' => 'news'
    ];

    public function type()
    {
      return Type::listOf(GraphQL::type('newsArticle'));
    }

    public function args()
    {
      return [
        'id' => [
          'type' => Type::int()
        ],
        'headline' => [
          'type' => Type::string()
        ],
        'slug' => [
          'type' => Type::string()
        ],
        'article' => [
          'type' => Type::string()
        ],
        'user_id' => [
          'type' => Type::int()
        ],
        'author' => [
          'type' => Type::listOf(GraphQL::type('user')),
        ],
        'offset' => [
          'type' => Type::int(),
	  'defaultValue' => 0
        ],
        'limit' => [
          'type' => Type::int(),
	  'defaultValue' => 3
        ],
        'total_news_count' => [
          'type' => Type::int()
        ],
        'date' => [
          'type' => Type::string()
        ]
      ];
    }

    public function resolve($root, $args)
    {
      if(isset($args['id']))
      {
        return News::where('id', $args['id'])->get();
      }
      else if(isset($args['slug']))
      {
        return News::where('slug', $args['slug'])->get();
      }
      else if(isset($args['offset']))
      {
        return News::skip($args['offset'])->take($args['limit'])->orderBy('id', 'DESC')->get();
      }
    }
}

Here is my Angular2 component

import { Component, OnInit } from '@angular/core';

import {Angular2Apollo} from 'angular2-apollo';
import {Subscription} from 'rxjs/Subscription';
import { ApolloQueryObservable } from 'angular2-apollo';

import {NewsArticle} from '../classes/NewsArticle';
import {NewsQuery} from './news.model';

@Component({
  selector: 'news',
  templateUrl: './news.component.html'
})
export class NewsComponent implements OnInit {
  public buttonDisabled:boolean = false; 
  public loading:boolean = true;

  private currentID:number = null;

  newsObs: ApolloQueryObservable<any>;
  newsSub: Subscription;
  newsArticles: NewsArticle[] = [];
  itemsPerPage:number = 3;
	
  constructor(private apollo: Angular2Apollo) { }
  
  ngOnInit() {
    this.newsObs = this.apollo.watchQuery({
      query: NewsQuery,
	variables: {
	  offset: 0,
	  limit: this.itemsPerPage
	},
	forceFetch: true,
    });
    
    this.newsSub = this.newsObs.subscribe(({data, loading}) => {
      this.newsArticles = data.news;
      this.loading = loading;
    });
  }
  
  fetchMore() {
    this.newsObs.fetchMore({
      variables: {
        offset: this.newsArticles.length,
      },
      updateQuery: (prev, { fetchMoreResult }) => {
        if (!fetchMoreResult.data)
	  return prev; 
        
        var t = Object.assign({}, prev, {
          newsArticles: [...prev.news, ...fetchMoreResult.data.news],
        });
      },
    });
  }
}

Config keys and Query names are diverging

I have noticed that the current implementation has bit of an ambiguity when it comes to the names of Queries(maybe types also). Let me illustrate that.

In my config I have:

'schema' => [
  'query' => [
    'usersQuery1' => 'App\GraphQL\Query\UsersQuery',
  ],
],

So when I query I need to use the name of the query like this.

query test {
  usersQuery1 {
    name
  }
}

However I still have the option to specify the query name inside the Query itself:

namespace App\GraphQL\Query;

class UsersQuery extends Query {

  protected $attributes = [
    // this name is returned for introspection queries
    'name' => 'usersQuery2',
    'description' => 'Query to fetch the user type',
  ];

  ...
}

So which one of the names is actually used? I was using the GraphiQL and it becomes obvious quickly that both are. I can only use usersQuery1 to query the data. But when I issue an introspection query (or open the docs in in GraphiQL) I get usersQuery2. This also breaks autocompletion in GraphiQL.

Is this something that anyone else noticed or has had issues with? Do you think it is worth fixing? As a workaround I am using the same name in the config and the query but I think it is bad practice and error prone to have the same name in two places. My suggestion would be to use the name of the Query if it is given and only use the key that is used in the config otherwise. What do you think of that?

API Authentication

Hey,

I have a GraphQL Api and I wanna protect some queries with with this recently introduced API Authentication:

https://laravel.com/docs/5.3/passport

But I only want to protect certain queries, not all of them, as there are a few public ones. Is this possible yet and if so, how?

Proper way to delete items

Hi there,

Forgive me if this is dead obvious. When I delete a row and then try to return it in a mutation, I get the error "Cannot return null for non-nullable type", presumably because something on the backend is querying a now deleted row. I can work around this by setting a type property return value to nullable, but then I get a null return values.

I want to return the object that I'm deleting. Or, at least return the id. Is this possible?

something like
mutation deleteThing(thing_id: 2){ thing_id}

or even just

mutation deleteThing(thing_id: 2){ message }

Ideas for doing this?

Thank you! (and I suppose this is more a request for documentation than anything)

custom field

If i use a class path to custom field i get

"message": "Undefined index: type",
"status_code": 500,
"debug": {
"line": 110,
"file": "/var/www/laravel/plugins/robocode/api/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php",

Eager Loading & iterable error

I have followed the Readme for eager loading

public function resolve($root, $args, ResolveInfo $info)
{
    $fields = $info->getFieldSelection($depth = 3);

    $users = User::query();

    foreach ($fields as $field => $keys) {
        if ($field === 'team') {
            $users->with('team');
        }
    }

    return $users->get();
}

This query runs successfully in my app.

[2015-11-12 11:22:46] View Logs.INFO: select * from `teams` where `teams`.`id` in (?, ?, ?) [1,2,3] []

And in my UserType class I have the following in the fields function

'team' => [
    'type' => Type::listOf(GraphQL::type('team')),
    'description' => 'The users team',
]

I am getting the following error:

User Error: expected iterable, but did not find one.

If I add a resolve function to the team array it works but I then loose the eager loading functionality:

'team' => [
    'type' => Type::listOf(GraphQL::type('team')),
    'description' => 'The users team',
    'resolve' => function($data, $args) {
         return $data->team()->get();
    }
]

Unique Validation

I'm using a graphql mutation to change a users email adress. Therefore I use the rule() method in my mutation but I need to pass the user id to the "unique" validation rule so that it ignores the user on updating.

How can I achieve this or is this not supported?

Add section to Advanved Usage

I don't know how to create a pull request, to change the Readme.MD file.
I found how to use the variables feature documented.

It would be useful to add how to use parameters in the queries.
Example:

query myQuery($size:Int,$array:[String]){
    query(fields:$array){
        picture(size:$size),
        name
    }
}

and along with the query, there should be a params query field JSON-encoded

www.[...]/graphql?query=[...]&params={size:10,array:["id1","id2","id3"]}

and the $args parameter in the resolve function will be filled accordingly.

I would do it, but I have no idea of how pull requests work. I'm a GitHub n00b, sorry.

cyclic relationships

Hi there,

does anybody else have the problem that cyclic type relationships lead to an empty white page when quering?

e.g. in my case I have a comment type. one comment can have sub-comments and so on... unfortunately it is not possible to define these type relationship.

Example code:

class CommentType extends GraphQLType {

    protected $attributes = [
        'name' => 'Comment',
        'description' => 'a comment to a wall entry'
    ];

    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => 'The id of the comment'
            ],
            'text' => [
                'type' => Type::nonNull(Type::string()),
                'description' => 'the content of the comment'
            ],
            'author' => [
                'type' => Type::nonNull(GraphQL::type("user")),
                'description' => 'The id of the wall entry'
            ],
            'parent' => [
                'type' => GraphQL::type("comment"),
                'description' => 'parent comment'
             ],
             'comments' => [
             'type' => Type::listOf(GraphQL::type("comment")),
                 'description' => 'comments on this comment'
             ]
        ];
    }

    /**
     * @param Comment $model
     * @param array $args
     * @return Comment[] mixed
     */
    protected function resolveCommentsField($model, $args){
        return $model->children;
    } ...

in my comment model i defined the relation as follows:

    public function children(){
        return $this->hasMany(self::class,"fk_comment_id","id");
    }

as i mentioned before, quering this type does lead to an empty white page. I remove the cyclic relations (parent and comments) it works just fine.

Am I doing something wrong or is it an graph-ql implementation problem?

Leonhard

Syntax Error GraphQL request (1:1) Unexpected EOF

I do the request as in the readme /graphql?query=query+FetchUsers{users{id,email}}, but i got error

{
    "data": null,
    "errors": [
        {
            "message": "Syntax Error GraphQL request (1:1) Unexpected EOF\n\n1: \n   ^\n",
            "locations": [
                {
                    "line": 1,
                    "column": 1
                }
            ]
        }
    ]
}

this is my query class

<?php
namespace App\Http\GraphQL\Query;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;
use App\User;

class UsersQuery extends Query {

    protected $attributes = [
        'name' => 'Users query'
    ];

    public function type()
    {
        return Type::listOf(GraphQL::type('user'));
    }

    public function args()
    {
        return [
            'id' => ['name' => 'id', 'type' => Type::string()],
            'email' => ['name' => 'email', 'type' => Type::string()]
        ];
    }

    public function resolve($root, $args)
    {
        if(isset($args['id']))
        {
            return User::where('id' , $args['id'])->get();
        }
        else if(isset($args['email']))
        {
            return User::where('email', $args['email'])->get();
        }
        else
        {
            return User::all();
        }
    }
}

this is my type class

<?php
namespace App\Http\GraphQL\Type;

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

class UserType extends GraphQLType {

    protected $attributes = [
        'name' => 'User',
        'description' => 'A user'
    ];

    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::string()),
                'description' => 'The id of the user'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => 'The email of user'
            ]
        ];
    }


    // If you want to resolve the field yourself, you can declare a method
    // with the following format resolve[FIELD_NAME]Field()
    protected function resolveEmailField($root, $args)
    {
        return strtolower($root->email);
    }

}

and this is my config

<?php


return [

    // The prefix for routes
    'prefix' => 'graphql',

    // The routes to make GraphQL request. Either a string that will apply
    // to both query and mutation or an array containing the key 'query' and/or
    // 'mutation' with the according Route
    //
    // Example:
    //
    // 'routes' => [
    //     'query' => '/query',
    //     'mutation' => '/mutation'
    // ]
    //
    'routes' => '/',

    // The controller to use in GraphQL request. Either a string that will apply
    // to both query and mutation or an array containing the key 'query' and/or
    // 'mutation' with the according Controller and method
    //
    // Example:
    //
    // 'controllers' => [
    //     'query' => '\Folklore\GraphQL\GraphQLController@query',
    //     'mutation' => '\Folklore\GraphQL\GraphQLController@mutation'
    // ]
    //
    'controllers' => '\Folklore\GraphQL\GraphQLController@query',

    // Any middleware for the graphql route group
    'middleware' => ['oauth:public', 'cors'],

    // The schema for query and/or mutation. It expects an array to provide
    // both the 'query' fields and the 'mutation' fields. You can also
    // provide directly an object GraphQL\Schema
    //
    // Example:
    //
    // 'schema' => new Schema($queryType, $mutationType)
    //
    // or
    //
    // 'schema' => [
    //     'query' => [
    //          'users' => 'App\GraphQL\Query\UsersQuery'
    //      ],
    //     'mutation' => [
    //
    //     ]
    // ]
    //
    'schema' => [
        'query' => [
            'users' => 'App\Http\GraphQL\Query\UsersQuery',
        ],
        'mutation' => [

        ],
    ],

    // The types available in the application. You can then access it from the
    // facade like this: GraphQL::type('user')
    //
    // Example:
    //
    // 'types' => [
    //     'user' => 'App\GraphQL\Type\UserType'
    // ]
    //
    'types' => [
        'users' => 'App\Http\GraphQL\Type\UserType',
    ],

    // This method will be passed the Error object for each errors GraphQL catch.
    // The method should return an array representing the error.
    // Typically ['message' => '','locations' => []].
    'error_formatter' => ['\Folklore\GraphQL\GraphQL', 'formatError']

];

Upstream changed, breaks examples on readme

I am getting the following error when following the examples you have written out on the readme.

ErrorException in Schema.php line 61:
GraphQL\Schema constructor expects config object now instead of types passed as arguments. See webonyx/graphql-php#36

You need to make folklore/graphql/src/Folklore/GraphQL/GraphQL.php:70 send an array in the form of this:
return new Schema(['query' => $queryType, 'mutation' => $mutationType]);

Union Type possible?

Is it possible to do union types? I can't get them too work. eg:

https://github.com/webonyx/graphql-php/blob/master/docs/type-system/unions.md

// inside Query
public function args()
{
    $stringOrStringArray = new \GraphQL\Type\Definition\UnionType([
        'name' => 'StringOrStringArray',
        'types' => [
            Type::string(),
            Type::listOf(Type::string()),
        ],
        'resolveType' => function($value) {
            if (is_array($value)) {
                return Type::listOf(Type::string());
            } else {
                return Type::string();
            }
        }
    ]);

    return [
        'id' => ['type' => Type::ID()],
         'model' => ['type' => $stringOrStringArray],
        'model_id' => ['type' => Type::ID()],
        'take' => ['type' => Type::int()],
        'page' => ['type' => Type::int()],
    ];
}

Authentication

I have a very generic question: How would you deal with protected queries? I don't really see a good way to implement it in any way? Is it possible that someone gives me an hint or an example?

(I'm using tymondesigns/jwt-auth for token based authentication in Laravel)

Support Laravel 5.3

I'm trying to install this package on top of a Laravel 5.3 project, but it seems to depend on illuminate/support 5.2.*. Would it be possible to support the latest Laravel version?

Thanks for reading ๐Ÿ˜„

Fail to publish in Lumen

Hey, It's Awesome Package~ ๐Ÿ˜ ๐Ÿ‘
But I just wondering why I got error when trying to publish the configuration of graphql package in my Lumen. The error look like this:

$ php artisan graphql:publish
  PHP Fatal error:  Call to undefined method Folklore\GraphQL\LumenServiceProvider::command() in /var/www/proyek/goodmovie/vendor/folklore/graphql/src/Folklore/GraphQL/LumenServiceProvider.php on line 50

  [Symfony\Component\Debug\Exception\FatalErrorException]
  Call to undefined method Folklore\GraphQL\LumenServiceProvider::command()

Did I make any mistake?

Add query complexity/dept config option ?

Hi, first of all thanks for the great package.

What do you think about adding config options for the QueryComplexity and QueryDept rules of graphql-php ? I know I can set them in my bootstrap for example :

$queryComplexity = DocumentValidator::getRule('QueryComplexity');
$queryComplexity->setMaxQueryComplexity($maxQueryComplexity = 1);

$queryDepth = DocumentValidator::getRule('QueryDepth');
$queryDepth->setMaxQueryDepth($maxQueryDepth = 1);

But I think adding options in config/graphql.php would be more user friendly. What do you think ? If you think it's a good idea I could send a PR.

Thanks.

Lumen Support

Hey guys, does this package also work in lumen?
I think it would make sense there, because lumen seems to be just for api stuff like this and should be faster than laravel by default.
What do you say?

per type field authorization

thanks for such a great package, however im a bit stuck for how to authorize access to specific fields from a model.

consider you have a model "reservations" which has the fields "table", "time", "person".

if i query a reservation and I AM NOT the owner of the reservation, or an admin i should only be able to return "table" and "time", even if the query requests "person".

how would you consider handling this?

GraphiQL issue

Hi,

I've just tried the GraphiQL support. It seems to work, a bit. I can query my GraphQL schema through it.

But unfortunately:

  • Docs pane does not load contents
  • Autocomplete does not work
  • I get an error in red in the right results pane on startup (I tried running gulp):
invariant@https://unpkg.com/[email protected]/graphiql.min.js:11:7912
defineFieldMap@https://unpkg.com/[email protected]/graphiql.min.js:12:9851
getFields@https://unpkg.com/[email protected]/graphiql.min.js:12:14838
https://unpkg.com/[email protected]/graphiql.min.js:13:12924
typeMapReducer@https://unpkg.com/[email protected]/graphiql.min.js:13:13087
reduce@[native code]
e@https://unpkg.com/[email protected]/graphiql.min.js:13:16026
buildClientSchema@https://unpkg.com/[email protected]/graphiql.min.js:14:5879
https://unpkg.com/[email protected]/graphiql.min.js:1:29756
promiseReactionJob@[native code]

Also, I noticed that the Docs pane does not load, and I cannot use autocomplete. So something seems to be going wrong here. Any clue?

The browser console shows no errors though.

Kind regards,

Sander

[Proposal] Artisan commands to make Type and Query

Was going to work on this next week or the week after as we use this tool in a project.

The commands would, like other generators, allow the user to make the model from the command line.

php artisan make:graphql:type UserType

That would then make the files, folders if needed, and update the config file as well.

php artisan make:graphql:query UsersQuery

Same here.

The user would fill in the args and resolve though later can add options.

Let me know if this is not something already in your planning and I will continue on with it.

Thanks!

Unable to perform mutation

When I attempt to submit a mutation, I am getting the following output:

{
  "data": null,
  "errors": [
    {
      "message": "Syntax Error GraphQL request (14:10) Expected Name, found {\n\n13: # will appear in the pane to the right.\n14: mutation {\n             ^\n15:   CreateUser (\n",
      "locations": [
        {
          "line": 14,
          "column": 10
        }
      ]
    }
  ]
}
# I initially attempted to use the name createUser (lowercase 'c'), but GraphiQL was giving me 
# an error that it couldn't query the field 'createUser' on Mutation and I still got the same
# error message as above
mutation {
  CreateUser (
    firstName: "John" 
    lastName: "Doe" 
    email: "[email protected]" 
    password: "secret"
  ) {
    firstName
    lastName
    email
  }
}
namespace App\Http\GraphQL\Mutations;

use GraphQL;
use Hash;
use App\Models\User;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;

class CreateUserMutation extends Mutation
{
    /**
     * Attributes of mutation.
     *
     * @var array
     */
    protected $attributes = [
        'name' => 'CreateUser'
    ];

    /**
     * Type that will be mutated.
     *
     * @return mixed
     */
    public function type()
    {
        return GraphQL::type('user');
    }

    /**
     * Arguments of mutation.
     *
     * @return array
     */
    public function args()
    {
        return [
            'firstName' => [
                'name' => 'firstName',
                'type' => Type::nonNull(Type::string())
            ],
            'lastName' => [
                'name' => 'lastName',
                'type' => Type::nonNull(Type::string())
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::nonNull(Type::string())
            ],
            'password' => [
                'name' => 'password',
                'type' => Type::nonNull(Type::string())
            ]
        ];
    }

    /**
     * Resolve mutation.
     *
     * @param  string $root
     * @param  array $args
     * @return User
     */
    public function resolve($root, $args)
    {
        $user = new User($args);
        $user->password = Hash::make($args['password']);
        $user->save();

        return $user;
    }
}
'schema' => [
        'query' => [
            'user' => App\Http\GraphQL\Queries\UserQuery::class,
            // ...
        ],
        'mutation' => [
            'createUser' => App\Http\GraphQL\Mutations\CreateUserMutation::class,
        ]
    ],

    'types' => [
        'user' => App\Http\GraphQL\Types\UserType::class,
        // ...
    ]
]

Laravel 4.2 support?

I quickly browsed through the code and didn't seem to find anything that wouldn't work on 4.2.

Is the 5.0 requirement due to something failing on 4.2 or did you just ignore 4.2 from the start?

Unable to use variables in query following the example

Used the type and query example shown and this query works fine

http://homestead.app/graphql?query=query+FetchUsers{users{id,email}}

However when I try the example to use variables in the query using this query

http://homestead.app/graphql?query=query+FetchUserByID($id:String){user(id:$id){id,email}}&params={"id":"1"}

I get this error:

{"data":null,"errors":[{"message":"Cannot query field user on Query","locations":[{"line":1,"column":33}]},{"message":"Variable \"$id\" is never used.","locations":[{"line":1,"column":21}]}]}

Unable to get auth middleware working

Has anyone successfully added auth middleware to the graphql endpoint? I am working on a clean Laravel 5.3 installation. Auth middleware is working for the rest of the app. GraphQL (and GraphiQL) are integrated and working fine. When I try adding:

'middleware' => [ 'auth' ]

to my graphql.php config file I cannot seem to get past the un-authenticated response.

Create pagaination and read from APIs

Thanks for this package I am facing two problems

The first one:

I need the output to be something like this:

{
  "total": 102,
  "per_page": 10,
  "current_page": 1,
  "last_page": 11,
  "next_page_url": "http://local.api.htr.com//api/v1/restaurant?page=2",
  "prev_page_url": null,
  "from": 1,
  "to": 10,
  "data": [
    {
      "id": 221,
      "owner_id": 691,
      "slug": "kfc2",
      "type": 1,
   }
]
}

The second problem is that I need to fetch the data from apis not from elouqant

Thanks

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.