IBM Cloudant に Node.js で @ibm-cloud/cloudant で外部からアクセスして await / async で非同期処理を書くメモ

IBM Cloudant に Node.js で @ibm-cloud/cloudant で外部からアクセスして await / async で非同期処理を書くメモ

この記事は IBM Cloud Advent Calendar 2021 の 10 日目の記事です。

IBM Cloudant に Node.js で @ibm-cloud/cloudant で外部からアクセスして await / async で非同期処理を書くメモです。

@cloudant/cloudant の非同期処理を書く記事のはずだった

もともとは @cloudant/cloudant で await async を使ったコードを見かけることが少なく、そりゃもちろん Promise と then のメソッドチェーンな形式で書けなくはないけども、ガッツリ書くときにはツラいなーという思いがあって、こちらの await / async で非同期処理をやってみる記事を書いていました。

そうしましたら、

@cloudant/cloudant の後継ライブラリ @ibm-cloud/cloudant を使ってみた : まだプログラマーですが何か?

こちらにもあるように @cloudant/cloudant が非推奨になっていく流れがあって、うわー、せっかく事前に記事書いたのに困った!となっていました。

よし @ibm-cloud/cloudant でやってみよう

幸い、@dotnsf さんが追いかけられているのもあって、追いやすそうです。

@cloudant/cloudant の後継ライブラリ @ibm-cloud/cloudant を使ってみた : まだプログラマーですが何か?

先ほど挙げたこちらの記事を参考に、やってみます。

サービス資格情報画面から apikey 設定を取ってくる

IBM Cloud 側で、自分の IBM Cloudant は作ってあります。Node-RED をつくるときに作ったものです。

IBM Cloudant のサービス資格情報の資格情報が並んでいるところをみてみます。

コピーボタンがあるのでクリップボードにコピーします。

このような内容になっています。IAM サービス情報の apikey にあたる部分は、こちらの apikey を使います。

管理画面から url 設定を取ってくる

サービス資格情報と同じメニューにある 管理 のところを見てみます。

こちらの

IAM サービス情報の url にあたる部分は、こちらのExternal endpoint にある URL を使います。

適当なフォルダでプロジェクトを作る

npm init -y

適当なフォルダを決めて npm の初期化をします。

npm i @ibm-cloud/cloudant

@ibm-cloud/cloudant をインストール。

Cloudant にデータを準備

Cloudant のダッシュボードから、 sampledb というデータベースに 3 つのドキュメントを用意しました。

動かしてみる(await async なし)

@ibm-cloud/cloudant - npm にあるソースコードも参考にして素直に接続してみました。

process.env['CLOUDANT_AUTH_TYPE'] = 'IAM';
process.env['CLOUDANT_APIKEY'] = '<CLOUDANT_APIKEY>'; // サービス資格情報 JSON の apikey の値
process.env['CLOUDANT_URL'] = '<CLOUDANT_URL>';  // 管理画面にある External endpoint の値

const { CloudantV1 } = require( '@ibm-cloud/cloudant' );

const client = CloudantV1.newInstance( { serviceName: 'CLOUDANT', disableSslVerification: true } ); 

// 2. Get server information ==================================================
// call service without parameters:
client.getServerInformation().then((serverInformation) => {
  const { version } = serverInformation.result;
  console.log(`Server version ${version}`);
});

// 3. Get database information for "animaldb" =================================
const dbName = 'sampledb';

// call service with embedded parameters:
client.getDatabaseInformation({ db: dbName }).then((dbInfo) => {
  const documentCount = dbInfo.result.doc_count;
  const dbNameResult = dbInfo.result.db_name;

  // 4. Show document count in database =================================
  console.log(
    `Document count in "${dbNameResult}" database is ${documentCount}.`
  );
});

// 5. Get zebra document out of the database by document id ===================
const getDocParams = {
  db: dbName,
  docId: '02c7bca54d5293b6286cec15b110a8d6',
};

// call service with predefined parameters:
client.getDocument(getDocParams).then((documentAboutZebra) => {
  // result object is defined as a Document here:
  const { result } = documentAboutZebra;
  console.log(
    `Document retrieved from database:\n${JSON.stringify(result, null, 2)}`
  );
});

