Circular Dependencies cannot be split into their respective files - javascript

There are two objects, Users and Company, each user works for a Company, thereby has a companyId which is referred to through GraphQL. Similarly, each Company has a list of users working for them.
Here's the code:
company.js
const UserType = require('./user')
const CompanyType = new GraphQLObjectType({
name: 'Company',
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
users: {
type: new GraphQLList(UserType), --------> Error:Expected {} to be a GraphQL type.
Expected UserType to be a GraphQL type.
async resolve(parentValue, args) {
return await axios(
`http://localhost:3001/company/${parentValue.id}/users`
).then(({ data }) => data)
},
},
}),
})
user.js
const CompanyType = require('./company')
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: { type: GraphQLString },
age: { type: GraphQLInt },
name: { type: GraphQLString },
company: {
type: CompanyType,
async resolve(parentValue, args) {
console.log(parentValue)
return await axios(
`http://www.localhost:3001/company/${parentValue.companyId}`
).then((response) => response.data)
},
},
}),
})
rootquery.js
const UserType = require('./user')
const CompanyType = require('./company')
const RootQuery = new GraphQLObjectType({
name: 'RootQueryObjectType',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLString },
},
resolve: async (parentValue, args) => {
return await axios(`http://localhost:3001/users/${args.id}`).then(
({ data }) => data
)
},
},
company: {
type: CompanyType,
args: {
id: { type: GraphQLString },
},
resolve: async (parentValue, args) => {
return await axios(`http://localhost:3001/company/${args.id}`).then(
({ data }) => data
)
},
},
},
})
The error is understandable due to Circular Dependencies.
In case I put the code of user.js and company.js into the rootquery.js, there's no error.
Is there a way to seperate out these files, without running into an empty object error?

After researching quite a bit, found out that wherever you'd need to use a circular dependency, you've got to require it at that point in your code, instead of requiring it as a variable.
E.g.
Previously:
const UserType = require('./user') ---> This was null/empty as it wasn't yet
created
const CompanyType = new GraphQLObjectType({
name: 'Company',
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
users: {
type: new GraphQLList(UserType), --------> Error:Expected {} to be a
GraphQL type.
Expected UserType to be a
GraphQL type.
async resolve(parentValue, args) {
return await axios(
`http://localhost:3001/company/${parentValue.id}/users`
).then(({ data }) => data)
},
},
}),
})
To overcome this issue, I required the neccessary module exactly where it is required
Solution:
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
name: { type: GraphQLString },
id: { type: GraphQLString },
age: { type: GraphQLInt },
company: {
**type: require('./company'),** -----> This is where a dynamic
import
is being made
async resolve(parentValue, args) {
return await axios(
`http://localhost:3001/users/${parentValue.id}`
).then(({ data }) => data)
},
},
}),
})

Related

Express GraphQL: I want to create a Team and populate with players, by passing the players IDs, but I can't find the correct syntax

