How to post data using node-http-ntlm? - node.js

I am trying to figure out how to actually post data using this node module:
https://github.com/SamDecrock/node-http-ntlm
It looks like posting should be similar to:
https://github.com/SamDecrock/node-httpreq#post
But the documentation for httpreq doesnt actually show POSTing a value, I only see parameters or how to POST an entire file. Im using node and have something along these lines:
NodeClient.prototype.create = function (xml) {
var options = {
url: this.url,
username: this.user,
password: this.pw,
domain: this.domain,
headers: {
'Content-type': 'text/plain'
}
};
return new Promise(function (resolve, reject) {
httpntlm.post(options,
function (err, resp) {
if(err) {
reject(err);
}
resolve(resp.body);
});
});
};
Obviously I never send my xml object, so I need to figure out how to include this. Reading the documentation hasnt lead me anywhere to this point.

You can POST xml like this:
var httpntlm = require('httpntlm');
var xml = '<?xml version="1.0" encoding="UTF-8"?>'; // replace this with your xml
httpntlm.post({
url: "https://someurl.com",
username: 'm$',
password: 'stinks',
workstation: 'choose.something',
domain: '',
body: xml,
headers: { 'Content-Type': 'text/xml' }
}, function (err, res){
if(err) return err;
console.log(res.headers);
console.log(res.body);
});

To add content to the post, you can include the following options:
json: if you want to send json directly (content-type is set to application/json)
files: an object of files to upload (content-type is set to multipart/form-data; boundary=xxx)
body: custom body content you want to send. If used, previous options will be ignored and your custom body will be sent. (content-type will not be set)

Related

Is there way to specify local file system path in nodeJS POST API request , am able to make api call using curl but not with nodejs

Following curl API is successfully deploying .zip file from the local file system into the Azure Function APP.
curl -X POST -u user123:P#ssword --data-binary #"C:\Ddrive\Porject\deploy-zip\wb-uc-code.zip" "https://abc-world.scm.azurewebsites.net/api/zipdeploy"
But I wanna achieve the same with NodeJs: So I converted it as -
function () {
var dataString = "#C:\Ddrive\Workbench\deploy-zip\wb-uc1.zip";
var options = {
url: 'https://abc-world.scm.azurewebsites.net/api/zipdeploy',
method: 'POST',
body: dataString,
auth: {
'user': 'user123',
'pass': 'P#ssword'
}
};
request.post(options, (response, error) => {
if (error) {
console.log("error");
}
else {
console.log(response.body);
}
})
}
while executing am getting error:
------->>>
Most Probably I think am unable to provide file-path appropriately in Options. Can someone help with this?
There are two things you need to pay attention to.
1.You should pass data-binary, you were passing path string in your code.
2.The order of response and error is reversed.
Please refer to the working code as below.
var request=require('request')
var fs = require("fs")
var dataString=fs.createReadStream("D:\\testProject\\NodeJs\\nodejs-docs-hello-world\\test4.zip");
var options = {
url: 'https://tonytestwebnode.scm.azurewebsites.net/api/zipdeploy',
method: 'POST',
body: dataString,
auth: {
'user': 'tonytestweb',
'pass': 'XXXX!'
}
};
request.post(options, (error, response) => {
console.log(response.statusCode);
})

Problem setting the name of a file when using the Google Drive REST API for resumable uploads

