フォーム読み込み中
2023年2月22日掲載
Alibaba Cloud Tablestoreは、大量の構造化データ及び半構造化データを保存したり処理する、フルマネージド型NoSQLデータベースサービスです。Tablestoreを使用すると、オンラインデータをミリ秒以内にクエリして取得し、保存されたデータに対して多次元分析を実行することができます。
本記事では、Alibaba Cloud上のTablestoreとPython or Node.jsを使って、簡単なRESTful APIサービスを構築する方法をご紹介します。
Tablestoreを使った、RESTful APIサービス作成方法としての流れ及び全体像は次の図の通りになります。
この構築作業に入る前に、Alibaba Cloudのアカウントを持っていること、およびTablestoreサービスを有効にします。Tablestoreはいくつかの方法でインスタンスとテーブルを準備することができますが、今回はコンソールから起動し、その他のデータに対する操作に焦点を当て、様々な方法で準備します。チャットサービス(IM Service)を想定し、このテーブルを使用してメッセージを保存します。
Tablestoreのコンソールページにアクセスし、次の画像通りにポップアップウィンドウで新規インスタンスを作成します。現在、日本リージョンでは、キャパシティインスタンスのみ対応しています。
完了すると、成功のメッセージが表示され、作成されたインスタンスがリストに表示されます。
次はテーブル作成に移ります。選択したインスタンスの詳細ページに移動し、「Create Table」でテスト用テーブルを作成します。
STRING、INTEGER、BINARYのデータ型は、主キーカラムでサポートされています。今回、idにINTEGERカラムを、groupにSTRINGカラムを追加します。このカラムは異なる方法でデータを分離するために使用しています。
必要に応じて、以下のように詳細設定を有効にすることができます。ここではデフォルトの設定を使用します。
すると、対象のテーブルが作成され、リストに表示されます。
テーブルの詳細を確認します。
データ挿入の作業に移ります。テーブルの詳細ページの 「Query Data」 タブに 「Insert」 ボタンがあります。
テーブルの詳細ページで「Query Data」 タブに移動します。
「Insert」ボタンをクリックすると、ポップアップウィンドウが表示されます。
主キーの値を入力します。
「Add Column」 ボタンをクリックし、新しいカラムの行を表示します。「date」という名前の新しいカラムを追加します。
新しいカラムの値を入力します。
操作が完了すると、結果テーブルに新しいレコードが取得されます。
最初はコンソールから同じように新しいデータを追加します。
1行または特定の範囲内のデータを照会することができます。
次はテストとして、1行のデータをクエリしてみます。コンソール画面でGUIによる操作からです。
「Search」 ボタンをクリックして、ポップアップ検索ウィンドウを開きます。
モードを「Get Row」に設定します。
主キーに特定の値を設定します。
以下、検索結果を確認します。データが取得出来ていることが確認できます。
もし、関連するデータがない場合は、空欄のリストを表示します。
今度は、テーブルから特定の範囲を持つデータを取得するようクエリしてみます。
「search」ボタンをクリックして、ポップアップ検索ウィンドウを開きます。
モードを「Range Search」に設定します。
「Start Primary Key Column」と「End Primary Key Column」を指定します。
そうすると、関連する検索結果が正常に表示されます。
今度はデータ更新を試します。特定の1行をピックアップして、以下のように更新します。
選択したデータのチェックボックスにチェックを入れると、「Update」ボタンが有効になります。
「Update」ボタンをクリックすると、更新処理のためのポップアップウィンドウが表示されます。
「Add Column」をクリックして、更新対象のデータに対して新しい列を追加します。
新しいカラムのキーと値を入力します。
そうすると、結果一覧に更新されたデータが表示されます。
コンソールからの更新操作は、単一データのみ対応していますのでご注意ください。チェックボックスで複数のデータを選択した場合、「Update」ボタンは無効となります。
今度はデータを削除してみます。削除操作は、更新操作と似ていて、コンソールから複数のデータをサポートします。ある特定のデータを削除することを例として説明します。
選択したデータのチェックボックスにチェックを入れると、「Delete」ボタンが有効になります。
「Delete」ボタンをクリックすると、確認のポップアップウィンドウが表示されます。
「OK」ボタンをクリックすると、削除が実行されます。
削除したデータを再度検索すると「No data available」という通知が表示されます。
コンソールからTablestoreを一通り操作したので、今度はTablestore CLIを使って操作をします。この操作にあたり、Tablestore CLI のインストールと設定が必要になります。
Tablestore CLI はAlibaba CloudからCLIツールとして配布されており、複数のOSにも対応しています。
<参考>
https://www.alibabacloud.com/help/en/tablestore/latest/download-the-tablestore-cli
ここではWindowsを例にとって説明します。ダウンロードしたTablestore CLIパッケージを解凍します。Tablestore CLIのルートディレクトリに移動し、ts.exeファイルをダブルクリックするか、コマンドラインでtsを実行し、Tablestore CLIを起動します。
関連する設定項目を設定するには、`config`コマンドを実行します。コマンドは endpoint、instance、id、key の4つのパラメータを受け取ります。最初の2つはテーブルストアのインスタンス、最後の2つはアクセスキーの情報です。
既存のインスタンスがない場合は、id と key だけを設定し、`create_instance` コマンドでインスタンスを作成することもできます。
create_instance -d <DESCRIPTION> -n <INSTANCE_NAME> -r <REGION>
今回は事前に準備したインスタンスとテーブルを使用するので、一度に4つのパラメータを設定します。
もし、インスタンスのエンドポイントがわからない場合は、インスタンスの詳細ページやヘルプドキュメントで確認することができます。
Tablestore CLIでインスタンスを記述します。設定が正しければ、インスタンス情報を含む応答が得られます。
describe_instance -r <REGION> -n <INSTANCE_NAME>
テーブルを指定するために `use` コマンドを実行します。テーブル名がわからない場合は、`list`コマンドを実行して確認します。
以下の手順で特定のテーブルに対する操作を開始する前に、特にターゲット・インスタンスとテーブルの構成が準備できていることを確認します。そうでない場合、以下のようなエラーメッセージが表示されます。
上述通り、TablestoreのCLI導入は無事完了したので、今度はTablestore CLIで簡単な操作を試してみます。
特定の主キーを持つデータ行を `get` コマンドで読み込みます。このコマンドは、後で操作結果を確認するために頻繁に使用します。
`put` コマンドは、データを一つずつ挿入するために使用します。パラメータ pk と attr が必要です。pk の値はプライマリキーの値を含む配列で、attr は属性カラムとしての JSON 配列にしなければなりません。
put --pk '[1,"cli"]' --attr '[{"c":"date", "v":"20220825"}, {"c":"os", "v":"Windows"}]'
行データのJSONファイルを準備し、それを元にデータを挿入することも可能です。
{
"PK": {
"Values": [
2,
"cli"
]
},
"Attr": {
"Values": [
{
"c": "date",
"v": "20220825"
},
{
"c": "os",
"v": "Windows10"
}
]
}
}
レコードの更新は、挿入操作とほとんど同じです。コマンド `update` で、パラメータ pk と attr に正しい値を設定します。JSONデータファイルもこのコマンドで受け付けることができます。
テーブルからデータ行を削除するために、`delete`コマンドで正しい主キー値を設定します。
次はTablestore CLIでデータを一括処理するというバッチオペレーション操作を試してみます。
データテーブルをスキャンして、データテーブルの全データまたは指定した行数のデータを取得することができます。
パラメータ o を使用すると、スキャンデータをローカルのJSONファイルにエクスポートすることができます。既存の属性カラムをすべてエクスポートしたくない場合は、パラメータ c を試してみてください。
生成されたJSONファイルを確認すると、パラメータに従って属性カラムがエクスポートされていることが分かります。
一方、元データを上記と同じフォーマットに基づいたJSONファイルで準備していた場合。それを `import` コマンドで一気に挿入することができます。
Tablestore CLIによる操作は概ね把握できたと思うので、今度はNode.jsを使って、TablestoreによるRESTful APIを作ります。この構築にはTablestoreのNode.js SDKが必要なので、Node.js SDKを事前に導入する必要があります。Tablestoreは、Node.js SDKを含む、複数のプログラミング言語用のSDKを提供しています。このSDKを使用するには、npmコマンド `npm install tablestore` でプロジェクトにインストールするだけです。
<参考>
Tablestore Node.js SDK Overview
https://www.alibabacloud.com/help/en/tablestore/latest/node-js-sdk-preface
参考情報として、Alibaba Cloudによる、Node.js SDKの紹介ドキュメントとサンプルコードを準備しています。
Node.js SDKの主な使い方は、Tablestoreクライアントインスタンスの初期化と、各関数の主キー、属性カラム、条件などのパラメータオブジェクトを準備することです。詳細は、以下の手順で確認できます。
<参考>
Tablestore Node.js SDK概要
https://www.alibabacloud.com/help/en/tablestore/latest/node-js-sdk
Tablestore Node.js SDKサンプルコード
https://github.com/aliyun/aliyun-tablestore-nodejs-sdk/tree/master/samples
Node.js SDKの導入が完了したら、Node.js SDKでRESTful API構築に入ります。Node.js SDKの使い方を説明するために、SDKとexpressパッケージをベースにRESTful APIを構築します。
データを読みやすくするために、APIサーバを起動する前にテーブルデータをクリアしておきます。
テーブルデータをクリアしたら、RESTful APIを構築するために、プロジェクトフォルダの準備に移ります。既存のテーブルが、あるチャットグループのメッセージを保存するために使用されていると仮定します。主キーidとgroupは、メッセージidとチャットグループ名でマッピングされます。
node_ali_tablestoreという名前のプロジェクトフォルダを作成し、依存パッケージであるtablestoreとexpressをインストールします。
そして、そのフォルダに以下のファイルを追加します。
ts.js → テーブルストアとの接続とデータ操作
server.js → expressサーバとルートの設定
message.js → シンプルなコントローラ
最後に、プロジェクトフォルダを以下のようにします。
.
├── node_modules
├── message.js
├── package.json
├── server.js
└── ts.js
プロジェクトフォルダの準備ができたら、コードを準備します。ts.jsは、SDKに基づいた機能を用意してくれます。クライアントを初期化し、クライアントを通じて関連する機能を呼び出すことになります。
"use strict";
const TableStore = require('tablestore');
var Long = TableStore.Long;
let client;
let tableName = process.env.tableName;
/**
* Generate and return TableStore client with specific configuration
* @returns TableStore client
*/
function getClient() {
if (!client) {
client = new TableStore.Client({
accessKeyId: process.env.accessKeyId,
secretAccessKey: process.env.secretAccessKey,
endpoint: process.env.endpoint,
instancename: process.env.instancename
});
}
return client;
}
/**
* Scan the TableStore data based on default range
* @returns
*/
async function getRange() {
client = getClient();
var params = {
tableName: tableName,
direction: TableStore.Direction.FORWARD,
inclusiveStartPrimaryKey: [{ "id": TableStore.INF_MIN }, { "group": TableStore.INF_MIN }],
exclusiveEndPrimaryKey: [{ "id": TableStore.INF_MAX }, { "group": TableStore.INF_MAX }],
limit: 10
};
return new Promise((resolve, reject) => {
client.getRange(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
resolve(data);
});
});
}
/**
* Scan the TableStore data based on default range
* @param {*} id
* @param {*} group
* @param {*} sender
*/
async function getRow(id, group, sender = null) {
client = getClient();
var params = {
tableName: tableName,
primaryKey: [{ 'id': Long.fromNumber(id) }, { 'group': group }],
};
if (null != sender) {
// Support CompositeCondition
// var condition = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
// condition.addSubCondition(new TableStore.SingleColumnCondition('sender', sender, TableStore.ComparatorType.EQUAL));
// condition.addSubCondition(new TableStore.SingleColumnCondition('sender', sender, TableStore.ComparatorType.EQUAL));
var condition = new TableStore.SingleColumnCondition('sender', sender, TableStore.ComparatorType.EQUAL);
params.columnFilter = condition;
}
return new Promise((resolve, reject) => {
client.getRow(params, function (err, data) {
if (err) {
console.log('error:', err);
if (err.code == 400) {
resolve({ "row": [] });
}
return;
}
resolve(data);
});
});
}
/**
* Put row in the target TableStore table
* @param {*} id
* @param {*} group
* @param {*} sender
* @param {*} message
*/
async function putRow(id, group, sender, message) {
client = getClient();
var params = {
tableName: tableName,
condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
primaryKey: [{ 'id': Long.fromNumber(id) }, { 'group': group }],
attributeColumns: [
{ 'sender': sender },
{ 'message': message }
],
returnContent: { returnType: TableStore.ReturnType.Primarykey }
};
return new Promise((resolve, reject) => {
client.putRow(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
resolve(data);
});
});
}
/**
* Put row in the target TableStore table
* @param {*} id
* @param {*} group
*/
async function deleteRow(id, group) {
client = getClient();
var params = {
tableName: tableName,
condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
primaryKey: [{ 'id': Long.fromNumber(id) }, { 'group': group }],
};
return new Promise((resolve, reject) => {
client.deleteRow(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
resolve(data);
});
});
}
module.exports = { putRow, getRange, getRow, deleteRow }
message.jsはコントローラとして動作し、結果を収集し、server.jsが読みやすい形式にパースします。
"use strict";
const ts = require('./ts');
async function listMessages() {
var result = await ts.getRange();
if (result.rows.length == 0) {
return { "rows": 0, "results": "No data" };
} else {
return { "rows": result.rows.length, "results": "Get top 10 messages successfully.", "data": result.rows };
}
}
async function getMessageByGroup(id, group) {
var result = await ts.getRow(id, group);
if (result.row.length == 0) {
return { "rows": 0, "results": "No data" };
} else {
return { "rows": result.row.length, "results": "Get target message successfully.", "data": result.row };
}
}
async function getMessageByGroupAndSender(id, group, sender) {
var result = await ts.getRow(id, group, sender);
if (result.row.length == 0) {
return { "rows": 0, "results": "No data" };
} else {
return { "rows": result.row.length, "results": "Get target message successfully.", "data": result.row };
}
}
async function saveMessage(id, group, sender, message) {
var result = await ts.putRow(id, group, sender, message);
if (result.consumed.capacityUnit.write == 0) {
return { "rows": 0, "results": "Failed to save message." };
} else {
return { "rows": result.row.length, "results": "Save target message successfully.", "data": result.row };
}
}
async function deleteMessage(id, group) {
var result = await ts.deleteRow(id, group);
return { "rows": 1, "results": "Delete target message successfully.", "data": result };
}
module.exports = { listMessages, getMessageByGroup, getMessageByGroupAndSender, saveMessage, deleteMessage }
server.js は express server のエントリポイントであり、対応するルートを定義しています。例として、RESTful APIを準備します。
ルートリクエストのウェルカムメッセージ
トップ10メッセージのクエリ
メッセージIDとチャットグループ名を指定してのメッセージ参照
メッセージID、チャットグループ名、送信者名を指定してのメッセージ参照
メッセージの保存
メッセージの削除
"use strict";
const express = require('express');
const app = express();
const message = require('./message');
app.use(express.json());
app.get('/', (req, res) => {
res.end('Welcome to Tablestore RESTful API demo!');
});
app.get('/api/msg', async (req, res) => {
var results = await message.listMessages();
res.json(results).end();
});
app.get('/api/msg/:id/:group', async (req, res) => {
var id = parseInt(req.params.id);
var group = req.params.group;
var results = await message.getMessageByGroup(id, group);
res.json(results).end();
});
app.get('/api/msg/:id/:group/:sender', async (req, res) => {
var id = parseInt(req.params.id);
var group = req.params.group;
var sender = req.params.sender;
var results = await message.getMessageByGroupAndSender(id, group, sender);
res.json(results).end();
});
app.post('/api/msg', async (req, res) => {
var id = req.body.id;
var group = req.body.group;
var sender = req.body.sender;
var msg = req.body.message;
var results = await message.saveMessage(id, group, sender, msg);
res.json(results).end();
});
app.delete('/api/msg/:id/:group', async (req, res) => {
var id = parseInt(req.params.id);
var group = req.params.group;
var results = await message.deleteMessage(id, group);
res.json(results).end();
});
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));
ここまで、コードら実行ファイルの準備ができたら、サーバーを起動し、RESTful APIをテストします。`npm run start`コマンドを実行し、expressサーバーを起動します。
`curl`コマンドでRESTful APIをテストします。期待する想定として、メッセージが無事取得できればOKです。
RESTful APIでトップ10メッセージを取得しますが、テーブルをクリアしているため、`No data`というメッセージが返されます。
curl -X GET http://localhost:5000/api/msg
RESTful APIとSDKのputRow()関数を使用して、以下のメッセージを保存します。
curl -H "Content-Type: application/json" -X POST -d "{\"id\":\"20220830101\",\"group\":\"restful\",\"sender\":\"bob\",\"message\":\"This is testing message.\"}" http://localhost:5000/api/msg
メッセージデータの保存に成功したら、top10メッセージクエリ、id-groupクエリ、id-group-senderクエリで対象データを取得します。
curl -X GET http://localhost:5000/api/msg
curl -X GET http://localhost:5000/api/msg/20220830101/restful
curl -X GET http://localhost:5000/api/msg/20220830101/restful/bob
もしスクリプトがクエリ条件と一致する行データがない場合は、`No data`というメッセージも表示されます。
curl -X GET http://localhost:5000/api/msg/20220830101/restful/bob121
以下のように、RESTful APIで行データを削除します。
curl -X DELETE http://localhost:5000/api/msg/20220830101/restful
Node.js によるRESTful APIは構築できたので、今度はPythonとflaskパッケージを使ってRESTful APIを作ってみます。この構築にはNode.js SDKと同様にTablestoreのPython SDKが必要なので、Tablestore Python SDKを事前に導入する必要があります。Tablestoreは、Python SDKを含む、複数のプログラミング言語用のSDKを提供しています。
python_ali_tablestoreという仮想環境によるプロジェクトフォルダを準備し、以下のコマンドで仮想環境を起動します。
py -m venv .venv
.venv\scripts\activate
pip installコマンドでflask-restfulとtablestoreのパッケージをインストールします。
フォルダに以下のファイルを追加します。
ts.py → テーブルストアに接続し、データを操作します。
server.py → flaskのサーバとルーティングの設定
最後に、プロジェクトフォルダを以下のようにします。
.
├── .venv
├── server.py
└── ts.py
プロジェクトフォルダ配下の構成ら準備ができたら、コードを準備します。ts.py は、Tablestore サービスとの通信を処理する OTSManager クラスを定義しています。
from tablestore import *
import os
class OTSManager:
def __init__(self):
self.endpoint = os.getenv('OTS_ENDPOINT')
self.access_key = os.getenv('OTS_ID')
self.access_secret = os.getenv('OTS_SECRET')
self.instance = os.getenv('OTS_INSTANCE')
self.table = os.getenv('OTS_TABLE')
self.client = OTSClient(self.endpoint, self.access_key, self.access_secret, self.instance)
def get_row(self, id, group, sender=None):
try:
primary_key = [('id',id), ('group',group)]
columns_to_get = [] # 取得する列のリスト、あるいは行全体を取得したい場合は空のリストを指定します
if sender:
condition = SingleColumnCondition('sender', sender, ComparatorType.EQUAL)
else:
condition = None
consumed, return_row, next_token = self.client.get_row(self.table, primary_key, columns_to_get, condition)
if return_row:
return {"status": "Success", "readCU": consumed.read, "data": {"primaryKey": return_row.primary_key, "attrColumn": return_row.attribute_columns}}
else:
return {"status": "Failed", "errMessage": "No target data row."}
except OTSClientError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message()}
except OTSServiceError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message(), "errCode": e.get_error_code()}
def put_row(self, id, group, sender, message):
try:
primary_key = [('id',id), ('group',group)]
attribute_columns = [('sender',sender), ('message',message)]
row = Row(primary_key, attribute_columns)
condition = Condition(RowExistenceExpectation.EXPECT_NOT_EXIST) # Expect not exist:この行が存在しない場合のみ、テーブルに入れる。
consumed, return_row = self.client.put_row(self.table, row, condition)
return {"status": "Success", "writeCU": consumed.write}
except OTSClientError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message()}
except OTSServiceError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message(), "errCode": e.get_error_code()}
def delete_row(self, id, group):
try:
primary_key = [('id',id), ('group',group)]
row = Row(primary_key)
condition = Condition(RowExistenceExpectation.IGNORE)
consumed, return_row = self.client.delete_row(self.table, row, condition)
return {"status": "Success", "writeCU": consumed.write}
except OTSClientError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message()}
except OTSServiceError as e:
return {"status": "Failed", "HTTPStatus": e.get_http_status(), "errMessage": e.get_error_message(), "errCode": e.get_error_code()}
server.pyは、flaskのサーバーとルートをRESTful APIとして設定します。
from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse
from ts import OTSManager
class Message(Resource):
def __init__(self):
self.manager = OTSManager()
super().__init__()
def get(self, id, group):
return jsonify(self.manager.get_row(int(id), group))
def post(self, id, group):
args = reqparse.RequestParser() \
.add_argument('sender', type=str, location='json', required=True, help="Empty sender") \
.add_argument('message', type=str, location='json', required=True, help="Empty message") \
.parse_args()
return jsonify(self.manager.put_row(int(id), group, args['sender'], args['message']))
def delete(self, id, group):
return jsonify(self.manager.delete_row(int(id), group))
app = Flask(__name__)
api = Api(app, default_mediatype="application/json")
api.add_resource(Message, '/api/msg/<id>/<group>')
app.run(host='0.0.0.0', port=5001, use_reloader=True)
ここまで、コードら実行ファイルの準備ができたら、サーバーを起動し、RESTful APIをテストします。`python server.py`コマンドを実行し、flask サーバを起動します。
curl コマンドで API 経由でテーブルに新しいメッセージを挿入できるかテストします。
curl -H "Content-Type: application/json" -X POST -d "{\"sender\": \"bob\", \"message\":\"Testing message from Python\"}" http://localhost:5001/api/msg/20220905001/python
追加されたメッセージをテーブルから確認します。
curl -X GET http://localhost:5001/api/msg/20220905001/python
テーブルからメッセージを削除します。
curl -X DELETE http://localhost:5001/api/msg/20220905001/python
グループ情報が間違っているリターンメッセージを確認します。
curl -X GET http://localhost:5001/api/msg/20220905001/python11
protobufのバージョンによっては、現在のインストールパッケージの*pb2.pyファイルと互換性がないため、手動で*pb2.pyファイルを生成して解決を試みることができます。これは次のように行います。
現在のバージョンのprotocを使用して、protoファイルに対応するコードを順番に生成します。
protoc --python_out=. tablestore/protobuf/search.proto
protoc --python_out=. tablestore/protobuf/table_store.proto
protoc --python_out=. tablestore/protobuf/table_store_filter.proto
生成された3つのファイルのサフィックスをpb2.pyに変更し、インストールディレクトリのtablestore/protobuf/ディレクトリにコピーして、元の*pb2.pyファイルを置き換えます。
上記の解決方法の詳細は、Alibabaのヘルプドキュメント(現在は中国語のみ)で確認することができます。関連するエラーメッセージは以下の通りです。
……
TypeError: Descriptors cannot not be created directly.
If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0.
If you cannot immediately regenerate your protos, some other possible workarounds are:
1. Downgrade the protobuf package to 3.20.x or lower.
2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower).
protocによる解決に慣れていない場合は、エラーメッセージからの示唆をもとに解決することができます。ここでは例として、protobuf パッケージを 3.19.0 にダウングレードしています。
レスポンスからOTSAuthFailedエラーが発生した場合、テーブルストアクライアントの初期化処理に起因する可能性があります。アクセス情報、エンドポイント、インスタンスの値をご確認ください。
レスポンスから Internal Server Error が発生した場合は、stderr 情報を確認し、エラーメッセージを元にコードの誤りを修正します。
これが完了すると、サーバーは更新されたコードを検知して再読み込みし、flaskサーバーを自動的に再起動します。
Tablestoreでは、データテーブルに対してマッピングテーブルを作成し、その情報をSQLモードで問い合わせることができます。
Tablestore CLIでコマンド `sql` を実行すると、簡単にSQLモードに移行することができます。
しかし、現在、日本Regionではサポートされていません。日本インスタンスでSQLモードを使用すると、OTSInternalServerErrorが表示されます。
関連するエラーメッセージは以下の通りです。
tablestore@SQL> show tables;
OTSInternalServerError Internal server error. 0005e70b-af4d-1323-8e6c-ca0b01cb1bee
tablestore@SQL>
SQLモードはコンソールからも利用可能です。このモードをサポートしているインスタンスでは、テーブル管理ページに「Query by Executing SQL Statement」タブが表示されます。詳細な手順はこちらで確認できますので、参考にします。
<参考>
Manage the Wide Column model in the Tablestore console
https://www.alibabacloud.com/help/en/tablestore/latest/manage-the-wide-column-model-in-the-tablestore-console#section-oes-zpq-fri
Alibaba Cloud TablestoreとNode.js もしくは Pythonで始めるRESTful APIサービス構築方法をご紹介しました。この方法は初心者向け記事としても、チャットサービス(IM Service)向けにも適用できますし、10分もせずにRESTful APIサービスを完成することができます。
Tablestore は NoSQLデータベースとして、Webやモバイルなどのアプリケーションから簡単にアクセスできるよう、Node.jsやPythonなど幅広い言語でのクライアントを提供しています。そのため、どんな言語でも通信プロトコルを意識せずにRESTful APIサービスとして展開することができます。RESTful APIサービスを構築してみたい方は是非参考にしてみるといいでしょう。
条件に該当するページがございません