Apollo-Server display errors in a clean mannor - javascript

I'm pretty sure that the question is self explanatory.
I'm using 'apollo-server-core' 3.6.5
Errors I want to get
{
"errors": [
{
"message": "Syntax Error: Unexpected <EOF>.",
"locations": [
{
"line": 1,
"column": 1
}
]
}
]
}
Errors I do get
{
"errors": [
{
"message": "GraphQL operations must contain a non-empty `query` or a `persistedQuery` extension.",
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"GraphQLError: GraphQL operations must contain a non-empty `query` or a `persistedQuery` extension.",
" at processGraphQLRequest (C:\\Users\\XXXX\\Documents\\Github\\XXXX-XXX\\node_modules\\apollo-server-core\\src\\requestPipeline.ts:204:7)",
" at processTicksAndRejections (node:internal/process/task_queues:96:5)",
" at async processHTTPRequest (C:\\Users\\XXXX\\Documents\\Github\\XXXX-XXXX\\node_modules\\apollo-server-core\\src\\runHttpQuery.ts:346:24)"
]
}
}
}
]
}
My initial thought was parse the error into an object, and map out any undesirables like so
const msg = JSON.parse(error.message).errors.map((err:any) => err = {message: err.message});
But that dose not work as it dose not tell you where the mistake occurred + it seems unnecessary to use JSON.parse and then stringify'ing it right back.

The apollo docs cover error handling.
https://www.apollographql.com/docs/apollo-server/data/errors/#throwing-errors
You can create a custom error like this:
import { ApolloError } from 'apollo-server-errors';
throw new ApolloError('My error message', 'MY_ERROR_CODE', myCustomExtensions);

Related

How to make custom response using globalPipse in nestjs

I wrote an api in user.controller using dto of 'class-validator'.
#Post('/')
public async createUser(
#Res() res,
#Body() createUserDto: CreateUserDto,
) {
... do something
}
And I put useGlobalPipes in main.ts.
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
transformOptions: {
enableImplicitConversion: true,
},
}),
);
When I request to the api, I get a response below.
{
"statusCode": 400,
"message": [
"userName should not be empty",
"userName must be a string",
],
"error": "Bad Request"
}
So far, it works without problem with nestjs.
But I want to get a custom response like this.
{
"code": 400,
"errorReason": [
"userName should not be empty",
"userName must be a string",
],
"msg": "Bad Request",
"success": false
}
Can I get this custom response maintaining the code above?
If it can do it, could you give me some advice or some code for this?
Thank you for reading my question.
In Nest, pipes are good for validation, transforming an incoming object, maybe talking to a database in some circumstances, and throwing errors if anything goes wrong. If you want to change the response, after an error is thrown, you'll need to look into using an ExceptionFilter Where you can do something like
#Catch()
export class CatchAllFilter implements ExceptionFilter {
catch(exception: Error, host: ArgumentHost) {
res
.status((exception.getStatus && exception.getStatus()) || 500)
.send({
(exception.getResponse && ...exception.getResponse()) || ...{ message: exception.message },
success: false
});
}
}
You're bound to get type errors with the above code, but it should lead you on the right track

Dialogflow Fulfilment webhook call failed

