kintoneにおける「添付ファイル」フィールド仕様まとめ　～標準・カスタマイズを俯瞰して～

# kintoneの添付ファイルフィールド
kintoneでは、「添付ファイル」フィールドと呼ばれる、
様々な形式の添付ファイルを保存できるフィールドが標準で用意されています。

簡単にファイル管理ができるため非常に便利な機能ですが、
カスタマイズなどで詰まってしまう、困ってしまう部分も多々あるため、
今回、標準機能からカスタマイズまで、「添付ファイル」を軸にしてまとめておこうと思います。

注意：下記記載の内容は**2022年12月時点**のkintoneの仕様で記載しています。

# 標準機能
## 添付方法
　kintoneの標準機能では、添付方法としては以下の二つがあります。
　画像引用：[kintoneヘルプ>添付ファイル](https://jp.cybozu.help/k/ja/id/040514.html)
　①[参照]をクリックして、ファイルを選択する
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584477/b4cc8a69-acf0-c6e0-559b-d1c3c8c9b4c4.png)
　②[参照]にファイルをドラッグアンドドロップして添付する
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584477/ec798e9b-eae4-f49d-41a7-246f901c7bb0.png)

## ファイル容量
　添付ファイルフィールドに添付できる、1ファイルの最大容量は**1GB**です。
　ドメイン全体の容量に達するまで、添付ファイル数には上限はありません。

