kintone: レコード取得 (kintone: Get Record)
kintone アプリのレコード(1件)の内容を取得します。
2020-10-15 (C) Questetra, Inc. (MIT License)
Configs
  • C1: API トークンを設定した認証設定 *
  • C2: ドメイン(xxxxx.kintone.com または xxxxx.cybozu.com) *
  • C3: ゲストスペース ID(ゲストスペース内のアプリの場合のみ)
  • C4: アプリ ID *
  • C5: レコード ID *
  • C6F: フィールドコード_1
  • C6V: 値_1 を保存するデータ項目
  • C7F: フィールドコード_2
  • C7V: 値_2 を保存するデータ項目
  • C8F: フィールドコード_3
  • C8V: 値_3 を保存するデータ項目
  • C9F: フィールドコード_4
  • C9V: 値_4 を保存するデータ項目
  • C10F: フィールドコード_5
  • C10V: 値_5 を保存するデータ項目
  • C11F: フィールドコード_6
  • C11V: 値_6 を保存するデータ項目
  • C12F: フィールドコード_7
  • C12V: 値_7 を保存するデータ項目
Script
const FIELD_NUM = 7; // 扱えるフィールドの数

main();
function main(){
//// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
const auth = configs.get("conf_auth");
const domain = configs.get("conf_domain");
const guestSpaceId = configs.get("conf_guestSpaceId");
const appId = configs.get("conf_appId");
const recordId = retrieveRecordId();

const fieldCodeList = [];
const fieldValueDefList = [];
retrieveFieldConfigs( fieldCodeList, fieldValueDefList );

const apiToken = httpClient.getOAuth2Token( auth );

//// == 演算 / Calculating ==
const apiUri = determineApiUri( domain, guestSpaceId, appId, recordId );
const fieldValueList = [];
const fieldTypeList = [];
getRecord( apiUri, apiToken, fieldCodeList, fieldValueList, fieldTypeList );

//// == ワークフローデータへの代入 / Data Updating ==
setDataByLists( fieldValueDefList, fieldValueList, fieldTypeList );
}

/**
* config からレコード ID を読み出す
* @return {Stromg} recordId レコード ID
*/
function retrieveRecordId() {
const recordIdDef = configs.getObject( "conf_recordId" );
let recordId = configs.get( "conf_recordId" );
if ( recordIdDef !== null ) {
recordId = engine.findData( recordIdDef );
}
return recordId;
}

/**
* config のフィールド情報を読み出し、配列に格納する
* 以下の場合はエラーとする
* 1. フィールドコードが空で、値を保存するデータ項目が設定されている
* 2. フィールドコードが設定されていて、値を保存するデータ項目が設定されていない
* 3. 値を保存するデータ項目が重複して設定されている
* 4. フィールドコードが一つも設定されていない
* @param {Array<String>} fieldCodeList フィールドコードを格納する配列
* @param {Array<ProcessDataDefinitionView>} fieldValueDefList フィールドの値を格納するデータ項目の ProcessDataDefinitionView を格納する配列
*/
function retrieveFieldConfigs( fieldCodeList, fieldValueDefList ) {
const dataItemNumList = []; // データ項目の重複確認用
for (let i = 0; i < FIELD_NUM; i++) {
const fieldCodeConfigName = `conf_fieldCode${i+1}`;
const fieldValueConfigName = `conf_fieldValue${i+1}`;
const fieldCode = configs.get( fieldCodeConfigName );
const fieldValueDef = configs.getObject( fieldValueConfigName );
const dataItemNum = configs.get( fieldValueConfigName ); // データ項目の重複確認用
if ( fieldCode === "" || fieldCode === null ) { // フィールドコードが空
if ( fieldValueDef !== null ) { // 値を保存するデータ項目が設定されている
throw `Field Code ${i+1} is empty but Data item that will save Value ${i+1} is set.`;
} else { // 値を保存するデータ項目が設定されていない
continue;
}
} else { // フィールドコードが設定されている
if ( fieldValueDef === null ) { // 値を保存するデータ項目が設定されていない
throw `Data item to save the value of ${fieldCode} is not set.`;
}
}
if ( dataItemNumList.indexOf( dataItemNum ) !== -1 ) { // 既に指定されているデータ項目
throw "The same data item is set multiple times.";
}
fieldCodeList.push( fieldCode );
fieldValueDefList.push( fieldValueDef );
dataItemNumList.push( dataItemNum ); // データ項目の重複確認用
}
if ( fieldCodeList.length === 0 ) { // フィールドコードが一つも設定されていない
throw "No Field Code is set.";
}
}

