Adding a new js file to my lambda function using Serverless - node.js

I'm trying to create an API on AWS Lambda, and using Serverless framework for deployment.
I'm a complete noob at it, so I'm not sure I'm doing the right thing. So here's the old favorite, hello world (index.js):
const serverless = require('serverless-http');
const express = require('express');
const app = express();
const Promise = require('promise');
app.get('/', function (req, res) {
res.send('Hello World!')
})
That works fine as is. But when I add the following:
const serverless = require('serverless-http');
const express = require('express')
const app = express()
const Register = require('./controller/registryController');
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.get('/createUserName', function (req, res) {
var prom = Register.createUser();
prom.then((message) => {
res.status(201).json(message);
})
.catch((message) => {
res.status(400).json(message);
});
})
module.exports.handler = serverless(app);
I get:
"Cannot find module './controller/registryController'"
Which is strange, cause the file is right there, when I look in lambda. Here's its contents:
const dbConnMysql = require('./dbMngrMysql');
var methods = {
createUser: function() {
return new Promise((resolve, reject) => {
let connection = dbConnMysql.createConnection();
dbConnMysql.startConnection(connection)
.then((fulfilled) => {
let table = 'userNamePool';
return dbConnMysql.selectFrom(connection, table, null);
})
.then((fulfilled) => {
return dbConnMysql.closeConnection(connection).then(function() {
let result = fulfilled;
let response = {
"statusCode": 200,
"headers": {"my_header": "my_value"},
"body": JSON.stringify(result),
"isBase64Encoded": false
};
resolve(response);
});
})
.catch((error) => {
let response = {
"statusCode": 404,
"headers": {"my_header": "my_value"},
"body": JSON.stringify(error),
"isBase64Encoded": false
};
resolve(response);
});
});
}
};
module.exports = methods;
Here's the project structure / directory:
And here's my serverless.yml for good measure:
service: sample-api
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: yapyap
deploymentBucket: yadayada
role: blahblahblah
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
createUserName:
handler: index.handler
events:
- http: 'GET /createUserName'
What am I doing wrong? Anything I can do to fix this?

There's a typo:
controller instead of controllers. 😊

Sorry, I can't comment because of the reputation restriction.
The problem may be because you haven't created controller folder.
To create it properly
create a folder. Name it controller. Create your registryController.js and put your code in it.
now you will be able to call it as
const Register = require('./controller/registryController');
Also on a side note, if you want to use a serverless architecture, separate your server side and client side code completely. Put your HTML files and client-side scripts in an S3 bucket. put your server-side code in lambda function and connect it with API Gateway. then use a JavaScript function to call the API. Keep server-side calls as less as possible.

Related

Node.js - How to Call External Function from AWS Lambda Index.js

I am very new to AWS Lambda and Node.js, so apologies for the elementary question. I have two JS files in my Lambda project's root directory:
index.js
engageMessage(); //For testing purposes - throws error
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('This is index'),
};
return response;
};
messenger.js
function engageMessage() {
console.log("Messenger, checking in!");
};
How do I call engageMessage() from my index.js file? Each time I try, I get a "TypeError: engageMessage is not a function" message, and am unsure of how to properly reference/import/require messenger.js.
In messenger.js you need to export your function
module.exports = { engageMessage }
Then require it in your index.js
const { engageMessage } = require("./messenger.js")

Node.js POST request working correctly in local but always giving 404 not found after deployment

I want to create an endpoint where others can post the data and then I can use it for further operations. I am using lambda and serverless framework for deployment. It is working fine in my local but each time I deploy it gives a 404 not foundError.(There are no issues in deployment).I get the following message in insomnia when testing the API-
Cannot POST /test/update
(test is my basePath)
I have cross-verified the domains and they are exactly the same as the ones present in serverless.yml file. Currently, I have the following code for the post request-
const express = require('express')
const eApp = express()
eApp.post('/update', async (req, res) => {
try {
// console.log('post req is:', req)
console.log('body', JSON.stringify(req.body))
res.sendStatus(200)
}
catch (e) {
console.log('error in post request is:',e)
res.sendStatus(200)
}
})
exports.eApp = eApp
const handler = serverless(eApp)
module.exports.handler = async (event, context) => {
context.callbackWaitsForEmptyEventLoop = false
const result = await handler(event, context)
return result
}
(The above code is present in index.js in routes folder).
The lambda function present in serverless.yml file is as following-
updateEndPoint:
handler: routes/index.handler
events:
- http:
path: /update
method: post
cors: true
I am also not getting any error in cloudwatch logs and can't find the root cause of the issue. Any help would be appreciated. Thanks in advance!!
EDIT- It is working with the domain address mentioned in lambda in aws (the one automatically assigned by aws) but not working with the domain address I have given in the serverless.yml file. Any fixes for this??

Why won't my node app and express server run following Google NLP tutorial?

I am trying to implement this code in my Node/Express server.
https://www.npmjs.com/package/#google-cloud/language?activeTab=readme
async function quickstart() {
// Imports the Google Cloud client library
const language = require('#google-cloud/language');
// Instantiates a client
const client = new language.LanguageServiceClient();
// The text to analyze
const text = 'Hello, world!';
const document = {
content: text,
type: 'PLAIN_TEXT',
};
// Detects the sentiment of the text
const [result] = await client.analyzeSentiment({document: document});
const sentiment = result.documentSentiment;
console.log(`Text: ${text}`);
console.log(`Sentiment score: ${sentiment.score}`);
console.log(`Sentiment magnitude: ${sentiment.magnitude}`);
}
The above code I guess cannot be on the frontend react side. So I tried to use it in my app.js file reference it from a GET request, but the server won't compile because it says require doesn't exits.
app.get('/sentiment', async (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
console.log('sentiment was called'.green.inverse);
var results = quickstart(req.params);
res.send(results);
});
Not sure how to resolve require or if even implementing this quickstart correctly?