Using Express-graphql, mongo/mongoose/ react.
Im Creating a database with Teams, Players, and Matches.
I want to write a mutation for creating a new team, which lists its players given their IDs, but I keep getting errors. I'm a newbie to GraphQL, so explain it accordingly please.
Can you help me populate "players" please?
The Models
const TeamSchema = new mongoose.Schema({
teamName: { type: String },
teamNumber: { type: Number },
inMatchIDs: { type: mongoose.Schema.Types.ObjectId, ref: "Match" },
players: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
});
const UserSchema = new mongoose.Schema(
{
name: { type: String },
wins: { type: Number },
matchesPlayed: { type: Number },
},
{ timestamps: true }
);
The GraphQL Schema
const TeamType = new GraphQLObjectType({
name: "Team",
fields: () => ({
id: { type: GraphQLID },
teamName: { type: GraphQLString },
teamNumber: { type: GraphQLInt },
inMatchIDs: { type: new GraphQLList(MatchType) },
players: {
type: UserType,
resolve(parent, args) {
return parent.players.map((player) => {
User.findById(player.id);
});
},
},
}),
});
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
wins: { type: GraphQLInt },
matchesPlayed: { type: GraphQLInt },
email: { type: GraphQLString },
password: { type: GraphQLString },
token: { type: GraphQLString },
}),
});
The Mutation Schema
createTeam: {
type: TeamType,
args: {
teamName: { type: GraphQLString },
players: { type: GraphQLList(GraphQLID) },
},
resolve(parent, args) {
const team = new Team({
teamName: args.teamName,
players: args.players,
});
return team.save();
},
},
... and the Request / Response
//send request:
mutation {
createTeam(teamName: "champions", players: ["63382ba421b2cbfcd0531f4c", "63382ba421b2cbfcd0531f4c"]) {
teamName
id
teamNumber
players{
name
}
}
}
//Response:
{
"data": {
"createTeam": {
"teamName": "champions",
"id": "63386d0a850a34f9823fd4cd",
"teamNumber": null,
"players": {
"name": null
}
}
}
}
Mongo:
So after a whole day and a half trying to wrap my head around the relationships, here is how I solved it:
The Mongoose model remains unchanged:
const TeamSchema = new mongoose.Schema({
teamName: { type: String },
teamNumber: { type: Number },
inMatchIDs: { type: mongoose.Schema.Types.ObjectId, ref: "Match" },
players: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
});
The TeamType in the Schema, is how the response displays the information and the subfields (see 'players' here) need to be resolved as this:
The TeamType
const TeamType = new GraphQLObjectType({
name: "Team",
fields: () => ({
id: { type: GraphQLID },
teamName: { type: GraphQLString },
teamNumber: { type: GraphQLInt },
inMatchIDs: { type: new GraphQLList(MatchType) },
players: {
type: GraphQLList(UserType),
resolve(parent, args) {
let players = [];
parent.players.map((id, i) => {
players.push(User.findById(id));
});
return players;
},
},
}),
});
But another important syntax to be careful of is the passing of the information in the args of the mutation:
The Mutation
createTeam: {
type: TeamType,
args: {
teamName: { type: GraphQLString },
players: { type: GraphQLList(GraphQLID) }, //no need for [] as GraphQLList spells it out
},
players: { type: GraphQLNonNull(GraphQLList(GraphQLID)) }, // here I am defining that the value for the key 'players' will be a non-nullable list of GraphQLID type
resolve(parent, args) {
const team = new Team({
teamName: args.teamName,
players: args.players, // so that here, the model for "Team" understand that I am passing it Ids
});
return team.save();
},
},

Express Graphql

I'm trying to learn graphql. I didn't find any good course witch will help me to learn it. So i started building it with little examples. In this moment i'm getting error when i'm trying to open http://127.0.0.1:3000/graphql. it's telling me "message": "Must provide query string."
I thinks i did something wrong with my users query?
This is my complete code of it. Can someone please help...
// user type
const UserType = new GraphQLObjectType({
name: "User",
description: "User Type",
fields: () => ({
id: { type: GraphQLInt },
firstname: { type: GraphQLString },
lastname: { type: GraphQLString },
email: { type: GraphQLString },
password: { type: GraphQLString },
}),
});
// register (mutation)
const register = {
type: UserType,
args: {
firstname: { type: GraphQLString },
lastname: { type: GraphQLString },
email: { type: GraphQLString },
password: { type: GraphQLString },
},
//#ts-ignore
async resolve(parent, args) {
const { firstname, lastname, email, password } = args;
const user = new User();
user.firstname = firstname;
user.lastname = lastname;
user.email = email;
user.password = password;
const result = await user.save();
console.log(result);
return result;
},
};
// users (query)
const users = {
// type: new GraphQLList(UserType),
type: UserType,
args: { id: { type: GraphQLInt } },
//#ts-ignore
async resolve(parent, args) {
const users = await User.find();
return users;
},
};
const MutationType = new GraphQLObjectType({
name: "MutationType",
description: "Mutations",
fields: { register },
});
const QueryType = new GraphQLObjectType({
name: "QueryType",
description: "Queries",
fields: { users },
});
const schema = new GraphQLSchema({ query: QueryType, mutation: MutationType });
app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
})
);
I have 2 problems.
when i type in browser: http://127.0.0.1:3000/graphql it's don't loading. it's telling me Loading... and stuck on it.
when i try it in insomnia it's telling me
{
"errors": [
{
"message": "Must provide query string."
}
]
}
how can i fixed it ?

GraphQL error - this.findById is not a function

