Google Cloud Print API - white page when printing PDF - node.js

I want to send a PDF file to be printed using the Google Cloud Print API. The code bellow will give me a positive message telling me that one page was generate. When I go and check what came out, I gate an empty page.
The same result happens if I save the print on Google Drive.
The code
unirest.post('https://www.google.com/cloudprint/submit')
.header('Authorization', 'Bearer ' + token)
.header("Accept-Charset", "utf-8")
.field('xsrf', xsrf_token)
.field('printerid', printerId)
.field('ticket', '{"version": "1.0", "print": {}}')
.field('title', 'Test from Simpe.li')
.field('contentType', 'application/pdf')
.attach('content', buffer)
.end(function (res) {
console.log(res);
});
I know that what I'm sending is a PDF, because when I change the
.field('contentType', 'application/pdf')
to
.field('contentType', 'text/plain')
I will get 53 pages of text which is the raw content of the PDF file.
Question
What I'm doing wrong?
Tech spec
NodeJS v4.1.1
Unirest v0.4.2

It turns out that the Google documentation left some key information out. To send a binary type data, like a PDF, you need to convert the file to base64. In addition to that you need to tell Google that you are going to send them a base64 blob with the add field contentTransferEncoding and set the value to base64.
Another important thing. There is a bug in Unirest (for NodeJS at least), where sending a base64 file won't set the Content-Size header. Nor even setting your own will fix the problem. To circumvent this issue I had to switch to Request. The following code shows a post to Google Cloud Print that works:
let buffer64 = buffer.toString('base64');
let formData = {
xsrf: xsrf_token,
printerid: printerId,
ticket: '{"version": "1.0"}',
title: 'Test Print',
contentTransferEncoding: 'base64',
contentType: 'application/pdf',
content: buffer64
};
let headersData = {
'Authorization': 'Bearer ' + token
};
request.post({
url: 'https://www.google.com/cloudprint/submit',
headers: headersData,
formData: formData
}, function (err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
I hope this will help others :)

Related

How can I use Axios to access the JSON data within a response sent using Expressjs?

I'm creating a web application that generates a pdf on a server then sends it to the client for display within the browser.
The client is using Vuejs / Axios to send a POST request. Afterwards, The server is receiving it with Expressjs, generating a unique PDF, converting the file to a base64 value then sending it back as a response.
I cannot seem to get the response correct. When I attempt to display response.data.pdfData within the client I get undefined in the console. I can see that there is indeed a response with the key and value pair using inspection tools within the Network tab under the Preview section but cannot seem to access it.
// FILE: ./Client/src/App.vue
submit(personalInfo) {
this.cardInfo.personalInfo = personalInfo;
console.log('Sending POST preview_card...');
axios({
url: 'http://localhost:5000/api/preview_card',
method: 'POST',
responseType: 'blob',
data: {
cardInfo: this.cardInfo,
},
}).then((response) => {
console.log(response.data.pdfData);
});
},
// FILE: ./Server/app.js
app.post('/api/preview_card', (req, res) => {
// Generate pdf
const doc = new jsPDF('p');
doc.setFontSize(40);
doc.text(req.body.cardInfo.templateInfo, 100, 100);
doc.save('response.pdf');
// Convert pdf to base64
var tempFile = path.resolve(__dirname, './response.pdf');
var pdfBase64 = fs.readFileSync(tempFile).toString('base64');
res.setHeader('Content-Type', 'application/json');
return res.send(JSON.stringify({ pdfData: pdfBase64 }));
});
I find it necessary to serve the pdf this way due to my client's compnents as well as to enforce a level of data coherency between concurrent users.

Not Getting Response From Another Nodejs Server?

I am learning Nodejs. I am facing a small problem. I am uploading file to google cloud service. All types of files are uploading and I am getting signed URL of file. I am sending the signed URL from one nodejs server to another nodejs server. While uploading jpg or png file its success and getting response back to the another server.
But the issues is that, when I upload xlsx (excel file) I am not getting response to the another server. Its happing only while I upload the excel file only.
Any solution for that?
First Nodejs Server from where File is uploaded to GCS->
if(is_valid_request){
interface.gcpFileUpload(req, (data)=>{
console.log("response = "+ JSON.stringify(data));
res.json(data)
})
} else{
res.json({success:0,err:"request is not valid"});
}
Another server where I want to get response->
getResponse(source, filename, destination, bucket_name, json_url, callback) {
var formData = {
file: fs.createReadStream(source),
filename: filename,
json_url: json_url,
destination: destination,
bucket_name: bname
}
var options = {
'method': 'POST',
'url': endpoint_of_another_server,
'headers': {
'api_key': key,
'Content-Type': 'application/json',
},
formData: formData,
}
console.log("I AM RUNNING TILL HERE")
request(options, function (error, response) {
console.log("WE ARE GETTING SOME RESPONSE " + response);
return callback(response.body);
})
}
It is hard to conclude on something without looking at the code snippets. But as per your problem statement, if it is only issue with *.xlsx (excel file) then it may have one of the below issue:
You may need to allow *.xlsx file extension in your code
If the file extension is already allowed, then there may be issue with the size of the file (assuming if it is having GBs of data)
Nevertheless, we can help you out more if you provide more details of code snippet.

Walmart Seller API "Bulk Item Setup" doesn't work

I tried to use Walmart API v4.2 to publish some items. I used "Bulk Item Setup" API method to create some feed. I used some types of ways to did it:
Send binary file (in the request body, for-data) with header "multipart/form-data" (this way was described in the Walmart API docs)
Send stringified object in the request body with header 'Content-Type': 'application/json',
Walmart API correctly returns me feedId.
But all of these ways didn't work! After feed creating, I saw "Submitted" status at the Walmart Seller Center. But this status was changed after few minutes to "Error". At the error column I see "ERROR TYPE: Data Error" with a description "Malformed data. Please check data file to ensure it is formatted properly.java.lang.NullPointerException".
I use my backend NodeJs app to do it. I use Axios for making a request.
My code example:
async createFeed(wdpId, wdpSecret, accessToken, feedsData) {
try {
const string = JSON.stringify(feedsData);
const file = Buffer.from(string);
const formData = new FormData();
formData.append('file', file);
const baseToken = WalmartService.getBaseAuthToken(wdpId, wdpSecret);
const options = {
params: {
feedType: 'MP_WFS_ITEM',
},
headers: {
Authorization: baseToken,
'WM_SEC.ACCESS_TOKEN': accessToken,
'WM_QOS.CORRELATION_ID': uuidv4(),
'WM_SVC.NAME': 'Walmart Marketplace',
Accept: 'application/json',
'Content-Type': 'application/json',
...formData.getHeaders(),
},
};
return (
axios
.post(`${process.env.WALMART_API_BASEURL}/feeds`, formData, options)
.then((response) => {
return response.data;
})
.catch((error) => {
console.error(error.message);
throw new BadRequestException('Walmart error, ', error.message);
})
);
} catch (error) {
throw new BadRequestException('Can not create listing');
}
}
It is difficult to identify the exact issue based on the information you provided. Few things that you might want to check
If you are appending/attaching a file (as I see it in the code), use Content-Type header as "multipart/form-data. Also, make sure the file name has a .json extension if you are sending data as a json string. If you don't use this, it might default to xml and you will get the same error as what you see.
Try invoking the API using a rest client like Postman and verify if that call is successful.
If you do want to send the data as HTTP body (instead of a file), that should work too with Content-Type as application/json. This has not been documented on their developer portal, but it works.

NodeJS request fetch pdf file and save on disk but opens as blank white page

I am fetching a pdf file and want to save that on disk. Below is my code:
request.post({
url: some_api_url,
json: true,
body: {
by: user,
password: 'mypassword'
}
}, function(err, response, body) {
if (err) next(err);
else {
if (typeof(body) == 'string') {
//console.log(body);
fs.writeFileSync(path.join(__dirname, 'abc.pdf'), body, 'binary', function(err) {
console.log(err);
});
} else {
console.log("invalid file");
}
}
});
This saves the pdf on disk with the right size (about 200kb) which means that there is data in body of the post request. However, the pdf opens up blank in document viewer in Ubuntu.
I have also compared "cat abd.pdf | less" outputs of a working pdf file (which opens fine) and the one downloaded through the request and top and bottom of both are same.
Below is the api code that serves the pdf file. If I make the request in postman, the pdf file downloads and save to disk and opens up fine.
let fileStat = fs.statSync(filePath);
res.writeHead(200, {
'Content-Disposition': 'attachment; filename="report.pdf"',
'Content-Type': 'application/pdf',
'Content-Length': fileStat.size
});
let readStream = fs.createReadStream(filePath);
res.on('finish', function() {
console.log("file sent");
});
readStream.pipe(res);
Writing my solution in case anyone needs it.
The problem was in encoding while reading the file and sending it. Now I am reading the file as base64, transmitting and then again saving from base64 and now it works fine.

how to send a pdf base64 variable through a nodejs request?

Trying to send a base64 pdf string with request, but I can't seem to figure out the proper structure of the request. Thanks in advance for the help!
var dpdf = pdfvar.toString('base64');
var options = {
method: 'POST',
body: dpdf,
url: FILEPICKER_URL,
headers: [
{
name: 'content-type',
value: 'application/pdf'
}
]
};
request(options, function(err, httpResponse, body){
console.log('body: ', body);
console.log('code ', httpResponse.statusCode)
});
The other side is expecting a PDF
application/pdf
and not a BASE64 representation of it.
Anyway, looking at what you are trying to do, without necessarily understanding how you are trying to do it... I would try and append a data url compatible header to your string like so :
var dpdf = 'data:application/pdf;base64,' + pdfvar.toString('base64')

Resources