How to debug Apollo Graphql - debugging

I am getting this error "Variable $id of required type "String!" was not provided"
This is quite a large project and I am using the variable name id at many places. How do I debug apollo graphql in a way that will tell me which query is causing the error?
This is how my apollo client is set up with regards to error debugging:
const errorLink = onError(({ graphQLErrors }) => {
if (graphQLErrors)
graphQLErrors.forEach((v) => {
console.log(
util.inspect(v, { showHidden: false, depth: 3, colorize: true })
);
});
});
const client = new ApolloClient({
connectToDevTools: isBrowser,
ssrMode: !isBrowser,
link: from([errorLink, authLink, httpLink]),
cache
});
This is the error I am getting:
{ message: 'Variable "$id" of required type "String!" was not provided.',
locations: [ { line: 1, column: 37 } ],
extensions:
{ code: 'INTERNAL_SERVER_ERROR',
exception:
{ stacktrace:
[ 'GraphQLError: Variable "$id" of required type "String!" was not provided.',
' at _loop (/app/node_modules/graphql/execution/values.js:92:17)',
' at coerceVariableValues (/app/node_modules/graphql/execution/values.js:119:16)',
' at getVariableValues (/app/node_modules/graphql/execution/values.js:48:19)',
' at buildExecutionContext (/app/node_modules/graphql/execution/execute.js:184:61)',
' at executeImpl (/app/node_modules/graphql/execution/execute.js:89:20)',
' at Object.execute (/app/node_modules/graphql/execution/execute.js:64:35)',
' at /app/node_modules/apollo-server-core/dist/requestPipeline.js:261:48',
' at Generator.next (<anonymous>)',
' at /app/node_modules/apollo-server-core/dist/requestPipeline.js:8:71',
' at new Promise (<anonymous>)',
' at __awaiter (/app/node_modules/apollo-server-core/dist/requestPipeline.js:4:12)',
' at execute (/app/node_modules/apollo-server-core/dist/requestPipeline.js:240:20)',
' at Object.<anonymous> (/app/node_modules/apollo-server-core/dist/requestPipeline.js:177:42)',
' at Generator.next (<anonymous>)',
' at fulfilled (/app/node_modules/apollo-server-core/dist/requestPipeline.js:5:58)',
' at processTicksAndRejections (node:internal/process/task_queues:96:5)' ] } } }
As you can see the error doesn't really give me much to work with, since the variable name is used often. And my project is really large at this point, so trial and error will take forever. Does anybody have any ideas on what I can try?
I am trying to use the apollo browser dev tool, but I am not really getting any interesting data from that one either.

Related

Apollo Client - Simultaneous subscriptions from same component

I'm trying to make 2 simultaneous subscriptions with Apollo Client but the connection get closed and reopened every 2 seconds:
This is my code concerning subscriptions:
//apollo.js
const httpLink = createHttpLink({
includeUnusedVariables: true,
uri:
process.env.API_GRAPHQL ||
// Change to your graphql endpoint.
headers: {
Authorization:
"Bearer TOKEN",
},
});
const wsLink = new GraphQLWsLink(
createClient({
url: process.env.WS_GRAPHQL,
connectionParams: {
Authorization:
"Bearer TOKEN",
},
options: {
reconnect: true,
},
})
);
const link = split(
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === "OperationDefinition" && operation === "subscription";
},
wsLink,
httpLink
);
// subscriber executer
const {
result: locationUpdates,
// loading: loadingLocation,
// error: devicesError,
// refetch: refetchDevices,
onResult: onResultLocations,
} = useSubscription(locationsLivesTrue, () => ({
}));
const { result: me, onResult: onResultMe } = useSubscription(
meUpdates,
() => ({})
);
If I execute only one subscription it works fine.
I also tried to subscribe directly from the client when I provide the app, but got the same result.
#juanmac My original post was deleted so I will answer here. Since you asked me a question there, I think it is fine I will answer inside your newest post ;)
A loop was used. Inside the loop, a subscribeToMore was used.
Inside that function, updateQuery was used.
There were some problems but I do not know if they were resolved. I will remind you, that it was React Native, and there are some stability issues with subscriptions etc.
I hope that helps.

How to handle Apollo Graphql query error in Vue.JS?