JavaScript HTTP requests fail on amazon ec2 instance

I am running a node express server on Amazon ec2 instance. I can connect to the website on my local machine from within the browser, and can view pages with only local files, but when accessing a page that makes an external HTTP request, it just hangs. I figure it has something to do with my inbound or outbound rules are prohibiting it somehow, but don't know enough about networking to solve it on my own.
These are the functions that are failing behind the scenes:
const axios = require('axios').default;
const freelancer = axios.create({
baseURL: 'https://www.freelancer.com/api/',
headers: {
'freelancer-oauth-v1': process.env.FREELANCER_TOKEN
}
});
/* Get User By Id */
async function getUserById(user_id) {
const result = await freelancer.get(`/users/0.1/users/${user_id}/`)
return result.data.result;
}
const GitHub = require('github-api');
const gh = new GitHub({
username: process.env.GHUSER,
password: process.env.GHPASS
});
const getRepos = async function () {
const user = await gh.getUser();
return new Promise(async (resolve, reject) => {
await user.listStarredRepos(function (err, repos) {
if (err) reject(err);
resolve(repos);
});
});
}
My routers look like this:
var express = require('express');
var router = express.Router();
const freelancer = require('../service/Freelancer');
/* GET home page. */
router.get('/', async (req, res, next) => {
const reviews = await freelancer.getMyReviews();
const self = await freelancer.getSelfData();
res.render('contact', {
header: 'Check out all my reviews!',
lead: '',
paragraphtext: 'Your review could be next on this list!',
reviews,
self
});
});
Based on the comments.
The issue was caused by using HTTP for www.github.com. The solution was to use HTTPS.

Why can't I access req.body with multer?

My app (using vue) allows users to upload files with some info about the data to my node backend. When the user submits the form, this function is triggered:
methods: {
buttonOK () {
const formData = new FormData()
formData.append('name', this.detailFirm.name)
formData.append('description', this.detailFirm.description)
formData.append('version', this.detailFirm.version)
formData.append('date', this.detailFirm.date)
formData.append('file', this.file)
for (var [key, value] of formData.entries()) {
console.log(key, value)
}
let headers = {
'Content-Type': 'multipart/form-data',
'Accept': 'multipart/form-data'
}
this.$http.put('/firmware', formData, {headers: headers})
this.visible = false
}
The log statement shows everything that it ought to, and when this request is made, the network tab in the chrome dev tools shows the post data going through, and it has all the values it should:
name: test
description: test
version: 1
date: 0555-05-05
file: (binary)
My multer middleware looks like this:
const multer = require('multer')
const mult = multer({
dest: '/firmware'
})
module.exports = function (req, res, next) {
/* --Convert multipart/form-data to useable format within express-- */
if (req.path === '/firmware') {
mult.single('file')
console.log('MULTER MIDDLEWARE')
}
next()
}
The log statement there works, leading me to believe that multer is working.
I can't seem to access this information in back end though. Here I have tried both file and formData as the file name in mult.single('').
Here is my controller function:
let firmware = {
name: req.body.name,
version: req.body.version,
description: req.body.description,
date: req.body.date,
file: req.body.file
}
firmwareRepo.create(firmware, (err, create) => {
.............
I've read some other questions, and have made a few adjustments, but I always get an empty object when I log req.body in the controller. Please advise.
https://github.com/expressjs/multer#diskstorage
Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.
EDIT:
Firstly, I remember I had one problem on the frontend (React), by adding headers, which are not needed (somehow by adding formdata headers u **** up everything), here is the example:
data append stuff goes here
const data = new FormData()
data.append('id', values.id)
......
return async (dispatch) => {
const respond = await fetch('/api/postdata', {
method: 'post',
headers: {
//SEE? THIS IS EMPTY
},
body: data
})
// send form to backend
dispatch(dataSend())
}
}
Second issue could be on the backend. The thing is, that you can't just simply access file info through the req.body. You need to access it through the req.file
.post('/api/post', (req, res, next)=> {
const photo = {}
const newData = {}
uploadData(req, res, (err) => {
if(err){
console.log('error')
}
else {
Object.assign(photo, {file: req.file})
Object.assign(newData, {newData: req.body})
Then pass the photo to where you want to do something with it
const addDataController = new AddDataController(req, res, next, newAdvertData, photo)
addAdvertController.postAdvert()
}
})
Basically what I did is I separated regular data with file, and passed them further to combine and conclude the form. Sorry if this won't help, you're very close anyways!
I don't know why this worked, but everything started functioning as it should when I stopped using multer as an imported middleware, like this:
module.exports = function (req, res, next) {
/* --Convert multipart/form-data to useable format within express-- */
if (req.path === '/firmware') {
mult.single('formData')
console.log('MULTER MIDDLEWARE')
}
next()
}
and instead applied it directly to the route function, like this:
router.put('/firmware', upload.single('formData'), firmware.create) // doesn't work as standalone middleware
If anyone knows why that would be the case, please let me know.

Resources