Skip to content

kintone カスタマイズのつまづきポイント 〜その他〜

API トークン利用時の REST API のエラーメッセージは多言語対応が難しい

REST API でエラーが発生した場合、利用者にはエラーの内容と適切な対応を案内したい、と考えました。しかし、kintone のエラーは公開されていないので、やむなく REST API が返すエラーメッセージを補足情報として案内することになりました。

そこでエラーメッセージの言語がどのように選択されるのかを調査したので共有します。

セッション認証の場合はユーザーの言語設定が優先されるようです。開発者コンソールで下記のコードを実行すると

const method = "POST";
const url = "/k/v1/record.json";
const body = JSON.stringify({ app: 5, id: 0 });
const headers = {
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
"X-HTTP-Method-Override": "GET",
};
const res = await fetch(url, { method, headers, body });
const json = await res.json();
console.log(json);

ユーザーの言語設定が日本語の場合は日本語、英語の場合は英語のエラーメッセージが返ってきました。

参考までに次のケースでも同じ結果になりました。

  • API トークン認証(上記コードのヘッダーに X-Cybozu-API-Token を追加)
  • パスワード認証(X-Cybozu-Authorization を利用)

今回問題となったのは REST API で API トークン利用時です。次のようなコードをクライアント端末から実行すると

const method = "GET";
const body = { app: 5, id: 0 };
const headers = {
"X-Cybozu-API-Token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
};
const searchParams = new URLSearchParams(body);
const querystring = searchParams.toString();
const url = "https://xxxxx.cybozu.com/k/v1/record.json?" + querystring;
try {
const res = await fetch(url, {
method,
url,
headers,
});
const text = await res.text();
console.log(text);
} catch (error) {
console.error(error);
}

ユーザーの言語設定は関係なく(当たり前ですが)、日本語のエラーメッセージが返ってきました。もう少し詳しく調べてみると Administrator ユーザーの言語設定に依存しているようでした。

言語設定が英語の利用者に日本語のエラーを表示するわけにはいかないので何らかの対応が必要になりそうです。

フィールド情報は fields.json と layout.json の併用が必要な場合がある

フィールド情報を網羅的に取得したい場合は /k/v1/app/form/fields.json だけでなく、/k/v1/app/form/layout.json も利用する必要があります。それぞれの API で取得できる情報が異なるので整理しました。

フィールド名(ラベル)やルックアップの判定、その他のフィールド設定は fields.json からしか取得できません。

/k/v1/app/form/fields.json/k/v1/app/form/layout.json
フィールド名(ラベル)×
フィールドタイプ
フィールドコード
テーブルのフィールド判定
ルックアップフィールドの判定×
その他のフィールド設定×

スペース、罫線、ラベルフィールドは layout.json からしか取得できません。プラグイン作成ではスペースフィールドも必要なことが多いので両方の API を利用する必要があります。

/k/v1/app/form/fields.json/k/v1/app/form/layout.json
スペース×
罫線×
ラベル×

ここからは補足情報です。

アプリ作成時に既に存在する次のフィールドは機能の有効、無効に関わらず fields.json からしか取得できません。

/k/v1/app/form/fields.json/k/v1/app/form/layout.json
カテゴリー×
ステータス×
作業者×

アプリ作成時に既に存在する次のフィールドはフォームに設置後のみ layout.json からも取得できます。

/k/v1/app/form/fields.json/k/v1/app/form/layout.json
レコード番号○ ※フォームに設置後
作成日時○ ※フォームに設置後
作成者○ ※フォームに設置後
更新日時○ ※フォームに設置後
更新者○ ※フォームに設置後

一部のフィールドコードはアプリ作成者の言語設定に依存する

アプリ作成時に既に存在するフィールドがあります。

  • RECORD_NUMBER
  • CREATED_TIME
  • CREATOR
  • UPDATED_TIME
  • MODIFIER
  • CATEGORY
  • STATUS
  • STATUS_ASSIGNEE

これらのフィールドコードはアプリ作成者の言語設定に依存します。さらに、CATEGORY、STATUS、STATUS_ASSIGNEE のフィールドコードは後から変更することはできません。

各言語でどのようになるかをまとめておきました。

