Express GraphQL schema error when requesting from a public API [duplicate] - node.js

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

Related

Update document in MongoDB via NodeJS

So my knowledge of NodeJS and MongoDD are non-existent (just need to do a small code update for a friend) and I'm stuck.
Need to update a single document inside a collection via a unique id but can't seem to do it.
Here's the Model (I've trimmed it down and cut out all unnecessary data). I'm trying to update the field notes inside a transaction.
In short each entry in the given (an Agent) table will have a collection of multiple Transactions & Documents. I need to update a specific Transaction with the unique _id that is auto generated.
import { Schema, model } from 'mongoose';
interface Transaction {
first_name: string;
last_name: string;
type: string;
notes: string;
}
interface Agent {
org_id: number;
transactions: Array<Transaction>;
documents: Array<string>;
}
const transactionSchema = new Schema<Transaction>({
first_name: { type: String },
last_name: { type: String },
type: { type: String },
notes: String,
});
const transactionsSchema = new Schema<Agent>({
org_id: { type: Number },
transactions: [transactionSchema],
documents: [documentTypesSchema],
});
const AgentTransaction = model<Agent>(
'agent_transaction_table',
transactionsSchema
);
export default AgentTransaction;
Here's what I tried but didn't work (obviously), again I've trimmed out all unnecessary data. Just to clarify, the endpoint itself works, but the DB update does not.
import AgentTransaction from '../models/transaction'; // the above model
transaction.put('/notes', async (req, res) => {
const { org_id, transaction_id, notes } = req.body;
try {
const notesResult = await AgentTransaction.updateOne({
'transactions._id': transaction_id,
}, {
$set: {
'notes': notes
},
});
res
.status(200)
.json({ message: 'Updated', success: true, notesResult });
} catch (error) {
res.status(400).send(error);
}
});
So I figured it out. Maybe it'll help someone else as well.
const notesResult = await AgentTransaction.updateOne({
'transactions._id': { $in: [trunc2] },
}, {
$set: {
'transactions.$.notes': notes
},
});
The main issue was that the payload object needed to target the collection folder + the wildcard + the field, not just only the field.

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

Mongoose: How to ensure row should be unique only if value of property is equal to something?

I have a simple Mongoose schema that looks like this:
const fruitSchema = new mongoose.Schema({
name: {
type: String
required: true
},
type: {
type: String,
required: true
}
})
schema.index({ name: 1, type: 1 }, { unique: true })
const Fruit = mongoose.model('Fruit', fruitSchema)
Under normal circumstances, the table is unique on (name, type) so the user is able to store multiple types for each fruit. However, I want to allow the user to only store one type if the name of the Fruit is apple.
So basically, I want make the following check before a save is made:
if (newFruit.name === 'apple') {
if (Fruit.find({ name: 'apple' }).count >= 1) throw new Error()
}
One way of enforcing this is to execute the code above in a pre-save hook. But, I was just wondering if there would be an in-built way to specify this within the Mongoose schema itself?
Thanks for the help!
SOLUTION:
In addition to the solution kindly provided by #SuleymanSah below, I thought I'd post what I finally ended up using.
const fruitSchema = new mongoose.Schema({
fruit: {
type: String
required: true,
async validate(name) {
if (name === 'apple') {
let fruit
try {
fruit = await Fruit.findOne({ name })
} catch (e) {
console.error('[Fruit Model] An error occurred during validation.')
console.error(e)
throw e // rethrow error if findOne call fails since fruit will be null and this validation will pass with the next statement
}
if (fruit) throw new Error(`A fruit for ${name} already exists.`)
}
},
type: {
type: String,
required: true
}
})
schema.index({ fruit: 1, type: 1 }, { unique: true })
const Fruit = mongoose.model('Fruit', fruitSchema)
You can use custom validators like this:
const schema = new mongoose.Schema({
name: {
type: String,
required: true
},
type: {
type: String,
required: true,
validate: {
validator: async function() {
if (this.name === "apple") {
let doc = await this.constructor.findOne({ name: "apple" });
return Boolean(!doc);
}
},
message: props => "For apple only one type can be."
}
}
});
You can do it like this with express, for example when saving a new fruit:
const express = require("express");
const router = express.Router();
router.post("/save", (req, res) => {
const { name, type } = req.body; //this is coming from front-end
Fruit.findOne({ name }).then(fruit=> {
if (fruit) return res.status(400).json({ name: "This fruit already exist!" });
This will prevent any fruit with same name from saving to database
i think this is similar query
you need to add index and set it to unique
restrict to store duplicate values in mongodb

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

Passing array as argument in GraphQL

I have started working on GraphQL.My schema contains one list item too.
Following is the code of my schema:
var userType = new graphql.GraphQLObjectType({
name: 'user',
fields: function () {
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
},
degrees:[
{type:graphql.GraphQLList}
]
}
}
});
AND the query is as follows:
var QueryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: () => ({
userArr: {
type: new graphql.GraphQLList(userType),
args:{
degrees:{type:new graphql.GraphQLList(userType)}
},
resolve: function(source, args) {
console.log(args);
resolve(args);
}
}
})
})
I got this error.
Basically i need to post the array from client graphql query and have to define query accordingly which i am unable to achieve.
Any suggestions because i can't find any help over this issue..
GraphQLObjectType is not a valid input type.
See Mutations and Input Types
"Input types can't have fields that are other objects, only basic scalar types, list types, and other input types."
You can use the suggestion above because GraphQLString is a scalar
degrees:{
type:new graphql.GraphQLList(graphql.GraphQLString)
}
Otherwise, you would need to define a GraphQLInputObjectType
const userInputType = new GraphQLInputObjectType({
name: 'userInput',
fields: { /* put your fields here */ }
});
/* some code in between */
degrees:{
type:new graphql.GraphQLList(userInputType)
}
I did something very similar recently. Your input arguments don't need to hold to the same type system as the when it's formatting the output data to send back. So your arg just needs to simply accept a list of strings or objects, or whatever standard type you want to send in.
In this case, I updated it to accept a list(array) of strings.
var QueryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: () => ({
userArr: {
type: new graphql.GraphQLList(userType),
args:{
degrees:{type:new graphql.GraphQLList(graphql.GraphQLString)}
},
resolve: function(source, args) {
console.log(args);
resolve(args);
}
}
})
})
Also, I noticed on your user type, you have degrees surrounded with array brackets.
Similar to your degrees input argument, you'll be outputting an array of strings.
Try something like this:
degrees:{
type:new graphql.GraphQLList(graphql.GraphQLString)
}
Happy coding!

Resources