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
}
]
});
}
Related
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);
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
I'm getting this below exception while running the script after redeployment.Earlier it was working fine but when I added some new functions and redeployed it as API executable., started getting this error.
[17-07-08 20:48:45:404 PDT] {
"error": {
"code": 401,
"message": "ScriptError",
"status": "UNAUTHENTICATED",
"details": [
{
"#type": "type.googleapis.com/google.apps.script.v1.ExecutionError",
"errorMessage": "Authorization is required to perform that action.",
"errorType": "ScriptError"
}
]
}
}
Your OAuth scopes have probably changed. Your client needs to add these new scopes and request a new token with them.
I am new to Meteor js and I am trying to create a form following the official guide http://guide.meteor.com/methods.html#method-form. It suggests to use mdg:validated-method package and aldeed:simple-schema for validation which are based on mdg:validation-error to return validation error messages to the client. The guide suggests this code then to handle validation
Invoices.methods.insert.call(data, (err, res) => {
if (err) {
if (err.error === 'validation-error') {
// Initialize error object
const errors = {
email: [],
description: [],
amount: []
};
// Go through validation errors returned from Method
err.details.forEach((fieldError) => {
// XXX i18n
errors[fieldError.name].push(fieldError.type);
});
// Update ReactiveDict, errors will show up in the UI
instance.errors.set(errors);
}
}
});
but the problem is that only fieldError.type, fieldError.name and first human readable message from simple-schema are available in err.error. I use translated messages and field labels in simple-schema to get nice understandable validation error messages. So getting just object property name with "required" is unacceptable, especially in the case when message includes min/max constraints for example. I could not find any way to get simple-schema's validation context to retrieve the full list of human readable errors.
So my question is can I get full error messages on the client and how?
Or maybe there are better ways to achieve what I am trying to do?
Thanks in advance
Hi! Recently I have encountered with the same problem.
So I just create pull request with some code enhancement to solve this issue. Now when you submit form and call validated-method from client side like following:
yourMethodName.call(data, (err) => {
if (err.error === 'validation-error') {
console.dir(err, 'error ')
}
});
You will see error object in the console:
{
"errorType": "ClientError",
"name": "ClientError",
"details": [
{
"name": "firstName",
"type": "required",
"message": "First name is required"
},
{
"name": "lastName",
"type": "required",
"message": "Last name is required"
},
{
"name": "phone",
"type": "required",
"message": "Phone is required"
},
{
"name": "email",
"type": "required",
"message": "Email is required"
}
],
"error": "validation-error"
}
So I just copy that from my console output.
In my case, the method is as follows:
export const yourMethodName = new ValidatedMethod({
name: 'my.awesome.method',
validate: new SimpleSchema({
firstName: { type: String },
lastName: { type: String },
phone: { type: Number },
email: { type: String, regEx: SimpleSchema.RegEx.Email }
}).validator({ clean: true }),
run(doc) {
YourCollection.insert(doc);
}
});
If my pull request will be accepted, you can easy use node-simple-schema (it is the next version of meteor-simple-schema).
If it won't you can use my fork.
Hope this helps!
EDIT: Now this feature available in official node-simple-schema package.
I am working on creating labels using JavaScript Gmail API.
function createLabel(userId, newLabelName, callback) {
var request = gapi.client.gmail.users.labels.create({
'userId': userId,
'label': {'name': newLabelName}
});
request.execute(callback);}
This is the code of Developer API Example
I am able to authenticate and even I'll get the label list but while creating the label I am getting the below error.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "invalidArgument",
"message": "Invalid request"
}
],
"code": 400,
"message": "Invalid request"
}
}
But when I am using the Try It example It's working but only difference is it's do the POST request with key={Your auth key} which the example provided won't attach that part to URL.
The data you send should be in the resource-parameter, and labelListVisibility and messageListVisibility are also mandatory fields:
function createLabel(userId, newLabelName, callback) {
gapi.client.gmail.users.labels.create({
userId: userId,
resource: {
name: newLabelName,
labelListVisibility: 'labelShow',
messageListVisibility: 'show'
}
}).execute(callback);
}