I am new to dialogflow fulfillment and I am trying to retrieve news from news API based on user questions. I followed documentation provided by news API, but I am not able to catch any responses from the search results, when I run the function in console it is not errors. I changed the code and it looks like now it is reaching to the newsapi endpoint but it is not fetching any results. I am utilizing https://newsapi.org/docs/client-libraries/node-js to make a request to search everything about the topic. when I diagnoise the function it says " Webhook call failed. Error: UNAVAILABLE. "
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const http = require('http');
const host = 'newsapi.org';
const NewsAPI = require('newsapi');
const newsapi = new NewsAPI('63756dc5caca424fb3d0343406295021');
process.env.DEBUG = 'dialogflow:debug';
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((req, res) =>
{
// Get the city
let search = req.body.queryResult.parameters['search'];// search is a required param
// Call the weather API
callNewsApi(search).then((response) => {
res.json({ 'fulfillmentText': response }); // Return the results of the news API to Dialogflow
}).catch((xx) => {
console.error(xx);
res.json({ 'fulfillmentText': `I don't know the news but I hope it's good!` });
});
});
function callNewsApi(search)
{
console.log(search);
newsapi.v2.everything
(
{
q: 'search',
langauge: 'en',
sortBy: 'relevancy',
source: 'cbc-news',
domains: 'cbc.ca',
from: '2019-12-31',
to: '2020-12-12',
page: 2
}
).then (response => {console.log(response);
{
let articles = response['data']['articles'][0];
// Create response
let responce = `Current news in the $search with following title is ${articles['titile']} which says that
${articles['description']}`;
// Resolve the promise with the output text
console.log(output);
}
});
}
Also here is RAW API response
{
"responseId": "a871b8d2-16f2-4873-a5d1-b907a07adb9a-b4ef8d5f",
"queryResult": {
"queryText": "what is the latest news about toronto",
"parameters": {
"search": [
"toronto"
]
},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"intent": {
"name": "projects/misty-ktsarh/agent/intents/b52c5774-e5b7-494a-8f4c-f783ebae558b",
"displayName": "misty.news"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 543
},
"languageCode": "en"
},
"webhookStatus": {
"code": 14,
"message": "Webhook call failed. Error: UNAVAILABLE."
},
"outputAudio": "UklGRlQqAABXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAAZGF0YTAqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... (The content is truncated. Click `COPY` for the original JSON.)",
"outputAudioConfig": {
"audioEncoding": "OUTPUT_AUDIO_ENCODING_LINEAR_16",
"synthesizeSpeechConfig": {
"speakingRate": 1,
"voice": {}
}
}
}
And Here is fulfillment request:
{
"responseId": "a871b8d2-16f2-4873-a5d1-b907a07adb9a-b4ef8d5f",
"queryResult": {
"queryText": "what is the latest news about toronto",
"parameters": {
"search": [
"toronto"
]
},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"intent": {
"name": "projects/misty-ktsarh/agent/intents/b52c5774-e5b7-494a-8f4c-f783ebae558b",
"displayName": "misty.news"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 543
},
"languageCode": "en"
},
"webhookStatus": {
"code": 14,
"message": "Webhook call failed. Error: UNAVAILABLE."
},
"outputAudio": "UklGRlQqAABXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAAZGF0YTAqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... (The content is truncated. Click `COPY` for the original JSON.)",
"outputAudioConfig": {
"audioEncoding": "OUTPUT_AUDIO_ENCODING_LINEAR_16",
"synthesizeSpeechConfig": {
"speakingRate": 1,
"voice": {}
}
}
}
Also here is the screenshot from the firebase console.
Can anyone guide me what is that I am missing in here?
The key is the first three lines in the error message:
Function failed on loading user code. Error message: Code in file index.js can't be loaded.
Did you list all required modules in the package.json dependencies?
Detailed stack trace: Error: Cannot find module 'newsapi'
It is saying that the newsapi module couldn't be loaded and that the most likely cause of this is that you didn't list this as a dependency in your package.json file.
If you are using the Dialogflow Inline Editor, you need to select the package.json tab and add a line in the dependencies section.
Update
It isn't clear exactly when/where you're getting the "UNAVAILABLE" error, but one likely cause if you're using Dialogflow's Inline Editor is that it is using the Firebase "Spark" pricing plan, which has limitations on network calls outside Google's network.
You can upgrade to the Blaze plan, which does require a credit card on file, but does include the Spark plan's free tier, so you shouldn't incur any costs during light usage. This will allow for network calls.
Update based on TypeError: Cannot read property '0' of undefined
This indicates that either a property (or possibly an index of a property) is trying to reference against something that is undefined.
It isn't clear which line, exactly, this may be, but these lines all are suspicious:
let response = JSON.parse(body);
let source = response['data']['source'][0];
let id = response['data']['id'][0];
let name = response['data']['name'][0];
let author = response['author'][0];
let title = response['title'][0];
let description = response['description'][0];
since they are all referencing a property. I would check to see exactly what comes back and gets stored in response. For example, could it be that there is no "data" or "author" field in what is sent back?
Looking at https://newsapi.org/docs/endpoints/everything, it looks like none of these are fields, but that there is an articles property sent back which contains an array of articles. You may wish to index off that and get the attributes you want.
Update
It looks like that, although you are loading the parameter into a variable with this line
// Get the city and date from the request
let search = req.body.queryResult.parameters['search'];// city is a required param
You don't actually use the search variable anywhere. Instead, you seem to be passing a literal string "search" to your function with this line
callNewsApi('search').then((output) => {
which does a search for the word "search", I guess.
You indicated that "it goes to the catch portion", which indicates that something went wrong in the call. You don't show any logging in the catch portion, and it may be useful to log the exception that is thrown, so you know why it is going to the catch portion. Something like
}).catch((xx) => {
console.error(xx);
res.json({ 'fulfillmentText': `I don't know the news but I hope it's good!` });
});
is normal, but since it looks like you're logging it in the .on('error') portion, showing that error might be useful.
The name of the intent and the variable I was using to make the call had a difference in Casing, I guess calls are case sensitive just be aware of that

Assistance needed with JSON

I'm creating a JSON file to hold information for commands.
The JSON file holds the trigger and repsonse for the commands, I have one in the file, but I want to add more, but when I do I get an error
{
"trigger": "twitter",
"repsonse": "https://www.twitter.com/Fhaelin"
}
{
"trigger": "test",
"repsonse": "This is a test command"
}
I get thrown errors and i dont know why
Here's the code I'm using to read it:
bot.on("message", function(message) {
var input = message.content.toLowerCase();
if (input === prefix + Commands.trigger)
{
bot.sendMessage(message, message.author + " : " + Commands.repsonse)
}
})
Whole code
http://hastebin.com/punabobisu.coffee
You get errors because that's an invalid JSON document. There can only be one top-level value in a JSON document.
To have a list of objects, put them in an array: [..., ...]:
[
{
"trigger": "twitter",
"response": "https://www.twitter.com/Fhaelin"
},
{
"trigger": "test",
"response": "This is a test command"
}
]
Side note: You have a consistent misspelling in your question: It's "response", not "repsonse". Only mentioning it because it'll come back to bite you at some stage if you actually put it in your code.

