Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle a partial error? #407

Closed
yaquawa opened this issue Oct 19, 2018 · 5 comments
Closed

How to handle a partial error? #407

yaquawa opened this issue Oct 19, 2018 · 5 comments
Labels
question Request for support or clarification

Comments

@yaquawa
Copy link
Contributor

yaquawa commented Oct 19, 2018

I thought there is a standard way to do this in the upstream lib webonyx/graphql-php.
But looks like there isn't? Does this means we should do the error handling things in Lighthouse…?

Copied from webonyx/graphql-php#374 (comment)

Suppose we are querying a list of post:

Query {
    posts: [Post]
}
query {
    posts {
        id
        title
        body
    }
}

The requesting user does not have the read permission of some of the retrieved posts.
Say if we got 10 posts, 2 of them are not allowed to be read by the requesting user (or maybe only the title field is can be read).

How can I handle such a "partial error" case?

Describe the solution you'd like

A response with errors field like:

{
    // with 8 posts
    "data":  {},
    // with 2 errors 
    "erros":  [ 
         {},{}
     ]
}

If you just new Error you are breaking the whole response.
How can I collect the error with out breaking the whole response with both data and errors in the json response?

I saw this piece of code here
https://github.com/nuwave/lighthouse/blob/master/src/GraphQL.php#L119-L145

does it mean I can inject error into the errors field while still output the data field?

@jthomaschewski
Copy link
Contributor

jthomaschewski commented Oct 20, 2018

With #395 it's possible to break only the response for the current field:

query {
    posts {
        id
        title
    }
    users {
       id
       name
    }
}

Given the request for users is not allowed or fails for any reason, result will be:

{
    // data of posts
    "data":  {"posts": [ ... ]},

    // error for "users"
    "errors":  [ 
         { ... }
     ]
}

Not what exactly what you where asking for, but still an improvement over the current behavior in stable releases (Right now the whole request is interrupted).

Not sure how to handle partial errors within a field though.
One possible way would be to use union types:

union UserRespone = User | Error
query {
   users {
     ... on Error { message }
     ... on User { id name }
   }
}

Not sure if this is a good idea. I do filter the models e.g using a (global) scope to only get the ones permitted in the first place.

@spawnia
Copy link
Collaborator

spawnia commented Oct 20, 2018

Multiple options here, really dependent on what you want to achieve and what scenario you are dealing with.

  • The user should not know of the very existence of the posts: Just return the posts that the user is allowed to see, no error ocurring at all.
  • The user is not allowed to see all the fields: Return all fields for posts that the user can see and null particular fields that they are not allowed to see, possible adding error messages for that particular field.
  • The user made a query they should not even have made in the first place: Error the whole query and work to ensure that they are directed to firing correct queries in the future.

All of those are already possible in Lighthouse. Does this satisfy your question?

@spawnia spawnia added the question Request for support or clarification label Oct 20, 2018
@yaquawa
Copy link
Contributor Author

yaquawa commented Oct 21, 2018

@JBBr
Thanks!
But in my case, I'm not using the middleware, instead fails in the resolver, and I want to inject partial error to the response.

union is a solution but I don't want to convert all my models into union types… Also I don't think this is the right way to use union type.

@spawnia

The user is not allowed to see all the fields: Return all fields for posts that the user can see and null particular fields that they are not allowed to see, possible adding error messages for that particular field.

This is what I want to achieve!
How can I do this?

@spawnia
Copy link
Collaborator

spawnia commented Oct 21, 2018

The best way would be @can.

Something like @method should work fine as well.

type Post {
  allowed: String
  restricted: String @method(name: "getRestrictedIfAdmin")
}

On the object that is returned by your posts query (so probably a Post model):

public function getRestrictedIfAdmin(array $args, Context $context)
{
  if(!$context->user()->isAdmin()){
    throw new AuthenticationException('This content is highly confidential.');
  }
  
  return $this->superSecretAttribute;
}

With #395 you will be able to use middleware here as well.

So yeah, plenty of options.

@talismandev
Copy link

talismandev commented Dec 15, 2020

Execuse me.
How can I achieve the following:

I have multiple queries
{
posts{ id, title, content }
comments{ id, title }
}

the posts query authorized via laravel policies and graphql @can directive and fails (policy return false).
I need not to interrupt the second query and expect result like this:

{
data: [
posts: [],
comments: [... actual list comments here ]
],

errors: [
{
"message": "You are not authorized to access posts",
"extensions": {
"category": "authorization"
},
....
]

If I understand correctly, I need to use ErrorPool, but where can I place it to collect errors?

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Request for support or clarification
Projects
None yet
Development

No branches or pull requests

4 participants