AWS AppSync not displaying custom error properties with in Lambda Resolver ResponseMappingTemplate - aws-appsync

We are trying to use custom error status codes with GraphQL so that our upstream services can better utilize the errors thrown.
We have a simple error class that extends the base Error class to include a status code:
export class ErrorWithStatusCode extends Error {
public statusCode: number;
constructor({
message,
name,
statusCode,
}: {
message: string;
name: string;
statusCode: number;
}) {
super(message);
this.name = name;
this.statusCode = statusCode;
}
}
export class BadRequestError extends ErrorWithStatusCode {
constructor(message: string) {
super({
message,
name: `BAD_REQUEST`,
statusCode: 400,
});
}
}
And then we throw that error in our code like so:
if (existingResource) {
throw new BadRequestError('An account with the email address already exists');
}
Inside our logs we see the Lambda invoke error:
2022-04-29T13:42:56.530Z 0e1688ac-89f1-46a7-b592-d6aeceb83fd7 ERROR Invoke Error
{
"errorType": "BAD_REQUEST",
"errorMessage": "An account with the email address already exists",
"name": "BAD_REQUEST",
"statusCode": 400,
"stack": [
"BAD_REQUEST: An account with the email address already exists",
" at Runtime.main [as handler] (/var/task/index.js:26908:19)",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)"
]
}
Then in our VTL template, we just associate all properties outside of name and message to the custom errorInfo object as described here
$util.error(String, String, Object, Object)
Throws a custom error. This can be used in request or response mapping templates if the
template detects an error with the request or with the invocation
result. Additionally, an errorType field, a data field, and a
errorInfo field can be specified. The data value will be added to the
corresponding error block inside errors in the GraphQL response. Note:
data will be filtered based on the query selection set. The errorInfo
value will be added to the corresponding error block inside errors in
the GraphQL response. Note: errorInfo will NOT be filtered based on
the query selection set.
#if (!$util.isNull($ctx.error))
$utils.error($ctx.error.errorMessage, $ctx.error.name, $ctx.result, $ctx.error)
#end
$utils.toJson($ctx.result)
But when we get the error back from AppSync (using the console), we do not have any additional error properties:
{
"data": null,
"errors": [
{
"path": [
"createResource"
],
"data": null,
"errorType": null,
"errorInfo": {
"message": "An account with the email address already exists",
"type": "Lambda:Unhandled"
},
"locations": [
{
"line": 2,
"column": 5,
"sourceName": null
}
],
"message": "A custom error was thrown from a mapping template."
}
]
}

Related

How to catch Next-Auth Email Provider's sign in errors in the client with redirect property set to 'false'?

I added Next-Auth's Email provider to my app, and having issues with catching signIn errors in the client. According to documentation as well as this answer, when using signIn with 'redirect: false' it will return a Promise, that resolves to the following:
{
error: string | undefined;
status: number;
ok: boolean;
url: string | null;
}
In case of errors, however, the 'error' property of the response object has only 'EmailSignin' value, and contains no other information about the kind of error. Instead, more detailed errors are printed in the terminal.
I have the following basic setup:
[...nextauth].js
EmailProvider({
name: "Email",
server: {
host: "smtp.gmail.com",
port: "587",
auth: {
user: "myusername",
pass: "mypassword",
},
},
from: "My App",
}),
And the code of my custom sign in form (modal window):
const handleSignInClick = async () => {
const { email } = formData;
const response = await signIn("email", {
redirect: false,
email,
});
...
...
...
};
Is there any way to catch the errors that are printing in the console, and send them to client instead?
Ok, after playing a little bit with the code + additional reading of the documentation I came up with a solution.
Basically, when you add normalizeIdentifier method to EmailProvider, it overrides the default normalization mechanism. In the method I return 'identifier' without any changes. This stops Next-Auth's logger from throwing 'invalid email' errors to the console. Here is the code:
'normalizeIdentifier' method
EmailProvider({
name: "Email",
server: {
host: "smtp.gmail.com",
port: "587",
auth: {
user: "myusername",
pass: "mypassword",
},
},
from: "My App",
normalizeIdentifier(identifier) {
// return indentifier as is, to avoid next auth logger to log failure for invalid email
return identifier;
},
})
In addition to that, I added 'signIn' callback. Which as per documentation runs 2 times. First when verification request is sent, and second after a user has clicked on a sign-in link. In the first run, you can check 'verificationRequest' which will be 'true'. And here you can do validation of the email, as well and throw an error (which will be sent to client).
'signIn' callback
callbacks: {
async signIn({ user: { email }, email: { verificationRequest } }) {
if (verificationRequest) {
try {
// validate email here
validateEmail(email);
} catch {
//thrown error will be sent to client
throw "Email is invalid";
}
}
},
},
Here is response for invalid request:
{
"error": "Email is invalid",
"status": 200,
"ok": true,
"url": null
}
NOTE: There is only one case in which this solution will not work, and it is when email is not provided at all (normalizeIdentifier and signIn will not be triggered). So default 'EmailSignin' error is sent to client. IMO this is still OK, because logger does not pollute the console, and you know that if it's not a custom error, then there was no email provided.