日本語英語フランス語
RECORD_NUMBERレコード番号Record_numberNúmero_de_registro
CREATED_TIME作成日時Created_datetimeFecha_hora_creación
CREATOR作成者Created_byCreado_por
UPDATED_TIME更新日時Updated_datetimeFecha_hora_actualización
MODIFIER更新者Updated_byActualizado_por
CATEGORYカテゴリーCategoriesCategorías
STATUSステータスStatusEstado
STATUS_ASSIGNEE作業者AssigneeAsignatario
中国語(簡体字)中国語(繁体字)
RECORD_NUMBER记录编号记录编号
CREATED_TIME创建时间创建时间
CREATOR创建人创建人
UPDATED_TIME更新时间更新时间
MODIFIER更新人更新人
CATEGORY类别类别
STATUS状态状态
STATUS_ASSIGNEE执行者执行者

プラグインの場合はフィールドタイプから判定することが多いと思うので問題になることは少なそうです。海外展開するアプリを作成している人は気をつけたほうが良いと思います。

ゲストスペース内アプリの扱い

ゲストスペース内アプリは REST API のエンドポイントが異なります。レコード取得を例にすると次のとおりです。

アプリの場所エンドポイント
通常アプリhttps://xxx.cybozu.com/k/v1/record.json
ゲストスペース内アプリhttps://xxx.cybozu.com/k/guest/スペースID/v1/record.json

kintone.api.url() を利用すればある程度のパターンは対応できます。対応できないパターンは次のページ下部でまとめられています。

が、そもそも kintone.api.url() に true などを指定せずとも勝手に判断してほしいです。

特定の環境でカスタマイズする場合は現在の仕様で問題ないと思います。しかし、カスタマイズを配布するような場合はアプリの場所がどこにあるかわからないので問題になります。

このあたりサイボウズさんが提供されているライブラリで吸収してくれるとありがたいのですがゲストスペース ID を指定する設計になっているので注意が必要です。

画面遷移は発生しないけれどイベントは発火される場合がある

詳細画面から編集画面への移動、編集画面でキャンセルして詳細画面への移動、では画面遷移が発生しません。そのため、編集、キャンセルを繰り返すと app.record.edit.show イベントが複数回呼ばれることになります。ロジックによっては処理が重複する場合があるので注意が必要です。例えば次のようなコードです。

const button = document.createElement("button");
button.innerText = "button";
kintone.events.on("app.record.edit.show", (event) => {
const spaceElement = kintone.app.record.getHeaderMenuSpaceElement();
spaceElement.appendChild(button);
console.log("add EventListener");
button.addEventListener("click", () => {
console.log("clicked");
});
});

このような動作になります。

main1

私はかなりハマりました。他にも次の現象が発生することを確認しています。

  • 詳細画面
    • 変更履歴の表示、コメント表示の繰り返しで app.record.detail.show が複数回呼ばれる
    • プロセス管理のアクション実行で app.record.detail.process.proceed が複数回呼ばれる
  • 一覧画面
    • フィールドクリックによるソートで app.record.index.show が複数回呼ばれる
    • 編集開始、編集キャンセルの繰り返しで app.record.index.edit.show が複数回呼ばれる

日時フィールドは秒を指定できるけど 00 秒固定になる

API のレコード登録で日時フィールドは秒まで指定できますが、登録される値は 00 秒になります。日時フィールドでソートする場合は注意が必要です。

const app = kintone.app.getId();
const resPost = await kintone.api("/k/v1/record", "POST", {
app,
record: { 日時: { value: "2012-01-11T12:13:14Z" } },
});
const resGet = await kintone.api("/k/v1/record", "GET", {
app,
id: resPost.id,
});
console.log(resGet.record.日時.value);

クエリーの条件でフィールドコードは左辺のみ

レコードの取得(GET)kintone API のクエリの書き方の基本に記載されているとおり、クエリーの形式は「<フィールドコード> <演算子> <値 または 関数>」にする必要があります。

日付 = TODAY()

逆にするとエラーになります。

TODAY() = 日付

kintone.api() の method は大文字のみ

kintone.api() の method を小文字にするとエラーになります。

const params = { app: 1, id: 1 };
try {
kintone.api(kintone.api.url("/k/v1/record", true), "get", params);
} catch (error) {
console.error(error);
}

fileKey は大文字小文字が区別される

ファイルダウンロードのプロパティ名 fileKey は k のみ大文字にする必要があります。

const method = "GET";
const headers = {
"X-Requested-With": "XMLHttpRequest",
};
const params = {
filekey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
};
const searchParams = new URLSearchParams(params);
const querystring = searchParams.toString();
const url = kintone.api.url("/k/v1/file", true) + "?" + querystring;
const response = await fetch(url, {
method,
headers,
});
console.log(response.status, response.statusText);
const blob = await response.blob();
console.log({ blob });