Graphql doesn't return the data - javascript

I'm trying to find a specific data based on the id in graphql.
But it is returning null .
I have also tried the mutation. Here is also it is returning null.
What's wrong with this below code.
const { ApolloServer } = require("#apollo/server");
const { startStandaloneServer } = require("#apollo/server/standalone");
const students = [
{
name: "langesh",
roll: 131,
},
{
name: "ram",
roll: 134,
},
];
const typeDefs = `#graphql
type Student {
name: String,
roll: Int,
}
type Query {
students: [Student]
student(roll: Int) : Student
}
`;
const resolvers = {
Query: {
students: () => students,
student: (parent, roll) => {
return students.find((s) => s.roll === roll);
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
async function startServer() {
const { url } = await startStandaloneServer(server, {
listen: {
port: 8000,
},
});
console.log(`url : ${url}`);
}
startServer();

You need to destructure the args in your resolver.
Instead of:
student: (parent, roll) => {
return students.find((s) => s.roll === roll);
}
do:
student: (parent, { roll }) => {
return students.find((s) => s.roll === roll);
}

Related

Call GraphQL mutation from another mutation

I have a GraphQL mutation that adds a book. I want to check if the author given exists yet and if not, add that author with a different mutation. Is this possible?
Mutation: {
addAuthor: (root, args) => {
const author = { ...args, id: uuid() }
authors = authors.concat(author)
return author
},
addBook: (root, args) => {
const existingAuthor = authors.filter(author => author.name === args.author).length > 0
if (!existingAuthor) {
addAuthor({ name: args.author }) /// This is how I want to call a mutation within my mutation
}
const book = { ...args, id: uuid() }
books = books.concat(book)
return book
}
}
Right now, this approach throws an error from the Apollo Studio Explorer:
"path": [
"addBook"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"ReferenceError: addAuthor is not defined"
Factor out your addAuthor function and use it in both places:
Mutation: {
addAuthor: _addAuthor,
addBook: (_, args) => {
const existingAuthor = authors.findIndex((a) => a.name === args.author) > -1;
if (!existingAuthor) _addAuthor(null,{ name: args.author });
const book = { ...args, id: uuid() }
books = books.concat(book)
return book
}
}
const _addAuthor = (_, args) => {
const author = { ...args, id: uuid() }
authors = authors.concat(author)
return author
}

[Error: Query.Mutation defined in resolvers, but not in schema]

const { ApolloServer, gql } = require('apollo-server-express');
const express = require('express');
const port = process.env.PORT || 4000;
const notes = [
{ id: '1', content: 'This is a note', author: 'Adam Scott' },
{ id: '2', content: 'This is another note', author: 'Harlow Everly' },
{ id: '3', content: 'Oh hey look, another note!', author: 'Riley Harrison' }
];
const typeDefs = gql `
type Note {
id: ID
content: String
author: String
}
type Query {
hello: String
notes: [Note]
note(id: ID!): Note
}
type Mutation {
newNote(content: String!): Note
}
`;
const resolvers = {
Query:{
hello: () => 'Hello World',
notes: () => notes,
note: (parent, args) => {
return notes.find(note => note.id == args.id);
},
Mutation: {
newNote: (parent, args) => {
let noteValue = {
id : String(notes.length + 1),
content : args.content,
author: 'Adam Scott',
};
notes.push(noteValue);
return noteValue;
}
}
},
}
Some people had naming issues but seems that I'm using the same in resolver as well as in schema.
Please bare with me, this is my second day in GraphQL and Express. I removed intentionally imports and assignment of express object, middleware since it does not let me post.
I think you are simply missing a curly bracket.
const resolvers = {
Query:{
hello: () => 'Hello World',
notes: () => notes,
note: (parent, args) => {
return notes.find(note => note.id == args.id);
}
}, <==== THIS IS MISSING =====>
Mutation: {
newNote: (parent, args) => {
let noteValue = {
id : String(notes.length + 1),
content : args.content,
author: 'Adam Scott',
};
notes.push(noteValue);
return noteValue;
}
}

Trying return an array built from a foreach loop of a returned mysql query [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
Trying to build a more complex return of a MySQL query but the return doesn't wait for the forEach loop to complete.
export const Query = (query: string, values?: Array<string | number>) => {
return new Promise<Array<any>>((resolve, reject) => {
pool.query(query, values, (err, results) => {
if(err) reject(err);
return resolve(results);
});
});
};
const getUsersChats = async(userid: number) => {
let chats = await Query('SELECT * FROM users_chats u JOIN direct_chats d ON d.id = u.chatid WHERE u.userid = ?', [userid]);
//console.log(chats);
let buildReturn: any = [];
const build = async() => {
chats.forEach(async(chat) => {
let buildInnerObject = {};
let lastMsg = await Query('SELECT * FROM messages WHERE chatid = ? ORDER BY created DESC LIMIT 1', [chat.id]);
buildInnerObject = {...chat, lastMSG: lastMsg}
buildReturn.push(buildInnerObject);
});
}
await build();
console.log(buildReturn)
return buildReturn;
}
I'm looking for a return of something like:
{
id: 12,
userid: 28,
chatid: 12,
created: 2021-01-05T23:14:03.000Z,
userid_1: 28,
userid_2: 31,
title: 'Title',
lastMSG: [ [RowDataPacket] ]
},
{
id: 13,
userid: 28,
chatid: 13,
created: 2021-01-05T23:18:40.000Z,
userid_1: 28,
userid_2: 33,
title: 'Title'
lastMSG: []
}
]
but right now my return is []
You are not calling the build function to get the values.
If you do not await the query for messages, you will not be able to returns it from your function.
You should type properly your data so it's easier to use and to spot errors
Look at the following and ask me questions if there is any point of interrogation
playground
function Query<T>(_query: string, _values?: Array<string | number>): Promise<T[]> {
return new Promise((resolve) => {
setTimeout(() => {
resolve([{
id: 'foo',
}] as unknown as T[]);
}, 50);
});
};
interface Chat {
id: string;
}
interface Messages {
example: string;
}
type MyExtendedChat = Chat & {
lastMSG: Messages[];
};
const getUsersChats = async(userid: number): Promise<MyExtendedChat[]> => {
const chats: Chat[] = await Query<Chat>(
'SELECT * FROM users_chats ...',
[
userid,
],
);
const buildReturn: MyExtendedChat[] = await Promise.all(chats.map(async(chat) => {
const lastMsg: Messages[] = await Query<Messages>(
'SELECT * FROM messages ...',
[
chat.id,
],
);
return {
...chat,
lastMSG: lastMsg,
};
}));
console.log(buildReturn);
return buildReturn;
}
(async() => {
await getUsersChats(42);
})();

Function work incorrectly when using promise in node js

I have routes like that:
router.get('/:projectid/, (req, res) => {
testCase.getTestCaseDetail(req.params.projectid, req.params.testcaseid, req.params.snapshotId).then(testcaseData => {
res.render('testCaseService', {
title: 'Page',
testcase: testcaseData,
layout: 'project_layout',
});
});
});
In the handler function, I have getTestCaseDetail function:
function getTestCaseDetail(projectId, id, snapshotId) {
let testCaseId = parseInt(id);
return new Promise(((resolve, reject) => {
return testCaseSchema.aggregate([
{ $match: { 'projectId': projectId, 'testCaseId': testCaseId } },
{
$lookup: {
from: snapshotInfoSchema.collection.collectionName,
localField: testCaseObj.SERVICE_ID,
foreignField: 'artifacts.id',
as: 'services',
},
},
{ $unwind: '$services' },
{
$match: {
'services.snapshot.id': snapshotId,
}
}
]).then(testCaseResult => {
resolve(addTestCasesV2(testCaseResult, snapshotId));
})
.catch(err => {
reject(err);
})
}));
}
and addTestCasesV2 function
const addTestCasesV2 = function (testcases, snapshotId) {
const result = [];
let serviceTypeMapping;
let serviceName;
let testCase = {
id: '',
testCaseId: '',
name: '',
serviceName: '',
serviceType: '',
modifiedAt: '',
testScripts: '',
snapshotId: '',
services: '',
inputs: [],
outputs: [],
};
let promiseInputResults, promiseOutputResults;
const testcasesList = lodash.map(testcases, (tc) => {
const artifacts = lodash.map(tc.services.artifacts, (art) => {
if (art.id === tc.service_id) {
serviceTypeMapping = art.processType.serviceTypeName;
serviceName = art.name;
if (!commonUtil.isUndefined(art.processParameters)) {
if (!commonUtil.isUndefined(art.processParameters.input)) {
promiseInputResults = lodash.map(art.processParameters.input, (ip) => {
let classId = commonUtil.getArtifactId(ip.classId);
return objectType.getObjectTypeByClassId(snapshotId, classId)
});
}
if (!commonUtil.isUndefined(art.processParameters.output)) {
promiseOutputResults = lodash.map(art.processParameters.output, (ip) => {
let classId = commonUtil.getArtifactId(ip.classId);
return objectType.getObjectTypeByClassId(snapshotId, classId)
});
}
}
testCase.id = tc.testCaseId;
testCase.testCaseId = tc.testCaseId;
testCase.name = tc.name;
testCase.serviceName = serviceName;
testCase.serviceType = serviceTypeMapping;
testCase.modifiedAt = tc.modifiedAt;
testCase.testScripts = tc.testScripts;
testCase.snapshotId = snapshotId;
testCase.services = tc.services;
Promise.all(promiseInputResults).then(inputItems => {
return testCase.inputs = inputItems;
});
Promise.all(promiseOutputResults).then(outputItems => {
return testCase.outputs = outputItems;
});
}
});
});
return testCase;
};
The inputs/outputs is an list of item, like that:
inputs:[
{
name: "test1",
type: "String"
},
{
name: "test2",
type: "number"
},
]
I have a problem with promise lifecycle, this is the current flow
1. Routes
2. function getTestCaseDetail
3. resolve(addTestCasesV2(testCaseResult, snapshotId));
4. addTestCasesV2 ==> return testCase but without go to 2 promise.all functions
5. resolve(addTestCasesV2(testCaseResult, snapshotId));
6. Routes
7. go back 2 promise.all functions
8. end at return testCase.outputs = outputItems;
Please see the image to more detail flow (the white number is current flow, the orange number is my expect flow)
Please advice me. Many thanks.
Your code doesn't seem correct. If testcases is an array with more than one item, your lodash.map callback will be called testcases.length time. Each time overwriting testCase.id assigned in previous callback.
Anyways, I have corrected bits of your code to make it in run order that you wanted. I have logged ==step== at various places for your help.
First Function:
function getTestCaseDetail(projectId, id, snapshotId) {
let testCaseId = parseInt(id);
return new Promise(((resolve, reject) => {
return testCaseSchema.aggregate([
{ $match: { 'projectId': projectId, 'testCaseId': testCaseId } },
{
$lookup: {
from: snapshotInfoSchema.collection.collectionName,
localField: testCaseObj.SERVICE_ID,
foreignField: 'artifacts.id',
as: 'services',
},
},
{ $unwind: '$services' },
{
$match: {
'services.snapshot.id': snapshotId,
}
}
]).then(testCaseResult => {
console.log('=======STEP 1=======');
resolve(addTestCasesV2(testCaseResult, snapshotId));//=======STEP 2=======
console.log('=======STEP 5=======')
})
.catch(err => {
reject(err);
})
}));
}
Second function
const addTestCasesV2 = function (testcases, snapshotId) {
console.log('=======STEP 2=======')
const result = [];
let serviceTypeMapping;
let serviceName;
let testCase = {
id: '',
testCaseId: '',
name: '',
serviceName: '',
serviceType: '',
modifiedAt: '',
testScripts: '',
snapshotId: '',
services: '',
inputs: [],
outputs: [],
};
let promiseInputResults, promiseOutputResults;
return Promise.resolve()
.then(()=>{
console.log('=======STEP 3=======');
const testcasesList = lodash.map(testcases, (tc) => {
const artifacts = lodash.map(tc.services.artifacts, (art) => {
if (art.id === tc.service_id) {
serviceTypeMapping = art.processType.serviceTypeName;
serviceName = art.name;
if (!commonUtil.isUndefined(art.processParameters)) {
if (!commonUtil.isUndefined(art.processParameters.input)) {
promiseInputResults = lodash.map(art.processParameters.input, (ip) => {
let classId = commonUtil.getArtifactId(ip.classId);
return objectType.getObjectTypeByClassId(snapshotId, classId)
});
}
if (!commonUtil.isUndefined(art.processParameters.output)) {
promiseOutputResults = lodash.map(art.processParameters.output, (ip) => {
let classId = commonUtil.getArtifactId(ip.classId);
return objectType.getObjectTypeByClassId(snapshotId, classId)
});
}
}
testCase.id = tc.testCaseId;
testCase.testCaseId = tc.testCaseId;
testCase.name = tc.name;
testCase.serviceName = serviceName;
testCase.serviceType = serviceTypeMapping;
testCase.modifiedAt = tc.modifiedAt;
testCase.testScripts = tc.testScripts;
testCase.snapshotId = snapshotId;
testCase.services = tc.services;
/*=======FOLLOWING IS NOT REQUIRED=======*/
// Promise.all([promiseOutputResults]).then(outputItems => {
// return testCase.outputs = outputItems;
// });
}
});
});
return Promise.all([promiseInputResults,promiseOutputResults]);
})
.then(inputItems => {//array of resolved values
console.log('=======STEP 4=======');
testCase.inputs = inputItems[0];
testCase.outputs = inputItems[1];
return testCase;
})
};
Now you can use following to extract testcase from first function:
getTestCaseDetail(myProjectId, id, mySnapshotId)
.then(testCase=>console.log(testCase))
JSfiddle for your understanding.

GraphQL subscriptions

I'm having a hard time with GraphQL today. Probably encountered every single error possible.
I want to be able to subscribe to websockets in my component so I wrote some code to do this. Subscription works fine and it seems like it work, but the problem I have is how to get the updated values that come from the subscription inside my component?.
const FIELD_QUE = gql`
query fieldChanged($fieldName: String!, $projectId: Int!) {
fieldChanged(fieldName: $fieldName, projectId: $projectId) {
usersEmail
value
projectId
}
}
`;
const FIELD_MUT = gql`
mutation ChangeFieldMutation($fieldName: String!, $projectId: Int!, $value: String!, $usersEmail: String!) {
changeField(fieldName: $fieldName, projectId: $projectId, value: $value, usersEmail: $usersEmail) {
projectId
value
usersEmail
}
}
`;
const withMutation = graphql(FIELD_MUT, {
props: ({ ownProps, mutate }) => ({
changeField: ({ fieldName, value, projectId, usersEmail }) => {
mutate({
variables: { fieldName, value, projectId, usersEmail },
});
},
}),
});
const FIELD_SUB = gql`
subscription onFieldChanged($projectId: Int!){
fieldChanged(projectId: $projectId){
projectId
value
usersEmail
}
}
`;
const withSubscription = graphql(FIELD_QUE, {
name: 'fieldChanged',
options: () => ({
variables: {
projectId: 1,
fieldName: 'description',
},
}),
props: props => ({
subscribeToFieldChange: (params) => {
return props.fieldChanged.subscribeToMore({
document: FIELD_SUB,
variables: {
projectId: params.projectId,
fieldName: params.fieldName,
},
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
const newValue = subscriptionData.data;
const result = { ...prev, ...newValue };
return result;
},
});
},
}),
});
All I get is this:

Categories