はじめに
僕は URL 文字列を操作する時、極力文字列操作ではなく専用のライブラリを使いたいと思っています。文字列操作では不正なフォーマットの文字列を作成してしまう危険性があるからです。例えば、クエリ文字列の ?
を付け忘れたり。
Node.js には url モジュールが存在します。このモジュールを使うことで URL 文字列のパースや生成を簡単に行えます。しかし、既存の URL 文字列のクエリ文字列を加工したいときに意外と苦労したので、今回メモを残しておきます。
方法
import 'url';
const addQueryTo = (href, query) => {
const urlObject = url.parse(href, true); // (1)
urlObject.search = undefined; // (2)
Object.assign(urlObject.query, query);
return url.format(urlObject);
};
addQueryTo('http://example.com', { hoge: 1 });
//=> 'http://example.com/?hoge=1'
addQueryTo('http://example.com?hoge=1', { fuga: 2 });
//=> 'http://example.com/?hoge=1&fuga=2'
addQueryTo('http://example.com?hoge=1', { hoge: 10, fuga: 20 });
//=> 'http://example.com/?hoge=10&fuga=20'
ポイントは 2 点あります。
(1) url.parse() の第 2 引数に true を指定する
parseQueryString If true, the query property will always be set to an object returned by the querystring module's parse() method.
こうすることで、クエリ文字列が querystring モジュールによりパースされ、オブジェクトとして扱えるようになります。オブジェクトにすることで更新やマージなどの操作が簡単になります。
(2) urlObject.search に undefined を代入する
これが重要な点です。
If the urlObject.search property is undefined and if the urlObject.query property is an Object, the literal string ? is appended to result followed by the output of calling the querystring module's stringify() method passing the value of urlObject.query.
urlObject.search
が undefined
の場合のみ、url.format()
の結果に urlObject.query
が反映させます。それ以外の場合は urlObject.search
の値が使用され、urlObject.query
をいくら更新しても、url.format()
の結果に反映されません。
const urlObject = url.parse('http://example.com?hoge=1', true);
urlObject.query //=> { hoge: '1' }
urlObject.search //=> '?hoge=1'
Object.assign(urlObject.query, { fuga: 2 });
urlObject.query //=> { hoge: '1', fuga: 2 }
urlObject.search //=> '?hoge=1'
url.format(urlObject) //=> 'http://example.com/?hoge=1'
ドキュメントをちゃんと読んでいなかったので、この仕様にハマって苦労しました
参考
- 公式ドキュメント
- Stack Overflow