kintone: Get Record
Get values of a record in a Kintone App.
2020-10-15 (C) Questetra, Inc. (MIT License)
Configs
  • C1: Authorization Setting in which API Token is set *
  • C2: Domain (such as xxxxx.kintone.com or xxxxx.cybozu.com) *
  • C3: Guest Space ID (required if the App is in a Guest Space)
  • C4: App ID *
  • C5: Record ID *
  • C6F: Field Code 1
  • C6V: Data item that will save Value 1
  • C7F: Field Code 2
  • C7V: Data item that will save Value 2
  • C8F: Field Code 3
  • C8V: Data item that will save Value 3
  • C9F: Field Code 4
  • C9V: Data item that will save Value 4
  • C10F: Field Code 5
  • C10V: Data item that will save Value 5
  • C11F: Field Code 6
  • C11V: Data item that will save Value 6
  • C12F: Field Code 7
  • C12V: Data item that will save Value 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. To get API Token, open the Settings of the App and click “API Token” in the App Settings tab.

    Click “Generate”, select Permissions (“View records” permission is required), and click “Save”.

    Do not forget to click “Update App” to apply the update.
  2. Guest Space ID (only when the App is in a guest space) and App ID can be confirmed in the API Token settings.
  3. Supported field types are: Record Number, Record ID, Revision, Status, Created datetime, Updated datetime, Text, Number, Calculated, Text area, Rich text, Radio button, Drop-down, Link, Date, Time, Date and time, Lookup.
  4. Field types that can be saved to each Data type item are shown in the following table:
Data typeField Types
StringAll the supported field types
NumericNumber, Calculated (only when the value type is Number), Lookup (only when the value type is Number)
SelectRadio button, Drop-down
* The value of the field will be saved as a choice whose choice ID is identical with it.
DateDate, Calculated (only when the value type is Date)
DatetimeCreated datetime, Updated datetime, Date and time, Calculated (only when the value type is Date and time)
%d bloggers like this: