How to resolve parsing error: Unexpected reserved word 'await' - javascript

Hi I am trying to deploy my react native function to Firebase. The pre-conigured firebase function (helloWorld)seems to deploy correctly so I am definitely connected to Firebase. I am trying to deploy my own function which is the chatGPT API and followed the syntax of the initial pre-configured function. The function is a node environment which receives data and sends the data to the chatGPT API which is the completetion function below in the code. It seems that 'await' is already a reserved keyword so I have tried putting 'async' in multiple places but can't seem to deploy this to firebase
const functions = require("firebase-functions"); // Firebase initial function
const OpenAIApi = require("openai") // ChatGPT dependency
const Configuration = require("openai")// ChatGPT dependency
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
// // Create and deploy your first functions
// // https://firebase.google.com/docs/functions/get-started
//
exports.helloWorld = functions.https.onRequest((request, response) => {
functions.logger.info("Hello logs!", {structuredData: true});
response.send("Hello from Firebase!");
});
exports.firebasePromptReceiver = functions.https.onRequest((request, response) => {
if (!configuration.apiKey) {
res.status(500).json({
error: {
message:
'OpenAI API key not configured, please follow instructions in README.md',
},
});
return;
}
const prompt = request.body.prompt || '';
if (prompt.trim().length === 0) {
res.status(400).json({
error: {
message: 'Please enter a valid prompt',
},
});
return;
}
try {
const completion = await openai.createCompletion({ //ChatGPT API
model: 'text-davinci-003',
prompt: generatePrompt(prompt),
temperature: 0.9,
max_tokens: 2048,
});
response.status(200).json({result: completion.data.choices[0].text});
console.log(completion);
} catch (error) {
// Consider adjusting the error handling logic for your use case
if (error.response) {
console.error(error.response.status, error.response.data);
res.status(error.response.status).json(error.response.data);
} else {
console.error(`Error with OpenAI API request: ${error.message}`);
res.status(500).json({
error: {
message: 'An error occurred during your request.',
},
});
}
}
});
Please any help is greatly appreciated

functions.https.onRequest(async(request, response) => {..}
await operator sould be used in async function

Related

Google Cloud Function Not Returning Error Message

I have the following code in a google cloud function. When the user account is created it returns status 200 and the name of the registered user which I can access from the return of the successful promise. All works as expected. However, when there is an error creating the new user the status changes to 400 but no matter what on the client side I get an error of "Error: invalid-argument". I want to pass the error message from the google cloud function. When I check the cloud function logs, I can see the error code and error message.
What I tried: I did try to use the throw new functions.https.HttpsError() but I get a CORS error message.
Any advice on getting the cloud function to pass the error message properly?
const { initializeApp, applicationDefault, cert } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
const { getAuth } = require('firebase-admin/auth')
const functions = require('firebase-functions')
const app = initializeApp();
const db = getFirestore();
exports.registerUser = (req, res) => {
let registerDetails = req.body.data;
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
console.log(registerDetails)
if(registerDetails.FirstName === undefined || registerDetails.FirstName === ""){
res.status(400).json({data: 'Invalid Request'})
} else {
console.log(registerDetails);
getAuth()
.createUser({
email: registerDetails.Email,
emailVerified: false,
password: registerDetails.Password,
displayName: registerDetails.DisplayName,
disabled: false,
})
.then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
let message = 'Registered user '+registerDetails.DisplayName+".";
res.status(200).json({data: message});
console.log('Successfully created new user:', userRecord.uid);
},(error)=>{
res.status(400).json({code:error.errorInfo.code,message:error.errorInfo.message})
console.log('Error creating new user:', error);
})
}
}
};
To anyone who views this post, the solution is that I was confusing HTTP and HTTPS Callable functions, which have different syntax.
See this post:
Google Cloud Function Cors Error Only When Error is Thrown

Express.js - Cannot Set Headers with exported function

