I have this strange issue . maybe i missed something
i have two tables , Vehicles and purchases
when i try to query the vehicles via
query {
vehicles{
id
}
}
It returns data normally 👍
{
"data": {
"vehicles": [
{
"id": 29
}
]
}
}
But with this query
query {
purchase{
id
}
}
I recieve this error
{
"error": {
"errors": [
{
"message": "Field \"purchase\" argument \"where\" of type \"purchaseWhereUniqueInput!\" is required, but it was not provided.",
"locations": [
{
"line": 2,
"column": 3
}
],
here is my code : -
export const PaymentQuery =extendType({
type :"Query",
definition(t) {
t.crud.purchase({filtering : true , pagination : true , ordering : true , })
}
})
export const VehicleQuery = extendType({
type : "Query",
definition(t) {
t.crud.vehicles({filtering : true , pagination : true , ordering : true , });
}
})
I realized that nexusjs use naming convention to determine if the query should return a list or not !
changing the table name from purchase to purchases solves the problem
How can I be able to update a node with only one field change and leave the rest of the fields alone?
My User Type
type User {
id: ID!
user_id: String!
username: String!
email: String!
role: Role!
isVerified: Boolean!
}
My Input Types
input UserUpdateInput {
user_id: String
username: String
email: String
password: String
role: Role
isVerified: Boolean
}
input UserWhereUniqueInput {
id: ID
user_id: String
email: String
}
My Mutation type
type Mutation {
updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput): User
}
My Resolver
function updateUser(root, args, context, info){
return context.db.mutation.updateUser({
data: args.data,
where: {
id: args.where.id
}
}, info)
}
This is the request am sending on the GraphQL playground
mutation{
updateUser(
data: {
isVerified: true
}
where:{
user_id : "afc485b"
}
)
{
isVerified
}
}
This is the error am getting
{
"errors": [
{
"message": "Cannot read property 'mutation' of undefined",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read property 'mutation' of undefined"
Someone help me. What am I missing?
After updating my server as suggested by Daniel Rearden on the answer section, am getting a new error
{
"message": "Cannot read property 'updateUser' of undefined",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read property 'updateUser' of undefined"
The error is the result of not correctly adding the db property to you context. Assuming you're still using version 1, your code should look something like this:
const { prisma } = require('./generated/prisma-client')
const server = new ApolloServer({
...
context: {
db: prisma,
},
})
First thing I notice is you GQL query is not correct.
Yours:
mutation{
updateUser(
data: {
isVerified: true
}
where:{
user_id : "afc485b"
}
)
{
isVerified
}
}
after the word "mutation" you set a name to the call, i.e.
"UpdateUser" but can literally be anything. for each part of the
where clause you need to make the check value an object, i.e.
where: { myProperty: {eq: "some value"}}
So your query should be more like this:
mutation UpdateUser {
updateUser(
data: {isVerified: true}
where:{user_id : {eq: "afc485b"}}
)
{
isVerified
}
}
Hope that helps a little... I didn't fully read the rest but thought this would help with the initial error you were getting.
I'm running an apollo-server-express as a gateway application. Setting up a few underlying GraphQL Applications with makeRemoteExecutableSchema and an apollo-link-http.
Usually every call just works. If an error is part of the response and data is null it also works. But if data contains just the data and errors contains an error. Data will be passed though but errors is empty
const headerSet = setContext((request, previousContext) => {
return setHeaders(previousContext);
});
const errorLink = onError(({ response, forward, operation, graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map((err) => {
Object.setPrototypeOf(err, Error.prototype);
});
}
if (networkError) {
logger.error(networkError, 'A wild network error appeared');
}
});
const httpLink = new HttpLink({
uri: remoteURL,
fetch
});
const link = headerSet.concat(errorLink).concat(httpLink);
Example A "Working Example":
Query
{
checkName(name: "namethatistoolooooooong")
}
Query Response
{
"errors": [
{
"message": "name is too long, the max length is 20 characters",
"path": [
"checkName"
],
"extensions": {
"code": "INPUT_VALIDATION_ERROR"
}
}
],
"data": null
}
Example B "Errors hidden":
Query
mutation inviteByEmail {
invite(email: "invalid!!!~~~test!--#example.com") {
status
}
}
Response from remote service (httpLink)
response.errors and graphQLErrors in onError method also contains the error
{
"errors": [
{
"message": "Email not valid",
"path": [
"invite"
],
"extensions": {
"code": "INPUT_VALIDATION_ERROR"
}
}
],
"data": {
"invite": {
"status": null
}
}
}
Response
{
"data": {
"invite": {
"status": null
}
}
}
According to graphql spec I would have expected the errors object to not be hidden if it is part of the response
https://graphql.github.io/graphql-spec/June2018/#sec-Errors
If the data entry in the response is present (including if it is the value null), the errors entry in the response may contain any errors that occurred during execution. If errors occurred during execution, it should contain those errors.
I am new in GraphQL. I am learning GraphQL.
My input is like below
mutation {
createEvent:{eventInput: {title: "A Test", description:"Does this work?", price:9.99, date:"2018-12-06T09:26:30.645Z"}
}
}
I am getting error like below
{
"errors": [
{
"message": "Syntax Error: Expected Name, found {",
"locations": [
{
"line": 2,
"column": 15
}
]
}
]
}
Well, I believe your createEvent mutation should return an object type. And for the object type , you have to specify at least one of the field from of return type for this Mutation.
It should be :
mutation {
createEvent(eventInput: {
title: "A Test"
description:"Does this work?"
price:9.99
date:"2018-12-06T09:26:30.645Z"
}){
someFieldInTheReturnType
}
}
This is closely related to my last question here. In short, I have 2 schemas, dbPosts and dbAuthors. They look somewhat like this (I've omitted some fields here for the sake of brevity):
dbPosts
id: mongoose.Schema.Types.ObjectId,
title: { type: String },
content: { type: String },
excerpt: { type: String },
slug: { type: String },
author: {
id: { type: String },
fname: { type: String },
lname: { type: String },
}
dbAuthors
id: mongoose.Schema.Types.ObjectId,
fname: { type: String },
lname: { type: String },
posts: [
id: { type: String },
title: { type: String }
]
I'm resolving my post queries like this:
const mongoose = require('mongoose');
const graphqlFields = require('graphql-fields');
const fawn = require('fawn');
const dbPost = require('../../../models/dbPost');
const dbUser = require('../../../models/dbUser');
fawn.init(mongoose);
module.exports = {
// Queries
Query: {
posts: (root, args, context) => {
return dbPost.find({});
},
post: (root, args, context) => {
return dbPost.findById(args.id);
},
},
Post: {
author: (parent, args, context, ast) => {
// Retrieve fields being queried
const queriedFields = Object.keys(graphqlFields(ast));
console.log('-------------------------------------------------------------');
console.log('from Post:author resolver');
console.log('queriedFields', queriedFields);
// Retrieve fields returned by parent, if any
const fieldsInParent = Object.keys(parent.author);
console.log('fieldsInParent', fieldsInParent);
// Check if queried fields already exist in parent
const available = queriedFields.every((field) => fieldsInParent.includes(field));
console.log('available', available);
if(parent.author && available) {
return parent.author;
} else {
return dbUser.findOne({'posts.id': parent.id});
}
},
},
};
And I'm resolving all author queries like this:
const mongoose = require('mongoose');
const graphqlFields = require('graphql-fields');
const dbUser = require('../../../models/dbUser');
const dbPost = require('../../../models/dbPost');
module.exports = {
// Queries
Query: {
authors: (parent, root, args, context) => {
return dbUser.find({});
},
author: (root, args, context) => {
return dbUser.findById(args.id);
},
},
Author: {
posts: (parent, args, context, ast) => {
// Retrieve fields being queried
const queriedFields = Object.keys(graphqlFields(ast));
console.log('-------------------------------------------------------------');
console.log('from Author:posts resolver');
console.log('queriedFields', queriedFields);
// Retrieve fields returned by parent, if any
const fieldsInParent = Object.keys(parent.posts[0]._doc);
console.log('fieldsInParent', fieldsInParent);
// Check if queried fields already exist in parent
const available = queriedFields.every((field) => fieldsInParent.includes(field));
console.log('available', available);
if(parent.posts && available) {
// If parent data is available and includes queried fields, no need to query db
return parent.posts;
} else {
// Otherwise, query db and retrieve data
return dbPost.find({'author.id': parent.id, 'published': true});
}
},
},
};
Again, I've left out bits not relevant to this question, such as mutations, in the interest of brevity. My objective is to make all queries work recursively while also optimizing database lookups. But somehow I'm unable to accomplish this. Here's one query I'm running, for instance:
{
posts{
id
title
author{
first_name
last_name
id
posts{
id
title
}
}
}
}
And it returns this:
{
"errors": [
{
"message": "Cannot return null for non-nullable field Post.author.",
"locations": [
{
"line": 5,
"column": 5
}
],
"path": [
"posts",
1,
"author"
]
}
],
"data": {
"posts": [
{
"id": "5ba1f3e7cc546723422e62a4",
"title": "A Title!",
"author": {
"first_name": "Bill",
"last_name": "Erby",
"id": "5ba130271c9d440000ac8fc4",
"posts": [
{
"id": "5ba1f3e7cc546723422e62a4",
"title": "A Title!"
}
]
}
},
null
]
}
}
If you notice, this query does return all values requested, but also adds an error message against the post.author query! What could be causing this?
I haven't included the entire codebase so as not to make things confusing, but should you wish to take a look, it's up on Github and a GraphiQL interface is up at https://graph.schandillia.com should you wish to see the results for yourself.
Thank you so much for your time, if you've come this far. Would really appreciate any pointer in the right direction!"
P.S.: If you notice, I'm logging the values of 3 variables in each resolver for debugging purposes:
queriedFields: An array of all fields being queried
fieldsInParent: An array of all fields being returned in the resolver's parent property
available: A boolean showing if all queriedFields members exist in fieldsInParent
And when I run a simple query like this:
{
posts{
id
author{
id
posts{
id
}
}
}
}
This is what gets logged:
-------------------------------------------------------------
from Post:author resolver
queriedFields [ 'id', 'posts' ]
fieldsInParent [ '$init', 'id', 'first_name', 'last_name' ]
available false
-------------------------------------------------------------
from Post:author resolver
queriedFields [ 'id', 'posts' ]
fieldsInParent [ '$init', 'id', 'first_name', 'last_name' ]
available false
-------------------------------------------------------------
from Author:posts resolver
queriedFields [ 'id' ]
fieldsInParent [ 'id', 'title' ]
available true
Shouldn't the post:author resolver execute only once? Also, it's funny how in the first 2 logs, fieldsInParent is missing the posts field even when the schema for author includes such a field.
Your query result does not in fact include all the requested data. The posts query resolves to an array that includes one Post object and a null. The null is there because GraphQL tried to fully resolve the other Post object and could not -- it encountered a validation error, namely that the post's author resolved to null.
You can change your schema to make the author field nullable, which would get rid of the error but would still leave you with the null post. Presumably, if a post exists, it should have an author (although with MongoDB I guess it's very possible you just have some bad data). If you look inside your resolver, there's two return statements -- one of them (probably the db call) is returning null for that second post.
As an aside, as a client, you probably don't want to deal with nulls inside the array and want an empty array instead of a null for the whole field. When using lists (arrays), you may want to make them both non-nullable and make each item in that list non-nullable as well. You do so like this:
posts: [Post!]!
You still need to ensure your resolver logic prevents those nulls from happening, but adding the validation can help you catch that sort of behavior more easily.