Not able to catch an error in the catch block javascript - javascript

I am using the web SDK to interact with the Appwrite GraphQL API for user login. However, I am encountering an issue where the API returns a 200 response and the following response., even when I enter an incorrect email or password.
{
"errors": [
{
"message": "Invalid credentials. Please check the email and password.",
"extensions": {
"category": "appwrite"
},
"locations": [
{
"line": 5,
"column": 9
}
],
"path": [
"accountCreateEmailSession"
]
}
],
"data": {
"accountCreateEmailSession": null
}
}
My code:
const login = async (email, password) => {
try {
const res = await graphql.mutation({
query: `mutation (
$email: String!,
$password: String!,
) {
accountCreateEmailSession(
email: $email,
password: $password,
) {
_id
}
}`,
variables: {
email: email,
password: password,
},
});
console.log(res);
} catch (error) {
console.log(error);
throw error;
}
};
It should log the error message from the catch block not from the try block when a user enters a wrong email or password.
Anyone please help me with this.

As docs say, in event of an error it will be inside the response body. However the HTTP status will be 200 OK at all times if HTTP request itself doesn't fail. You can consider implementing your own error handling logic.

Related

How to return a rejected Promise to Graphql?

I've got a login method that returns a Promise to GraphQL to resolve. If the user is found and authenticated it resolves the user and works as it should. However, if the account doesn't exist or couldn't be resolved, the promise is rejected with a message Invalid credentials. This is fine but it seems I'm getting a GraphQL error when this happens so I think I'm sending GraphQL something its not expecting.
Here's my code:
mutations.js:
login: {
type: UserType,
args: {
email: { type: GraphQLString },
password: { type: GraphQLString }
},
resolve(parentValue, { email, password }, req) {
return AuthService.login({ email, password, req })
}
}
AuthService.login:
function login({ email, password, req }) {
return new Promise((resolve, reject) => {
passport.authenticate('local', (err, user) => {
if (!user) { reject('Invalid credentials.') }
req.login(user, () => resolve(user));
})({ body: { email, password } });
});
}
The GraphQL error I'm getting back is this:
{
"errors": [
{
"message": "Unexpected error value: \"Invalid credentials.\"",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"login"
]
}
],
"data": {
"login": null
}
}
But I think if I was returning a proper GraphQLFieldResolver wouldn't I get a much simpler error result? Like just an array or (in this case an array of one) error messages?
For example, lets say I change the resolver to this:
resolve(parentValue, { email, password }, req) {
throw "Error!"
// return AuthService.login({ email, password, req })
}
I'm getting the error message "message": "Unexpected error value: \"Error!\"". Shouldn't I be getting "message": "Error!" instead? Is that a GraphQL standard to return error messages with Unexpected error value: X?
The problem is that you're returning a promise that is rejected with a string, instead of an Error object. Or in your simpler version, you're throwing a string instead of an Error object.
Just don't do that.
I doubt there's something in the GraphQL standard about this (after all, this is the implementation not the API protocol), it's just graphql.js expecting Error objects (so that it can send stacktraces etc in development mode) and complaining about non-Error exceptions with an "Unexpected error value"message.
To fix your code, use
function login({ email, password, req }) {
return new Promise((resolve, reject) => {
passport.authenticate('local', (err, user) => {
if (!user) { reject(new Error('Invalid credentials.')) }
// ^^^^^^^^^^ ^
req.login(user, () => resolve(user));
})({ body: { email, password } });
});
}
or even better just reject(err).

Automate user creation using google app script in Google Admin SDK

I want to automate user creation in google as an Admin where I use app script to do it, however from the documentation I'm reading I'm not quite sure if I'm doing it right since I'm getting some errors in my code, like after POST and the Script not working.
function createUsers() {
const userjson = {
"primaryEmail": "atest#example.com",
"name": {
"givenName": "afirstName",
"familyName": "alastName"
},
"suspended": false,
"password": "pass2022",
"hashFunction": "SHA-1",
"changePasswordAtNextLogin": true,
"ipWhitelisted": false,
"orgUnitPath": "myOrgPath",
};
const optionalArgs = {
customer: 'my_customer',
orderBy: 'email'
};
POST https://admin.googleapis.com/admin/directory/v1/users
try {
const response = AdminDirectory.Users.list(optionalArgs);
const users = response.users;
//check if user exists
if (!users || users.length === 0)
//create new user
return AdminDirectory.newUser(userjson);
// Print user exists
Logger.log('User Existing');
} catch (err) {
// TODO (developer)- Handle exception from the Directory API
Logger.log('Failed with error %s', err.message);
}
}
As per the official documentation, if you want to do it with Google Apps Script, you should format your code as follows:
function createUsers() {
const userInfo = {
"primaryEmail": "jvd#domain.com",
"name": {
"givenName": "Jackie",
"familyName": "VanDamme"
},
"suspended": false,
"password": "thisisasupersecret",
"changePasswordAtNextLogin": true,
"ipWhitelisted": false
};
try{
AdminDirectory.Users.insert(userInfo);
console.log("User added");
} catch(error){
const {code, message} = error.details;
if(code === 409 && message === "Entity already exists."){
console.log("User already exists");
} else {
console.log(`${code} - ${message}`);
}
}
}
If you have any doubts about how to use the user resource payload, please refer to the official documentation of the REST API.