I am using Vue.js with Vue-Apollo and trying to fetch shared member list using query. I am using the graphQL service in backend.
I am using apollo 'error' function to handle GraphQL error. When the request is made with invalid input, I can see the errors in the network tab, I can see the JSON for the custom errors messages. But I can't console the errors in 'error' function.
Here is the apollo query that is used to fetch shared member list -
apollo: {
sharedMembers: {
query: gql`
query item($uuid: ID) {
item(uuid: $uuid) {
...itemTemplate
members {
...member
permission
}
}
}
${ITEM_TEMPLATE}
${MEMBER}
`,
variables() {
return {
uuid: this.$route.params.uuid,
}
},
update(data) {
return data.item.members
},
error(error) {
console.log('errors', error)
}
},
},
The network response I got -
network_error
Using graphQLErrors
You could get the errors by looking in the error object for graphQLErrors:
error(error) {
console.log('errors', error.graphQLErrors)
}
or
error({ graphQlErrors }) {
console.log('errors', graphQLErrors)
}
Using apollo-error-link
You can use apollo-error-link to help solve your problem if the above doesn't work, docs here.
Here's an example from the docs and I added to it in the networkErrors section to show what you can do to edit the error message you see in your error block, or catch block if its a mutation.
import { onError } from "apollo-link-error";
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) {
// Add something like this to set the error message to the one from the server response
networkError.message = networkError.result.errors[0].debugMessage
console.log(`[Network error]: ${networkError}`)
};
});
And then in your code:
error(error) {
console.log('error-message', error.message)
}
The console should then log your debugMessage from the server.
unfortunately i couldn't find out how i'd handle errors in such of graphql method call, but as an option you could provide onError method to ApolloClient constructor options. first argument is the error object. hopefully it may help. like so..
const apolloClient = new ApolloClient({
uri: 'http://localhost:4000',
onError(err) {
console.log(err)
},
})

Converting working Ajax call to Angular Observable

I have an existing JavaScript application that submits documents (.pdf, .txt...) to Solr for text extraction. I am now trying to convert that capability to an Angular-6 implementation and am struggling with the whole observable pattern. Below is the working js code, followed by my angular component and service .ts files. I think I'm close, but no cigar.
let myReader = new FileReader();
myReader.onloadend = function() {
fileAsBlob = myReader.result;
sendToSolr(fileAsBlob);
};
fileAsBlob = myReader.readAsArrayBuffer(file);
/* Get the unique Id for the doc and append to the extract url*/
let docId = $("#post_docId").val();
let extractUrl = "http://localhost:8983/solr/" + core + "/update/extract/?commit=true&literal.id=" + docId;
/* Ajax call to Solr/Tika to extract text from pdf and index it */
function sendToSolr(fileAsBlob) {
$.ajax({
url: extractUrl,
type: 'POST',
data: fileAsBlob,
cache: false,
jsonp: 'json.wrf',
processData: false,
contentType: false,
echoParams: "all",
success: function(data, status) {
//console.log("Ajax.post successful, status: " + data.responseHeader.status + "\t status text: " + status);
//console.log("debug");
getDocument(docId);
},
error: function(data, status) {
//console.log("Ajax.post error, status: " + data.status + "\t status text:" + data.statusText);
},
done: function(data, status) {
//console.log("Ajax.post Done");
},
});
}
All the above does is use a fileReader to read a local file into an ArrayBuffer, and submits that ArrayBuffer to Solr via an Ajax call. In my success I do call another function (getDocument) which just queries Solr (By docId) for the document I just submitted and displays it. Not beautiful, but it works.
For the angular version I have the following service:
constructor(private http: HttpClient) { }
postDocToSolr(fileAsBlob: any): Observable<any> {
let httpHeaders = new HttpHeaders()
.set('type' , 'POST')
.set('jsonp', 'json.wrf')
.set('processData', 'false')
.set('echoParams', 'all')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('charset', 'utf-8')
.set('data', fileAsBlob);
let options = {
headers: httpHeaders
};
return this.http.post(this.extractUrl, fileAsBlob, options);
}
}
I tried posting the entire service, but it threw the formatting off so here is the POST part of the service.
And in my component I call the service:
extractText(fileContents: any) {
console.log("In the Document.extractText() method");
//this.processDocument(fileContents);
this.textExtractor.postDocToSolr(fileContents)
.subscribe(data => {
console.log("Debug");
console.log("Data: ") + data;
},
error => {
console.log("Error" + error);
}
);
console.log("Debug");
}
Note I've done the fileReader already and am submitting basically the same ArrayBuffer.
The only hint is the in the error => log the error callback(Right term?)on the observable. I get an error code 400, bad request with the message:
"msg":"URLDecoder: Invalid digit (P) in escape (%) pattern"
Which doen't help me much. I'm wondering if it's an encoding issue (UTF-8) but not sure where to begin. Would appreciate a nudge in the right direction.
It looks like the problem is how angular is encoding your URI, I would open your network tool of choice (network tab, fiddler, etc) and look at the sent request URI of each. I suspect they'll be different.
Well, it's often the small things that trip me up. I needed to set the Content-Type to "false" and everything works fine. I also re-did the creation of the httpHeaders, but I think either way would have worked. The working postToSolr Service method is:
export class TextExtractorServiceService {
extractUrl: string = "http://localhost:8983/solr/tater/update/extract/?commit=true&literal.id=778";
constructor(private http: HttpClient) { }
postDocToSolr(fileAsBlob: any): Observable<any> {
const httpOptions = {
headers: new HttpHeaders({
"jsonp": "json.wrf",
"processData": "false",
"echoParams" : "all",
"Content-Type": "false",
"cache": "false"
})
};
return this.http.post(this.extractUrl, fileAsBlob, httpOptions);
}
}
Thanks to all who took a look.

