3

Firstly, I understand that there are modules that could be used (https://www.npmjs.com/package/elasticsearch), but I'm looking for a way to solve this with node.js build in modules.

I'm looking for a way to do the following curl request in nodejs using the http module:
source: https://www.elastic.co/guide/en/elasticsearch/reference/2.4/search-count.html

curl -XGET 'http://localhost:9200/twitter/tweet/_count' -d '
{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}'

E.g, making a request with a request body.


I have tried as described in the manual for writing post data: https://nodejs.org/api/http.html#http_http_request_options_callback

req.write(parsedData);
superhero
  • 5,547
  • 9
  • 56
  • 88

2 Answers2

6

Here is an example to make an HTTP GET request with a body using only the http module:

var http = require('http');

var options = {
  host: 'localhost',
  path: '/twitter/tweet/_count',
  port: '9200',
  method: 'GET',
  headers: {'Content-Type': 'application/json'}
};

var callback = function (response) {
  var str = '';
  response.on('data', function (chunk) {
    str += chunk;
  });
  response.on('end', function () {
    console.log(str);
  });
};

var data = {a: 1, b: 2, c: [3,3,3]};
var json = JSON.stringify(data);
var req = http.request(options, callback);
req.write(json);
req.end();

To test it you can start netcat listening on port 9200 with:

nc -l 9200

Running my Node example sends the following request:

GET /twitter/tweet/_count HTTP/1.1
Content-type: application/json
Host: localhost:9200
Connection: close

{"a":1,"b":2,"c":[3,3,3]}

If you don't want to use any npm modules like request then you need to get familiar with the low-level API of the built-in http module. It is very well documented on:

rsp
  • 91,898
  • 19
  • 176
  • 156
  • The data event is irrelevant, I think you missunderstood the question. – superhero Nov 24 '16 at 15:49
  • I need to send a request body as described in the question, equalent to the curl flag `-d`: https://curl.haxx.se/docs/manpage.html#-d – superhero Nov 24 '16 at 15:52
  • @ErikLandvall You're right. I thought that you want to make request with curl and get it with Node. I updated my answer. – rsp Nov 24 '16 at 16:04
  • Idk why, but it still won't work through the examples I run. I even copy pasted your example code.. I still get the same response as if there was no body.. I'm starting to think this is not related to node.js :( – superhero Nov 24 '16 at 16:16
  • @ErikLandvall Sending a body to a GET request may be not supported by the server. HTTP spec says "A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests." – rsp Nov 24 '16 at 16:20
  • It's supported, else the curl option would fail – superhero Nov 24 '16 at 16:22
  • @ErikLandvall A body is usually sent in POST or PUT requests. GET requests usually get all their parameters in the query - like `GET /path?x=1&y=2` etc – rsp Nov 24 '16 at 16:23
  • 2
    I found the problem, I forgot the `Content-Length` header – superhero Nov 24 '16 at 16:23
  • I know it's not the usal way to work with http, it's however how ElasticSearch works. – superhero Nov 24 '16 at 16:24
  • Content-Length SHOULD always be set as per RFC https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html. You can also omit it and use Transfer-Encoding. And the worst case is to ignore both like in this example and just close the connection which is not supported by all servers and keep-alive obviously can't be used there for multiple requests. In node.js client examples this is done by 'Content-Length': Buffer.byteLength(bodyData). – Petar May 08 '18 at 11:37
1

I have tweaked rsp answer a bit to support https

import https from 'https';
import http from 'http';

const requestWithBody = (body, options = {}) => {
  return new Promise((resolve, reject) => {
    const callback = function(response) {
      let str = '';
      response.on('data', function(chunk) {
        str += chunk;
      });
      response.on('end', function() {
        resolve(JSON.parse(str));
      });
    };

    const req = (options.protocol === 'https:' ? https : http).request(options, callback);
    req.on('error', (e) => {
      reject(e);
    });
    req.write(body);
    req.end();
  });
};

// API call in async function
const body = JSON.stringify({
  a: 1
});
const result = await requestWithBody(body, options = {
  host: 'localhost',
  port: '3000',
  protocol: 'http:', // or 'https:'
  path: '/path',
  method: 'GET',
  headers: {
    'content-type': 'application/json',
    'Content-Length': body.length
  }
};)
nnattawat
  • 656
  • 5
  • 11