Dialogflow - Firestore - Webhook call failed. Error: UNAVAILABLE, State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500

I am trying for a fulfillment in Dialogflow using Firebase. There is data in Firestore and the intent is expected to retrieve the results based on the given parameter in the related intent. The intent is enables for webhook call. But the intent returns with one of the predefined responses.
I always get the error "message": "Webhook call failed. Error: UNAVAILABLE, State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500."
Following is the Diagnostic Info from the test console
{
"responseId": "e27d24ba-cb14-4170-a7d8-a97314aee001-cad07fe1",
"queryResult": {
"queryText": "novaluron",
"parameters": {
"chemical": "novaluron"
},
"allRequiredParamsPresent": true,
"fulfillmentText": "This molecule is useful",
"fulfillmentMessages": [
{
"text": {
"text": [
"This molecule is useful"
]
}
}
],
"intent": {
"name": "projects/ppcagent-ahe9/agent/intents/6d9df198-9517-4d61-a480-87c158accdc5",
"displayName": "ChemicalDetails"
},
"intentDetectionConfidence": 0.3,
"diagnosticInfo": {
"webhook_latency_ms": 106
},
"languageCode": "en",
"sentimentAnalysisResult": {
"queryTextSentiment": {
"score": 0.3,
"magnitude": 0.3
}
}
},
"webhookStatus": {
"code": 14,
"message": "Webhook call failed. Error: UNAVAILABLE, State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500."
}
}
Any help will be greatly appreciated.
This error could be due to different reasons, you can check these points:
Use of insecure connection.
You need to use HTTP requests. The service must use HTTPS and the URL must be publicly accessible in order for the fulfillment to function. DialogFlow does not support self-signed SSL certs. For information on SSL setup:
Permission errors.
Server files and folders need correct permissions and ownerships set in order to work properly. If Websites request files for which the server has no access then it will lead to an error.You can see more documentation about permission.
Bad scripting.
You need to check the code and check if there are any errors and modify them.

I'm trying to the customzing the error format structure .for the Rest API

I'm trying to customize the error format with the below structure but not able to set the the error and httpCodeMessage
Error Fromat :
[
{
"headers": {},
"body": {
"timestamp": "2020-08-17T10:22:14.538+0000",
"error": null,
"message": "User Not Found in the system",
"path": "/claims/search/",
"httpCodeMessage": null
},
"statusCode": "BAD_REQUEST",
"statusCodeValue": 400
}
]
#ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse[]> process(ValidationException ex, HttpServletRequest req) {
return new ResponseEntity(Arrays.asList(generateErrorResponse(ex, req)), HttpStatus.BAD_REQUEST);
}
private Object generateErrorResponse(ValidationException ex, HttpServletRequest req) {
ErrorResponse error = new ErrorResponse();
if (ex.getMessage().equalsIgnoreCase("Resource Not Found")) {
error.setTimestamp(new Date());
error.setMessage(NOT_FOUND.value(), ex.getMessage());
error.setPath(req.getRequestURI().toString());
error.setError(ResponseEntity.status(NOT_FOUND));
return ResponseEntity.status(NOT_FOUND).body(error);
}
}
Can anyone suggest how to get the error and httpCodeMessage values .Is it possible to remove the statusCode and statusCodeValue attributes.
You normally have to go to the original HttpClientErrorException and getRawStatusCode() to get the HTTP error code
javadoc

How to validate response in Postman?

I am trying to validate response body including errors in postman. How can I validate the response and text below?
{
"responseHeader": {
"publisherId": "12345",
"responseId": "abbcb15d79d54f5dbc473e502e2242c4abbcb15d79d54f5dbc473e502e224264",
"errors": [
{
"errorCode": "1004",
"errorMessage": "XXXX Not Found"
}
]
}
}
These are my tests which are failing:
tests['response json contains responseHeader'] = _.has(responseJSON, 'responseHeader');
tests['response json contains errors'] = _.has(responseJSON, 'responseHeader.publisherId');
tests["Response has publisher id"] = responseJSON.publisherId === 10003;
In the "Test" tab, parse your response body into an object, then use JavaScript to perform your tests.
var data = JSON.parse(responseBody);
tests["publisherId is 12345"] = data.responseHeader.publisherId === "12345";
Take a look at the test examples at the Postman site:
https://www.getpostman.com/docs/postman/scripts/test_scripts
https://www.getpostman.com/docs/postman/scripts/test_examples

Sails shows no error when model validation fails

in my production environment that uses MongoDB, whenever a model validation fails it shows nothing, while on my development environment with no database it shows something like this:
{
"error": "E_VALIDATION",
"status": 400,
"summary": "10 attributes are invalid",
"model": "Restaurant",
"invalidAttributes": {...}
}
I need my API to show these validation errors.
You can return validation error as response:
For example (inside controller):
create: function (req, res, next) {
......
User.create(data, function userCreated(err, user) {
if (err)
return res.negotiate(err);
return res.ok({ user: user });
}
}