Testing express app with mocha - node.js

I have the following request that I need to test:
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"content":{"value":"18.5", "date": "20120413"}}' 'http://SERVER:PORT/marks'
I'm using expressjs and mocha. I did not find the way to add some header and specify some json parameters in a mocha's request:
it('Checks creation of a new mark', function(done){
request.post('http://SERVER:PORT/marks', function(err, response, body){
// Some headers and parameters should be set in the request
response.statusCode.should.equal(201);
done();
});
});
The test below (GET request) works well though:
it('Checks existence of marks for user dummyuser', function(done){
request.get('http://SERVER:PORT/user/dummyuser/marks', function(err, response, body){
response.statusCode.should.equal(200);
done();
});
});
UPDATE
The following works like a charm: (I though request what some kind of variable created by mocha).
request(
{ method: 'POST'
, uri: 'http://SERVER:PORT/marks'
, headers: { 'content-type': 'application/json' , 'accept': 'application/json' }
, json: { "content":{"value":"18,5", "date": "2012-04-13"} }
}
, function(err, response, body){
response.statusCode.should.equal(201);
done();
});

Take a look at the documentation. There is a great explaination of how to do a post with custom headers. One way of doing it which works for me could be the following.
var options = {
host: 'localhost',
port: 80,
path: '/echo/200',
method: 'POST',
headers: {
"X-Terminal-Id" : terminalId
}
};
var data = ""
var req = https.request(options, function(res) {
res.on('data', function(d) {
data += d;
});
res.on('end', function(err){
//Check that data is as expected
done(null, data)
})
});
req.end();
req.on('error', function(err) {}
done(err)
});

Related

nodejs request post large json fail

