Netlify Lambda Functions - aws-lambda

I am having an issue getting a 502 error back when I call my Netlify function. Is there something I am doing wrong in my Axios call or does the "error" sent in the callback need to be an actual Error object?
Below is the example of my function:
const axios = require('axios')
require('dotenv').config()
const https = require('https')
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
}
exports.handler = function (event, context, callback) {
// your server-side functionality
axios
.post(
`https://us18.api.mailchimp.com/3.0/lists/${
process.env.LIST_ID
}/members/`, {
email_address: 'deuce3608#gmail.com',
status: 'subscribed'
}, {
auth: {
username: 'admin',
password: process.env.MAILCHIMP_API_KEY
}
}
)
.then(response => {
callback(null, {
statusCode: 200,
headers,
body: response.data
})
})
.catch(err => {
callback(JSON.stringify(err.response.data))
})
}

Netlify announced in April (2018) that Node.js 8.10 would be the default in Netlify functions.
Using Callback Parameter:
When you need to return an error in Lambda functions on Netlify using the Callback Parameter, it will be the same format as the Lambda functions for AWS.
You will need to return an Error in the first parameter of the callback as you can see in the AWS documentation
callback(Error error, Object result);
The error is used if not null and the result will be ignored.
Using Async Handler:
You also have the option to return your error in the response with an error status code like the example function below.
import fetch from "node-fetch";
const API_ENDPOINT =
"https://08ad1pao69.execute-api.us-east-1.amazonaws.com/dev/random_joke";
exports.handler = async (event, context) => {
return fetch(API_ENDPOINT)
.then(response => response.json())
.then(data => ({
statusCode: 200,
body: `${data.setup} ${data.punchline} *BA DUM TSSS*`
}))
.catch(error => ({ statusCode: 422, body: String(error) }));
};
Showing simple tests
Error
exports.handler = function(event, context, callback) {
const err = new Error("this is an error")
callback(err);
}
Response (response status code 502):
{"errorMessage":"this is an error","errorType":"Error","stackTrace":["48.exports.handler (/var/task/showerror.js:75:13)"]}
Object
exports.handler = function(event, context, callback) {
const err = {statusCode: 422, body: "this is an error"}
callback(err);
}
Response (response status code 502):
{"errorMessage":"[object Object]"}
String
exports.handler = function(event, context, callback) {
const err = "this is an error"
callback(err);
}
Response (response status code 502):
{"errorMessage":"this is an error"}
NOTE:
If you want to use callback and have the error status code in the response, you would just pass it in an object to the response.
exports.handler = function(event, context, callback) {
const err = {statusCode: 422, body: "this is an error"}
callback(null, err);
}
Response (response status code 422):
this is an error

You could arrange the response like so:
var response = {
statusCode: 4xx
body: ''
}
and then pass it to the callback to return the error
response.body = 'some error text here';
callback(response);
They are using AWS Lambda, so if you can do it in the console you should in theory be able to call things the same way since they are taking your code and deploying it via Cloudformation in their infrastructure.

Related

GET lambda function using postman (authorization header)

I'm trying to do simple GET lambda function via postman using API gateway.I'm getting 200 OK using authorization code in lambda function but
I want to pass authorization token when calling from postman
exports.handler = async(event) => {
try {
const res = await axios.get('https://hellothere.com/1435',{
headers : {
'Authorization': 'Bearer XXXXXXX',
'Content-Type' : 'application/json'
}
})
console.log(res)
return {
statusCode: 200,
body: JSON.stringify(res.data)
}
} catch (e) {
console.log(e)
return {
statusCode: 400,
body: JSON.stringify(e)
}
}
};
I don't want to give Authorization token in the code instead when I can call from postman I want to pass the token

How to get error from backend with axios?