## ダウンロード
　添付ファイル名をクリックするとダウンロードされます。
　※標準機能では、ファイルを一括でダウンロードすることはできないため、各ファイルをクリックする必要があります。
　　一括ダウンロードのJavaScriptでのカスタマイズについてはcybozu developer networkに記事がアップされています。
　・[kintoneの添付ファイルをJSZipで一括ダウンロードしよう](https://developer.cybozu.io/hc/ja/articles/214068923-kintone%E3%81%AE%E6%B7%BB%E4%BB%98%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92JSZip%E3%81%A7%E4%B8%80%E6%8B%AC%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%97%E3%82%88%E3%81%86)

## 検索機能
　kintoneの標準機能の検索（[アプリ内絞り込み](https://jp.cybozu.help/k/ja/id/040458.html)、[アプリ内検索](https://jp.cybozu.help/k/ja/id/040689.html#search_search_details_40)、[全体検索](https://jp.cybozu.help/k/ja/id/040689.html)）では、
　添付ファイルの内容も含めて検索することが可能です。

## レコード再利用時
　添付ファイルの情報は**コピーされません。**

## 【注意点①】表示順
　kintoneの表示順は**添付順で表示され**、ユーザーが後からドラッグアンドドロップ等で並び替えることはできません。

## 【注意点②】添付ファイル更新方法
　同一ファイル名のファイルをアップロードしても、kintoneの内部ではIDが別に割り振られるため、別ファイルとして認識されます。
　更新を行う際には、**一度ファイルを削除して、もう一度更新後のファイルをアップロードしなおす必要があります**
　![同一ファイル添付イメージ_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584477/19c293a9-cac6-c43a-1dd9-95baa0e8a5da.png)
　上記の仕様のため、添付ファイルの更新頻度が多く、かつ履歴を残していくことが重要な場合、
　SharePointなどの他サービスのリンクを配置することも考えておく必要があります。

# カスタマイズ（イベント）
## レコード保存時イベント(app.record.create.submit等)
　レコード保存時イベントのイベント発火時には、
　新たに添付したファイル情報は入ってきていません。
　つまり、レコード保存時に**添付ファイルの情報をもとに処理(エラーチェック、他アプリ連携等)を行うこと**ができません。
　（標準の必須チェックでは対応できないチェックもあるので困ることが多い・・・）
　![レコード保存時処理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584477/69c79a7f-1e91-9cd5-1725-4d45af0d8948.png)

## レコード保存成功時イベント(app.record.create.submit.success等)
　では、どのイベントで添付ファイルの情報を取得できるかというと、レコード保存成功時イベントになります。
　![レコード保存成功時処理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584477/800acf38-0094-bc24-35d0-112e0807d3f5.png)

　この場合、処理自体は可能ですが、エラー発生時にも保存自体は成功してしまっているため、
　**保存をキャンセルしてロールバック等ができなくなります。**

## レコード値変更時イベント(app.record.edit.change.<フィールドコード>等)
　レコード保存時イベントの値を考えると理解できる部分かと思いますが、
　**レコード値変更時イベントは発火しない**ため、
　kintoneのイベントでは、「添付ファイル」フィールドの変更を検知することができません。

# カスタマイズ(API)
## レコードの情報を取得・セットする(kintone.app.record.get/set)
　上記、ボタン押下時にレコードの情報を書き換えたりできる便利なAPIですが、
　**添付ファイルには変更が反映されません**
　（イベントの仕様と合わせて、レコードの追加・編集画面では添付ファイルフィールドに対するカスタマイズはほぼできない状況です）

## 添付ファイルアップロード/ダウンロードRESTAPI
### kintone.api()が使えない
　ファイルアップロード、ファイルダウンロードのRESTAPI(https://(サブドメイン名).cybozu.com/k/v1/file.json)
　については、**kintone.api()を利用したREST APIリクエストは対応していません**
　よって、APIについて記載する際にはXMLHttpRequestを利用した書き方をする必要があります。

　レスポンスのステータスコード等も判断する必要があるので、コード量がどうしても多くなってしまいます。
　ただし、kintone REST APIをJavaScriptで扱うために必要な処理をまとめたライブラリである、
　[rest-api-client](https://www.npmjs.com/package/@kintone/rest-api-client)を利用すると、エラーハンドリングまで含めて他のAPIと同様に対応することができて便利です。

**【コード例 ※[rest-api-clientのコード例から](https://github.com/kintone/js-sdk/blob/master/packages/rest-api-client/docs/file.md)】**
```JavaScript
(async () => {
    const client = new KintoneRestAPIClient();
    const APP_ID = 1;

    const FILE = {
        name: "Hello.txt",
        data: "Hello World!",
    };
    try {
        // ファイルアップロード
        const { fileKey } = await client.file.uploadFile({
            file: FILE,
        });

        const { id } = await client.record.addRecord({
            app: APP_ID,
            record: {
                添付ファイル: {
                    value: [{ fileKey }], // アップロード後のファイルキー
                },
            },
        });

        // ファイルダウンロード
        const { record } = await client.record.getRecord({
            app: APP_ID,
            id,
        });

        const data = await client.file.downloadFile({
            fileKey: record.添付ファイル.value[0].fileKey,
        });
    } catch(e){
        window.alert(e);
        return false;
    }
})();
```

### ファイルのアップロードキーとダウンロードキーは別
　レコード情報を見たときに書かれているキーはファイルダウンロード時に利用するキーとなりますが、
　アップロードキーとして利用することはできません。同様に、ファイルアップロードAPIを利用して得られたキーを
　レコード情報に追加してレコード更新を行いますが、同じファイルキーを利用してダウンロードをすることはできません。


# まとめ
　書いてみると残しておきたい情報は結構ありますね
　特にカスタマイズについてはもう少し充実すると一気にいろいろできることが増えそうな気がします。
　
　またkintoneのカスタマイズに関わるヘルプは、イベントごとにまとめられているため、
　細かい仕様については忘れてしまい、エラーがでて思い出すことも多いので、
　今後も上記のように備忘録としてフィールドごとの特性をまとめていこうと思いました
　
　※アドベントカレンダー遅刻してしまって申し訳ありませんでした・・・。


# 参考サイト
・[kintoneヘルプ>添付ファイル](https://jp.cybozu.help/k/ja/id/040514.html)
・[kintoneの添付ファイルをJSZipで一括ダウンロードしよう](https://developer.cybozu.io/hc/ja/articles/214068923-kintone%E3%81%AE%E6%B7%BB%E4%BB%98%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92JSZip%E3%81%A7%E4%B8%80%E6%8B%AC%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%97%E3%82%88%E3%81%86)
・[一覧に表示するレコードを絞り込む](https://jp.cybozu.help/k/ja/id/040458.html)
・[データを検索する](https://jp.cybozu.help/k/ja/id/040689.html)
・[添付ファイルの容量の上限値を変更できますか？](https://jp.cybozu.help/k/ja/id/040162.html)
・[レコード追加画面の保存実行前イベント](https://developer.cybozu.io/hc/ja/articles/201941984#step2)
・[レコード追加画面の保存成功後イベント](https://developer.cybozu.io/hc/ja/articles/201941984#step2)
・[レコード追加画面のフィールド値変更時イベント](https://developer.cybozu.io/hc/ja/articles/201941984#step3)
・[レコードに値をセットする](https://developer.cybozu.io/hc/ja/articles/201942014#step4)
・[ファイルアップロード](https://developer.cybozu.io/hc/ja/articles/201941824)
・[ファイルアップロードで必須となる3つの手順](https://developer.cybozu.io/hc/ja/articles/200724665)
・[ファイルダウンロード](https://developer.cybozu.io/hc/ja/articles/202166180)
・[ファイルダウンロードで必須となる2つの手順](https://developer.cybozu.io/hc/ja/articles/200814380)
・[rest-api-client：添付ファイル操作ドキュメント](https://github.com/kintone/js-sdk/blob/master/packages/rest-api-client/docs/file.md)