I'm currently building a node implementation of the new Box View API and I'm getting a 202 everytime I upload a document and retrieve a session. However, if I do a curl call, I dont get a 202. Is there anyone else experiencing this issue?
Here is my Ember Implementation:
export default Ember.View.extend({
document: null,
documentID: null,
session: null,
sessionID: null,
getDocument: function() {
var self = this;
return Ember.$.ajax({
url: 'http://localhost:3000/doc',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({ "docURL": this.textField.value })
}).then(function(response){
self.set('document', response);
self.set('documentID', response.document_id);
});
},
getSession: function() {
var self = this;
return Ember.$.ajax({
url: 'http://localhost:3000/sess/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ "docID": this.get('documentID') })
}).
then(function(response) {
self.set('session', response);
self.set('sessionID', response.session_id);
});
}.observes('documentID'),
actions: {
upload: function() {
this.getDocument();
}
}
});
Here is my node implementation:
var https = require('https');
var requestCount = 0;
exports.doc = function(req, res) {
var docURL = req.body.docURL;
var httpReq;
var opts = {
hostname: 'view-api.box.com',
path: '/1/documents',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Token <my token>' }
};
res.header('Access-Control-Allow-Origin', '*');
httpReq = https.request(opts, function(preq, pres) {
var output = '';
preq.on('data', function(chunk) {
output += chunk;
});
preq.on('end', function() {
output = JSON.parse(output);
output.document_id = output.id;
delete output.id;
res.json(output);
});
});
httpReq.write(JSON.stringify({ "url": docURL }));
httpReq.end();
};
exports.sess = getSession;
function getSession(req, res) {
var docID = req.body.docID;
var httpReq;
var opts = {
hostname: 'view-api.box.com',
path: '/1/sessions',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Token <my token>' }
};
res.header('Access-Control-Allow-Origin', '*');
httpReq = https.request(opts, function(preq, pres) {
var output = '';
if(preq.statusCode === 202) {
setTimeout(function() {
console.log('Retrying Request :: Count(' + requestCount + ')');
if (requestCount >= 3) {
res.json({ 'error': "Retry Again.", 'time': preq.headers['retry-after'] });
return;
}
getSession(req, res);
requestCount += 1;
}, 2000);
return;
}
preq.on('data', function(chunk) {
output += chunk;
});
preq.on('end', function() {
console.log('Successful Request!');
requestCount = 0;
output = JSON.parse(output);
output.session_id = output.id;
delete output.id;
res.json(output);
});
});
httpReq.write(JSON.stringify({ "document_id": docID, "duration": 60 }));
httpReq.end();
}
But now I'm getting this error. Is there a UI that can help me remove the uploaded documents?
{
"message": "You have exceeded your document upload rate-limit.",
"type": "error",
"request_id": "49f8b480b304496987b8cf21f5850c90"
}
You have the correct approach with retry-after for sessions.
The rate limiting you're seeing is actually due to the 2-document rate limit in place for the View API beta. See the FAQ for more info.
You can use webhooks to be notified when your documents finish converting (allowing you to upload another), so you don't have to poll the /documents endpoint for status.
Related
I'm trying to integrate Paytm's Payment gateway [Custom Checkout]. However, while UPI Integration, after sending the request i'm getting Invalid payment mode response code on the callback url.
As suggested in documentation,
First i'm calling the Initiate Transaction API for token.
initialise(order, res, next) {
const paytmParams = {};
paytmParams.body = {
requestType: 'Payment',
mid: paytm.mid,
websiteName: paytm.website,
orderId: order.orderId,
callbackUrl: paytm.callbackUrl,
txnAmount: {
value: order.amount,
currency: 'INR',
},
userInfo: {
custId: order.custId,
},
};
const paytmChecksum = PaytmChecksum.generateSignature(paytmParams.body, paytm.merchantKey);
paytmChecksum.then(function (checksum) {
paytmParams.head = {
signature: checksum,
};
const post_data = JSON.stringify(paytmParams);
const options = {
hostname: paytm.host,
port: 443,
path: `/theia/api/v1/initiateTransaction?mid=${paytm.mid}&orderId=${order.orderId}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length,
},
};
let response = '';
const post_req = https.request(options, function (post_res) {
post_res.on('data', function (chunk) {
response += chunk;
});
post_res.on('end', function () {
const result = JSON.parse(response);
if (result.body.resultInfo.resultStatus === 'S') {
res.status(200).json({ token: result.body.txnToken, orderId: order.orderId });
} else {
next(new ApiError(httpStatus.EXPECTATION_FAILED, result.body.resultInfo.resultMsg));
}
});
});
post_req.write(post_data);
post_req.end();
});
}
After this i'm taking the user's vpa and validating that via Validate VPA API.
validateUpi(data, res, next) {
const paytmParams = {};
paytmParams.body = {
vpa: data.upiId,
};
paytmParams.head = {
tokenType: 'TXN_TOKEN',
token: data.token,
};
const post_data = JSON.stringify(paytmParams);
const options = {
hostname: paytm.host,
port: 443,
path: `/theia/api/v1/vpa/validate?mid=${paytm.mid}&orderId=${data.orderId}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length,
},
};
let response = '';
const post_req = https.request(options, function (post_res) {
post_res.on('data', function (chunk) {
response += chunk;
});
post_res.on('end', function () {
const result = JSON.parse(response);
if (result.body.resultInfo.resultStatus === 'S') {
res.status(200).json({
action: `https://${paytm.host}/theia/api/v1/processTransaction?mid=${paytm.mid}&orderId=${data.orderId}`,
params: {
mid: paytm.mid,
orderId: data.orderId,
txnToken: data.token,
paymentMode: 'UPI',
payerAccount: data.upiId,
},
});
} else {
next(new ApiError(httpStatus.EXPECTATION_FAILED, result.body.resultInfo.resultMsg));
}
});
});
post_req.write(post_data);
post_req.end();
}
After the successfull response, i'm returning the action URL and the params to the front end to create the form and post it in front end.
const res = await paymentAPI.validateUpiId(body);
paymentHelpers.createFormAndSubmit(res.action, res.params, 'redirect');
export const createFormAndSubmit = (url: string, data: any, type = "") => {
const form = document.createElement("form");
form.method = "POST";
form.action = url;
form.type = type;
Object.keys(data).forEach((key) => {
const input = document.createElement("input");
input.type = "text";
input.name = key;
input.value = data[key];
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
};
But after this form is being submitted, i'm getting redirected to callbackUrl with error message
http://localhost:3000/callback/paytm?retryAllowed=false&errorMessage=Invalid%20payment%20mode&errorCode=317
Im trying to upload modfiles with the api but it keeps saying that Im not including filedata. Ive tried with fetch like in the docs but it just gives the same error. If I try http it just gives a list of the files as if it was a GET request.
var zip = `./mod.zip`; // it exists!
var body = {
//filedata: `#${zip}`,
filedata: fs.readFileSync(zip, `binary`),
//filehash: crypto.createHash('md5').update(fs.readFileSync(zip, `binary`)).digest('hex'),
//version: version,
//active: active,
//changelog: changelog,
//metadata_blob: meta,
};
var res = await fetch(`https://api.mod.io/v1/games/${config.modio.gameid}/mods/${config.modio.modid}/files`, { // actually HTTP
method: 'POST',
headers: {
'Authorization': `Bearer ${config.modio.token}`,
'Content-Type': 'multipart/form-data',
'Accept': 'application/json',
},
body: JSON.stringify(body),
});
//console.log(body.filedata);
res = await res.json();
if (res.error)
console.log(res.error);
else
console.log(res);
{
"error": {
"code": 422,
"error_ref": 13009,
"message": "Validation Failed. Please see below to fix invalid input:",
"errors": {
"filedata": "The filedata field is required when upload id is not present.",
"upload_id": "The upload id field is required when filedata is not present."
}
}
}
Yes, ive submitted a bug report to them already, twice. Now they are ghosting me. (I'll probably submit a link to this as well)
They replied!
Hi
As mentioned, you would need to send data using FormData, not JSON.
You can find details at https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
Thanks,
Danny King
Developer Relations Specialist
So, I remade my code
const https = require(`https`);
var crypto = require('crypto');
var FormData = require('form-data');
function ObjectToForm(obj = {}) {
var form = new FormData();
Object.keys(obj).forEach(key => {
var val = obj[key];
switch (typeof val) {
case `boolean`:
val = String(val);
break;
}
form.append(key, val);
});
return form;
}
if (fs.statSync(zip).size > 5368709120) return consolelog(`Zip bigger then 5gb`);
var body = {
filedata: fs.createReadStream(zip),
filehash: crypto.createHash('md5').update(fs.readFileSync(zip)).digest('hex'),
version: version,
active: active,
changelog: changelog,
metadata_blob: meta,
};
var form = ObjectToForm(body);
var options = {
hostname: 'api.mod.io',
port: 443,
path: `/v1/games/${config.modio.gameid}/mods/${config.modio.modid}/files`,
method: 'POST',
headers: {
'Authorization': `Bearer ${config.modio.token}`,
...form.getHeaders(),
'Accept': 'application/json',
},
};
var req = https.request(options, (res) => {
var data = [];
res.on('data', (d) => data.push(d));
req.on(`close`, () => {
var buffer = Buffer.concat(data);
var resp = JSON.parse(buffer.toString());
if (resp.error)
console.log(resp.error);
else if (res.statusCode == 201)
r(true);
});
});
req.on('error', (e) => {
console.log(`Error publishing:`);
console.log(e);
r(e);
});
form.pipe(req)
.on(`close`, () => req.end());
And it worked. Thanks King.
Im using nodejs to make a call to a 3rd party API. My code code returns the correct data for an id that I'm passing in my backend. When I run my app, to retrieve the data I go to localhost:5000/api/Dls.
My code
app.get("/api/Dls", (req, res) => {
const response = {
success: false
};
if (req.user && Authorized.myToken) {
response.success = true;
response.data = {};
response.data.user = req.user;
const id = response.data.user.sub;
var options = {
method: 'GET',
url: 'https://someApi/byId/' + 'id',
headers:
{
Accept: 'application/json',
Authorization: 'Bearer' + ' ' + Authorized.myToken
}
};
request(options, function (error, response, body){
if (error) {
console.log(error);
return;
}
const data = response.body;
const userDls = JSON.parse(data)
return res.json(userDls);
});
}
});
Now I'm trying to do something like this localhost:5000/api/Dls/1234 instead of using a hard coded id in the backend
I attempted doing the following but when I enter a valid id in the url (ex. localhost:5000/api/Dls/1234) I get this "", any idea to what I should be doing?
app.get("/api/Dls/:id", (req, res) => {
const response = {
success: false
};
if (Authorized.myToken) {
response.success = true;
var options = {
method: 'GET',
url: 'https://someApi/byId/',
headers:
{
Accept: 'application/json',
Authorization: 'Bearer' + ' ' + Authorized.myToken
}
};
request(options, function (error, response, body){
if (error) {
console.log(error);
return;
}
const data = response.body;
const userDls = JSON.parse(data)
return res.json(userDls);
});
}
});
Any feedback would be appreciated!
You are not passing the route id to the api.
response.success = true;
var options = {
method: 'GET',
url: 'https://someApi/byId/' + req.params.id,
headers:{
Accept: 'application/json',
Authorization: 'Bearer' + ' ' + Authorized.myToken
}
};
i try to execute a http.request POST and my data are passed to FormValue and not in Body.
It's my first experiment in Node.js http calls so I apologize if the question is trivial.
I passed the call to a servere and i got the data at the end of the code.
function doHttpApiCall(session,callback) {
var http = require('http');
var isEndedOk;
var outValue = '';
var postData = JSON.stringify({
grant_type: 'client_credentials',
scope: 'OOB',
my_id: 'my_id_value'
});
var postOptions = {
host: 'dummyapisite.com',
path: '/t/litf9-1571295453/post',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
// Set up the request
var post_req = http.request(postOptions, function(res) {
var statusCode = res.statusCode;
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = rawData;
if (error) {
isEndedOk = false;
console.error(error.message);
console.error('Response Content=' + String(parsedData));
res.resume();
} else {
isEndedOk = true;
console.log('Response Content=' + String(parsedData));
}
callback(session.attributes,
callBack_doHttpApiCall(outValue, statusCode, session, callback, isEndedOk));
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
post_req.write(postData);
post_req.end();
}
this is the result got by the server and the data are not in the right place.
{
"Timestamp":"2019-10-17T13:53:52.941575Z",
"Method":"POST",
"RemoteAddr":"34.245.148.80",
"ID":390940052,
"Headers":{
"Content-Length":[
"118"
],
"Content-Type":[
"application/x-www-form-urlencoded"
],
"Host":[
"ptsv2.com"
],
"X-Cloud-Trace-Context":[
"deff20a349bfb409fab118aa361ebc54/925376340939905763"
],
"X-Google-Apps-Metadata":[
"domain=gmail.com,host=dummyapisite.com"
]
},
"FormValues":{
"{\"body\":[{\"grant_type\":\"client_credentials\",\"scope\":\"OOB\",\"my_id\":\"my_id_value\"}]}":[
""
]
},
"Body":"",
"Files":null,
"MultipartValues":null
}
The problem is that you're sending a JSON body, but the Content-Type you're sending is: application/x-www-form-urlencoded, so change it to application/json
The server you're posting to, is putting the value in FormValues because you're telling them that you're sending a form (x-www-form-urlencoded)
var postOptions = {
host: 'dummyapisite.com',
path: '/t/litf9-1571295453/post',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': postData.length
}
};
I am receiving http POST response OK 200, but I see no file present on JIRA issue. From my research I can understand that it could be some problem with formData I am sending with request. Below is my code:
var newBuffer = new Buffer(req.Payload, 'base64');
var myReadableStreamBuffer = new streamBuffers.ReadableStreamBuffer({
frequency: 10, // in milliseconds.
chunkSize: 2048 // in bytes.
});
// With a buffer
myReadableStreamBuffer.put(newBuffer);
var formData = {
'file': {
'content': myReadableStreamBuffer,
'filename': req.FileName,
'mimeType': req.MimeType //mimeType from JSON
}
};
var options = {
url: 'https://comapny.atlassian.net/rest/api/2/issue/' + req.ReferenceId + '/attachments',
method: "POST",
json: true,
headers: {
'ContentType': 'multipart/form-data',
'Authorization': 'Basic ' + new Buffer(config.jira.jiraUser.userName + ':' + config.jira.jiraUser.password).toString('base64'),
'X-Atlassian-Token': 'nocheck'
},
formData: JSON.stringify(formData)
};
request(options,
function (error, response, body) {
if (error) {
errorlog.error(`Error Message : PostAttachmentToCSMS : ${error}`);
return response.statusCode;
}
else {
successlog.info(`Attachment posted for issue Key: ${req.ReferenceId} ${response.statusMessage}`);
return response.statusCode;
}
});
I can write file from myReadableStreamBuffer, so that seems ok. Please help me to identify the problem. Many thanks!
After spending some more time on it, I have found the correct format for formData:
var newBuffer = new Buffer(req.Payload, 'base64');
var formData = {
file: {
value: newBuffer,
options: {
filename: req.FileName,
contentType: req.MimeType
}
}
};
For whom like me getting errors with this API.
After struggling so many hrs on this thing, I finally found this works like a charm. I've got "XSRF check failed" 403/404 error message before writing this code.
// Don't change the structure of formData.
const formData = {
file: {
value: fs.createReadStream(filepath),
options: {
filename: filename,
contentType: "multipart/form-data"
}
}
};
const header = {
"Authentication": "Basic xxx",
// ** IMPORTANT **
// "Use of the 'nocheck' value for X-Atlassian-Token
// has been deprecated since rest 3.0.0.
// Please use a value of 'no-check' instead."
"X-Atlassian-Token": "no-check",
"Content-Type": "multipart/form-data"
}
const options = {
url: "http://[your_jira_server]/rest/api/2/issue/[issueId]/attachments",
headers: header,
method: "POST",
formData: formData
};
const req = request(options, function(err, httpResponse, body) {
whatever_you_want;
};
I was able to post attachments to JIRA using axios in the following way:
const axios = require('axios');
const FormData = require('form-data')
const fs = require('fs');
const url = 'http://[your_jira_server]/rest/api/2/issue/[issueId]/attachments';
let data = new FormData();
data.append('file', fs.createReadStream('put image path here'));
var config = {
method: 'post',
url: url,
headers: {
'X-Atlassian-Token': 'no-check',
'Authorization': 'Basic',
...data.getHeaders()
},
data: data,
auth: {
username: '',
password: ''
}
};
axios(config)
.then(function (response) {
res.send({
JSON.stringify(response.data, 0, 2)
});
})
.catch(function (error) {
console.log(error);
});