Importing helper functions in Serverless - javascript

I want to import a helper function into a Node.js Lambda function in Serverless (AWS). I've tried using Layer functions, as well as a wrapper module for Serverless - but nothing has worked so far.
This is the function I want to use with other Lambda functions - helperFunc.js:
class HelperClass { ... } //a helper class that I want to use in other functions
module.exports = HelperClass
This is one of my Lambda functions. It also serves an API Gateway endpoint - users.js:
"use strict";
const helperClass = require('./helperFunc') //I don't know how to do this
module.exports.get = (event, context, callback) => {
const params = { ... } //DynamoDB Params
// a bunch of code that uses the helper class wrapper
callback(null, {
headers: {
"Access-Control-Allow-Origin" : "*", // Required for CORS support to work
"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
}, body: JSON.stringify(res), statusCode: 200})
}
};
This is what my serverless.yml currently looks like:
...
getUsers:
handler: src/users.get
events:
- http:
path: users
method: get
authorizer: authFunc
And this what my project directory looks like:
./
serverless.yml
./src
helperFunc.js
users.js
./auth
UPDATE 1: I was finally able to achieve this functionality using Lambda Layers. However, it still feels as if it's not the best way to do this mainly due to the complex directory set-up.
Here's the updated project directory:
./
serverless.yml
./layers/helperFunc/nodejs/node_modules/helperFunc
index.js
./src
users.js
./auth
And here is the updated serverless.yml file:
layers:
helperFunc:
path: layers/helperFunc
...
functions:
getUsers:
handler: src/users.get
layers:
- {Ref: HelperFuncLambdaLayer} # referencing the layer in cf
events:
- http:
path: users
method: get
authorizer: authFunc

The solution is to use serverless-webpack-plugin.

Related

Can not get Nuxt.js configuration for Axios to work

I am using Nuxt.js first time now. However I struggle with using the axios module of it somewhat. I like the fact that I can configure the baseUrl in the nuxt.config.js file. I expect. So this is what I did:
// nuxt.config.js
...
axios: {
baseUrl: 'http://localhost:3001',
publicRuntimeConfig: {
axios: {
browserBaseURL: "http://localhost:3004"
}
},
privateRuntimeConfig: {
axios: {
baseURL: "http://localhost:3005"
}
},
},
modules: [
'#nuxtjs/axios',
'#nuxtjs/auth-next',
'#nuxtjs/proxy'
],
...
Here comes my vue components method I declared to use the Nuxt.js axios module (using this.$axios.$get insteand of this.$axios.get). However I am not sure if there is a difference using this.$axios and just $axios. the latter is called a "plugin" according to the documentation. I did not manage to get axios working with only calling $axios - it can't be resolved so I stick with this.$axios.
Anyway here is method code containing the axios get call. As you can see I am omitting the base url https://localhost since I expect it to be prepended through the nuxt.config.js configuration.
updateTeams: function () {
this.$axios.$get('/api/teams')
.then(({data}) => {
this.teams = data
}).catch((error) => {
console.error(error)
})
}
The result is disappointing. The call is still done with http://localhost:3000 instead of one of the others I configured in the nuxt.config.js file. I rechecked the documentation twice but could not find any hint what I am doing wrong.
Request URL: http://localhost:3000/api/teams

How to attach files and folders with AWS Lambda Handler?

I have an AWS Lambda
service: serverlesslambda
provider:
name: aws
runtime: nodejs12.x
functions:
changeWeeklyStarterStatus:
handler: handler.changeWeeklyStarterStatus
schedule: cron(0 0 0 ? * SUN *)
And its Handler :
"use strict";
module.exports.changeWeeklyStarterStatus = async event => {
// TODO : Put the logic of the handler here
return {
statusCode: 200,
body: JSON.stringify(
{
message: `TODO ...`,
input: event
},
null,
2
)
};
};
Please notice the line :
// TODO : Put the logic of the handler here
I need to connect to mongo and run a query , for that I've created a few files and folders :
config folder
-db.js - mongo connection
-production.json - params and connection string
-default.json - localhost params
modules folder
-EmployeesSchema - A collection that I run the queries on
utils folder
DateUtil.js - dates manipulation
LambdaUtils.js - the actual query that I run on `EmployeesSchema`
How do I upload all that to AWS and actually use those files with the Lambda Handler ?
If you are asking , how do you deploy these files to AWS, you can keep the files inside your project and deploy your project.
By default, the serverless framework will include the files in the directory where serverless.yml is. This is not true if you use plugins like serverless-webpack, because such plugins only include what's being used (referred by other files)

serverless: function doesn't exist in this service