設定情報は

process.env['CLOUDANT_AUTH_TYPE'] = 'IAM';
process.env['CLOUDANT_APIKEY'] = '<CLOUDANT_APIKEY>'; // サービス資格情報 JSON の apikey の値
process.env['CLOUDANT_URL'] = '<CLOUDANT_URL>';  // 管理画面にある External endpoint の値

<CLOUDANT_APIKEY> は、先ほど取ってきたサービス資格情報 JSON の apikey の値を入れて、 <CLOUDANT_URL> も先ほど取ってきた管理画面にある External endpoint の値を使います。

実行してみると、無事に値が取れました!

Server version 3.2.1
Document count in "sampledb" database is 3.
Document retrieved from database:
{
  "_id": "02c7bca54d5293b6286cec15b110a8d6",
  "_rev": "1-3e2023d8d36baf57898eae080f78f70c",
  "data": "sample03"
}

await async で書き換えてみる

いよいよ、await async で書き換えてみます。

サンプルコードの時点で、then で動いていて Promise を返り値で出してくれているので移植は楽でした。

process.env['CLOUDANT_AUTH_TYPE'] = 'IAM';
process.env['CLOUDANT_APIKEY'] = '<CLOUDANT_APIKEY>'; // サービス資格情報 JSON の apikey の値
process.env['CLOUDANT_URL'] = '<CLOUDANT_URL>';  // 管理画面にある External endpoint の値

const { CloudantV1 } = require( '@ibm-cloud/cloudant' );

const client = CloudantV1.newInstance( { serviceName: 'CLOUDANT', disableSslVerification: true } ); 

async function main(){

  // 2. Get server information ==================================================
  // call service without parameters:
  const responseServerInformation = await client.getServerInformation();

  const { version } = responseServerInformation.result;
  console.log(`Server version ${version}`);

  // 3. Get database information for "animaldb" =================================
  const dbName = 'sampledb';

  // call service with embedded parameters:
  const responseDatabaseInformation = await client.getDatabaseInformation({ db: dbName });

  const documentCount = responseDatabaseInformation.result.doc_count;
  const dbNameResult = responseDatabaseInformation.result.db_name;

  // 4. Show document count in database =================================
  console.log(
    `Document count in "${dbNameResult}" database is ${documentCount}.`
  );
  // 5. Get zebra document out of the database by document id ===================
  const getDocParams = {
    db: dbName,
    docId: '02c7bca54d5293b6286cec15b110a8d6',
  };

  // call service with predefined parameters:
  const responseThisDocument = await client.getDocument(getDocParams);

  // result object is defined as a Document here:
  const { result } = responseThisDocument;
  console.log(
    `Document retrieved from database:\n${JSON.stringify(result, null, 2)}`
  );

}

main();

うん、やはり、処理の流れが見やすいですね。

今回は main 関数をあえて作って async つけて、await async をサポートしている Node.js であれば実行できるようにしていますが、

Node.jsでTop-Level Awaitを試す - Qiita

のとおり v14.8.0 以降は、いきなりトップレベルから async / await で書きけます。

ということで、こちらを実行してみると、同じ値が取得できました。やった。

Server version 3.2.1
Document count in "sampledb" database is 3.
Document retrieved from database:
{
  "_id": "02c7bca54d5293b6286cec15b110a8d6",
  "_rev": "1-3e2023d8d36baf57898eae080f78f70c",
  "data": "sample03"
}

ということで、IBM Cloudant に Node.js で @ibm-cloud/cloudant で外部からアクセスして await / async で非同期処理を書くことができました。

これで、いざ使うときに、いろんなサービスと連携したり、たくさんの非同期処理が走っても await / async だと可読性を保ちながら組んでいけるので、やりやすくなりそうです!

あと、IBM/cloudant-node-sdk: Cloudant SDK for Node.js あたりに、以前の cloudant/nodejs-cloudant: Cloudant Node.js client library と同じように、ちょっとでも await / async 処理できるよって触れていれば、もう少し取っつきやすくなって、 await / async の書き方を試してみる人が増えるんじゃないかなあと思いました。