Skip to content

Conversation

@mahmoodbazdar
Copy link
Contributor

@mahmoodbazdar mahmoodbazdar commented Sep 11, 2019

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets Fixes #3024
License MIT
Doc PR api-platform/docs#986

Allows developer to format exceptions based on exception type. For now I just added ValidationException support built in. I think we can add several others but I thought first its better to receive your feedback and then add them.
These are the exceptions I think its good to add builtin support:

@lukasluecke
Copy link
Contributor

@mahmoodbazdar Looks good, I like the change to have clearer validation messages. What do you think about moving the part you added in EntryPointAction to the Executor directly?

@mahmoodbazdar
Copy link
Contributor Author

@lukasluecke I think its good Idea. Do you think we should apply to these exceptions too?

} catch (\Exception $e) {
$executionResult = new ExecutionResult(null, [new Error($e->getMessage(), null, null, null, null, $e)]);
}

If we want to support that we can't move it to Executor

@lukasluecke
Copy link
Contributor

@mahmoodbazdar Good question - I'm not sure. Do you know which Exceptions this catch block actually applies to?

However this doesn't change anything - if we want to handle this part as well we need to extract the code somehow anyway. What do you think about a new global service that accepts an Error/Exception and just returns the correct formatted output? Then we could pass that to the Executor as a formatter, and also call it manually for the one-off exception in the catch. (Hope this is understandable 🙈)

@mahmoodbazdar
Copy link
Contributor Author

@lukasluecke Its the exceptions that happen during GraphQL schema generation(Before GraphQL library calls for operation). They mainly happen because of user misconfiguration (500 errors).I'm not sure if we want to allow developers to format these kind of errors.

We can create this separate service but it should return a callable because setErrorFormatter only accept callable.

Simpler solution will be something like this:

$formatter = function (Error $error) {
      $formatters = $this->exceptionFormatterFactory->getExceptionFormatters();
      usort($formatters, function ($a, $b) {
          /**
           * @var ExceptionFormatterInterface
           * @var ExceptionFormatterInterface $b
           */
          if ($a->getPriority() == $b->getPriority()) {
              return 0;
          }

          return ($a->getPriority() > $b->getPriority()) ? -1 : 1;
      });
      /** @var ExceptionFormatterInterface $exceptionFormatter */
      foreach ($formatters as $exceptionFormatter) {
          if (null !== $error->getPrevious() && $exceptionFormatter->supports($error->getPrevious())) {
              return $exceptionFormatter->format($error);
          }
      }

      // falling back to default GraphQL error formatter
      return FormattedError::createFromException($error);
};
try {
    $executionResult = $this->executor->executeQuery($this->schemaBuilder->getSchema(), $query, null, null, $variables, $operation)
      ->setErrorFormatter($formatter);
} catch (\Exception $e) {
    $executionResult = (new ExecutionResult(null, [new Error($e->getMessage(), null, null, null, null, $e)]))
      ->setErrorFormatter($formatter);
}

@lukasluecke
Copy link
Contributor

@mahmoodbazdar If the service has an __invoke-method it should be able to be used as a callable (this would be similar to the custom resolvers for queries and mutations). I think this would be the cleanest solution, as it would not pollute either the Executor or the EntrypointAction unnecessarily.

@mahmoodbazdar
Copy link
Contributor Author

@lukasluecke You are right. I'll do that.

@lukasluecke
Copy link
Contributor

Looks good! Maybe @alanpoulain can chime in on the additional exceptions listed in the issue description? I think it would be good to have more control over these as well 👍

@mahmoodbazdar mahmoodbazdar force-pushed the graphql-error-formatter branch from 97fd40f to aa6fb01 Compare September 14, 2019 11:17
@mahmoodbazdar
Copy link
Contributor Author

@lukasluecke Thanks for your help and review.😊