Production-quality error handling in node.js

I'm working on request error handling in a node.js server application. I have defined a callback function handling these errors:
app.use(function errorHandler(err, req, res, next) {
res.send(err, {status: err, message: 'error'});
}
);
which is fine for me as a developer, as it prints a stack trace like this:
{
"status": {
"stack": "Error\\\n at MongooseError.ValidationError (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/error/validation.js:22:16)\\\n at model.Document.invalidate (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/document.js:1216:32)\\\n at /home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/document.js:1090:18\\\n at validate (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:653:7)\\\n at /home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:681:9\\\n at Array.forEach (native)\\\n at SchemaString.SchemaType.doValidate (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:658:19)\\\n at /home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/document.js:1088:11\\\n at process._tickCallback (node.js:415:13)",
"message": "User validation failed",
"name": "ValidationError",
"errors": {
"email": {
"properties": {
"regexp": {},
"type": "regexp",
"message": "Path `{PATH}` is invalid ({VALUE}).",
"path": "email",
"value": "test#exa#mple.com"
},
"stack": "Error\\\n at MongooseError.ValidatorError (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/error/validator.js:25:16)\\\n at validate (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:652:13)\\\n at /home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:681:9\\\n at Array.forEach (native)\\\n at SchemaString.SchemaType.doValidate (/home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/schematype.js:658:19)\\\n at /home/osboxes/skipodium_rest_server/node_modules/mongoose/lib/document.js:1088:11\\\n at process._tickCallback (node.js:415:13)",
"message": "Path `email` is invalid (test#exa#mple.com).",
"name": "ValidatorError",
"kind": "regexp",
"path": "email",
"value": "test#exa#mple.com"
}
}
},
"message": "error"
}
However, I'd like to display it in a neat, user-friendly format for the production version, without leaking the entire stack trace. Now I could specify the error status and message in every request handling function, but there is still specific information, like above, that the entered email is invalid, and I don't feel like typing it by hand for every single field that is checked by validator. Is there any existing boilerplate that will do the job for me?
Mongoose validation errors are a pain to handle. My general approach is to only take the first error (let the user deal with one at a time) and send the path and message since the rest won't really contribute much additional meaning to a non-developer.
first = err.errors[Object.keys(err.errors)[0]]
res.send({
path: first.path,
message: first.message
});
I'd also recommend having a custom API-style error format that you stick with for all of your errors- it will make maintainability much easier.
I have a set of pre-defined error templates that I rely on- here's one.
// If the client missed a required parameter
exports.missingParam = function (res, domain, param) {
res.status(400).send({
status: "failed",
errors: [
{
status: "400",
domain: domain,
reason: "required",
message: "Required parameter: "+param,
locationType: "parameter",
location: param
}
]
});
}

Error every time I run datastore.runQuery: one of fields Query.query and Query.gql_query must be set

I'm trying to run a simple query against my Google Cloud datastore using google-api-nodejs-client. I want to query for all entities matching a given kind. When I run this query using the "Try it now" tool it works fine:
Request
POST https://www.googleapis.com/datastore/v1beta2/datasets/healthier-staging/runQuery?key={YOUR_API_KEY}
{
"query": {
"kinds": [
{
"name": "Subscriber"
}
]
}
}
Response
200 OK
{
"batch": {
"entityResultType": "FULL",
"entityResults": [
{
"entity": {
"key": {
"partitionId": {
"datasetId": "s~healthier-staging"
},
"path": [
{
"kind": "Subscriber",
"name": "+1215XXXXXXX"
}
]
},
"properties": {
...
I'm able to authenticate using my credentials, create a transaction, etc. so I know it's not an authentication issue.
Here's the code I'm trying to run in Node:
this.datastore.runQuery({
datasetId: 'healthier-staging',
query: {
kinds: [{name: 'Subscriber'}]
},
}, (function(err, result) {
if (err) {
console.error(err);
return;
}
}).bind(this));
When I try to run the same query using the Node module, I get this error:
{ [Error: one of fields Query.query and Query.gql_query must be set]
code: 400,
errors:
[ { domain: 'global',
reason: 'INVALID_ARGUMENT',
message: 'one of fields Query.query and Query.gql_query must be set' } ] }
This doesn't make sense, since I've specified the query field. I've tried all sorts of things: removing datasetId (produces an error about needing datasetId), using gql_query instead (same error), encapsulating the datasetId inside a transaction and passing that along inside readOptions, etc.
Is this a bug or am I doing something silly?
Thanks!
I mentioned this on your other StackOverflow question, but your request should be included in the resource section:
this.datastore.runQuery({
datasetId: 'healthier-staging',
resource: {
query: {
kinds: [{name: 'Subscriber'}]
},
},
}, (function(err, result) {
if (err) {
console.error(err);
return;
}
}).bind(this));

Categories

Resources