Learning how to do testing with Express with using Mocha, Chai, Chai-HTTP plugin, and MongoDB with Mongoose. I have a test to purposely detect if MongoDB will send back an error from trying to find a document using a faulty _id value (too short).
I noticed that part of my code is repeating around my other Express routes, and want to reuse it for other routes so I exported it from another module, but now I get this:
Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Not sure why I am getting this error. If I have the same code, as the exported function, inside the route code it works fine, but exported it just complains.
Here is the code:
test/route/example.test.js Snippit
it('Bad request with a too short ID string (12 characters minimum)', () => {
// /api/v1/example is the endpoint
// /blah is the param
chai.request(app).get('/api/v1/example/blah').end((err, res) => {
// Insert all the nice assert stuff. :)
});
});
route/example.js Snippit
// Packages
const router = require('express').Router();
// Models (Mongoose Schemas)
const Example = require('../models/example.model');
// Helpers
const { foundMongoError } = require('../helpers/routes');
// -----Snipped-----
router.route('/:exampleId').get((req, res) => {
// Retrieve the exampleId parameter.
const exampleId = req.params.exampleId;
Example.findById(exampleId, (mongoError, mongoResponse) => {
foundMongoError(mongoError, res); // Having an issue
// If I have the same code that makes up foundMongoError inside here, no issues,
// but it will no longer be DRY.
// Check if any responses from MongoDB
if(mongoResponse) {
res.status(200).json(mongoResponse);
} else {
return res.status(404).json({
errorCode: 404,
errorCodeMessage: 'Not Found',
errorMessage: `Unable to find example with id: ${exampleId}.`
});
}
});
});
helpers/routes.js
const foundMongoError = (mongoError, res) => {
if(mongoError) {
return res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
}
};
module.exports = {
foundMongoError
};
That just means you send and response res twice back. The first time you send it back at here:
if(mongoError) {
return res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
}
You sended an response back but the function still continue its work, that means the function moves on till here then:
if(mongoResponse) {
res.status(200).json(mongoResponse);
} else {
return res.status(404).json({
errorCode: 404,
errorCodeMessage: 'Not Found',
errorMessage: `Unable to find example with id: ${exampleId}.`
});
}
Here happens the second response, and here you get the error.
I would rewrite the code like this:
Instead of returning the response, you return an true that means there is an error, otherwise false :
const foundMongoError = (mongoError, res) => {
if(mongoError) {
res.status(400).json({
errorCode: 400,
errorCodeMessage: 'Bad Request',
errorMessage: mongoError.message
});
return true;
}
return false;
};
module.exports = {
foundMongoError
};
Then you can write it like this:
if(foundMongoError(mongoError, res)) return;
The return will stop the function to execute the rest of the code

Why can my code run in a standard Node.js file, but not in a AWS Lambda Function?

What I'm trying to do is create a lambda function where the function calls two commands on an ec2 instance. When I had trouble running this code in a lambda function, I removed the code from the exports.handler() method and ran the code in a standalone node.js file in the same ec2 instance and I was able to get the code to work. The command I ran was 'node app.js'.
exports.handler = async (event) => {
const AWS = require('aws-sdk')
AWS.config.update({region:'us-east-1'});
var ssm = new AWS.SSM();
var params = {
DocumentName: 'AWS-RunShellScript', /* required */
InstanceIds: ['i-xxxxxxxxxxxxxxxx'],
Parameters: {
'commands': [
'mkdir /home/ec2-user/testDirectory',
'php /home/ec2-user/helloWorld.php'
/* more items */
],
/* '<ParameterName>': ... */
}
};
ssm.sendCommand(params, function(err, data) {
if (err) {
console.log("ERROR!");
console.log(err, err.stack); // an error occurred
}
else {
console.log("SUCCESS!");
console.log(data);
} // successful response
});
const response = {
statusCode: 200,
ssm: ssm
};
return response;
};
I figured that it could have been a permissions related issue, but the lambda is apart of the same vpc that the ec2 instance is in.
You're trying to combine async/await with callbacks. That won't work in a lambda AWS Lambda Function Handler in Node.js. The reason it's working locally, or in a node server, is because the server is still running when the function exits, so the callback still happens. In a Lambda the node process is gone as soon as the lambda exits if you are using async (or Promises), so the callback is not able to be fired.
Solution based on Jason's Answer:
const AWS = require('aws-sdk');
const ssm = new AWS.SSM();
exports.handler = async (event,context) => {
AWS.config.update({region:'us-east-1'});
const params = {
DocumentName: 'AWS-RunShellScript', /* required */
InstanceIds: ['i-xxxxxxxxxxxxxx'],
Parameters: {
'commands': [
'mkdir /home/ec2-user/testDirectory',
'php /home/ec2-user/helloWorld.php'
/* more items */
],
/* '<ParameterName>': ... */
}
};
const ssmPromise = new Promise ((resolve, reject) => {
ssm.sendCommand(params, function(err, data) {
if (err) {
console.log("ERROR!");
console.log(err, err.stack); // an error occurred
context.fail(err);
}
else {
console.log("SUCCESS!");
console.log(data);
context.succeed("Process Complete!");
} // successful response
});
});
console.log(ssmPromise);
const response = {
statusCode: 200,
ssm: ssm
};
return response;
};