@mahmoodbazdar mahmoodbazdar force-pushed the graphql-error-formatter branch from aa6fb01 to bc93d98 Compare September 22, 2019 07:01
@mahmoodbazdar mahmoodbazdar changed the base branch from master to 2.5 September 22, 2019 07:01
@mahmoodbazdar mahmoodbazdar force-pushed the graphql-error-formatter branch 2 times, most recently from ddda7ea to dcd104c Compare September 30, 2019 10:10
@alanpoulain alanpoulain changed the base branch from 2.5 to master October 7, 2019 15:51
@alanpoulain alanpoulain force-pushed the graphql-error-formatter branch from dcd104c to 65755e6 Compare October 19, 2019 20:31
@alanpoulain
Copy link
Member

alanpoulain commented Oct 19, 2019

Thank you very much for your work @mahmoodbazdar!

After playing with your code, I realized using normalizers was preferable than introducing new interfaces and an exception formatter: it's a lot less code to maintain and it's more in the "API Platform's way" of doing this kind of things.

I've kept your code in the first commit and I added mine in the second one. Sorry for doing this, I know it would have been better if I commented your code instead of adding mine, but I needed to play and try some things to understand it correctly and I ended up in this state. I hope you will take this well but please tell me if you don't.

Could you also tell me if this approach is correct to you? @lukasluecke could you have a look too?

As you suggested, I added more normalizers:

  • a HTTP exception one,
  • a runtime exception one,

and I changed all the Error exceptions by classical PHP exceptions.

@mahmoodbazdar
Copy link
Contributor Author

@alanpoulain I think your approach is better. Thanks fo updating the code.
About the error format I think I was wrong to add extra data it in first level of the array and we should add status and violations in extensions based on here:
https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md
to follow the graphql spec.
What do you think?

@alanpoulain
Copy link
Member

Oh yes you're right! Would you want to take care of it?

@mahmoodbazdar
Copy link
Contributor Author

@alanpoulain Sure, Should I add tests for other normalizers (to fix code coverage failure)?

@alanpoulain
Copy link
Member

I've added some tests for the other normalizers so I don't really understand if there is an issue or not (but I don't think there is).

@mahmoodbazdar mahmoodbazdar force-pushed the graphql-error-formatter branch from 65755e6 to 91b025d Compare October 27, 2019 11:56
@alanpoulain alanpoulain force-pushed the graphql-error-formatter branch from 847a803 to ef7a56e Compare November 13, 2019 10:12
@alanpoulain alanpoulain force-pushed the graphql-error-formatter branch from ef7a56e to 2c6080b Compare November 17, 2019 16:43
@alanpoulain alanpoulain merged commit 9920f15 into api-platform:master Nov 17, 2019
@alanpoulain
Copy link
Member

Merged at last! Thank you very much @mahmoodbazdar, I think this feature is very useful to have.

norkunas pushed a commit to norkunas/core that referenced this pull request Dec 2, 2019
* Adding GraphQL custom error format support

* Use error normalizers

* Changing error format to follow GraphQL spec


Co-authored-by: Alan Poulain <[email protected]>
@CvekCoding
Copy link
Contributor

@alanpoulain what do you think when this feature will be released?

@soyuka
Copy link
Member

soyuka commented Apr 17, 2020

Hi @CvekCoding this was merged on master, master will be the next minor cycle, for now we're still on 2.5. We don't really have a due date for a new 2.6 release in the meantime you could use our dev-master version directly :/.

@CvekCoding
Copy link
Contributor

CvekCoding commented Apr 17, 2020

@soyuka is it safe to use dev-master?

CvekCoding pushed a commit to CvekCoding/core that referenced this pull request Jul 13, 2020
* Adding GraphQL custom error format support

* Use error normalizers

* Changing error format to follow GraphQL spec

Co-authored-by: Alan Poulain <[email protected]>

(cherry picked from commit 9920f15)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GraphQL] Custom errors for graphql endpoint

5 participants