kintone chatGPT によるスペース&アプリ作成

kintone アプリをchatGPT に聞いた node で作成してみました。

# 概要

kintone 顧客管理アプリを作成するコードを chatGPT に聞いて実行してみた。
いろいろエラーを解消しながら、コードを作成
スペース情報取得は、よくわからないエラーで試行錯誤した。

※API ラボで、開発中のAPI を利用しています。
・「スペースの情報を取得できるJavaScript API」を有効にする

アプリ項目を要件として、リクエストすると、アプリフォームまで定義してくれる。
これをたたき台にして、項目追加等を行うことも可能。
テストデータも生成してくれるので、簡単なテストも可能です。

- スペース(APP-TEST)作成
    - スペース管理者設定
        - スペース情報取得には、スペース管理者権限が必要
- スペース情報取得
    - アプリを作成する defaultThread を取得
    - ※ header 部に 'Content-Type': 'application/json'を入れて、リクエストボディで指定するとエラー"不正なリクエストです。"
        - axiosリクエストボディの場合、data : { id: spaceId } のような 階層が必要だった
- 顧客管理アプリ作成
    - 項目指定
        - 会社名・住所・TEL 担当者名 メールアドレス
        - ほかに必要と思われる項目があれば提案してください
    - レイアウトを項目に合わせて横幅調整
- テストデータの生成
    - 「作成したアプリに、csv でテストデータを10件用意してください」で生成
    - csv の読み込みで、問題なくインポート

# 作成した顧客管理アプリ

なんとなくそれらしい顧客アプリになっている。

![2024-07-21_17h05_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/37cba33b-1bdf-da72-42c8-d406b8bb1a0e.png)


# スペース&アプリ作成

- 実行ログ

```.log
> node .\make_app.js
スペースを作成しています...
作成されたスペースID: 259
デフォルトスレッドを取得しています...
デフォルトスレッドID: 290
アプリを作成しています...
作成されたアプリID: 3062
フィールドを設定しています...
フィールドの設定が完了しました
フォームレイアウトを設定しています...
フォームレイアウトの設定が完了しました
アプリをデプロイしています...
アプリのデプロイが完了しました
```

- node コード

```make_app.js
const axios = require('axios');

// Kintoneの設定
const domain = 'your_domain'; // 例: example.cybozu.com
const username = 'your_username'; // Kintoneのユーザー名
const password = 'your_password'; // Kintoneのパスワード
const spaceName = 'APP_TEST';
const appName = '顧客管理アプリ';

// ベーシック認証のための認証情報
const auth = Buffer.from(`${username}:${password}`).toString('base64');
const headers = {
  'X-Cybozu-Authorization': auth,
  'Content-Type': 'application/json'
};
const headers2 = {
    'X-Cybozu-Authorization': auth
};
  
// Axiosインスタンスの作成
const kintone = axios.create({
  baseURL: `https://${domain}/k/v1`,
  headers: headers
});

const kintone2 = axios.create({
    baseURL: `https://${domain}/k/v1`,
    headers: headers2
});
  
  // エラーの詳細を表示する関数
const displayError = (error) => {
  if (error.response) {
    console.error('Error status:', error.response.status);
    console.error('Error data:', JSON.stringify(error.response.data, null, 2));
  } else {
    console.error('Error message:', error.message);
  }
};