I'm trying to display an error I recieve in my backend to the user in my JSX frontend file.
This is the initial call from frontend
dispatch(createGoal({ values }))
Goalslice, directly called from JSX:
export const createGoal = createAsyncThunk(
'goals/create',
async (goalData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await goalService.createGoal(goalData, token)
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
}
)
Goalservice, directly called from goalslice:
const createGoal = async (goalData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
}
const response = await axios.post(API_URL, goalData, config)
return response.data
}
Goalcontroller, my backend:
const setGoal = asyncHandler(async (req, res) => {
const goals = await Goal.find({ user: req.user.id })
var count = Object.keys(goals).length
if(count >2){
res.status(400)
throw new Error('Maximum of 3 trackers per user')
}
if (!req.body.values) { //if this isnt there. check if the body is there.
res.status(400) //This is an error
throw new Error('Please add a date field') //this is express error handler
}
console.log(req.body.values.dates)
const goal = await Goal.create({
values: req.body.values.dates, //get from request body
permit: req.body.values.permits,
numpermit: req.body.values.num,
user: req.user.id,
})
res.status(200).json(goal)
})
I want to display this error:
throw new Error('Maximum of 3 trackers per user')
I tried a try/catch method, but I'm very new to this and I feel like i'm missing a very key point in how it all fits together.
This is my custom error handler if it helps:
const errorHandler = (err, req, res, next) => { //overwrite express error handler, next to handle any new req
const statusCode = res.statusCode ? res.statusCode : 500 //500 is server error. conditional
res.status(statusCode)
res.json({
message: err.message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack, //gives additional info if in development mode : is else
})
}
module.exports = { //export for others to use
errorHandler,
}

Async Lambda function returning null on calling DynamoDB

I am new to async functions and promises. I have written a Lambda function which queries a DynamoDB table and returns the result. The code is executing inside the callback success block and I am able to see the response in the log from the console.log(res) line. However the Lambda response is always showing as null, i.e. the response object below is not returned at all. I was able to make this work using a Synchronous Lambda function using a callback to return the data. Can you please suggest what I may be doing incorrectly.
const doc = require('dynamodb-doc');
var dynamodbclient;
const tablename = process.env.TABLE_NAME;
exports.handler = async(event) => {
if (!dynamodbclient) {
dynamodbclient = new doc.DynamoDB();
}
let id = event.params.id;
let queryparams = {
TableName: 'table-name',
Key: { id: id }
};[![enter image description here][1]][1]
var getItemsCallback = (err, res) => {
console.log('inside');
if (err) {
}
else {
console.log('success');
console.log(res);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
}
};
var item = await dynamodbclient.getItem(queryparams, getItemsCallback).promise();
};
Your callback is still executing after the promise resolves, so the lambda will terminate and your callback will not finish.
Try:
try {
const item = await dynamodbclient.getItem(queryparams).promise();
} catch (err) {}
console.log('success');
console.log(item);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;

Apollo Server: How can I send a response based on a callback?

I am currently trying to validate iOS receipts for in app purchases using this package: https://github.com/Wizcorp/node-iap
This is my incomplete resolver:
export default {
Query: {
isSubscribed: combineResolvers(
isAuthenticated,
async (parent, args, { models, currentUser }) => {
const subscription = await models.Subscription.find({ user: currentUser.id });
const payment = {
...
};
iap.verifyPayment(subscription.platform, payment, (error, response) => {
/* How do I return a response here if it is async and I don't have the response object? */
});
}
),
},
};
How do I return a response here if it is async and I don't have the response object? Normally, I'm just used to returning whatever the model returns. However, this time I'm using node-iap and it's callback based.
You can use a Promise:
const response = await new Promise((resolve, reject) => {
iap.verifyPayment(subscription.platform, payment, (error, response) => {
if(error){
reject(error);
}else{
resolve(response);
}
});
});

AWS Lambda async/await boilerplate

Is there an example how to completely use async/await in aws lambda functions? Most lambda example starts with:
module.exports.handler = (event, context, callback) => {
Now I tried to use:
module.exports.hello = async (event, context) => {
but now I have to call a lambda-function in this lambda function.
Can I just write:
'use strict';
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda({
region: 'my-region'
});
let params = {
FunctionName: process.env.lambdafunc, /* required */
Payload: "",
InvocationType: "Event"
};
module.exports.hello = async (event, context) => {
/** HERE COMES SOME CODE AND BUSINESS LOGIC
* ...
* ...
*/
params.Payload = new Buffer(JSON.stringify(MYJSONDATA));
data = await lambda.invokeAsync(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
return {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
data: data
}),
};
};

Resources