GraphQL argument passing - node.js

I start to learning graphql. But I can't pass the arguments. when I console.log the args, that is undefined. I want to pass the name value of greeting from a client and pass it as an argument.
//schema
//resolvers
import { GraphQLServer } from "graphql-yoga";
//Scalar type: string, Boolean, Int, Float, ID
// ! must return same scalar type
// type name always cap
const typeDefs= `
type Query{
greeting(name: String): String!
me: User!
post: Post!
}
type User{
id: ID!
name: String!
email: String!
age: Int
}
type Post{
id:ID!
title: String!
body: String!
}
`
//age value is not must
//resolvers get four args parent,args,ctx,info
const resolvers={
Query:{
greeting:(args)=>{
console.log(args)
return `Konika said to ${args.name}`
},
me:()=>{
return{
id:"12345",
name: "jalmal",
email: "ja#gmail.com",
age: null
}
},
post:()=>{
return{
id: "12345",
title:"I am ok with it",
body:"Why I am failed"
}
}
}
}
const server = new GraphQLServer({typeDefs, resolvers})
server.start(()=>console.log(`server is running`));
my query is like this
query{
greeting(name: "milar")
me{
id
email
age
}
post{
id
title
}
}
I can't find why args is undefined.

The args from the client-side are passed as the second parameter of a resolver. See Root fields & resolvers
It should be:
const resolvers={
Query:{
greeting:(_, args)=>{
console.log(args)
return `Konika said to ${args.name}`
}
}
}

Related

Expected Iterable, but did not find one for field \"Query.customers\ [duplicate]