I am trying to post large json to a http server(a grafana server actually):
here is my code:
const http = require('http')
const request = require('request')
const fs = require('fs')
const opts = {
hostname: 'myip',
port: 3000,
path: '/api/dashboards/uid/KPEiIQVWk',
method: 'GET',
timeout: 5000,
headers : {
'Authorization' : 'Bearer ********************************************',
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
}
const req = http.request(opts, res => {
console.log(`Fetch: statusCode: ${res.statusCode}`)
var origin = ''
res.on('data', d => {
origin += d
})
res.on('end', function(){
dash = JSON.parse(origin)
dash.dashboard.panels.forEach(p => {
if(p.id == 26){
fs.readFile(__dirname + '/grafana/pm/branch-graph.html','utf-8', function(err, newPanel){
if(err){
console.log(err)
}
p.content = newPanel
const fresh = JSON.stringify(dash)
const updateOptions = {
uri: 'http://myip:3000/api/dashboards/db',
method: 'post',
headers : {
'Authorization' : 'Bearer *************************',
'Accept' : 'application/json',
'Content-Type' : 'application/json',
'Content-length' : fresh.length
},
json: fresh
}
fs.writeFile('tmp.json', fresh, function(err){
if(err){
console.error(err)
}
})
request(updateOptions, function(error, response, body){
console.log(`update: statusCode=${response.statusCode}`)
console.log(`update: ${body}`)
})
})
}
})
})
})
req.on('error', error => {
console.error(error)
})
req.on('timeout', () => {
req.abort()
})
req.end()
as you can see, I first fetch a grafana dashboard's source, then make some udpate, then post it back to grafana server. but always get 400 error. The strange thing is that if I dump the json to a file and use curl to post, it will work.
curl -vH "Authorization: Bearer $TOKEN" -H "Expect:" -d #tmp.json -H "Content-Type:application/json" http://myip:3000/api/dashboards/db
the whole json is about 40000+ bytes. any hint on this? I am not very famillar with nodejs. I am just trying to write some CI scripts.
First, I don't think it's necessary to use both the http and request modules. http is a module built into nodejs, and request is an npm package.
I recommend you use the npm request package because it's easier. You can read its documentation here: https://www.npmjs.com/package/request#http-authentication
Second, the options you're passing to the request module is not formatted correctly, I think this is why it is not working. With your current code, I would console.log('POST error', error); to print out the error. The correct options for the request module is proposed below.
const options = {
url: 'https://myip:3000/api/dashboards/db',
body: fresh, // the json from the fs.read callback
auth: {
'bearer': 'bearerToken'
},
json: true // from docs: If json is true, then body must be a JSON-serializable object.
}
request.post(
options,
(err, httpResponse, body) => {
console.log(err, body);
});

what is the nodejs code for this curl command

I can successfully execute this curl command from a Unix shell script and I can see output in C:\Users\OutputFile.csv. What is the equivalent code in NodeJS
curl -k -v --user 'helloworld:hello_password'
--header 'Accept: application/vnd.myDMS-dms-api+json; version=1'
-X POST 'https://DMS.com:3001/download/csv'
--data header=true -o C:\Users\OutputFile.csv
I tried using the Online curl to nodeJS converter and it has generated the following NodeJs code:-
var request = require('request');
var headers = {
'Accept': 'application/vnd.myDMS-dms-api+json; version=1'
};
var options = {
url: 'https://DMS.com:3001/download/csv',
method: 'POST',
headers: headers,
auth: {
'user': 'helloworld',
'pass': 'hello_password'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
request(options, callback);
However, when I run this NodeJS code it does not show any output. Also how can I get this output to C:\Users\OutputFile.csv
Maybe the response isn't return before the script is terminated. You would want the request to be asynchronous:
You can use request-promise
Here's an example
var rp = require('request-promise');
function someFunction() {
let options = {
url: `someURL`,
method: 'POST',
body: {
some: 'payload'
},
json: true
};
return rp(options);
}
This will await the response.
A simple version of your API parameters using request-promise:
var rp = require('request-promise');
function downloadFile() {
var options = {
uri: 'https://DMS.com:3001/download/csv',
method: 'POST',
auth: {
user: 'helloworld',
pass: 'hello_password',
sendImmediately: true
},
headers: {
Accept:'application/vnd.myDMS-dms-api+json; version=1'
},
form: {
'header': 'true'
}
};
rp(options)
.then(function (body) {
console.log('Downloaded body was %d long', repos.length);
})
.catch(function (err) {
console.log(err)
});
}
downloadFile()

Query ElasticSearch on Node.js with HTTP module Ignores Request Body

StackOverflow community. I've started to play with ES and Node.js, and right now I'm trying to query my ES instance using the HTTP module.
I'm trying to mimic the following curl GET request:
curl -XGET 'localhost:9200/_search?pretty' -H 'Content-Type: application/json' -d'
{
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
}
'
like this:
var options = {
hostname: '127.0.0.1',
port: 9200,
method: 'GET',
path: '/twitter/tweet/_search?pretty',
headers: {
'Content-Type': 'application/json',
'accept': 'application/json'
},
json: query
body: {
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
}
};
var req = http.request(options, function (response) {
var responseBody = "";
response.setEncoding("UTF-8");
response.on('data', function (chunk) {
responseBody += chunk;
});
response.on("end", function() {
fs.writeFile("responseBody.json", responseBody, function(err) {
if (err) {
throw err;
}
});
});
});
req.on("error", function(err) {
console.log(`problem with request: ${err.message}`);
});
req.end();
But ES is returning ALL the records (like if I was hitting the _all field), not just the hits for the query I'm passing. It's like if the request body is being ignored.
I've also tried to pass it by saving the query in a variable, and the simply put in in the json key:
json: query
But the result is the same. If I enclose the json with single quotes, I get the "unexpected token" error when trying to run the app, so I'm lost on what to do to succesfully pass a query to Node.js with the HTTP module :S.
EDIT:
The solution is to pass the query (JSON stringified) in the request.write method:
req.write(query);
The whole request should look like this:
var query = JSON.stringify({
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
});
var options = {
hostname: '127.0.0.1',
port: 9200,
method: 'GET',
path: '/twitter/tweet/_search?pretty',
headers: {
'content-length': Buffer.byteLength(query),
'Content-Type': 'application/json'
}
};
var req = http.request(options, function (response) {
var responseBody = "";
response.setEncoding("UTF-8");
response.on('data', function (chunk) {
responseBody += chunk;
});
response.on("end", function() {
fs.writeFile("responseBody.json", responseBody, function(err) {
if (err) {
throw err;
}
});
});
});
req.on("error", function(err) {
console.log(`problem with request: ${err.message}`);
});
req.write(query);
req.end();
So the GET request of the http.request won't respect the body, it will always ignore the request body. So, you should send a POST request if you want to send body to the elasticsearch.
The elasticsearch handles both POST and GET call in the same manner.

cURL call to API in NodeJS Request

it's me again with another lame question. I have the following call to a Rattic password database API which works properly:
curl -s -H 'Authorization: ApiKey myUser:verySecretAPIKey' -H 'Accept: text/json' https://example.com/passdb/api/v1/cred/\?format\=json
I tried to replicate this call in NodeJS, however the following returns blank:
var request = require('request');
url='https://example.com/passdb/api/v1/cred/?format=json';
request({
url: url,
method: 'POST',
headers: [
{ 'Authorization': 'ApiKey myUser:verySecretAPIKey' }
],
},
function (error, response, body) {
if (error) throw error;
console.log(body);
}
);
Any help is appreciated.
As pointed out in the comments already, use GET, not POST;
headers should be an object, not an array;
You're not adding the Accept header.
All combined, try this:
request({
url : url,
method : 'GET',
headers : {
Authorization : 'ApiKey myUser:verySecretAPIKey',
Accept : 'text/json'
}, function (error, response, body) {
if (error) throw error;
console.log(body);
}
});
One thing you can do is import a curl request into Postman and then export it into different forms. for example, nodejs:
var http = require("https");
var options = {
"method": "GET",
"hostname": "example.com",
"port": null,
"path": "/passdb/api/v1/cred/%5C?format%5C=json",
"headers": {
"authorization": "ApiKey myUser:verySecretAPIKey",
"accept": "text/json",
"cache-control": "no-cache",
"postman-token": "c3c32eb5-ac9e-a847-aa23-91b2cbe771c9"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Headers should be an object.
var request = require('request');
url='https://example.com/passdb/api/v1/cred/?format=json';
request({
url: url,
method: 'POST',
headers: {
'Authorization': 'ApiKey myUser:verySecretAPIKey'
}
}, function (error, response, body) {
if (error) throw error;
console.log(body);
});

make a post request with in node.js application

I've a node.js service with /api/authenticate endpoint. I can call this service successfully from POSTMAN with 'username' and 'password' as input (body parameters). How do I call the same services from another node.js server?
With postman I get,
body: {name: 'xxxxxx', password: 'xxxxxx' }
headers: { 'content-type': 'application/x-www-form-urlencoded',
host: 'xx.xx.xx.xx:xxxx',
connection: 'close',
'content-length': '0' }
POST /api/authenticate 200 1.336 ms - 72
Following is another nodejs application ... which makes a successful request call but doesn't have any body parameters (username and password) when it reaches to the authentication server api.
var my_http = require('http');
app.get('/makeacall', function(req, res) {
var output = '';
var options = {
body: { name: 'xxxxxx', password: 'xxxxxx' },
method: 'POST',
host: 'xx.xx.xx.xx',
port: 'xxxx',
path: '/api/authenticate',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
console.log('before request');
var req = my_http.request(options, function(response) {
console.log('response is: ' + response);
console.log('Response status code: ' + response.statusCode);
response.on('data', function(chunk) {
console.log('Data ..');
output += chunk;
});
response.on('end', function(chunk) {
console.log('Whole Data ..' + output);
});
});
req.on('error', function(err) {
console.log('Error: ' + err);
});
req.end();
console.log('444');
res.send({ message: 'View record message'});
});
From this nodejs application I get empty body on the server.
body: {}
headers: { 'content-type': 'application/x-www-form-urlencoded',
host: 'xx.xx.xx.xx:xxxx',
connection: 'close',
'content-length': '0' }
POST /api/authenticate 200 1.336 ms - 72
What am I missing? Any help is appreciated.
Using stock http library of NodeJS doesn't allow you to use that syntax.
Take a look at RequestJS as a much simpler solution. It will make your life a lot easier and allow you to use the syntax you want.
This is the solution to do it with stock Node.
https://nodejs.org/api/http.html#http_http_request_options_callback
Relevant Parts:
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
And then, at the end:
// write data to request body
req.write(postData);
req.end();
But use a library unless you absolutely can't.
Are you trying to get the posted data from a form/etc?
Try using express.
npm install express -save
You can get posted data from a url with the ff:
app.post('*', function(request, response){
var post = {};
if(Object.keys(request.body).length){
for(var key in request.body){
post[key] = request.body[key];
console.log(key+'=>'+post[key];
}
}
});

Resources