Hi guys I'm trying to add lyrics to my songs via using mutation but it returns an error of this.findById is not a function. The mutation format is correct since I am following a tutorial, however its quite old so I'm not sure if that's a factor...
song_type.js
const mongoose = require('mongoose');
const graphql = require('graphql');
const {
GraphQLObjectType,
GraphQLString,
GraphQLID,
GraphQLList
} = graphql;
const LyricType = require('./lyric_type');
const Song = mongoose.model('song');
const SongType = new GraphQLObjectType({
name: 'SongType',
fields: () => ({
id: {
type: GraphQLID
},
title: {
type: GraphQLString
},
lyrics: {
type: new GraphQLList(LyricType),
resolve(parentValue) {
return Song.findLyrics(parentValue.id);
}
}
})
});
module.exports = SongType;
mutations.js
const graphql = require('graphql');
const {
GraphQLObjectType,
GraphQLString,
GraphQLID
} = graphql;
const mongoose = require('mongoose');
const Song = mongoose.model('song');
const Lyric = mongoose.model('lyric');
const SongType = require('./song_type');
const LyricType = require('./lyric_type');
const mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addSong: {
type: SongType,
args: {
title: {
type: GraphQLString
}
},
resolve(parentValue, {
title
}) {
return (new Song({
title
})).save()
}
},
addLyricToSong: {
type: SongType,
args: {
content: {
type: GraphQLString
},
songId: {
type: GraphQLID
}
},
resolve(parentValue, {
content,
songId
}) {
return Song.addLyric(songId, content);
}
},
likeLyric: {
type: LyricType,
args: {
id: {
type: GraphQLID
}
},
resolve(parentValue, {
id
}) {
return Lyric.like(id);
}
},
deleteSong: {
type: SongType,
args: {
id: {
type: GraphQLID
}
},
resolve(parentValue, {
id
}) {
return Song.remove({
_id: id
});
}
}
}
});
module.exports = mutation;
lyric_type.js
const mongoose = require('mongoose');
const graphql = require('graphql');
const {
GraphQLObjectType,
GraphQLList,
GraphQLID,
GraphQLInt,
GraphQLString
} = graphql;
const Lyric = mongoose.model('lyric');
const LyricType = new GraphQLObjectType({
name: 'LyricType',
fields: () => ({
id: {
type: GraphQLID
},
likes: {
type: GraphQLInt
},
content: {
type: GraphQLString
},
song: {
type: require('./song_type'),
resolve(parentValue) {
return Lyric.findById(parentValue).populate('song')
.then(lyric => {
console.log(lyric)
return lyric.song
});
}
}
})
});
module.exports = LyricType;
Not really sure if that's enough files to solve this error, if not the full repo is here - https://github.com/puyanwei/lyrical-graphql

"BETWEEN ... AND ..." in GraphQL and Sequelize

