How to set null to field in graphql? - graphql

We use graphql on our project and use graphql-java 2.3.0 (we plan to update but it is not possible at the moment).
I'm trying to perform such mutation:
mutation {
UPDATE_User(
id:3,
type: null
) {id}
}
Response:
{
"errors": [
{
"validationErrorType": "WrongType",
"message": "Validation error of type WrongType: argument value EnumValue{name='null'} has wrong type",
"locations": [
{
"line": 5,
"column": 7
}
],
"errorType": "ValidationError"
}
],
"data": null
}

Null keyword is a relatively new addition to the GraphQL spec, and the graphql-java version you're using doesn't yet have it implemented. In fact, even 3.0.0 still doesn't have it. The soon-to-be-released 4.0 will have support for the null keyword.
And the reason it is treated as an enum is because unquoted strings are normally enums, null being the only exception. This is also explained in this issue.

In your schema, is 'type' parameter required ?
If not then simply omit it ! On your backend when you will retrieve the value of typethen it will be null

Related

Directus - Retrieve relations with GraphQL

I try to retrieve the relations of the database of my directus app.
I use GraphQL with following endpoint https://myapp.directus.app/graphql.
Using a query for the relations according to the docs
query {
relations {
collection
field
}
}
leads to an validation error:
{
"errors": [
{
"message": "GraphQL validation error.",
"extensions": {
"code": "GRAPHQL_VALIDATION_EXCEPTION",
"graphqlErrors": [
{
"message": "Cannot query field "relations" on type "Query". Did you mean "locations"?",
"locations": [
{
"line": 2,
"column": 2
}
]
}
]
}
}
]
}
I use Postman so far and started with a query for the database entries
query {
boards {
id
columns {
id
name
}
}
}
which works as expected.
What I find interesting is, that Postman shows an mouseover text on the keyword "relations" of the 2nd query -->
"Cannot query field relations on type Query. Did you mean locations?"
But unfortunately I have no idea what to do with that message.
Any ideas what is wrong here?
Meanwhile I found the problem. The endpoint for queries on relations is https://myapp.directus.app/graphql/system
With that the query
query {
relations {
collection
field
}
}
is working

Can I create a single validation error bag for Lighthouse PHP, include GraphQL validation issues

Is there a way when using Lighthouse PHP to get the GraphQL validation error to appear side by side with the Laravel validation errors? Currently the graph QL validations cause a different type of error, before the Laravel error are run.
For example if I submit the following mutation:
mutation register(
password: 123456
) {
id
}
I will get back just an error back
{ "message": "Variable username not present. Expected type String",
"extensions": {
"category": "graphql"
}
}
Then when I submit:
mutation register(
username: somethingStupid
password: 123456
) {
id
}
Then I will get this error:
{ "message": "Validation failed for the field [register].",
"extensions": {
"validation": {
"username": [
"Username must be unique."
]
},
"password": [
"Password must contain letters and numbers"
]
},
"category": "validation"
},
}
For my front end I'd like them only to have to expect a single error bag, but this seems to require them to expect two different types of errors. Assuming my Laravel validations cover the schema definition, I would like for them never to see the GraphQl errors. Or am I missing the concept of GraphQL somehow?

How can i provide a a value for an argument in GraphQL?

I'm very new to GraphQL, and i'm trying to perform some example queries to this graph. In particular i'm trying the User schema.
According to that documentation, the schema is the following:
id: ID!
liquidityPositions: [LiquidityPosition!]
usdSwapped: BigDecimal!
And here is query i tried:
{
user (where: {id: "0x7c9C48b7cBEbBDA3268435F20c81f15A538C566C"}) {
id
liquidityPositions
usdSwapped
}
}
This query fails, i keep getting the following response:
{
"errors": [
{
"locations": [
{
"line": 0,
"column": 0
}
],
"message": "No value provided for required argument: `id`"
}
]
}
How can i provide the id field and where am i supposed to provide it? Thanks in advance!
You've got a couple of problems with that query. First, to get a user by id, remove the "where" and curly braces from your query. Secondly, the liquityPositions field needs a selection of subfields. Like so:
{
user (id: "0x7c9C48b7cBEbBDA3268435F20c81f15A538C566C") {
id
liquidityPositions {
id
}
usdSwapped
}
}
That website you linked to will show you errors with your query so you can interactively learn more about what is supported.
I would also suggest running through the introduction to GraphQL here: https://graphql.org/learn/ to get a handle on how things are done.

Is it possible to accessing GraphQL validation errors from a Relay mutation?