async function createResumableSession(filePath, authClient){
try {
const fileStats = await statsAsync(filePath);
const fileSize = fileStats.size;
const postResult = await new Promise((resolve, reject)=>{
request({
method: 'post',
url: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable',
followAllRedirects: true,
headers: {
Authorization: "Bearer " + authClient.credentials.access_token,
"X-Upload-Content-Length": `${fileSize}`,
"Content-Length": "0",
"Content-Type": "application/json; charset=UTF-8"
},
body:JSON.stringify({
title: "myfile.backup"
})
}, function (error, response) {
if (error)
return reject(error);
resolve({
statusCode: response.statusCode,
location: response.headers.location,
body: response.body
});
})
})
return {
postResult,
fileSize
}
} catch (error) {
throw error;
}
}
I have this function to create a resumable upload on the Google Drive API, its creating the session correctly but I cant set the file name, after the upload is completed the file name always end as "untitled"
How about this modification?
Modification points:
In your script, from the endpoint of https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable, it is found that you are using Drive API v3. In this case, in order to set the filename, it is required to use the property of name. In your script, title is used. In this case, it is for Drive API v2. So please modify as follows.
Modified script:
Please modify your script as follows.
From:
title: "myfile.backup"
To:
name: "myfile.backup"
Reference:
Files: create
If this was not the direct solution of your issue, I apologize.
Added:
As a simple sample script, I added a sample script. In this sample script, a text file is uploaded using the resumable upload. In this case, the file is uploaded as the filename of "sample". And you can see the text of foo in the uploaded file.
Sample script:
const request = require('request');
const accessToken = "###"; // Please set your access token.
request({
method: 'POST',
url: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable',
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify({name: "sample", mimeType: "text/plain"})
}, (err, res) => {
if (err) {
console.log(err);
return;
}
request({
method: 'PUT',
url: res.headers.location,
headers: {"Content-Range": "bytes 0-2/3"},
body: Buffer.from("foo")
}, (err, res) => {
if (err) {
console.log(err);
return;
}
console.log(res.statusCode)
console.log(res.body)
});
});
Using the property of name, the metadata of file has the filename of sample.
But unfortunately, from your replying, I cannot understand about your current issue. So can I ask you about the detail information about the problem persists? And in order to correctly understand about your situation, can you provide the detail flow and whole script for replicating your issue? Of course, please remove your personal information. By this, I would like to confirm it. If you can cooperate to resolve your issue, I'm glad.

New to Typescript & Angular problems with Http Post