Error: Node.js module defined by file index.js is expected to export function named xxxx

Hello there dev community. I´m trying to debug a firebase function and being trying using several tutorials, but with no success...
I´ve tried
(https://medium.com/#mwebler/debugging-firebase-functions-with-vs-code-3afab528bb36)
(https://medium.com/#david_mccoy/build-and-debug-firebase-functions-in-vscode-73efb76166cf)
My purpose is to get google contacts.
functions/index.js
const { google } = require('googleapis');
const oauthUserCredential = require('./oauthUserCredential.json')
const OAuth2 = google.auth.OAuth2
const key = require('./serviceAccountKey.json')
const jwt = new google.auth.JWT(key.client_email, null, key.private_key, 'https://www.googleapis.com/auth/contacts')
exports.getGoogleContacts = functions.https.onCall(async (data, context) => {
const requestingUser = data.requestingUser
console.log('getGoogleContacts-requestingUser', requestingUser)
const oauth2Client = new google.auth.OAuth2(
'client_id',
'client_secret',
'http://localhost:5000/xxx-xxx/us-central1/OAuthCallbackUrl'
);
const contacts = google.people({
version: 'v1',
auth: oauth2Client,
});
console.log('contacts ?', contacts)
(async () => {
const { data: groups } = await contacts.people.get({
resourceName: 'contactGroups',
});
console.log('Contact Groups:\n', groups);
})()
jwt.authorize((err, response) => {
console.log('inside authorize')
if (err) {
console.error(err);
response.end();
return;
}
// Make an authorized request to list contacts.
contacts.people.connections.list({
auth: authClient,
resourceName: 'people/me'
}, function (err, resp) {
if (err) {
console.error(err);
response.end();
return;
}
console.log("Success");
console.log(resp);
response.send(resp);
});
});
// this is another approach I´ve tried, but it´s also not working
const oAuth2Client = new OAuth2(
oauthUserCredential.web.client_id,
oauthUserCredential.web.client_secret,
oauthUserCredential.web.redirect_uris,
)
oAuth2Client.setCredentials({
refresh_token: oauthUserCredential.refresh_token
})
return new Promise((resolve, reject) => {
console.log('[INSIDE PEOPLE CONNECTIONS]')
contacts.people.connections.list({
auth: oauth2Client //authetication object generated in step-3
}, function (err, response) {
if (err) {
console.log('contacts.people.connections error')
console.log(err)
reject(new Error(err))
} else if (response) {
console.log('contacts.people.connections response')
console.log(response)
resolve(response)
}
});
})
.then(result => { return { found: result } })
.catch(err => { return { error: err } })
})
I´ve tried several different approachs and followed different tutorials
(Using Google People API with Cloud Functions for Firebase)
(https://flaviocopes.com/google-api-authentication/)
(https://medium.com/#smccartney09/integrating-firebase-cloud-functions-with-google-calendar-api-9a5ac042e869)
(https://cloud.google.com/community/tutorials/cloud-functions-oauth-gmail)
but none of them show clearly how could I get my contacts list.
I was able to use a client side code by following this tutorial (https://labs.magnet.me/nerds/2015/05/11/importing-google-contacts-with-javascript.html)
but I thought that living the client_id, client_secret and apiKey exposed in the client side would be a security problem...
I´m submitting also a tutorial request to make it very clear how to get contacts list from google account using firebase functions.
The Error you are receiving is because the cloud function cannot find the function named xxxx to execute, as you have not defined any function named xxxx in the index.js file.
Your Cloud Function to execute name, according to the error message is xxxx but the function that you are calling in index.js is getGoogleContacts. Please make sure that these names are the same, for example change getGoogleContacts to xxxx or change function to execute to getGoogleContacts

Wait for AWS SNS publish callback to return a value to calling method

I am attempting to send a text message when a user requests to reset their password. I would like to wait for the message to be sent to alert the user if it was successful or not. I am currently attempting to do it as follows:
async function sendResetPasswordTextMessage(req, res) {
let result = {};
let phoneNumber = req.body.phoneNumber;
if (phoneNumber === undefined) {
return sendInvalidParametersMessage(res);
}
phoneNumber = phoneNumber.toString();
const userProfile = await models.UserProfile.findOne({
where: {
phoneNumber: phoneNumber
}
});
************************** RELEVANT CODE TO ISSUE *************************
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
const sent = await AWSSNSClient.sendMessage(message, phoneNumber);
if (!sent) {
result.error = setTitleAndMessage("Error", "An error occurred");
} else {
result.success = setTitleAndMessage("Success", "Message sent");
}
}
return res.send(result);
***************************************************************************
}
In my other class AWSSNSClient, I have the following sendMessage function:
function sendMessage(message, phoneNumber) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
let sent = false;
sns.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
sent = true;
}
});
return sent;
}
I cannot figure out how to make sendMessage wait for sns.publish to return before it returns itself. I have tried making it an async method and adding await on sns.publish, but the function still returns before sent gets set to true.
I know that the messages are sending without error because I am receiving them and no console logs are printed.
Stumbled on this one via Google trying to figure this out myself today - short answer that I am now using:
You can now do this with Async/Await — and Call the AWS service (SNS for example) with a .promise() extension to tell aws-sdk to use the promise-ified version of that service function (SNS) instead of the call back based version.
The only caveat here is the containing function must ALSO be async to utilize the await syntax.
For example:
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("SNS Push Failed:");
console.log(err.stack);
return;
}
console.log('SNS push suceeded: ' + data);
return data;
}).promise();
The important part is the .promise() on the end there. Full docs on using aws-sdk in an async / promise based manner can be found here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html
In order to run another aws-sdk task you would similarly add await and the .promise() extension to that function (assuming that is available).
For anyone who runs into this thread and is actually looking to simply push multiple aws-sdk promises to an array and wait for that WHOLE array to finish (without regard to which promise executes first) I ended up with something like this:
let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return;
}
console.log('Search push suceeded: ' + data);
return data;
}).promise();
snsPromises.push(snsResult)
await Promise.all(snsPromises)
Hope that helps someone that randomly stumbles on this via google like I did!
stackdave will that actually wait?
Necevil "Search push suceeded will get logged twice" because you're mixing calling operations by passing a callback and using promises. You should only use one method of getting the result
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn}).promise()
will do the trick
You can simply use callbacks for that. Modify your sendMessge like this
function sendMessage(message, phoneNumber, cb) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
sns.publish(params, cb);
}
then on your main file you can supply callback like this
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
if (err) {
result.error = setTitleAndMessage("Error", "An error occurred");
}
else {
result.success = setTitleAndMessage("Success", "Message sent");
}
res.send(result);
});
}
Here the right updated API, August 2018, Necevil answer send the sms twice.
// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
accessKeyId: process.env.AMAZON_SMS_ID,
secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});
// parameters
let params = {
Message: contentSMS, // here your sms
PhoneNumber: mobile, // here the cellphone
};
const snsResult = await sns.publish(params, async (err, data) => {
if (err) {
console.log("ERROR", err.stack);
}
console.log('SNS ok: ' , JSON.stringify (data));
});
If you're having issues with duplicate SNS messages being sent, I fixed this issue by utilizing examples from AWS:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
By utilizing a traditional .then() I was able to squash the duplicate message bug mentioned in comments above.
You can create a async function what use the promise method
async function sendMessage(message, phoneNumber){
const params = {
Message: message,
PhoneNumber: phoneNumber
};
return new Promise((resolve, reject) => {
SNS.publish(params, (err, data) => {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return reject(err);
} else {
console.log('Search push suceeded:' + phoneNumber);
return resolve(data);
}
})
});
}
and then you can call
var s= await sendMessage(message,phoneNumber);

Categories

Resources