I'm currently trying GraphQL with NodeJS and I don't know, why this error occurs with the following query:
{
library{
name,
user {
name
email
}
}
}
I am not sure if the type of my resolveLibrary is right, because at any example I had a look at they used new GraphQL.GraphQLList(), but in my case I really want to return a single user object, not an array of users.
My code:
const GraphQL = require('graphql');
const DB = require('../database/db');
const user = require('./user').type;
const library = new GraphQL.GraphQLObjectType({
name: 'library',
description: `This represents a user's library`,
fields: () => {
return {
name: {
type: GraphQL.GraphQLString,
resolve(library) {
return library.name;
}
},
user: {
type: user,
resolve(library) {
console.log(library.user);
return library.user
}
}
}
}
});
const resolveLibrary = {
type: library,
resolve(root) {
return {
name: 'My fancy library',
user: {
name: 'User name',
email: {
email: 'test#123.de'
}
}
}
}
}
module.exports = resolveLibrary;
Error:
Error: Expected Iterable, but did not find one for field library.user.
So my library schema provides a user field which returns the right data (the console.log is called).
I ran into this problem as well. It appears that what you're returning from your resolver doesn't match the return type in your schema.
Specifically for the error message Expected Iterable, but did not find one for field library.user., your schema expects an array(Iterable) but you aren't returning an array in your resolver
I had this in my schema.js:
login(email: String, password: String): [SuccessfulLogin]
I changed that to:
login(email: String, password: String): SuccessfulLogin
Notice the square brackets around "SuccessfulLogin". It's up to you whether you want to update the resolver return type or update the schema's expectations
I guess your user is an instance of GraphQLList that is why the field user is expecting to resolve to an iterable object.
I had the same problem. I was using find instead filter.
I ran into the same issue but i was using GraphQL with Go.
Solution:
I mentioned the return type to be a list( or you can say an array), but my resolver function was returning an interface and not a list of interfaces.
Before it was =>
Type: graphql.NewList(graphqll.UniversalType)
Later i changed it to =>
Type: graphqll.UniversalType
graphqll.UniversalType : 'graphqll' is the name of my user-defined package and 'UniversalType' is the GraphQL object i have created.
The previous structure of graphql object was :
var GetAllEmpDet = &graphql.Field{
Type: graphql.NewList(graphqll.UniversalType),
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It worked when i changed this to:
var GetAllEmpDet = &graphql.Field{
Type: graphqll.UniversalType,
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It's usually a simple mistake. Caused by declaring in the schema a List instead of a Field. The reverse will happen if you interchange. An example from Django-graphene. Switch from this:
my_query_name = graphene.List(MyModelType, id=graphene.Int())
to this:
my_query_name = graphene.Field(MyModelType, id=graphene.Int())
In my case it was related to django-graphene I didn't have a resolve method defined.
class SomeNode(DjangoObjectType):
things = graphene.List(ThingNode)
def resolve_things(self, info, **kwargs):
return self.things.all()
For me, it was a simple fix.
items: {
type: new GraphQLList(VideoType),<-- error
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
and change it to
items: {
type: VideoType,
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
I faced the same issue. For me, it was an issue with Mongo DB model.js file.
GraphQL kept throwing that error because my model was saving the field as an object whereas graphQL was returning it as an array.
The code that caused the error was this.
tableHeaders: {
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
It was corrected to the following.
tableHeaders: [
{
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
],
Changing type from object to array fixed it.
i had the same issue i was using findOne and that seems like the issue that didnt worked. i changed to find and it worked
#Query(()=> [Post])
async getSinglePost(
#Arg('post_id') id: string,
){
/*
const post = await getConnection().getRepository(Post).findOne({uuid:postuid})
console.log(post);
return post
*/
const post = Post.find({uuid:id})
return post
}
This simply results due to the import error
earlier code
const books =require('./data')
// Resolvers define the technique for fetching the types defined in the
// schema. This resolver retrieves books from the "books" array above.
const resolvers = {
Query: {
books(){
return books;
},
},
}
module.exports = { resolvers };
just replace the import statement with
const {books} =require('./data')
as you had ex

Why do subfields conflict when they are in different interfaces?

I am trying to query a single MongoDB document (trivia) using GraphQL (Apollo Server), but am having trouble with one of the document fields.
LightningRoundQuestion.answer and PictureRoundPicture.answer should return a String, and MultipleChoiceRoundQuestion.answer should return an Int. See the schema:
schema
const typeDefs = gql`
# ROOT TYPES ==================================================
type Query {
trivia(_id: String!): Trivia
}
# INTERFACES ==================================================
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
type PictureRound implements Round {
type: String!
theme: String!
pointValue: Int!
pictures: [PictureRoundPicture]
}
# QUERY TYPES =================================================
type LightningRoundQuestion {
question: String!
answer: String!
}
type MultipleChoiceRoundQuestion {
question: String!
options: [String!]!
answer: Int!
}
type PictureRoundPicture {
url: String!
answer: String!
}
type Trivia {
_id: String!
createdAt: String!
triviaId: String!
triviaPin: String!
host: String!
rounds: [Round]!
tieBreaker: TieBreaker!
}
type TieBreaker {
question: String
answer: Int
}
`
resolvers & server
const resolvers = {
Query: {
trivia: async (root, { _id }) => {
return triviaCollection.findOne(ObjectId(_id))
}
},
Round: {
__resolveType(obj) {
if (obj.type === 'multipleChoice') {
return 'MultipleChoiceRound'
} else if (obj.type === 'lightning') {
return 'LightningRound'
} else if (obj.type === 'picture') {
return 'PictureRound'
}
}
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`)
})
query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
triviaId
triviaPin
host
rounds {
... on LightningRound {
questions {
question
answer
}
}
... on MultipleChoiceRound {
questions {
question
options
answer
}
}
... on PictureRound {
pictures {
url
answer
}
}
}
}
}
I get the error message:
"message": "Fields \"questions\" conflict because subfields \"answer\" conflict because they return conflicting types \"String!\" and \"Int!\". Use different aliases on the fields to fetch both if this was intentional."
Not quite sure what to do next, I looked at Alias in the Apollo documentation, but there's little help there.
This is a bit of a gotcha when using abstract types and occurs as a result of how GraphQL handles merging field selections. What it boils down to is that if you request a field with the same name (or alias) multiple times inside the same selection set, the field has to return the same type. In the above schema, it doesn't -- questions could have the type [LightningRoundQuestion], or [PictureRoundPicture] and so on.
For a detailed explanation, see this section of the spec.
There's two workarounds for this. On the client side, you can use aliases to ensure GraphQL won't try to merge the fields in the first place:
rounds {
... on LightningRound {
lightningQuestions: questions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions: questions {
question
options
answer
}
}
}
This is your best bet when you can't change the schema. However, you can also just change the names of the fields on the server-side for better client-side DX.
rounds {
... on LightningRound {
lightningQuestions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions {
question
options
answer
}
}
}
Notice that we don't have to do that with, type, theme or pointValue because these fields have the same type across all your implementing types.

Express GraphQL schema error when requesting from a public API [duplicate]

I'm currently trying GraphQL with NodeJS and I don't know, why this error occurs with the following query:
{
library{
name,
user {
name
email
}
}
}
I am not sure if the type of my resolveLibrary is right, because at any example I had a look at they used new GraphQL.GraphQLList(), but in my case I really want to return a single user object, not an array of users.
My code:
const GraphQL = require('graphql');
const DB = require('../database/db');
const user = require('./user').type;
const library = new GraphQL.GraphQLObjectType({
name: 'library',
description: `This represents a user's library`,
fields: () => {
return {
name: {
type: GraphQL.GraphQLString,
resolve(library) {
return library.name;
}
},
user: {
type: user,
resolve(library) {
console.log(library.user);
return library.user
}
}
}
}
});
const resolveLibrary = {
type: library,
resolve(root) {
return {
name: 'My fancy library',
user: {
name: 'User name',
email: {
email: 'test#123.de'
}
}
}
}
}
module.exports = resolveLibrary;
Error:
Error: Expected Iterable, but did not find one for field library.user.
So my library schema provides a user field which returns the right data (the console.log is called).
I ran into this problem as well. It appears that what you're returning from your resolver doesn't match the return type in your schema.
Specifically for the error message Expected Iterable, but did not find one for field library.user., your schema expects an array(Iterable) but you aren't returning an array in your resolver
I had this in my schema.js:
login(email: String, password: String): [SuccessfulLogin]
I changed that to:
login(email: String, password: String): SuccessfulLogin
Notice the square brackets around "SuccessfulLogin". It's up to you whether you want to update the resolver return type or update the schema's expectations
I guess your user is an instance of GraphQLList that is why the field user is expecting to resolve to an iterable object.
I had the same problem. I was using find instead filter.
I ran into the same issue but i was using GraphQL with Go.
Solution:
I mentioned the return type to be a list( or you can say an array), but my resolver function was returning an interface and not a list of interfaces.
Before it was =>
Type: graphql.NewList(graphqll.UniversalType)
Later i changed it to =>
Type: graphqll.UniversalType
graphqll.UniversalType : 'graphqll' is the name of my user-defined package and 'UniversalType' is the GraphQL object i have created.
The previous structure of graphql object was :
var GetAllEmpDet = &graphql.Field{
Type: graphql.NewList(graphqll.UniversalType),
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It worked when i changed this to:
var GetAllEmpDet = &graphql.Field{
Type: graphqll.UniversalType,
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It's usually a simple mistake. Caused by declaring in the schema a List instead of a Field. The reverse will happen if you interchange. An example from Django-graphene. Switch from this:
my_query_name = graphene.List(MyModelType, id=graphene.Int())
to this:
my_query_name = graphene.Field(MyModelType, id=graphene.Int())
In my case it was related to django-graphene I didn't have a resolve method defined.
class SomeNode(DjangoObjectType):
things = graphene.List(ThingNode)
def resolve_things(self, info, **kwargs):
return self.things.all()
For me, it was a simple fix.
items: {
type: new GraphQLList(VideoType),<-- error
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
and change it to
items: {
type: VideoType,
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
I faced the same issue. For me, it was an issue with Mongo DB model.js file.
GraphQL kept throwing that error because my model was saving the field as an object whereas graphQL was returning it as an array.
The code that caused the error was this.
tableHeaders: {
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
It was corrected to the following.
tableHeaders: [
{
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
],
Changing type from object to array fixed it.
i had the same issue i was using findOne and that seems like the issue that didnt worked. i changed to find and it worked
#Query(()=> [Post])
async getSinglePost(
#Arg('post_id') id: string,
){
/*
const post = await getConnection().getRepository(Post).findOne({uuid:postuid})
console.log(post);
return post
*/
const post = Post.find({uuid:id})
return post
}
This simply results due to the import error
earlier code
const books =require('./data')
// Resolvers define the technique for fetching the types defined in the
// schema. This resolver retrieves books from the "books" array above.
const resolvers = {
Query: {
books(){
return books;
},
},
}
module.exports = { resolvers };
just replace the import statement with
const {books} =require('./data')
as you had ex

GraphQL Expected Iterable, but did not find one for field xxx.yyy

I'm currently trying GraphQL with NodeJS and I don't know, why this error occurs with the following query:
{
library{
name,
user {
name
email
}
}
}
I am not sure if the type of my resolveLibrary is right, because at any example I had a look at they used new GraphQL.GraphQLList(), but in my case I really want to return a single user object, not an array of users.
My code:
const GraphQL = require('graphql');
const DB = require('../database/db');
const user = require('./user').type;
const library = new GraphQL.GraphQLObjectType({
name: 'library',
description: `This represents a user's library`,
fields: () => {
return {
name: {
type: GraphQL.GraphQLString,
resolve(library) {
return library.name;
}
},
user: {
type: user,
resolve(library) {
console.log(library.user);
return library.user
}
}
}
}
});
const resolveLibrary = {
type: library,
resolve(root) {
return {
name: 'My fancy library',
user: {
name: 'User name',
email: {
email: 'test#123.de'
}
}
}
}
}
module.exports = resolveLibrary;
Error:
Error: Expected Iterable, but did not find one for field library.user.
So my library schema provides a user field which returns the right data (the console.log is called).
I ran into this problem as well. It appears that what you're returning from your resolver doesn't match the return type in your schema.
Specifically for the error message Expected Iterable, but did not find one for field library.user., your schema expects an array(Iterable) but you aren't returning an array in your resolver
I had this in my schema.js:
login(email: String, password: String): [SuccessfulLogin]
I changed that to:
login(email: String, password: String): SuccessfulLogin
Notice the square brackets around "SuccessfulLogin". It's up to you whether you want to update the resolver return type or update the schema's expectations
I guess your user is an instance of GraphQLList that is why the field user is expecting to resolve to an iterable object.
I had the same problem. I was using find instead filter.
I ran into the same issue but i was using GraphQL with Go.
Solution:
I mentioned the return type to be a list( or you can say an array), but my resolver function was returning an interface and not a list of interfaces.
Before it was =>
Type: graphql.NewList(graphqll.UniversalType)
Later i changed it to =>
Type: graphqll.UniversalType
graphqll.UniversalType : 'graphqll' is the name of my user-defined package and 'UniversalType' is the GraphQL object i have created.
The previous structure of graphql object was :
var GetAllEmpDet = &graphql.Field{
Type: graphql.NewList(graphqll.UniversalType),
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It worked when i changed this to:
var GetAllEmpDet = &graphql.Field{
Type: graphqll.UniversalType,
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
...
...
// Your resolver code goes here, how you handle.
...
return models.Universal, nil // models.Universal is struct and not list of struct so it gave that error.
},
}
It's usually a simple mistake. Caused by declaring in the schema a List instead of a Field. The reverse will happen if you interchange. An example from Django-graphene. Switch from this:
my_query_name = graphene.List(MyModelType, id=graphene.Int())
to this:
my_query_name = graphene.Field(MyModelType, id=graphene.Int())
In my case it was related to django-graphene I didn't have a resolve method defined.
class SomeNode(DjangoObjectType):
things = graphene.List(ThingNode)
def resolve_things(self, info, **kwargs):
return self.things.all()
For me, it was a simple fix.
items: {
type: new GraphQLList(VideoType),<-- error
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
and change it to
items: {
type: VideoType,
resolve(parentValue, args) {
const url = 'www'
return axios.get(url)
.then(res => res.data);
}
}
I faced the same issue. For me, it was an issue with Mongo DB model.js file.
GraphQL kept throwing that error because my model was saving the field as an object whereas graphQL was returning it as an array.
The code that caused the error was this.
tableHeaders: {
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
It was corrected to the following.
tableHeaders: [
{
text: {
type: String,
required: false,
},
align: {
type: String,
required: false,
},
sortable: {
type: Boolean,
required: false,
},
value: {
type: String,
required: false,
},
},
],
Changing type from object to array fixed it.
i had the same issue i was using findOne and that seems like the issue that didnt worked. i changed to find and it worked
#Query(()=> [Post])
async getSinglePost(
#Arg('post_id') id: string,
){
/*
const post = await getConnection().getRepository(Post).findOne({uuid:postuid})
console.log(post);
return post
*/
const post = Post.find({uuid:id})
return post
}
This simply results due to the import error
earlier code
const books =require('./data')
// Resolvers define the technique for fetching the types defined in the
// schema. This resolver retrieves books from the "books" array above.
const resolvers = {
Query: {
books(){
return books;
},
},
}
module.exports = { resolvers };
just replace the import statement with
const {books} =require('./data')
as you had ex

Graphql Query Returning a null value (Apollo Server)

I created a mock programmatically for testing at my query but it only returns a null value what am i doing wrong. I am using the casual library for generating values for my mock
Here are my files:
index.js
import express from 'express'
import bodyParser from 'body-parser'
import { graphqlExpress,graphiqlExpress } from 'graphql-server-express'
import { makeExecutableSchema } from 'graphql-tools'
import mock from './mock'
import schema from './schema'
const app = express()
const executableSchema = makeExecutableSchema({
typeDefs: schema,
mock
})
app.post(
'/graphql',
bodyParser.json(),
graphqlExpress(() => ({
schema: executableSchema
}))
)
app.use('/graphiql',graphiqlExpress({
endpointURL: '/graphql',
}))
app.listen(8080)
console.log("listening at 8080")
schema.js
const schema = `
interface Novel {
artist: String
author: String
chapters: [Chapter]
description: String
genre: [String]
id: String
image: String
language: String
modified: String!
name: String!
status: String
tags: [String]
type: String
year: String
}
interface Chapter {
chapter: String!
volume: String!
content: String!
}
type NovelCrawler implements Novel{
artist: String
author: String
chapters: [Chapter]
description: String
genre: [String]
id: String
image: String
language: String
modified: String!
name: String!
novelurl: String
status: String
tags: [String]
type: String
year: String
}
type ChapterCrawler implements Chapter {
chapter: String!
chapterurl: String
content: String!
novelurl: String
volume: String!
}
`
const Query = `
type Query {
novels: [Novel]
}
`
export default [schema, Query]
mock.js
import casual from 'casual'
const genre = ['romance', 'comedy', 'action']
const Novel = () => ({
artist: casual.name,
author: casual.name,
description: casual.sentences(3),
genre: [casual.random_element(genre), casual.random_element(genre)],
id: casual.url,
image: 'sdfgrtw3wedfgb2345y675trfdvfbghdsfdssfd',
language: casual.random_element(['chinese', 'japanese', 'korean']),
modified: casual.date('YYYY-MM-DD'),
name: casual.word,
status: casual.random_element(['Completed', 'Ongoing']),
tags: [],
novelurl: casual.url,
type: casual.random_element(['Web Novel', 'Light Novel']),
year: casual.year
})
const Chapter = () => ({
chapter: casual.integer(1, 50),
chapterurl: casual.url,
content: casual.sentences(10),
novelurl: casual.url,
volume: casual.integer(1, 5)
})
const arrNovel = []
const arrChapter = []
for (let x = 0; x < 20; ++x) {
arrNovel.push(Novel())
arrChapter.push(Chapter())
}
const mock = {
// Query: { novels: () => ({}) },
Novel: {
__resolveType(obj, context, info) {
return 'NovelCrawler'
}
},
Chapter: {
__resolveType(obj, context, info) {
return 'ChapterCrawler'
}
},
NovelCrawler: () => arrNovel,
ChapterCrawler: () => arrChapter
}
export default mock
When i run the following query:
{
novels{
description
}
}
it returns:
{
"data": {
"novels": null
}
}
so i tried:
{
novels{
... on NovelCrawler{
artist
}
}
}
this returns
{
"errors": [
{
"message": "Unknown operation named \"null\"."
}
]
}
what am i doing wrong
Thanks for providing complete code and examples. Here's a few notes to get you going in the right direction:
Make sure you are implementing mocks correctly. I think makeExecutableSchema used to accept a mocks option at one point, but now you have to use addMockFunctionsToSchema in conjunction with it to implement mocking. I would read Apollo's guide to mocking for detailed steps on how to do that.
graphqlExpress is actually middleware, so you should implement it with app.use instead of app.post. GraphQL Server can handle both POST and GET requests.
You probably don't need interfaces for what you're trying to do. An interface requires that every type that implements it also has the fields defined in the interface. They're used when two or more types share fields, which isn't the case here. I would suggest making Chapter a regular type and nesting it inside ChapterCrawler like below. Ditto for Novel.
type ChapterCrawler {
chapter: Chapter!
chapterurl: String
novelurl: String
}
type Chapter {
chapter: String!
content: String!
volume: String!
}
If you go with the above method, you will need to eventually change your query to fetch [NovelCrawler] instead. Wait! Before making things more complicated and harder to debug, I would suggest mocking just Chapter and adding a query to get [Chapters] first. Once you have that working, you'll know you have the basic functionality down and can starting mocking and querying more complex data structures.
If you do need interfaces, make sure you get what function they serve and how to correctly implement them. This article may help clarify things.
Keep in mind makeExecutableSchema takes typeDefs and resolvers separately once you're no longer mocking everything.

Resources