I'm building an API to query a single table in a MySQL database.
I have a field in the table with a date.
I am trying to get all the records between a range of dates (sort of like the mysql "BETWEEN AND" statement.
const Person = new GraphQLObjectType({
name: 'Person',
Description: 'This represents a person',
fields: () => {
return {
firstName: {
type: GraphQLString,
resolve(bg) {
return bg.name;
}
},
middleName: {
type: GraphQLString,
resolve(bg) {
return bg.middleName;
}
},
lastName: {
type: GraphQLString,
resolve(bg) {
return bg.familyName;
}
},
dateOfBirth: {
type: GraphQLString,
resolve(bg) {
return bg.bornOn;
}
},
sex: {
type: GraphQLString,
resolve(bg) {
return bg.ses;
}
},
regCode: {
type: GraphQLString,
resolve(bg) {
return bg.regCode;
}
},
pinCode: {
type: GraphQLString,
resolve(bg) {
return bg.pinCode;
}
},
}
}
});
const dateOB = new GraphQLObjectType({
name: 'date',
Description: 'This represents a date interval',
fields: () => {
return {
between: {
type: GraphQLString,
},
and: {
type: GraphQLString,
}
}
}
});
const Query = new GraphQLObjectType({
name: 'query',
description: 'This is a root query',
fields: ()=> {
return {
people: {
type: new GraphQLList(Person, dateOB),
args: {
name: {
type: GraphQLString
},
familyName: {
type: GraphQLString
},
bornOn: {
type: GraphQLString
}
},
resolve(root, args) {
return Db.models.bg.findAll({where: args});
}
}
}
}
});
const Schema = new GraphQLSchema({
query: Query
});
I would like to be able to query via a date range on the bornOn argument
sth like "1972-05-05, 2002-01-01" so it only shows records within that range.

Why is my Graphql query returning null? [duplicate]

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 3 years ago.
I am trying to set up a graphql app to all me to easily access data from games.espn.com and I am having an issue of my queries returning null. I'm wondering if I may have missed a return or resolve function somewhere? I have been scouring this code for a few days and can't seem to figure out why this is not returning a value.
Here is my schema.js file:
const {
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLSchema,
GraphQLList,
GraphQLNonNull,
GraphQLBoolean,
GraphQLFloat
} = require('graphql');
const axios = require('axios');
const request = require('request');
const PlayerType = new GraphQLObjectType({
name: 'Player',
fields:() => ({
droppable: {type:GraphQLBoolean},
percentStarted: {type:GraphQLFloat},
jersey: {type:GraphQLString},
playerRatingSeason: {type:GraphQLFloat},
isIREligible: {type:GraphQLBoolean},
draftRank: {type:GraphQLInt},
universeId: {type:GraphQLInt},
firstName: {type:GraphQLString},
lastName: {type:GraphQLString},
sportsId: {type:GraphQLInt},
healthStatus: {type:GraphQLInt},
percentOwned: {type:GraphQLFloat},
proTeamId: {type:GraphQLInt},
tickerId: {type:GraphQLInt},
isActive: {type:GraphQLBoolean},
playerId: {type:GraphQLInt},
percentChange: {type:GraphQLFloat},
defaultPositionId: {type: GraphQLInt},
totalPoints: {type:GraphQLFloat},
})
});
const CurrentPeriodProjectedStatsType = new GraphQLObjectType({
name: 'CurrentPeriodProjectedStats',
fields:() => ({
appliedProjectedStatTotal: {type:GraphQLFloat}
})
});
const CurrentPeriodRealStatsType = new GraphQLObjectType({
name: 'CurrentPeriodRealStats',
fields:() => ({
appliedRealStatTotal: {type:GraphQLFloat}
})
});
const PlayerSlotType = new GraphQLObjectType({
name: 'PlayerSlot',
fields:() => ({
pvoRank: {type:GraphQLInt},
player: {
type: PlayerType
},
watchList: {type:GraphQLBoolean},
isKeeper: {type:GraphQLBoolean},
isTradeLocked: {type:GraphQLBoolean},
currentPeriodProjectedStats: {
type: CurrentPeriodProjectedStatsType
},
opponentProTeamId: {type:GraphQLInt},
slotCategoryId: {type:GraphQLInt},
lockStatus: {type:GraphQLInt},
isQueuedWaiverLocked: {type:GraphQLBoolean},
currentPeriodRealStats: {
type: CurrentPeriodRealStatsType
}
})
});
const SlotsType = new GraphQLObjectType({
name: 'Slots',
fields:() => ({
player0: {
type: PlayerSlotType
},
player1: {
type: PlayerSlotType
},
player2: {
type: PlayerSlotType
},
player3: {
type: PlayerSlotType
},
player4: {
type: PlayerSlotType
},
player5: {
type: PlayerSlotType
},
player6: {
type: PlayerSlotType
},
player7: {
type: PlayerSlotType
},
player8: {
type: PlayerSlotType
},
player9: {
type: PlayerSlotType
},
player10: {
type: PlayerSlotType
},
player11: {
type: PlayerSlotType
},
player12: {
type: PlayerSlotType
},
player13: {
type: PlayerSlotType
},
player14: {
type: PlayerSlotType
},
player15: {
type: PlayerSlotType
},
})
});
const DivisionType = new GraphQLObjectType({
name: 'Division',
fields:() => ({
divisionName: {type:GraphQLString},
divisionId: {type:GraphQLInt},
size: {type:GraphQLInt}
})
});
const TeamType = new GraphQLObjectType({
name: 'Team',
fields:() => ({
divisionStanding: {type:GraphQLInt},
overallStanding: {type:GraphQLInt},
waiverRank: {type:GraphQLInt},
division: {
type: DivisionType
},
teamAbbrev: {type:GraphQLString},
teamNickname: {type:GraphQLString},
logoUrl: {type:GraphQLString},
teamLocation: {type:GraphQLString},
teamId: {type:GraphQLInt},
logoType: {type:GraphQLString}
})
});
const List0Type = new GraphQLObjectType({
name: 'List0',
fields: () => ({
slots: {
type: SlotsType
},
team: {
type: TeamType
},
teamId: {type: GraphQLInt},
appliedActiveProjectedTotal: {type: GraphQLFloat},
appliedInactiveProjectedTotal: {type: GraphQLFloat},
appliedActiveRealTotal: {type: GraphQLFloat},
appliedInactiveRealTotal: {type: GraphQLFloat},
})
});
const TeamsType = new GraphQLObjectType({
name: 'Teams',
fields: () => ({
list0: {
type: List0Type
},
list1: {
type: List0Type
}
})
});
// need to define each type individually, working from the bottom up and creating types as needed
const BoxscoreType = new GraphQLObjectType({
name: 'Boxscore',
fields: () => ({
teams: {
type: TeamsType,
/*resolve(boxscore){
return boxscore.teams;
}*/
},
scoringPeriodId: {
type: GraphQLInt,
},
matchupPeriodId: {
type: GraphQLInt,
},
homeTeamBonus: {
type: GraphQLInt,
}
})
});
const MetadataType = new GraphQLObjectType({
name: 'metadata',
fields: {
leagueId: {type: GraphQLString},
status: {type: GraphQLString},
dateModifiedLeague: {type: GraphQLString},
seasonId: {type: GraphQLString},
}
});
const BoxscoreDataType = new GraphQLObjectType({
name: 'BoxscoreData',
fields: {
boxscore: {type:BoxscoreType},
metadata: {type:MetadataType},
},
});
const EspnQuery = new GraphQLObjectType({
name: 'EspnQuery',
fields: {
getBoxscore: {
type: BoxscoreDataType,
args: {
leagueId: {
name: 'leagueId',
type: new GraphQLNonNull(GraphQLInt)
},
seasonId: {
name: 'seasonId',
type: new GraphQLNonNull(GraphQLInt)
},
teamId: {
name: 'teamId',
type: new GraphQLNonNull(GraphQLInt)
},
scoringPeriodId: {
name: 'scoringPeriodId',
type: new GraphQLNonNull(GraphQLInt)
},
},
resolve: (obj, {leagueId, seasonId, teamId, scoringPeriodId}) => {
const url = 'http://games.espn.com/ffl/api/v2/boxscore?leagueId=1150587&seasonId=2017&teamId=5&scoringPeriodId=7'
//const url = 'http://games.espn.com/ffl/api/v2/boxscore?leagueId='+ leagueId + '&seasonId=' + seasonId + '&teamId=' + teamId + '&scoringPeriodId=' + scoringPeriodId
//console.log('leagueId is: ' + leagueId + 'seasonId is: '+seasonId+'teamId is: '+teamId+'scoringPeriodId is: '+scoringPeriodId);
return axios(url)
.then(res => res.data);
}
}
},
});
// Keep at the bottom //
module.exports = new GraphQLSchema({
query: EspnQuery
});
And the query I'm running in Graphiql is:
{
getBoxscore(leagueId: 1150587, seasonId: 2017, teamId: 5, scoringPeriodId: 7) {
boxscore{
teams {
list0{
slots{
player0{
player{
firstName
}
}
}
}
}
}
}
}
Which unfortunately is returning:
{
"data": {
"getBoxscore": {
"boxscore": {
"teams": {
"list0": null
}
}
}
}
}
The structure of your schema doesn't match the structure of the data. Where ever there is an array being returned, you should utilize a GraphQLList -- there's no need for the ListType you've added.
For example, if you look at the JSON being returned by the endpoint, teams is an array, not an object. You've created a TeamType that matches the structure of the team data, but we need to tell GraphQL that teams is going to be a List (array) of TeamType objects, not just a single one. So we write:
teams: { type: new GraphQLList(TeamsType) }
Written in GraphQL schema language, that would be [TeamsType]. Most of the fields in TeamsType are objects, or scalars. However, slots is also an array, so for that you would similarly write:
slots: { type: new GraphQLList(SlotsType) }
And so on.

Categories