I'm somewhat new to GraphQL, so, still piecing all moving parts together in my head.
On my server side I'm using TypeGraphQL which uses class-validator to perform validation of the queries coming in. On the client side I'm using Relay. When the validations fail, my commitMutation call in Relay calls onError and passes a string representation of the error, but the actual response from the server looks like this:
{
"errors": [
{
"message": "Argument Validation Error",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateCurrentUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"validationErrors": [
{
"target": {
"name": "ueoa",
"nickname": "ueoa",
"email": ""
},
"value": "",
"property": "email",
"children": [],
"constraints": {
"isEmail": "email must be an email"
}
}
],
"stacktrace": [
"Error: Argument Validation Error",
" at Object.validateArg (C:\\Users\\pupeno\\Documents\\Flexpoint Tech\\imok\\node_modules\\type-graphql\\dist\\resolvers\\validate-arg.js:24:15)",
" at runMicrotasks (<anonymous>)",
" at processTicksAndRejections (internal/process/task_queues.js:97:5)",
" at async Promise.all (index 0)"
]
}
}
}
],
"data": null
}
In this case, I left the email blank and thus on errors[0].extensions.exception.validationErrors[0].constraints.isEmail I have the error: "email must be an email".
Is there a way for Relay to let me access this structure to turn this errors into UI errors for the user? Or are these errors the equivalent of a 500 and I should implement my own separate error handling (equivalent of a 401)?
I do most of my validation on the client, but uniqueness can only be on done on the server and I'm trying to figure out the protocol between the two.
I don't know much about relay but I have used Typegraphql for sometime. What I can tell is that error from class-validator is nested differently from standard error (I am talking about throw new Error('this will be different'). I would advice for you to have an error formatter function on back-end so that regardless of type of error is thrown you can just return a standard graphql error. In apollo server there is option for formating error I believe other graphql servers has one too. Here is how it looks
const apolloServer = new ApolloServer({
formatError: (error) => error,
});
If class-validator's error is thrown error above will be ArgumentValidationError So if error is instance of ArgumentValidationError you need to proper format it and return to the client with all constraints values extracted and appended on message field. In this way all errors will behave the same on front-ent.
It is really hard to handle the error when it comes to graphQL as at the end of the result you will going to get 200 OK responses.
These errors you are getting are the INTERNAL SERVER ERROR, Equivalent to 500.
So, in this case, you'll need to handle it on your own.
As Nux wrote, Apollo has error handling modules, you can refer it from here This might be helpful.
Also As you mention that you are doing most of the validation from the client end, it is not a good idea to do validations only client-side as it can be brack and might become the Major breach.

graphql-java error data (like extensions) is being stuffed into "message" field on client

In graphql-java, I'm overriding getExtensions on a GraphQLError, in order to pass a "code" extension for Apollo Client to consume.
When I added a breakpoint, I can see that GraphQLObjectMapper sees the error in the executionResult with all its fields, including extensions properly set as expected.
However, when the error arrives at apollo, it gets strangely morphed and the entire error object (including the extensions array) appears to be stuffed into the string message field like so:
{
"errors": [
{
"message": "Unexpected error value: { message: \"Exception while fetching data (/myQuery) : Didn't work\", locations: [[Object]], path: [\"myQuery\"], extensions: { code: \"MY_CODE\", classification: \"DataFetchingException\" } }",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"mailLabels"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR"
}
}
],
"data": null
}
As far as I can tell apollo is not doing anything wrong. My suspicion is that graphql-java may be the one stuffing this entire error into the "message" field" and then setting the code as "INTERNAL_SERVER_ERROR", but I'm not really sure. Is there something I can do on the graphql-java end to prevent this and make it properly pass the extensions and not stuff them into the message value? Any assistance would be appreciated.
It is not caused by graphql-java but graphql-java-servlet. In some old version , by default it does not serialize GraphQLError to the structure defined by the GraphQL specification , which should be fixed in 7.5.1 in this issue.
If you cannot upgrade to the latest version , the simplest way is customize GraphQLObjectMapper and overriding its convertSanitizedExecutionResult :
public class CustomObjectMapper extends GraphQLObjectMapper {
#Override
public Map<String, Object> convertSanitizedExecutionResult(ExecutionResult executionResult, boolean includeData) {
Map<String, Object> result = super.convertSanitizedExecutionResult(executionResult, includeData);
if(result.containsKey("errors")){
result.put("errors", executionResult.getErrors().stream().map(err->err.toSpecification()).collect(toList()));
}
}
}

Resources