/**
* kintone REST API のレコード取得の URI を決定する
* ドメインが空、または kintone のドメインとして不正な文字列であればエラーとする
* @param {String} domain ドメイン
* @param {String} guestSpaceId ゲストスペース ID
* @param {String} appId アプリ ID
* @param {String} recordId レコード ID
* @return {String} apiUri API の URI
*/
function determineApiUri( domain, guestSpaceId, appId, recordId ) {
checkDomainAndIds( domain, appId, recordId );
let apiUri = "";
if ( guestSpaceId === "" || guestSpaceId === null ) {
apiUri = `https://${domain}/k/v1/record.json?app=${appId}&id=${recordId}`;
} else {
if ( !isValidId(guestSpaceId) ) {
throw "Invalid Guest Space ID.";
}
apiUri = `https://${domain}/k/guest/${guestSpaceId}/v1/record.json?app=${appId}&id=${recordId}`;
}
return apiUri;
}

/**
* ドメイン、アプリ ID、レコード ID が空または不正な文字列であればエラーとする
* @param {String} domain ドメイン
* @param {String} appId アプリ ID
* @param {String} recordId レコード ID
*/
function checkDomainAndIds( domain, appId, recordId ) {
if ( domain === "" || domain === null ) {
throw "Domain is empty.";
}
const reg = new RegExp( '^[0-9a-zA-Z-]{3,32}.(?:kintone.com|cybozu.com)$' );
if ( !reg.test(domain) ) {
throw "Invalid Kintone domain.";
}
if ( appId === "" || appId === null ) {
throw "App ID is empty.";
}
if ( !isValidId(appId) ) {
throw "Invalid App ID.";
}
if ( recordId === "" || recordId === null ) {
throw "Record ID is empty.";
}
if ( !isValidId(recordId) ) {
throw "Invalid Record ID.";
}
}

/**
* ID が有効か(自然数か)を判定する
* @param {String} idString ID の文字列
* @return {Boolean} 有効な ID かどうか
*/
function isValidId( idString ) {
const idReg = new RegExp( '^[1-9][0-9]*$' );
return idReg.test( idString );
}

/**
* kintone REST API にレコード取得の GET リクエストを送信する
* @param {String} apiUri API の URI
* @param {String} apiToken API トークン
* @param {Array<String>} fieldCodeList フィールドコードが格納された配列
* @param {Array<String>} fieldValueList フィールドの値を格納する配列
* @param {Array<String>} fieldTypeList フィールドの型を格納する配列
*/
function getRecord( apiUri, apiToken, fieldCodeList, fieldValueList, fieldTypeList ) {
engine.log(`API URI: ${apiUri}`);
const response = httpClient.begin()
.header( "X-Cybozu-API-Token", apiToken )
.get( apiUri );
//when error thrown
const responseJson = response.getResponseAsString();
const status = response.getStatusCode();
const accessLog = `---GET request--- ${status}\n${responseJson}\n`;
engine.log(accessLog);
if (status >= 300) {
throw `Failed to get record. status: ${status}`;
}
const json = JSON.parse(responseJson);
extractFieldValues( json.record, fieldCodeList, fieldValueList, fieldTypeList );
}

/**
* レコード情報の JSON オブジェクトからフィールドコードに対応する値を読み出し、配列に格納する
* @param {Object} recordObj レコード情報の JSON オブジェクト
* @param {Array<String>} fieldCodeList フィールドコードが格納された配列
* @param {Array<String>} fieldValueList フィールドの値を格納する配列
* @param {Array<String>} fieldTypeList フィールドの型を格納する配列
*/
function extractFieldValues( recordObj, fieldCodeList, fieldValueList, fieldTypeList ) {
for ( const i in fieldCodeList ) {
if ( recordObj[fieldCodeList[i]] === undefined ) { // レコード情報に一致するフィールドコードがない場合、エラー
throw `${fieldCodeList[i]} does not exist in the record.`;
}
const fieldValueObj = recordObj[fieldCodeList[i]].value;
const fieldType = recordObj[fieldCodeList[i]].type;
if ( fieldValueObj === null ) { // null であれば、値の配列に空文字列を push する
fieldValueList.push( "" );
fieldTypeList.push( fieldType );
} else if ( typeof fieldValueObj === 'string' ) { // String であれば、値の配列に文字列を push する
fieldValueList.push( fieldValueObj );
fieldTypeList.push( fieldType );
} else { // String 以外のクラス(Object)であればエラー
throw `Unable to save the value of ${fieldCodeList[i]}. Field Type ${fieldType} is not supported.`;
}
}
}