// スペースの作成
const createSpace = async () => {
  console.log('スペースを作成しています...');
  try {
    const spaceResponse = await kintone.post('/space.json', {
      name: spaceName,
      isPrivate: false,
      members: [
        {
          entity: {
            type: 'USER',
            code: username
          },
          isAdmin: true
        }
      ]
    });
    const spaceId = spaceResponse.data.id;
    console.log(`作成されたスペースID: ${spaceId}`);
    return spaceId;
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// デフォルトスレッドの取得
const getDefaultThread = async (spaceId) => {
  console.log('デフォルトスレッドを取得しています...');
  try {
    const spaceResponse = await kintone2.get('/space.json?id=' + spaceId, {});
    const defaultThread = spaceResponse.data.defaultThread;
    console.log(`デフォルトスレッドID: ${defaultThread}`);
    return defaultThread;
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// アプリの作成
const createApp = async (spaceId, threadId) => {
  console.log('アプリを作成しています...');
  try {
    const appResponse = await kintone.post('/preview/app.json', {
      name: appName,
      space: spaceId,
      thread: threadId
    });
    const appId = appResponse.data.app;
    console.log(`作成されたアプリID: ${appId}`);
    return appId;
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// フィールドの設定
const setFields = async (appId) => {
  console.log('フィールドを設定しています...');
  const fields = {
    properties: {
      company_name: {
        type: 'SINGLE_LINE_TEXT',
        code: 'company_name',
        label: '会社名'
      },
      address: {
        type: 'SINGLE_LINE_TEXT',
        code: 'address',
        label: '住所'
      },
      tel: {
        type: 'SINGLE_LINE_TEXT',
        code: 'tel',
        label: 'TEL'
      },
      person_in_charge: {
        type: 'SINGLE_LINE_TEXT',
        code: 'person_in_charge',
        label: '担当者名'
      },
      email: {
        type: 'SINGLE_LINE_TEXT',
        code: 'email',
        label: 'メールアドレス'
      },
      notes: {
        type: 'MULTI_LINE_TEXT',
        code: 'notes',
        label: '備考'
      }
    }
  };

  try {
    await kintone.post('/preview/app/form/fields.json', {
      app: appId,
      properties: fields.properties
    });
    console.log('フィールドの設定が完了しました');
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// フォームのレイアウト設定
const setLayout = async (appId) => {
  console.log('フォームレイアウトを設定しています...');
  const layout = [
    {
      type: 'ROW',
      fields: [
        { type: 'SINGLE_LINE_TEXT', code: 'company_name', size: { width: 400 } },
        { type: 'SINGLE_LINE_TEXT', code: 'person_in_charge', size: { width: 300 } }
      ]
    },
    {
      type: 'ROW',
      fields: [
        { type: 'SINGLE_LINE_TEXT', code: 'address', size: { width: 500 } },
        { type: 'SINGLE_LINE_TEXT', code: 'tel', size: { width: 200 } }
      ]
    },
    {
      type: 'ROW',
      fields: [
        { type: 'SINGLE_LINE_TEXT', code: 'email', size: { width: 400 } }
      ]
    },
    {
      type: 'ROW',
      fields: [
        { type: 'MULTI_LINE_TEXT', code: 'notes', size: { width: 600 } }
      ]
    }
  ];

  try {
    await kintone.put('/preview/app/form/layout.json', {
      app: appId,
      layout: layout
    });
    console.log('フォームレイアウトの設定が完了しました');
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// アプリのデプロイ
const deployApp = async (appId) => {
  console.log('アプリをデプロイしています...');
  try {
    await kintone.post('/preview/app/deploy.json', {
      apps: [{ app: appId }]
    });
    console.log('アプリのデプロイが完了しました');
  } catch (error) {
    displayError(error);
    process.exit(1);
  }
};

// 5秒待つ関数
const wait = async (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

// メイン関数
const main = async () => {
  // スペースを作成し、スペース管理者を設定する
  const spaceId = await createSpace();

  // デフォルトスレッドを取得する
  const threadId = await getDefaultThread(spaceId);

  // アプリを作成する
  const appId = await createApp(spaceId, threadId);

  // アプリのフィールドを設定する
  await setFields(appId);

  // フォームレイアウトを設定する
  await setLayout(appId);

  // アプリをデプロイする
  await deployApp(appId);
};

main();
```

# テストデータ生成

「作成したアプリに、csv でテストデータを10件用意してください」で作成されたCSV

```.testData.csv
会社名,住所,TEL,担当者名,メールアドレス,備考
株式会社A,東京都千代田区1-1-1,03-1234-5678,田中太郎,tanaka@example.com,メモ1
株式会社B,東京都港区2-2-2,03-2345-6789,佐藤花子,sato@example.com,メモ2
株式会社C,東京都新宿区3-3-3,03-3456-7890,鈴木一郎,suzuki@example.com,メモ3
株式会社D,東京都渋谷区4-4-4,03-4567-8901,高橋健,takahashi@example.com,メモ4
株式会社E,東京都目黒区5-5-5,03-5678-9012,伊藤直子,ito@example.com,メモ5
株式会社F,東京都世田谷区6-6-6,03-6789-0123,山田次郎,yamada@example.com,メモ6
株式会社G,東京都品川区7-7-7,03-7890-1234,中村三郎,nakamura@example.com,メモ7
株式会社H,東京都大田区8-8-8,03-8901-2345,小林四郎,kobayashi@example.com,メモ8
株式会社I,東京都足立区9-9-9,03-9012-3456,加藤五郎,kato@example.com,メモ9
株式会社J,東京都葛飾区10-10-10,03-0123-4567,森田六郎,morita@example.com,メモ10
```

- csv 読み込み後の一覧

![2024-07-21_17h19_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/197fb208-b5eb-f13c-72d6-e3535b4948e0.png)