I'm new to Angular and Typescript and I try to create a simple login page. I've created a service in typescript which is invoked when the user presses the 'Login' button. The textboxes which contains the username and password is bound correctly to the model, but when I send the request to my backend written in C#, it will not hit the breakpoint which I suspect is because of the format of the message being sent on the wire.
So using PostMan, I'm able to invoke the service and get back an access_token When exporting the request to code in PostMan this is what the NodeJS variant look like:
var request = require("request");
var options = { method: 'POST',
url: 'http://localhost:8081/login',
headers:
{ 'postman-token': '34dd4d0f-ff16-db4f-ebae-dab945729410',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded' },
form: { username: 'test', password: 'test', grant_type: 'password' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
And this is my Typescript code
login(userName: string, password:string) : Observable<boolean> {
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded')
var content = JSON.stringify({
username: userName,
password: password,
grant_type: this.grant_type
});
return this.http.post(this.authenticationEndpoint, content, {headers: headers})
.map((response:Response) => {
let token = response.json() && response.json().token;
if(token){
//this.token = token;
localStorage.setItem('user', JSON.stringify({userName: userName, token:token}));
return true;
}
return false;
});
}
This results in an error in Visual Studio Code, which says:
I'm not really sure how I should interpret this error message, but since the method in my webservice is not invoked I'm pretty sure that it has something to do with the HTTP headers or the format of the Http Post.. Any ideas?
Using URLSearchParams as the body of the request and angular will automatically set the content type to application/x-www-form-urlencoded
import { URLSearchParams } from "#angular/http"
let body = new URLSearchParams();
body.set('username', username);
body.set('password', password);
.....
this.http.post(this.authenticationEndpoint, body).map(..)

In node-soap, how can I see/debug the generated XML SOAP request?

I try to use the node-soap module like this:
const soap = require('soap');
soap.createClient('some-wsdl-url', function(err, client) {
const args = {
'ValidateCustomerRequest': {
'memberNumber': 12345
}
};
client.ValidateCustomer(args, function(err, result) {
console.log(result);
});
});
Now I get an "invalid format" response from the webservice. To debug this I would very much like to see what the actual XML looks like that is sent to the webservice.
I already tried this one:
require('request').debug = true
... which was suggestes in another SO answer.
But the output is not that helpful:
[ERROR] REQUEST { uri:
Url { ... },
method: 'GET',
headers:
{ 'User-Agent': 'node-soap/0.18.0',
Accept: 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'none',
'Accept-Charset': 'utf-8',
Connection: 'close',
Host: 'xxx' },
followAllRedirects: true,
body: null,
callback: [Function] }
I don't see my "ValidateCustomerRequest" in there and body is null. Also I'm wondering why method is GET, shouldn't that be POST?
So does this debug output looks normal and/or is there another way to see the created XML request?
I overlooked this bit of the documentation:
Client.lastRequest - the property that contains last full soap request for client logging
You can log this within the callback of the webservice call. So above code will look like this:
const soap = require('soap');
soap.createClient('some-wsdl-url', function(err, client) {
const args = {
'ValidateCustomerRequest': {
'memberNumber': 12345
}
};
client.ValidateCustomer(args, function(err, result) {
console.log(result);
console.log('last request: ', client.lastRequest) // <-- here
});
});
This will output the generated XML request.

Uploading file using POST request in Node.js

I have problem uploading file using POST request in Node.js. I have to use request module to accomplish that (no external npms). Server needs it to be multipart request with the file field containing file's data. What seems to be easy it's pretty hard to do in Node.js without using any external module.
I've tried using this example but without success:
request.post({
uri: url,
method: 'POST',
multipart: [{
body: '<FILE_DATA>'
}]
}, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
Looks like you're already using request module.
in this case all you need to post multipart/form-data is to use its form feature:
var req = request.post(url, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
var form = req.form();
form.append('file', '<FILE_DATA>', {
filename: 'myfile.txt',
contentType: 'text/plain'
});
but if you want to post some existing file from your file system, then you may simply pass it as a readable stream:
form.append('file', fs.createReadStream(filepath));
request will extract all related metadata by itself.
For more information on posting multipart/form-data see node-form-data module, which is internally used by request.
An undocumented feature of the formData field that request implements is the ability to pass options to the form-data module it uses:
request({
url: 'http://example.com',
method: 'POST',
formData: {
'regularField': 'someValue',
'regularFile': someFileStream,
'customBufferFile': {
value: fileBufferData,
options: {
filename: 'myfile.bin'
}
}
}
}, handleResponse);
This is useful if you need to avoid calling requestObj.form() but need to upload a buffer as a file. The form-data module also accepts contentType (the MIME type) and knownLength options.
This change was added in October 2014 (so 2 months after this question was asked), so it should be safe to use now (in 2017+). This equates to version v2.46.0 or above of request.
Leonid Beschastny's answer works but I also had to convert ArrayBuffer to Buffer that is used in the Node's request module. After uploading file to the server I had it in the same format that comes from the HTML5 FileAPI (I'm using Meteor). Full code below - maybe it will be helpful for others.
function toBuffer(ab) {
var buffer = new Buffer(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buffer.length; ++i) {
buffer[i] = view[i];
}
return buffer;
}
var req = request.post(url, function (err, resp, body) {
if (err) {
console.log('Error!');
} else {
console.log('URL: ' + body);
}
});
var form = req.form();
form.append('file', toBuffer(file.data), {
filename: file.name,
contentType: file.type
});
You can also use the "custom options" support from the request library. This format allows you to create a multi-part form upload, but with a combined entry for both the file and extra form information, like filename or content-type. I have found that some libraries expect to receive file uploads using this format, specifically libraries like multer.
This approach is officially documented in the forms section of the request docs - https://github.com/request/request#forms
//toUpload is the name of the input file: <input type="file" name="toUpload">
let fileToUpload = req.file;
let formData = {
toUpload: {
value: fs.createReadStream(path.join(__dirname, '..', '..','upload', fileToUpload.filename)),
options: {
filename: fileToUpload.originalname,
contentType: fileToUpload.mimeType
}
}
};
let options = {
url: url,
method: 'POST',
formData: formData
}
request(options, function (err, resp, body) {
if (err)
cb(err);
if (!err && resp.statusCode == 200) {
cb(null, body);
}
});
I did it like this:
// Open file as a readable stream
const fileStream = fs.createReadStream('./my-file.ext');
const form = new FormData();
// Pass file stream directly to form
form.append('my file', fileStream, 'my-file.ext');
const remoteReq = request({
method: 'POST',
uri: 'http://host.com/api/upload',
headers: {
'Authorization': 'Bearer ' + req.query.token,
'Content-Type': req.headers['content-type'] || 'multipart/form-data;'
}
})
req.pipe(remoteReq);
remoteReq.pipe(res);

Resources