kintone: Get Record

kintone: レコード取得

This item gets values of a record in a Kintone App.

Auto Step icon
Basic Configs
Step Name
Note
Configs for this Auto Step
conf_auth
C1: Authorization Setting in which API Token is set *
conf_basic
C2: Basic Auth Setting (required if enabled on Kintone)
conf_domain
C3: Domain (such as xxxxx.kintone.com or xxxxx.cybozu.com) *
conf_guestSpaceId
C4: Guest Space ID (required if the App is in a Guest Space)
conf_appId
C5: App ID *
conf_recordId
C6: Record ID *
conf_fieldCode1
C7F: Field Code 1
conf_fieldValue1
C7V: Data item that will save Value 1
conf_fieldCode2
C8F: Field Code 2
conf_fieldValue2
C8V: Data item that will save Value 2
conf_fieldCode3
C9F: Field Code 3
conf_fieldValue3
C9V: Data item that will save Value 3
conf_fieldCode4
C10F: Field Code 4
conf_fieldValue4
C10V: Data item that will save Value 4
conf_fieldCode5
C11F: Field Code 5
conf_fieldValue5
C11V: Data item that will save Value 5
conf_fieldCode6
C12F: Field Code 6
conf_fieldValue6
C12V: Data item that will save Value 6
conf_fieldCode7
C13F: Field Code 7
conf_fieldValue7
C13V: Data item that will save Value 7

Notes

  • To get the API Token, open the App Settings and click “API Token” in the App Settings tab on Kintone

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

    Do not forget to click “Update App” to apply the update
  • Guest Space ID (only when the Kintone App is in a guest space) and App ID can be confirmed in the API Token settings on Kintone
  • 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
  • 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)

Capture

See also

Script (click to open)
  • An XML file that contains the code below is available to download
    • kintone-record-get.xml (C) Questetra, Inc. (MIT License)
    • If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step


const FIELD_NUM = 7; // 扱えるフィールドの数

main();
function main() {
    //// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
    const auth = configs.get("conf_auth");
    const basic = configs.get("conf_basic");
    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, basic, fieldCodeList, fieldValueList, fieldTypeList);

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

/**
  * config からレコード ID を読み出す
  * @return {String} recordId  レコード ID
  */
function retrieveRecordId() {
    const recordIdDef = configs.getObject("conf_recordId");
    if (recordIdDef.matchDataType("SELECT_SINGLE")) { // 選択型データ項目の場合
        const select = engine.findData(recordIdDef);
        if (select === null || select.size() === 0) { // 未選択
            throw "Record ID is not selected.";
        }
        return select.get(0).getValue();
    }
    return engine.findData(recordIdDef); // 文字型データ項目の場合
}

/**
  * 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) { // required="true" なので空になることはないが、チェック
        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) { // required="true" なので空になることはないが、チェック
        throw "App ID is empty.";
    }
    if (!isValidId(appId)) {
        throw "Invalid App ID.";
    }
    if (recordId === "" || recordId === null) { // required="true" だが、データ項目の値が空の可能性がある
        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 {String} basic  Basic 認証設定
  * @param {Array<String>} fieldCodeList  フィールドコードが格納された配列
  * @param {Array<String>} fieldValueList  フィールドの値を格納する配列
  * @param {Array<String>} fieldTypeList  フィールドの型を格納する配列
  */
function getRecord(apiUri, apiToken, basic, fieldCodeList, fieldValueList, fieldTypeList) {
    let request = httpClient.begin()
        .header("X-Cybozu-API-Token", apiToken);
    if (basic !== "" && basic !== null) {
        request = request.authSetting(basic);
    }
    //when error thrown
    const response = request.get(apiUri);
    const responseJson = response.getResponseAsString();
    const status = response.getStatusCode();
    if (status >= 300) {
        engine.log(`API URI: ${apiUri}`);
        const accessLog = `---GET request--- ${status}\n${responseJson}\n`;
        engine.log(accessLog);
        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':
                    // DateFormatWrapper#parse() で AddableTimestamp にパース
                    convertedData = dateFormatter.parse("yyyy-MM-dd'T'HH:mm:ssX", dataString);
                    break;
            }
        } catch (e) { // 変換できない値の場合はエラー
            throw `Returned value "${dataString}" cannot be saved to ${dataTypeLabel} type data item.`;
        }
    }
    engine.setData(dataDef, convertedData);
}

1 thought on “kintone: Get Record”

  1. Pingback: Using kintone from Workflow – Questetra Support

Comments are closed.

%d