Serverless Lambda function doesn't map to response correctly - aws-lambda

I have a problem with correcltly returning the response of a Lambda function that I deploy using the Serverless framework:
module.exports.hello = async (event, context, callback) => {
const content = fs.readFileSync('./cn23_template.html', 'utf-8')
const Vue = require('vue')
const app = new Vue({
template: content,
data: function () {
return event
}
})
const renderer = require('vue-server-renderer').createRenderer()
const html = await renderer.renderToString(app)
const browser = await chromium.puppeteer.launch({
// Required
executablePath: await chromium.executablePath,
// Optional
args: chromium.args,
defaultViewport: chromium.defaultViewport,
headless: chromium.headless || true
});
const page = await browser.newPage();
await page.setContent(html);
let pdf = await page.pdf({ pageRanges: '1', format: 'a4', printBackground: true });
await browser.close();
return {
statusCode: 200,
headers: {
'Content-Type': 'application/pdf',
'Content-Length': pdf.length
},
body: pdf ? pdf.toString('base64') : null,
isBase64Encoded: true
}
}
My serverless.yml file:
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: post
integration: lambda
response:
headers:
Content-Type: "'Test'"
Cache-Control: "'max-age=120'"
The problem is that what I return from the function is not correctly mapped to the response. The response doesn't include the statusCode and headers, it just uses the whole returned object as body of the response.
Besides this, the headers as configured in the .yml are also not being used.
It seems like a very silly mistake, but I'm just doing exactly what is inside the Serverless API gateway docs.
So my question is: How do I properly configure the response properties so that the HTTP request gives the correct response using the Serverless framework?

You need to configure your lambda function to be invoked as a lambda-proxy event.
See Serverless Example Lambda Proxy

Related

Nextjs api resolving before form.parse completes so i cant send response back

I am trying to send an image to Next.js api and then use that image to upload to db.
I am using :
const body = new FormData();
body.append("file", prewiedPP);
const response = await fetch("/api/send-pp-to-server", {
method: "POST",
body ,
headers: {
iext: iExt,
name: cCtx.userDetail ,
},
});
Then in the api :
async function handler(req, res) {
if (req.method === "POST") {
console.log("In");
const form = new formidable.IncomingForm();
form.parse(req,
async (err, fields, files) =>
{
// console.log(req.headers.iext);
// console.log(req.headers.name);
const fdata = fs.readFileSync(files.file.filepath);
await delUserPP(req.headers.name , req.headers.iext);
await setUserPP(
fdata ,
req.headers.name ,
req.headers.iext ,
files.file.mimetype
);
fs.unlinkSync(files.file.filepath);
return;
});
console.log("out");
}
}
export default handler;
The callback function in the from.parse happens after the handler already resolved.
Is there anyway to make the api call only resolve after the setUserPP function is done?
I want to send a response back to the client but the api script finishes to "fast" and before the callback in form.parse runs.
Thanks

JEPG Multipart form data in S3 is always corrupt

Duplicate Question explanation:
This question is not a duplicate of this one because I am trying to submit the image via a lambda function not straight to S3. I have to go through lambda to verify the user and permissions as well as make DB calls to find out where the data should be stored and to update the DB on the data location.
I am trying to use Lambda to put a binary image into S3. The image gets posted to an API gateway endpoint and proxied to the lambda function. The function successfully puts the data into an S3 object, but when I download and read the object (via console) it is always corrupted, sometimes smaller than the input object, and unable to be opened.
I think corruption has something to do with the multipart/form-data and something potentially being added onto the file/encoding the file, but I can't exactly figure out how to extract the image data directly.
How do I properly put the multipart/form-data image into S3?
React Native code to post to lambda
const body = new FormData();
body.append('photo', {
uri: image.image,
name: image.name,
type: image.type,
});
fetch('https://ov2eat1o5h.execute-api.us-east-1.amazonaws.com/dev/uploadImage', {
method: 'POST',
headers: {
Authorization: token,
'Content-Type': 'multipart/form-data',
},
body,
})
.then(response => response.json())
.then(responseJson => {
console.log(responseJson);
})
.catch(error => {
console.error(error);
});
Lambda code:
const AWS = require('aws-sdk');
exports.handler = async event => {
const s3 = new AWS.S3();
const params = {
Body: event.body,
Bucket: 'projectr.app',
Key: 'exampleobject.jpg',
};
const response = await s3.putObject(params).promise();
console.log(response);
};
Corrupted Image
Other things tried:
parse-multipart: always returns an empty array
const boundary = event.headers['content-type'].slice(20);
let {body} = event;
if (event.isBase64Encoded) {
body = Buffer.from(event.body, 'base64');
}
const parts = multipart.Parse(body, boundary);
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
console.log(`PART ${i}: ${part}`);
}
Defining ContentType in S3 params: no descernable difference.
const params = {
Body: event.body,
Bucket: 'projectr.app',
Key: 'exampleobject.jpg',
ContentType: 'multipart/form-data',
};

