I'm trying to test out my API using FrisbyJS (which sits on top of Jasmine for Node). I was wondering if anyone knew how to submit/send an image using Jasmine?
http://frisbyjs.com/
My current code is...
var frisby = require('frisby');
var URL = 'http://localhost/api';
frisby.globalSetup({
request: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'api': 'key'
}
},
timeout: (30 * 1000)
});
frisby.create('submit an image')
.post(URL + 'image', {images: '#test.jpg'}, {method: 'POST'})
.expectStatus(200)
.afterJSON(function(cart){
console.log('made it!');
})
}).toss();
And I get the following error:
1) Frisby Test: submit an image
[ POST http://localhost/api ]
Message:
timeout: timed out after 30000 msec waiting for HTTP Request timed out before completing
Stacktrace:
undefined
Finished in 31.458 seconds
And yes, the image test.jpg does exist in the same folder :) as the spec file and where I'm executing the spec itself (jasmine-node .).
I found a solution based on the example given at https://github.com/vlucas/frisby/blob/master/examples/httpbin_multipart_spec.js
var frisby = require('frisby');
var fs = require('fs');
var path = require('path');
var FormData = require('form-data');
var contentPath = path.resolve(__dirname, './path/to/image.jpg');
var form = new FormData();
form.append('file', fs.createReadStream(contentPath), {
knownLength: fs.statSync(contentPath).size
});
frisby.create('Create content asset')
.post(apiPath + '/assets', form, {
json: false,
headers: {
'content-type': 'multipart/form-data; boundary=' + form.getBoundary(),
'content-length': form.getLengthSync(),
}
})
.expectStatus(201)
.toss()
Related
i'm trying to upload my files as form-data, after i've created a scene. But I receive always the error "Specified Photoscene ID doesn't exist in the database" (which were created directly before).
My upload function:
// Upload Files
async function uploadFiles(access_Token, photoSceneId, files) {
try {
const params = new URLSearchParams({
'photosceneid': photoSceneId,
'type': 'image',
'file': files
})
const headers = Object.assign({
Authorization: 'Bearer ' + access_Token,
'Content-Type': 'multipart/form-data' },
files.getHeaders()
)
let resp = await axios({
method: 'POST',
url: 'https://developer.api.autodesk.com/photo-to-3d/v1/file',
headers: headers,
data: params
})
let data = resp.data;
return data;
} catch (e) {
console.log(e);
}
};
I've also tried a few varaints, e.g. adding the photosceneId to the form data (form.append(..), but doesn't works either.
Any helpful suggestion are appreciated. Thx in advance.
There might be two problems here.
First, I am not sure of it, as I don't have experience of URLSearchParams as a "packer" for POST requests. This might be the reason why you get "Specified Photoscene ID doesn't exist in the database" error - perhaps the way the data are serialized using URLSearchParams is not compatible.
The second problem, I am sure of it, is regarding the way you submit the files.
According to documentation, you have to pass the files one by one, like
"file[0]=http://www.autodesk.com/_MG_9026.jpg" \
"file[1]=http://www.autodesk.com/_MG_9027.jpg"
and not just passing an array to the "file" field.
Having this said, try this approach:
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
var TOKEN = 'some TOKEN';
const photoSceneID = 'some_photoscene_id';
data.append('photosceneid', photoSceneID);
data.append('type', 'image');
data.append('file[0]', fs.createReadStream('/C:/TEMP/Example/DSC_5427.JPG'));
data.append('file[1]', fs.createReadStream('/C:/TEMP/Example/DSC_5428.JPG'));
data.append('file[2]', fs.createReadStream('... and so on ...'));
var config = {
method: 'post',
url: 'https://developer.api.autodesk.com/photo-to-3d/v1/file',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + TOKEN,
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Also, I always recommend instead of jumping right into the code, to check first the workflow using apps like Postman or Insomnia and then, after you validated the workflow (created the photoscene, all images were properly uploaded and so on), you can translate this into the code.
At the end of this blogpost you will find the link to alrady created Postman collection, but I highly recommend building your own collection, as part of the learning step.
This is the solution that worked for me. Please note that the upload should be limited by a maximum of 20 files per call.
// Upload Files
async function uploadFiles(access_Token, photoSceneId) {
try {
let dataPath = path.join(__dirname, '../../data')
let files = fs.readdirSync(dataPath)
var data = new FormData();
data.append('photosceneid', photoSceneId)
data.append('type', 'image')
for(let i=0; i < files.length; i++) {
let filePath = path.join(dataPath, files[i])
let fileName = 'file[' + i + ']'
data.append(fileName, fs.createReadStream(filePath))
}
const headers = Object.assign({
Authorization: 'Bearer ' + access_Token,
'Content-Type': 'multipart/form-data;boundary=' + data.getBoundary()},
data.getHeaders()
)
let resp = await axios({
method: 'POST',
url: 'https://developer.api.autodesk.com/photo-to-3d/v1/file',
headers: headers,
maxContentLength: Infinity,
maxBodyLength: Infinity,
data: data
})
let dataResp = resp.data;
return dataResp;
} catch (e) {
console.log(e);
}
};
I'm using the stream-to-promise npm module to create the multipart/form-data payload in my jasmine test. My payload includes an image file as a buffer but when the payload is put through stream-to-promise it changes or corrupts my original image buffer in the payload somehow and so my tests are failing. Is there a way to prevent this?
it('test /identity-verification/your-first-form-of-id POST with validation passing', function(done){
var form = new FormData();
var image = fs.createReadStream("image.png");
streamToBuffer(image, function (err, buffer) {
form.append('firstID', 'passport');
form.append('firstIDImage', buffer);
var headers = form.getHeaders();
streamToPromise(form).then(function(payload) {
var options = {
method: 'POST',
url: '/identity-verification/your-first-form-of-id',
payload: payload,
headers: headers
};
server.inject(options, function(response) {
expect(response.statusCode).toBe(302);
expect(response.headers.location).toMatch('/identity-verification/your-first-form-of-id/upload-successful');
done();
});
});
});
});
The buffer in the payload after being put through stream-to-promise looks like this:
You don't need stream-to-buffer. You've already got the buffer from createReadStream. If you get rid of that, it should work. One thing to be careful of is that your maxBytes is set high enough to accomodate your test image. This was causing some cryptic errors when I was testing.
The code below is working fine for me.
var streamToPromise = require("stream-to-promise");
var FormData = require("form-data");
var fileTypeModule = require("file-type");
var fs = require("fs");
var q = require("q");
var Hapi = require('hapi');
var server = new Hapi.Server({ debug: { request: ['error'] } });
server.connection({
host: 'localhost',
port: 8000
});
server.route({
method: 'POST',
path: '/test',
handler: function(request, reply) {
var data = request.payload.firstIDImage;
var fileType = fileTypeModule(data);
reply(fileType);
},
config: {
payload: { maxBytes: 1048576 }
}
});
var start = server.start();
var form = new FormData();
var headers = form.getHeaders();
form.append('firstID', 'passport');
form.append('firstIDImage', fs.createReadStream("image.png"));
var append = streamToPromise(form);
q.all([start, append]).then((results) => {
var options = {
method: 'POST',
url: '/test',
payload: results[1],
headers: headers
};
server.inject(options, function(response) {
console.log(response.payload);
});
});
Who knows what did I wrong in implementing this on a Node.js server?
The parameter were valid and it worked with the Poster on my local Mac.
Node.js and MFP 8 Beta are running locally on the Mac.
Here is the code for the server.js file and the steps are:
prepare the header
MFP Settings
create post options
create the JSON object for MFP Push
Do the POST call using http
write the json Push Data
app.post('/award', function(req, res){
var notificationMessage = req.body.message;
// prepare the header
// MFP Settings
var theAuthorization = "Bearer eyJhbGciOiJSUzI1NiIsImp…….Wg";
var appname = 'com.ionicframework.checkapp';
var http = require('http');
var theHost = 'localhost'; // here only the domain name
var thePort = 9080;
var thePath = 'imfpush/v1/apps/' + appname + '/messages';
var theMethode = 'POST';
var postheaders = {
'Authorization' : theAuthorization ,
'Content-Type' : 'application/json'
};
// the post options
var optionspost = {
host : theHost,
port : thePort,
path : thePath,
method : theMethode,
headers : postheaders
};
// create the JSON object for MFP Push
var jsonObject = JSON.stringify({"message":{"alert" :notificationMessage}});
console.info('---> Options prepared:');
console.info(optionspost);
console.info('---> Do the POST call');
// do the POST call using http
var reqPost = http.request(optionspost, function(res) {
console.log("---> statusCode: ", res.statusCode);
console.log("---> headers: ", res.headers);
res.on('data', function(d) {
console.info('---> POST result:\n');
process.stdout.write(d);
console.info('\n\n---> POST completed');
});
});
// write the json Push Data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
res.end("OK");
});
I get the statusCode:400 and this is console output:
Options prepared:
{ host: 'localhost',
port: 9080,
path: 'imfpush/v1/apps/com.ionicframework.checkapp/messages',
method: 'POST',
headers:
{ 'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJSUzI1NiIsImp3ayI6......DjbgjqVz5JFVcT8i5k_JWg' } }
---> Do the POST call
---> statusCode: 400
---> headers: { 'content-length': '0',
connection: 'Close',
date: 'Wed, 22 Jun 2016 12:02:50 GMT' }
These were my information sources:
https://isolasoftware.it/2012/05/28/call-rest-api-with-node-js/ and
https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/notifications/sending-push-notifications/
Thanks #Idan for the text validation and #Nathan for the comment.
I found the problem and now it works.
I changed the order of the request preparation and some changes in the code.
prepare the header
MFP Settings
create the JSON object for MFP Push -> Moved UP
create post options -> Moved Down
Do the POST call using http
write the json Push Data
Code changes:
Insert 'Content-Length': Buffer.byteLength(jsonObject) inside the header.
Adding a slash to the path var thePath = '/imfpush/v1/apps/' + appname + '/messages';
I am trying to automatically post some assets on a Github release I programmatically create.
Here is my upload function:
function uploadFile(fileName, uploadUrl, callback){
var uploadEndPoint = url.parse(uploadUrl.substring(0,uploadUrl.indexOf('{')));
options.host = uploadEndPoint.hostname;
options.path = uploadEndPoint.pathname+'?name=' + fileName;
options.method = 'POST';
options.headers['content-type'] = 'application/zip';
var uploadRequest = https.request(options, callback);
uploadRequest.on('error', function(e) {
console.log('release.js - problem with uploadRequest request: ' + e.message);
});
var readStream = fs.ReadStream(path.resolve(__dirname,'builds',fileName));
readStream.pipe(uploadRequest);
readStream.on('close', function () {
req.end();
console.log('release.js - ' + fileName + ' sent to the server');
});
}
At the end of this I get a 404 not found
I tried auth from token and user/password
I checked the url
I though it might be because of SNI, but I don't know how to check that.
Any clue ? Thanks !
I found a solution to that problem by NOT using the low level node.js modules and using instead restler which is a library that handles SNI.
Here is how is used it:
rest = require('restler'),
path = require('path'),
fs = require('fs');
fs.stat(path.resolve(__dirname,'builds',fileName), function(err, stats){
rest.post(uploadEndPoint.href+'?name=' + fileName, {
multipart: true,
username: GITHUB_OAUTH_TOKEN,
password: '',
data: rest.file(path.resolve(__dirname,'builds',fileName), null, stats.size, null, 'application/zip')
}).on('complete', callback);
});
Hope that will help someone :)
EDIT on 27/02/2015: We recently switched from restler to request.
var
request = require('request'),
fs = require('fs');
var stats = fs.statSync(filePath);
var options = {
url: upload_url.replace('{?name}', ''),
port: 443,
auth: {
pass: 'x-oauth-basic',
user: GITHUB_OAUTH_TOKEN
},
json:true,
headers: {
'User-Agent': 'Release-Agent',
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/zip',
'Content-Length': stats.size
},
qs: {
name: assetName
}
};
// Better as a stream
fs.createReadStream(filePath).pipe(request.post(options, function(err, res){
// Do whatever you will like with the result
}));
The upload_uri can be retrieved through a get request on an existing release or in the response directly after the release creation.
I am trying to post a task in asana with the following node/express function
exports.addTask = function(req, res) {
var url ='/api/1.0/tasks?workspace=' + req.session.workspace_id
var postBase = "app.asana.com";
var options = {
host: postBase,
port: 443,
path: url,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + JSON.parse(req.session.user).access_token,
}
};
var req2 = https.request(options, function(res2) {
res2.on('data', function(chunk) {
console.log(chunk + "");
});
res2.on('error', function(e){
console.log(e.message);
});
});
req2.end();
}
I get the correct response back from asana which is:
{"data":{"id":8253508011735,"created_at":"2013-10-20T16:17:53.140Z","modified_at":"2013-10-20T16:17:53.140Z","name":"","notes":"","completed":false,"assignee_status":"upcoming","completed_at":null,"due_on":null,"workspace":{"id":1361701377437,"name":"getspur.com"},"assignee":null,"parent":null,"followers":[{"id":1050147548705,"name":"Gorkem Yurtseven"}],"projects":[],"tags":[]}}
but nothing seems to be added in my asana tasks..
ps. I am currently at the Facebook Hackathon in New York,so bring it on!
It could be because the assignee is null, and it's not in any projects - that basically makes it impossible to find (except perhaps via Search?)
Without seeing the post body I'm not sure if that's intentional or just a formatting issue.