GraphQL + firebase questions [duplicate]

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 2 years ago.
I have been losing all Saturday trying to figure out this. I am good in frontend and decided to jump in and learn back end as well. I have been very interested in graphQl and since I was already doing a lot with firebase it was a go.
I decided to learn the graphQl server but cannot figure out what I am doing wrong.
I have this resolver to create a firebase account:
module.exports = {
Mutation: {
registerUser: async (
_,
{ registerInput: { username, email, password } },
context,
info
) => {
const register = await admin
.auth()
.createUser({
email,
emailVerified: false,
password: password,
displayName: username,
disabled: false
})
.then(function(userRecord) {
console.log("Successfully created new user:", userRecord.uid);
const {userData} = admin
.firestore()
.collection("users")
.doc(userRecord.uid)
.set(
{
email,
role: "user",
username,
uid: userRecord.uid
}, {merge: true});
return register
})
.catch(function(error) {
console.log("Error creating new user:", error);
});
return register
}
and in the schema:
type Mutation {
registerUser(registerInput: RegisterInput): User!
type User {
firstName: String
lastName: String
password: String!
adress: String
postCode: String
role: String
ort: String
email: String!
phone: String
responseRate: Float
responseTime: Int
profilePicture: String
token: String
username: String!
personnummer: Int
}
input RegisterInput{
username: String!
email: String!
password: String!
}
However when I run it in the playground, sometimes the account and the document about the user gets created, other times doesn't, but I always get the same error on the playground:
"errors": [
{
"message": "Cannot return null for non-nullable field Mutation.registerUser.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"registerUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Cannot return null for non-nullable field Mutation.registerUser.",
" at completeValue
Your resolver is an async function, so it will always return a Promise, but that promise will resolve to whatever is returned inside the function. If you return undefined or null, then the field in question (registerUser) will resolve to null. Since you've told GraphQL that can't happen, it throws an error to that effect.
When you call then on a Promise, whatever is returned inside then's callback becomes the value the Promise resolves to (provided no errors are thrown that would cause the Promise to reject). What you're returning inside the then callback in your code is register, which is effectively undefined because it's being used before being initialized.
If you're already using async/await syntax, there's no point in continuing to use then. Just stick with await -- it will keep your code cleaner, easier to read and less error-prone.
const userRecord = await admin
.auth()
.createUser({...})
// if `set` returns a Promise, we should await that as well
const { userData } = await admin
.firestore()
.collection("users")
.doc(userRecord.uid)
.set(...)
return userData
Note that GraphQL will catch any errors or rejected Promises for you and surface them as part of the response, so you don't need to use try/catch here unless you want to mask or otherwise format the error.

JOI validation is not returning all the errors despite setting abort early false

i've been trying to validate my payload via joi schema. But it's not returning the error what I've written in schema rather it's showing only one error. Even if i give payload like name=int only one custom error is showing up despite giving 2nd input aka username a integer value:
{
"statusCode": 400,
"error": "Bad Request",
"message": "name expecting a string"
}
rather it should have printed
{
"statusCode": 400,
"error": "Bad Request",
"message": "name expecting a string"/"username expecting a string"
}
this is my code:
server.js
const server = Hapi.server({
port: 3000,
routes: {
validate: {
options: {
abortEarly: false
},
failAction: async (request, response, err) => {
throw Boom.badRequest(err.message);
},
},
},
});
joi-schmea.js
const NamePayload = Joi.object().keys({
name: Joi.string().required().error(new Error('name expecting a string')),
username: Joi.string().required().error(new Error('username expecting a string')),
age: Joi.integer().required().error(new Error('age expecting a number')),
});
routes.js:
validate: {
payload: Schema.NamePayload,
},
I want postman to show all the error message not only the first error message. And I also dont wanna use default error message child must be string/int type error that's why I'm using new error. I've read all the stackoverflow article about that error but nothing solved my problem . This is the hapi and joi version im using:
#hapi/joi: ^15.0.3,
#hapi/hapi: ^18.3.1,
For what I understand, each Joi error throws a ValidationError that contains a key details, which is an array of errors, each one, among other things, has your custom error message, and by doing new Error() in your schema you are overriding that key details. So, this is what I suggest you to do:
Replace your schema errors with this:
Joi.object().keys({
name: Joi.string().required().error(() => 'name expecting a string'),
username: Joi.string().required().error(() => 'username expecting a string'),
age: Joi.number().integer().required().error(() => 'age expecting a number'),
});
And then in your failAction concat those messages that are inside err.details:
failAction: async (request, response, err) => {
throw Boom.badRequest(err.details.map((error) => error.message).join('/'));
}
For this payload:
{
"name": 10
}
You will get this response:
{
"statusCode": 400,
"error": "Bad Request",
"message": "name expecting a string/username expecting a string/age expecting a number"
}
Writing this if someone finds this helpful:
use: { abortEarly: false } in joi.validate()
eg: const joiResult = joiSchema.validate(
{
name,
email,
},
{ abortEarly: false }
);

How to handle multiple errors in promise chain?

I'm using AWS Amplify for authentication and Stripe for the payment to create sign up page.
PROBLEM: I can't find a way to combine validations for Email and password section(from AWS Amplify) with payment info section(from Stripe).
My current code creates a Stripe token and call API(with valid payment info) then handles the error message from userSignupRequest which takes care of email and password fields.
How do I validate the email and password with payment info then create account in AWS and Stripe?
// Stripe payment process
this.props.stripe.createToken(
{
email: this.state.email
}
).then(result => {
// PROBLEM: Form server validation from Stripe
if(result.error){
return this.setState({ errors: { errorMsg: result.error.message }, isLoading: false })
}
// if success, create customer and subscription with result.token.id
const apiName = 'NameOfAPI';
const path = '/stripe/signup';
let myInit = {
body: {
"stripeToken": result.token.id,
"email": this.state.email
}
}
API.post(apiName , path, myInit).then(reponse => {
this.props.userSignupRequest(this.state.email, this.state.password, reponse).then(user => {
this.setState({
confirmAccount: true,
isLoading: false,
userEmail: this.state.email,
errors: {}
})
this.props.history.push('/signup#confirm-account')
}).catch(err => {
// PROBLEM: Form server validation
this.setState({ errors: { errorMsg: err.message }, isLoading: false })
})
}).catch(err => {
console.log(err)
this.setState({ errors: { errorMsg: err }, isLoading: false })
});
})
It seems like we have a very similar stack. My solution was to handle everything server-side. You'll need to give your lambda functions the appropriate IAM permissions to access Cognito. The code below is a little long. I use async/await, which really cleans things up for me. You'll need to use Lambda with node 8 to use async/await though.
I validate that everything matches the right format client-side (i.e. emails are really emails, passwords are the right length). I realized the only error that could come up is an "existing user" error from Cognito. The idea is: test if the user exists before you attempt to sign the person up with Stripe. There's no way to "test" if the user's credit card is valid with Stripe. It's all or nothing. If it's valid it will go through, if not, you'll get an error. If it goes through, you can then sign up the user with Cognito, knowing you should not get an error (you've validated the email and password client-side and, you know the use doesn't already exist).
For reference, here's the aws-sdk for cognito.
const AWS = require('aws-sdk');
const cognito = new AWS.CognitoIdentityServiceProvider({
region: "region",
userPoolId: "cognito_user_pool_id",
});
module.exports.signUpUser = (payload) => {
const usernamePayload = {
UserPoolId: "cognito_user_pool_id",
Username: payload.email,
};
// I use emails for usernames.
new Promise((resolve, reject) => {
cognito.adminGetUser(usernamePayload, (error, response) => {
if (error && error.code === 'UserNotFoundException') {
resolve(false);
} else if (error) {
reject(error);
} else {
// if adminGetUser doesn't fail, it means the username exists
resolve(true);
}
});
}).then((usernameExists) => {
if (!usernameExists) {
// run stripe API stuff
// always run before sign up below to catch stripe errors
// and return those errors to client
// before you sign up the user to Cognito
// since you've already verified the user does not exist
// it would be rare for an error to come up here
// as long as you validate passwords and emails client-side
const signUpPayload = {
ClientId: "cognito_user_pool_client_id",
Username: payload.email,
Password: payload.password,
UserAttributes: [
{
Name: 'email',
Value: payload.email,
},
],
};
new Promise((resolve, reject) => {
cognito.signUp(signUpPayload, (error, response) => {
if (error) {
reject(error);
} else {
resolve(response);
}
});
}).catch((error) => {
// you should hopefully encounter no errors here
// once you get everything setup correctly
console.log(error);
})
} else {
// means username already exists, send error to client
// saying username exists
}
}).catch((error) => {
// may want to dispatch this error to client
console.log(error);
});
return null;
};

Categories

Resources