trying to fetch on aws lambda using serverless

I'm trying to run a simple script on AWS Lambda using Serverless to push it, the script fetches a url and returns it (a proxy), for some reason I can't see the response.
The script in question:
'use strict';
let axios = require('axios')
module.exports.hello = async (event, context) => {
let res = await axios.get('http://example.com')
return {
statusCode: 200,
body: JSON.stringify({
message: res,
input: event,
}),
}
};
My serverless YML:
service: get-soundcloud-tracks
provider:
name: aws
runtime: nodejs8.10
profile: home
functions:
hello:
handler: handler.hello
events:
- http:
path: users/create
method: get
cors: true
The solution was changing res to res.data inside the JSON.stringify

I can't use json to make a Post request to my web api using react

I created a webapi in ASP.NET Core, and I need to consume it using React, the web api works normally, if I use curl or postman among others, it works normally. The problem starts when I'm going to use React, when I try to make any requests for my API with js from the problem.
To complicate matters further, when I make the request for other APIs it works normally, this led me to believe that the problem was in my API, but as I said it works with others only with the react that it does not. I've tried it in many ways.
The API is running on an IIS on my local network
Attempted Ways
Using Ajax
$ .ajax ({
method: "POST",
url: 'http://192.168.0.19:5200/api/token',
beforeSend: function (xhr) {
xhr.setRequestHeader ("Content-type", "application / json");
},
date: {
name: 'name',
password: 'password'
},
success: function (message) {
console.log (message);
},
error: function (error) {
/ * if (error.responseJSON.modelState)
showValidationMessages (error.responseJSON.modelState); * /
console.log (error);
}
});
Using Fetch
const headers = new Headers ();
headers.append ('Content-Type', 'application / json');
const options = {
method: 'POST',
headers,
body: JSON.stringify (login),
mode: 'cors' // I tried with cors and no-cors
}
const request = new Request ('http://192.168.0.19:5200/api/token', options);
const response = await fetch (request);
const status = await response.status;
console.log (response); * /
// POST adds a random id to the object sent
fetch ('http://192.168.0.19:5200/api/token', {
method: 'POST',
body: JSON.stringify ({
name: 'name',
password: 'password'
}),
headers: {
"Content-type": "application / json; charset = UTF-8"
},
credentials: 'same-origin'
})
.then (response => response.json ())
.then (json => console.log (json))
Using Request
var request = new XMLHttpRequest ();
request.open ('POST', 'http://192.168.0.19:5200/api/token', true);
request.setRequestHeader ('Content-Type', 'application / json; charset = UTF-8');
request.send (login);
ERRORS
Console
Network tab
When I do this without being change the content type to JSON it works
because the API returns saying that it is not a valid type.
Apart from allowing CORS in you .NET configuration. You also need to return 200 OK for all OPTION requests.
Not sure how it's done in .NET but just create a middleware that detects the METHOD of the request, and if it's OPTIONS, the finish the request right there with 200 status.
Well I had the same issue and it seems that you need to add the action to the HttpPost attribute in the controller.
Here is an example.
[HttpPost("[action]")]
public void SubmitTransaction([FromBody] SubmitTransactionIn request)
{
Ok();
}
Try like this
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(option => option.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
app.UseAuthentication();
app.UseMvc();
}

Redirect link to distribution slack app

I'm trying to redirect URL to distribute (OAuth 2.0)my slack app with API gateway and lambda function (AWS) but I can't realize how to get the code.
the event that returns is null.
My lambda code :
// Lambda handler
exports.handler = (event, context, callback) => {
var messageTest = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code: event.code
};
var queryTest = qs.stringify(messageTest);
https.get(`https://slack.com/api/oauth.access?${queryTest}`, (res, err) => {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
var result = JSON.parse(data.join(''))
console.log(result);
});
});
callback(null);
};
My redirect URL is the lambda URL.
The event that i get is null.
How can i get the "code" from the oAuth 2.0?
Assuming you are using Lambda Proxy integration (and therefore you don't use a Body Mapping Template), the JSON payload that you send to your API Gateway will be received by your Lambda as a stringified JSON in event.body.
So, you'll need to parse that first and you can get your code.
const body = JSON.parse(event.body)
const code = body.code
Reference: Input Format of a Lambda Function for Proxy Integration

Resources