I am trying to send a bas64 encoded image to my express server and parse it there to save it to disk. Id like to implement this with a simple http post request but couldn't get it to work. My first implementation utilized a websocket server and worked well:
Client:
const object = JSON.stringify({
action: "add_image",
data: dataUrl,
})
ws.send(object)
Server:
ws.on("message", (message) => {
const req = JSON.parse(message);
fs.writeFile(
"path/to/file.png",
data.split(";base64,").pop(),
{ encoding: "base64" },
(err) => err && console.log(err)
)
}
This is my trying to get the same result with an http request.
Client:
const object = JSON.stringify({
action: "add_image",
data: dataUrl,
})
fetch("http://localhost:3001/add_image", {
method: "POST",
headers: new Headers({
Origin: window.origin,
Accept: "image/png",
"Content-Type": "image/png",
}),
mode: "cors",
body: object,
})
Server:
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.post("/add_image", function (req, res) {
console.log(req.body);
});
Unfortunately, req.body always logs an empty object.
I am not quite sure what I am lacking. Any help would be greatly appreciated.
I found the answer in this article. I needed to combine all individual chunks of the request and then use the data once the process is complete.
app.post("/add_image", function (req, res) {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
console.log(JSON.parse(body));
res.end('ok');
});
});
Related
I tried integrating Stripe into my React app using the official doc at https://stripe.com/docs/recipes/elements-react. If you could go through this doc, you'll find out they're using a static value as amount (2000).
// server.js
const app = require("express")();
const stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
app.use(require("body-parser").text());
app.post("/charge", async (req, res) => {
try {
let {status} = await stripe.charges.create({
amount: 2000,
currency: "usd",
description: "An example charge",
source: req.body
});
res.json({status});
} catch (err) {
res.status(500).end();
}
});
The post API from frontend using fetch is:
async submit(ev) {
let {token} = await this.props.stripe.createToken({name: "Name"});
let response = await fetch("/charge", {
method: "POST",
headers: {"Content-Type": "text/plain"},
body: token.id
});
if (response.ok) console.log("Purchase Complete!")
}
Here, they're sending the token ID and referencing it in the backend as source:req.body.
Now I have tried to send amount from the frontend through the POST request as follows:
body:{
amount: 2000,
tokenId: token.Id
}
and then referencing it in backend as
...
amount: req.body.amount,
source: req.body.tokenid
...
It doesn't work. And consoling both returns undefined
I have tried many things like removing content-type header and pretty little things. Someone pointed out that I should change content-type to application/json and I've thought of setting
app.use(require("body-parser").text()) to app.use(require("body-parser").json()) but decided to consult you guys first.
If I understand you correctly, you want to post a json from client to express server. If so:
Client
fetch({
method: 'POST',
body: JSON.stringify({
amount: 2000,
tokenId: token.Id
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
Server
const app = express();
// if express >= 4
app.use(express.json());
app.post("/charge", async (req, res) => {
console.log(req.body);
});
Any by the way tokenId !== tokenid (in req.body.tokenid)
It says me syntax error: JSON Parse error. unrecognized token '<'
Iam using Fetch to do the request.It let me send short base64 strings i tried so what can i do?
This is my call to the api:
export function uploadPost(post) {
let data = {
body: post.body,
picture: post.picture,
type: post.type,
user: {
_id: post.user._id,
name: post.user.name,
picture: post.user.picture
}
}
var headers = {
'Content-Type': 'application/json',
'Access-Control-Origin': '*'
}
return fetch(URL + "/uploadPost", {
method: "post",
headers: headers,
body: JSON.stringify(data)
})
.then(response => Promise.resolve(response.json()))
.catch(err => {
return Promise.reject(err);
})
}
I finally solved it. The problem was that the response was returning a 413 status and I found out that means payload too large. So I added to my node js express server this lines:
var app = express();
//after
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
I am using serverless and axios to "passthrough" a PDF generated by the
stampery api, which needs credentials I do not want to save client-side.
In principle I get the PDF as an arraybuffer from axios, transform the arraybuffer to an buffer, which I then use to create a base64 string, needed by API Gateway binary treatment, which can be "activated" by including the isBase64Encoded: true property in the callback response object.
The following code yields an empty PDF:
const axios = require('axios');
const stamperyClientId = 'xxx';
const stamperySecret = 'xxx';
const stampery = axios.create({
baseURL: 'https://api-prod.stampery.com',
auth: {
username: stamperyClientId,
password: stamperySecret
}
});
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
headers: {
'Content-Type' : 'application/pdf',
'Content-Disposition': 'inline; filename="certificate.pdf"'
},
isBase64Encoded: true
};
stampery.get(`/stamps/5b2a612680e0190004bcccc8.pdf`, {
responseType: 'arrayBuffer',
})
.then(res => {
const buffer = Buffer.from(res.data)
const base64Str = buffer.toString('base64')
response.body = base64Str
callback(null, response);
})
};
The PDF is retrieved by: `curl https://xxx.execute-api.eu-west-1.amazonaws.com/dev/certificate -o my.pdf -H "Accept: application/pdf"
I tested the setup with fileReadSync, which turned out fine:
module.exports.hello = (event, context, callback) => {
const content = fs.readFileSync("data/sample.pdf");
const response = {
statusCode: 200,
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": "inline; filename=\"sample.pdf\""
},
body: content.toString("base64"),
isBase64Encoded: true
};
return callback(null, response);
};
What am I missing? Is this the right way to transform an axios arraybufferinto a base64 string?
P.S. My serverless.yml is given by:
functions:
hello:
handler: handler.hello
events:
- http:
path: certificate.pdf
method: get
package:
include:
- data/sample.pdf
resources:
Resources:
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: dev-stamper
BinaryMediaTypes:
- "application/pdf" # or whichever ones you need
where I already thought of the necessary binary media types.
Ok... the error was a simple typo. I wrote arraybuffer in camel case arrayBuffer, so Axios returned a string instead of an arraybuffer.
Change this line:
stampery.get(`/stamps/5b2a612680e0190004bcccc8.pdf`, {
responseType: 'arrayBuffer',
})
to
stampery.get(`/stamps/5b2a612680e0190004bcccc8.pdf`, {
responseType: 'arraybuffer',
})
and everything works as a charm...
I'm using Fetch API to send POST request to my Express server, but I always get empty JSON ({}) instead of the data I have sent.
var postData = function (url, data) {
return fetch(url, {
body: JSON.stringify(data),
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(function (response) {
return response.json();
})
.then(function (data) {
return data;
});
};
var firstField = document.querySelector('#first-field').value;
var secondField = document.querySelector('#second-field').value;
if (firstField.trim().length && secondField.trim().length) {
postData('http://localhost:3000/test', { x: firstField, y: secondField })
.then(function (data) { console.log(data) })
.catch(function (error) { console.error(error) });
}
Here is the Express route:
app.post('/test', (req, res, next) => {
const x = req.body.x;
const y = req.body.y;
res.send(JSON.stringify({
x: x,
y: y
}));
});
spend the good amount of yesterday figuring this out.
You can solve it by installing cors middleware to express.
https://www.npmjs.com/package/cors
npm install cors
and add it to your app. before the body-parsers.
app.use( cors() )
app.use( bodyparser.urlencoded({ extended: true }) )
This should fix the empty body express is returning with Fetch API. Apparently using jQuery ajax post request works out of the box. Haven't investigating further why.
Good Luck.
/S
I am using express to return an api response retrieved via a request call.
router.post('/', function(req, res){
var options = {
...
}
rp(options)
.then(function (parsedBody) {
console.log(parsedBody);
res.json(parsedBody)
})
The console log displays the expected payload, also when I use Postman I also see the expected payload.
When though my client app gets the response it is:
Response {type: "cors", url: "http://localhost:3001/api/", redirected: false, status: 200, ok: true, …}
Ive tried adding CORS middleware:
app.use(function(request, response, next) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers",
"Origin, X-Rquested-With, Content-Type, Accept");
next();
});
My client is a very simple react app using fetch:
fetch('http://localhost:3001/api/', {
method: 'POST',
dataType: 'JSON',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: data,
}).then((response) => {
console.log(response);
}).catch((response) => {
console.log('Error');
});
My react app is localhost:3000 and the express api localhost:3001, the expected payload is a very simple object...
{
athlete: {
firstname: "Matt"
...
}
}
How can I just forward on the api request response to the clients fetch success method?
The problem is not CORS related, the response within the react app needed parsing as json:
.then((response) => {
console.log(response.json());
})