9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【2019年6月版】fs.writeFile したら ERR_INVALID_CALLBACK ですって

Last updated at Posted at 2019-06-23

Qiitaの記事、10000件?!

こちらの記事「Qiitaの記事をランダムに読める API / サービス を4時間ぐらいで作った」を見て私も「Qiitaの最新記事10000件、取ってみよ!」と思いついたのでございます。

さっそくコーディング

上記記事のGithubリポジトリ https://github.com/redshoga/random-qiita-api を参考にしつつ、軽量な Http Client らしい 「phin」を使って意気揚々とプログラムを作成いたしました。

まずはプロジェクトの準備から。

$ npm init
...
$ npm i phin

で〜package.jsonscripts"start":"node indes.js",を追記してnpm startコマンドでindex.jsが実行されるように仕掛け、以下のような感じでindex.jsを作成いたします。

index.js
const p = require('phin');
const fs = require('fs');

(async ()=>{
    const TOKEN = '...';

    // 1ページあたり100件は固定
    const q = ((n) => (p) => `?page=${p}&per_page=${n}`)(100);

    for(let i = 1 ;i <= 100; i++) {
        const res = await p({
            'url' : 'https://qiita.com/api/v2/items' + q(i),
            'headers' :{
                'Authorization' : `Bearer ${TOKEN}`
            },
            'parse': 'json'});
        fs.writeFile(`./items/qiita_item_${i}.json`, JSON.stringify(res.body, '', ' '));
    }
})();

Qiita の APIは認証キーがないと1時間に60回までのリクエストしか送れないため、短時間に100ページを取得して「最新の10000万件」を取ってくることができないのです。
というわけで、TOKEN で定義している認証キーをこちらの「Qitta APIのヘルプ#認証認可」のページを参照して取得します。今回は手っ取り早く、"ユーザーの管理画面"からサクッと取得してきました。

ついでにクエリパラメータの作成で、ちょっぴりカリー化(「3歳娘「パパ、関数をカリー化して?」」をかじった程度)を試してみたり、jsonのフォーマットでインデント指定してみたり。

そして実行、ポチッとな!

いよいよ npm start で実行してみます!

$ npm start
...
(node:13149) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
    at maybeCallback (fs.js:128:9)
    at Object.writeFile (fs.js:1158:14)
...

ERR_INVALID_CALLBACKッ! ERR_INVALID_CALLBACKッッ!!! ガーン!!!( ̄◇ ̄;)!!!

writeFileCallback must be a function のエラーってなんだそりゃ?!

node.jsの公式ドキュメントをちゃんと確認

はい、node.jsの公式ヘルプを覗くと・・・
https://nodejs.org/dist/latest-v10.x/docs/api/fs.html#fs_fs_writefile_file_data_options_callback

fs.writeFile(file, data[, options], callback)

・・・いつの間にか必須になっていたんですね、第3引数。ていうか、非同期になっていたのですね・・・
ってことで、callback は必須です。

ちなみに、更新履歴は・・・

Version Changes
v10.10.0 The data parameter can now be any TypedArray or a DataView.
v10.0.0 The callback parameter is no longer optional. Not passing it will throw a TypeError at runtime.
v7.4.0 The data parameter can now be a Uint8Array.
v7.0.0 The callback parameter is no longer optional. Not passing it will emit a deprecation warning with id DEP0013.
v5.0.0 The file parameter can be a file descriptor now.
v0.1.29 Added in: v0.1.29

Oh... The callback parameter is no longer optional. の文字が踊る。。。
v.7 の時点で必須だったかぁ・・・

というわけで、以下のようにコールバックを追加して再チャレンジいたしました。

index.js
const p = require('phin');
const fs = require('fs');

(async ()=>{
    const TOKEN = '....';

    // 1ページあたり100件は固定
    const q = ((n) => (p) => `?page=${p}&per_page=${n}`)(100);

    for(let i = 1 ;i <= 100; i++) {
        const res = await p({
            'url' : 'https://qiita.com/api/v2/items' + q(i),
            'headers' :{
                'Authorization' : `Bearer ${TOKEN}`
            },
            'parse': 'json'});
        fs.writeFile(`./items/qiita_item_${i}.json`, JSON.stringify(res.body, '', ' '), (err)=>{
            if(err) console.log(`error!::${err}`);
        });
    }
})();

はい、こちらのコードで無事にjsonファイル100個、10000件の記事データが取得できました。

このjsonでこれから〇〇なことや、××をことを試してみたいと思います♪ :sunglasses:

参考ページ

宣伝

JSネタ、こちらもどうぞ〜!

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?