/**
* データ項目に出力する
* @param {Array<ProcessDataDefinitionView>} dataDefList 保存先データ項目の ProcessDataDefinitionView が格納された配列
* @param {Array<String>} dataStringList 出力するデータが格納された配列
* @param {Array<String>} fieldTypeList 出力するデータのフィールド型が格納された配列
*/
function setDataByLists( dataDefList, dataStringList, fieldTypeList ) {
if ( (dataDefList.length !== dataStringList.length) || (dataDefList.length !== fieldTypeList.length) ) {
throw "Array length does not match.";
}
for (let i in dataDefList) {
if ( dataDefList[i] !== null ) {
if ( dataDefList[i].matchDataType("STRING") ) { // 保存先データ項目が文字型の場合
// 保存先データ項目が改行に対応しておらず、保存する文字列に改行が含まれる場合のエラーは QBPMS のバリデーションに任せる
engine.setData( dataDefList[i], dataStringList[i] );
} else if ( dataDefList[i].matchDataType("DECIMAL") ) { // 保存先データ項目が数値型の場合
convertTypeAndSetData( dataDefList[i], dataStringList[i], fieldTypeList[i], "DECIMAL", "Numeric" );
} else if ( dataDefList[i].matchDataType("SELECT") ) { // 保存先データ項目が選択型の場合
convertTypeAndSetData( dataDefList[i], dataStringList[i], fieldTypeList[i], "SELECT", "Select" );
} else if ( dataDefList[i].matchDataType("DATE") ) { // 保存先データ項目が日付型の場合
convertTypeAndSetData( dataDefList[i], dataStringList[i], fieldTypeList[i], "DATE", "Date" );
} else if ( dataDefList[i].matchDataType("DATETIME") ) { // 保存先データ項目が日時型の場合
convertTypeAndSetData( dataDefList[i], dataStringList[i], fieldTypeList[i], "DATETIME", "Datetime" );
}
}
}
}

/**
* データ項目の型にしたがってデータを変換して出力する
* 対応しないフィールド型の場合はエラーとする
* 変換できない値の場合はエラーとする
* @param {ProcessDataDefinitionView} dataDef 保存先データ項目の ProcessDataDefinitionView
* @param {String} dataString 出力するデータ(変換前の文字列データ)
* @param {String} fieldType 出力するデータのフィールド型
* @param {String} dataType 保存先データ項目のデータ型
* @param {String} dataTypeLabel 保存先データ項目のデータ型の表示名(エラー出力用)
*/
function convertTypeAndSetData( dataDef, dataString, fieldType, dataType, dataTypeLabel ) {
const supportedFieldTypes = { // 保存先データ項目が文字型以外の場合にサポートするフィールド型
"DECIMAL": [ "NUMBER", "CALC" ],
"SELECT": [ "DROP_DOWN", "RADIO_BUTTON" ],
"DATE": [ "DATE", "CALC" ],
"DATETIME": [ "DATETIME", "CREATED_TIME", "UPDATED_TIME", "CALC" ]
};
if ( supportedFieldTypes[dataType].indexOf( fieldType ) === -1 ) { // 対応しないフィールド型の場合はエラー
throw `The value of Field Type ${fieldType} cannot be saved to ${dataTypeLabel} type data item.`;
}
let convertedData;
if ( dataString === "" || dataString === null ) { // 空値の場合は null を設定
convertedData = null;
} else {
try { // CALC 等、フィールド型だけでは変換可否を判定できないものがあるので try-catch でエラーを捕捉
switch (dataType) {
case 'DECIMAL':
convertedData = new java.math.BigDecimal( dataString );
break;
case 'SELECT': // 一致する選択肢 ID がない場合のエラーは QBPMS のバリデーションに任せる
convertedData = new java.util.ArrayList();
convertedData.add( dataString );
break;
case 'DATE':
convertedData = java.sql.Date.valueOf( dataString );
break;
case 'DATETIME':
const dateFormatter = new java.text.SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssX" );
convertedData = new java.sql.Timestamp( dateFormatter.parse( dataString ).getTime() );
break;
}
} catch (e) { // 変換できない値の場合はエラー
throw `Returned value "${dataString}" cannot be saved to ${dataTypeLabel} type data item.`;
}
}
engine.setData( dataDef, convertedData );
}

Download

Capture

Notes

  1. API トークンを取得するには、アプリの設定画面の「設定(App Settings)」のタブを開き、「API トークン(API Token)」へと進みます。

    「生成する(Generate)」をクリックし、権限(Permissions)を選択(「レコード参照(View records)」権限が必要です)したあと、「保存(Save)」をクリックします。

    「アプリを更新(Update App)」をクリックして変更を適用するのも忘れないようにしてください。
  2. ゲストスペース ID(アプリがゲストスペースにある場合)とアプリ ID は、API トークンの設定画面で確認することができます。
  3. このアドオンがサポートするフィールド型は、レコード番号レコード IDリビジョンステータス作成日時更新日時文字列(1行)数値計算文字列(複数行)リッチエディターラジオボタンドロップダウンリンク日付時刻日時ルックアップです。
  4. 各データ型に保存できるフィールド型は下表の通りです:
データ型フィールド型
文字サポートされているフィールド型すべて
数値数値計算(値が数値型の場合のみ)、ルックアップ(値が数値型の場合のみ)
選択ラジオボタンドロップダウン
※ フィールドの値は、一致する選択肢 ID をもつ選択肢として保存されます。
日付日付計算(値が日付型の場合のみ)
日時作成日時更新日時日時計算(値が日時型の場合のみ)
%d人のブロガーが「いいね」をつけました。