AJFaraday
AJFaraday

Reputation: 2450

Different data format when using the Stack Exchange API in browser and from NodeJS or curl

I'm trying to retrieve answer data via the StackExchange API. So far I've found the URL I want to pull from my application and in the browser it returns the expected data in plain text, JSON format.

https://api.stackexchange.com/2.2/questions/18632/answers?site=codegolf.meta&filter=!.FjsvG2X2tViZPCgDuGvW88wrGptD

This returns the expected data

{"items":[{"owner":{"display_name":"AJFaraday"},"answer_id":18633,"body":"<h1>My Answer</h1>\n\n<pre><code>class...

The problem is, when I try to access this same URL from my code (a NodeJS application, using the https module), the returned body data is showing some nonsense chars, presumably raw data, instead of the expected plain text.

Here's the JS code I'm trying out, using the request library in NodeJS.

const request = require('request');
this.url = 'https://api.stackexchange.com/2.2/questions/' + question_id +
  '/answers?site=' + site + '&filter=!.FjsvG2X2tViZPCgDuGvW88wrGptD';

request(
  this.url,
  {json: true},
  function (err, res, body) {
    if (err) {
      return console.log(err);
    }
    console.log(body);
  }
);

I can reproduce this with curl to show you the data I'm recieving...

$ curl 'https://api.stackexchange.com/2.2/questions/18632/answers?site=codegolf.meta&filter=!.FjsvG2X2tViZPCgDuGvW88wrGptD'
�
|�Qk�0ǿʑ�QZ�s��܃?�J��لդ$鴔~����@r����?�a�dH�m�:K�$�,h�JzB��ךj�hMڀPiΨS�HM�dJ���*�I���2���Jc�C�raBS*�*
                               #p���P�CM%S'χ�̝��,����#^?�9��[�x�n���8�:X������9��#���G���o��^���`ō�-{���D���v
��[�N�v����yi��:[

Why is this behaving differently in the browser and programatic requests?

Do I need to indicate something about text encoding in my request?

What am I missing here?

Upvotes: 0

Views: 94

Answers (1)

double-beep
double-beep

Reputation: 5520

You need to send the Accept-encoding: gzip header because the API is returning you gzipped content. You can use the --compressed option in curl and zlib in Node.js (to create new Gunzip object):

$ curl 'https://api.stackexchange.com/2.2/questions/18632/answers?site=codegolf.meta&filter=!.FjsvG2X2tViZPCgDuGvW88wrGptD' --compressed -w '\n'
{"items":[{"owner":{"display_name":"AJFaraday"},"answer_id":18653,"body":"<h1>MoreJunk</h1>\n\n<pre><code>throw 'ha ha haaa!';\n</code></pre>\n"},{"owner":{"display_name":"AJFaraday"},"answer_id":18652,"body":"<h1>Invalid</h1>\n\n<pre><code>Behaviours.Invalid = class Invalid extends Behaviour {\n\n  constructor(snake) {\n    super(snake);\n  }\n\n  name() {\n    return 'Invalid Invalid Invalid Invalid Invalid Invalid Invalid ';\n  }\n\n  colour() {\n    return 'rgba(0,999,255,0.1)';\n  }\n\n  set_target() {\n    this.target(this.food()[0]);\n  }\n\n  idle() {\n    console.log('idling');\n  }\n\n};\n</code></pre>\n"},{"owner":{"display_name":"AJFaraday"},"answer_id":18633,"body":"<h1>Imported</h1>\n\n<pre><code>Behaviours.Imported = class Imported extends Behaviour {\n\n  constructor(snake) {\n    super(snake);\n    this.spot = {\n      x: (Math.random() * this.game_width()),\n      y: (Math.random() * this.game_height())\n    };\n  }\n\n  name() {\n    return 'Imported';\n  }\n\n  colour() {\n    return 'rgba(0,255,255,0.4)';\n  }\n\n  set_target() {\n    this.target(this.spot);\n    //this.target(this.food()[0])\n  }\n\n  idle() {\n    this.target(this.spot);\n  }\n\n};\n</code></pre>\n"}]}

And in Node.js it must look like:

const request = require('request');
const zlib = require('zlib');

this.url = 'https://api.stackexchange.com/2.2/questions/18632/answers?site=codegolf.meta&filter=!.FjsvG2X2tViZPCgDuGvW88wrGptD';

request(
  this.url,
  {json: true},
  function (err, res, body) {
    if (err) {
      return console.log(err);
    }
  }
).pipe(zlib.createGunzip()).pipe(process.stdout);
{"items":[{"owner":{"display_name":"AJFaraday"},"answer_id":18653,"body":"<h1>MoreJunk</h1>\n\n<pre><code>throw 'ha ha haaa!';\n</code></pre>\n"},{"owner":{"display_name":"AJFaraday"},"answer_id":18652,"body":"<h1>Invalid</h1>\n\n<pre><code>Behaviours.Invalid = class Invalid extends Behaviour {\n\n  constructor(snake) {\n    super(snake);\n  }\n\n  name() {\n    return 'Invalid Invalid Invalid Invalid Invalid Invalid Invalid ';\n  }\n\n  colour() {\n    return 'rgba(0,999,255,0.1)';\n  }\n\n  set_target() {\n    this.target(this.food()[0]);\n  }\n\n  idle() {\n    console.log('idling');\n  }\n\n};\n</code></pre>\n"},{"owner":{"display_name":"AJFaraday"},"answer_id":18633,"body":"<h1>Imported</h1>\n\n<pre><code>Behaviours.Imported = class Imported extends Behaviour {\n\n  constructor(snake) {\n    super(snake);\n    this.spot = {\n      x: (Math.random() * this.game_width()),\n      y: (Math.random() * this.game_height())\n    };\n  }\n\n  name() {\n    return 'Imported';\n  }\n\n  colour() {\n    return 'rgba(0,255,255,0.4)';\n  }\n\n  set_target() {\n    this.target(this.spot);\n    //this.target(this.food()[0])\n  }\n\n

References:

Upvotes: 1

Related Questions