In serverless i have the following directory structure for my functions:
serverless.yml
functions -
stories -
create.js
get.js
my serverless.yml then looks like this:
functions:
stories:
create:
handler: functions/stories/create.main
events:
- http:
path: stories/create
method: post
cors: true
authorizer: aws_iam
get:
handler: functions/stories/get.main
events:
- http:
path: stories/{id}
method: get
cors: true
authorizer: aws_iam
however when i run a test to check the create: serverless invoke local --function create --path mocks/create-event.json i get the following error:
Serverless Error ---------------------------------------
Function "create" doesn't exist in this Service
I managed to get one function working that looks like this:
functions:
stories:
handler: functions/stories/create.main
events:
- http:
path: stories/create
method: post
cors: true
authorizer: aws_iam
Since i added the get function, i decided i needed to add the create and get parts after stories, but no matter how i change the handler the functions never seem to exist.
I've tried changing the path to functions/stories/create/create.main with no difference, is there anything obvious i'm missing to allow multiple handlers within the same location?
I was looking at the following example, which uses one folder of "todos" which contains multiple functions, but i can't see any obvious difference between it and mine, except i've added an extra folder.
Your template is invalid. You can't just put your function under an arbitrary node to tell the framework that it applies to some object of your app. Your stories: node should be a comment.
Try something like this:
functions:
# Stories related functions
createStory:
handler: functions/stories/create.main
events:
- http:
path: stories # You can post directly to stories to be more RESTful
method: post
cors: true
authorizer: aws_iam
getStory:
handler: functions/stories/get.main
events:
- http:
path: stories/{id}
method: get
cors: true
authorizer: aws_iam
# More examples to understand the routing
getAllStories:
handler: functions/stories/getAll.main # Returns a list of all stories
events:
- http:
path: stories
method: get
cors: true
authorizer: aws_iam
deleteStory:
handler: functions/stories/delete.main # Deletes a story
events:
- http:
path: stories/{id}
method: delete
cors: true
authorizer: aws_iam
Took so much time on this! Just figured out that when I typed the command below, I mentioned the function name in the handle.js file which is wrong! I should call the handler name itself that exists in the serverless.yml file instead
For example
This was wrong:
sls invoke local --function testFunction
This is right:
sls invoke local --function test

Using the AWS SDK for Javascript with Vue.js 2.0

I'm accessing API's hosted by AWS API Gateway with Vue.Js.
There's some pretty good instructions here http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk-javascript.html.
I have a bunch of different components, each of which will get data from a different API GET call. Initially I tried adding all the script files to my index.html and doing the following:
RetailerDetails.vue:
<script>
export default {
name: 'RetailerDetails',
mounted() {
var apigClient = apigClientFactory.newClient({
accessKey: 'blah',
secretKey: 'blah',
});
apigClient.businessGet = function (params, body, additionalParams) {
if (additionalParams === undefined) { additionalParams = {}; }
apiGateway.core.utils.assertParametersDefined(params, [], ['body']);
var businessGetRequest = {
verb: 'get'.toUpperCase(),
path: pathComponent + uritemplate('/business').expand(apiGateway.core.utils.parseParametersToObject(params, [])),
headers: apiGateway.core.utils.parseParametersToObject(params, []),
queryParams: apiGateway.core.utils.parseParametersToObject(params, []),
body: body
};
return apiGatewayClient.makeRequest(businessGetRequest, authType, additionalParams, config.apiKey);
};
},
}
That didn't work, I got ReferenceError: apigClientFactory is not defined.
So then I tried taking the script tags out of my index.html and adding the following lines to my component:
require('../assets/js/lib/axios/dist/axios.standalone.js');
require('../assets/js/lib/CryptoJS/rollups/hmac-sha256.js');
require('../assets/js/lib/CryptoJS/rollups/sha256.js');
require('../assets/js/lib/CryptoJS/components/hmac.js');
require('../assets/js/lib/CryptoJS/components/enc-base64.js');
require('../assets/js/lib/url-template/url-template.js');
require('../assets/js/lib/apiGatewayCore/sigV4Client.js');
require('../assets/js/lib/apiGatewayCore/apiGatewayClient.js');
require('../assets/js/lib/apiGatewayCore/simpleHttpClient.js');
require('../assets/js/lib/apiGatewayCore/utils.js');
require('../assets/js/custom/apigClient.js');
This don't work either, now I get ReferenceError: Can't find variable: CryptoJS
which from what I understand is because I haven't referenced the flles properly?
What do I need to do?
Don't put javascript files in the assets folder. Put them in the static folder instead. If you are using the CLI install, Webpack sorts through the assets and takes care of things like image and fonts, but not javascript files.
When I put the files in the /static/ or something like /static/js/ and then bring them in with:
<script type="text/javascript" src="/static/apigClient.js"></script>
the functions are available to my Vue components. Maybe there's a nicer way that doesn't pollute the global namespace, but this is a pretty easy solution (assuming it also works for you).

Hapijs route registration pattern

As the "Inert" plugin now has to be loaded separately. I want to register the routes of my application. I have 2 choices
1) Export a function that takes "server" as an argument and write code as
module.exports = function(server) {
server.register('inert', function(err) {});
server.routes([....]);
}
And simply call it from server.js as require('./routes.js')(serverObj)
2) Export the routing mechanism as a hapi plugin
exports.register = function(server, opts, next) {
server.register('inert', function(err) {});
server.routes([....]);
next();
}
and call it from server.js as server.register(require('./routes.js'), function(err) {});
Which is a better / more standardized approach ? OR is there a 3rd way I don't know about.
Side Q: Also, should I register the 'inert' plugin before calling the route function / plugin in the server.js file ?
server.route() can be passed an array of routes so you could simply export routes as an array:
routes.js
module.exports = [
{
method: 'GET',
path: '/',
handler: function (request, reply) {
...
}
},
...
];
And then require that file when you're doing the main app setup:
index.js
server.register(require('inert'), function (err) {
if (err) {
throw err;
}
server.route(require('./routes'));
server.start(...)
});
Side Q: Also, should I register the 'inert' plugin before calling the route function / plugin in the server.js file ?
Yes, if you're using the file handler or the directory handler, you need to make sure inert is loaded first, otherwise you'll get an error when registering the routes.
If you choose to register routes in a plugin that depends on these handlers, you can use server.dependency() to express this dependency and delay registering the routes until inert is loaded. This means you don't have to care about which order you list your plugins in server.register(). Useful if you're working with lots of plugins or on a big application/team.

Categories