SuperAgentでXMLのレスポンスのtextがundefinedになる

SuperAgentでXMLにアクセスした時にレスポンスのbodyやtextが取れなかったので調べてみました。

環境

  • OS X El Capitan バージョン 10.11.3
  • Node.js バージョン 5.5.0
  • SuperAgent バージョン 1.7.2
  • superagent-xml2jsparser バージョン 0.1.1

SuperAgent?

Super Agent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!

SuperAgent - Ajax with less suck

単純にgetする

適当なXMLとして、復旧・復興支援制度データベース API V2 リファレンから、例にある http://api.r-assistance.go.jp/v2/supports.xml?appkey=0 にアクセスしてみます。 appkeyは「常に0を指定してください。」というAPI共通仕様のようなので、クエリーストリング(.query())で指定しています。

// a.js
const request = require('superagent');

(() => {
  const url = 'http://api.r-assistance.go.jp/v2/supports.xml';
  request.get(url)
    .query({ appkey: 0 })
    .end((err, res) => {
      console.log(`res.text: ${res.text}`);
    });
})();

実行してみるとundefinedになりました。

$ node a.js
res.text: undefined

buffer()をする

in later superagents you have to do .buffer() if the response is not text/* or application/json

res.text is undefined · Issue #129 · visionmedia/superagent · GitHub

ここでtjさんが「レスポンスのcontent-typetext/*application/json以外の場合は.buffer()をする」ように言っていました。

以下のところでもそういった内容が記載されていました。

To force buffering of response bodies as res.text you may invoke req.buffer(). To undo the default of buffering for text responses such as “text/plain”, “text/html” etc you may invoke req.buffer(false).

When buffered the res.buffered flag is provided, you may use this to handle both buffered and unbuffered responses in the same callback.

SuperAgent - Ajax with less suck

なので、.buffer()をしてみます。

// a.js
const request = require('superagent');

(() => {
  const url = 'http://api.r-assistance.go.jp/v2/supports.xml';
  request.get(url)
    .query({ appkey: 0 })
    .buffer()
    .end((err, res) => {
      console.log(`res.text: ${res.text}`);
    });
})();

実行してみるとtextが取れました。

$ node a.js
res.text: <supports_response xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><total_count>1136</total_count><supports><support><id>6039</id><name>住まいの復興給付金</name>
# ... 略

XMLをパースする

superagent-xml2jsparserを使うとJSONに変換した状態のものをbodyに入れてくれるようなので使ってみます。

// a.js
const request = require('superagent');
const xml2jsParser = require('superagent-xml2jsparser');

(() => {
  const url = 'http://api.r-assistance.go.jp/v2/supports.xml';
  request.get(url)
    .query({ appkey: 0 })
    .accept('xml')
    .parse(xml2jsParser)
    .buffer()
    .end((err, res) => {
      console.log(`res.body: ${JSON.stringify(res.body)}`);
    });
})();

実行してみると使いやすいJSONに変換することができました。

$ node a.js
res.body: {"supports_response":{"$":{"xmlns:i":"http://www.w3.org/2001/XMLSchema-instance"},"total_count":["1136"],"supports":[{"support":[{"id":["6039"],"name":["住まいの復興給付金"],
# ... 略

終わり

superagent-xml2jsparserのUsageに次のようなコードが記載されていたんですけど、ここに.buffer()と記載されていたらわかりやすかったと思いました。

request = require('superagent');
xml2jsParser = require('superagent-xml2jsparser');

request
  .get('http://api.openweathermap.org/data/2.5/weather?q=Los Angeles&mode=xml')
  .accept('xml')
  .parse(xml2jsParser) // add the parser function
  .end(function(err, res){
    console.log(res.body)
  })

参考