How can I catch RelayObervable Unhandled error when graphql errors are returned?

My backend is returning the following response:
const errorMessage = {
errors: [
{
message: 'User is logged out',
},
],
data: null,
};
return res.status(200).json(errorMessage);
My react-native app using relay is returning the following error:
RelayObservable: Unhandled Error Error:
Relay request for `HomeQuery` failed by the following reasons:
This error shows up when I try to query the backend and it returns the above 'errorMessage' graphql errors array. I have no way of catching this error in my relay network layer BEFORE it throws the redscreen. My Relay Environment looks like this:
const network = new RelayNetworkLayer([
urlMiddleware({
url: () => Promise.resolve(`${config.endpoint}backend`),
headers: async () => authenticateHeaders(fetchHeaders),
}),
retryMiddleware({ fetchTimeout: 1000 }),
next => req => {
if (!req.uploadbles) {
req.Accept = 'application/json';
req['Content-Type'] = 'application/json';
}
return next(req);
},
next => async req => {
const res = await next(req);
if (isLoggedOut(res)) {
// Using react-navigation, route to the login screen
dispatch(routeToLogin())
// I also tried returning `dispatch(routeToLogin())` and `{ data: null, errors: res.payload.errors }` without luck
}
return res;
}
]);
Is there a way I can navigate using dispatch(routeToLogin()) without seeing the redscreen error when graphql errors are returned?
Edit 1
For react-relay-network-modern: You can add the noThrow option like so: new RelayNetworkLayer(middlewares, { noThrow: true });
The noThrow option doesn't exist for react-relay-network-layer (relay classic), is there anything I can do to work around it?
Please try noThrow option:
const network = new RelayNetworkLayer(middlewares, { noThrow: true });

.post Node.js/Express/Mongoose call, not saving posts (.save) after the first post.. Further updated, Closures Issue?

With AJAX/Node.js/Express/Mongoose/MongoDB, the data is being delivered successfully over ajax to node.js and is logging properly, but only the first post is being saved in MongoDB..
Sending posts after the first post still logs all the new data, but the console gets held on an empty line (the cursor just stands still)..after the 'post success!' console.log, which follows the .save call, but the db doesn't receive that new data!?
Only after refreshing the webpage, or saving the file (nodemon auto-starts thereafter), does a new post save.
Here's the console log (the '|' on the last line represents the hanging cursor..):
Server is starting
posting a new Message..from: 53aada6f8b10eb0000ec8a90
[ 'username1' ]
element: username1
To: username1
Message: testTwo
Created: Tue Jul 01 2014 15:53:57 GMT-0400 (EDT)
post success!
|
And here's the Node.js/Express/Mongoose .post & .save:
router.route('/messages')
// create a message (accessed by POST # http://localhost:4200/api/v1/messages)
.post(function(req, res) {
console.log('posting a new Message..from: ' + req.session.user );
var message = new Models.Message();
var toWhom = req.body.to;
console.log(toWhom); // [ 'user1', 'user2' ]
toWhom.forEach(toWhomLoop);
function toWhomLoop(element, index, array) {
console.log('element: ' + element); // 'user1'
message.to.push({
user : user,
username : element,
read :
{
marked : false,
datetime : null
},
updated : req.body.nowDatetime
}); // push: to MessageUserSchema [array]
}
message.from.push({
user : req.session.user,
username : req.session.username,
updated : req.body.nowDatetime
}); // push: from MessageUserSchema [array]
message.message = req.body.message;
message.created = req.body.nowDatetime;
console.log('To: ' + req.body.to);
console.log('Message: ' + req.body.message);
console.log('Created: ' + req.body.nowDatetime);
// save the message, and check for errors
message.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Message "' + message.message + '" Created' });
});
console.log('post success!');
})
Upon a further look, and with sublime highlighting the closures.. the .post(function(req, res) { closures ({ }) don't highlight on either side (start or end), except when the following elements are cut from the .post:
message.from.push({
user : req.session.user,
username : req.session.username,
updated : req.body.nowDatetime
}); // push: from MessageUserSchema [array]
message.message = req.body.message;
message.created = req.body.nowDatetime;
console.log('To: ' + req.body.to);
console.log('Message: ' + req.body.message);
console.log('Created: ' + req.body.nowDatetime);
Only when all the above is commented/cut from the .post the closures highlight.. Is there a syntax issue?
Try changing the save() function to:
// save the message, and check for errors
message.save(function(err, result) {
if (err) {
console.log(err);
res.send(err);
}
console.log("The result: ", result);
res.json({ message: 'Message "' + message.message + '" Created' });
});

Resources