ファイルのアップロード・ダウンロード
kintone の添付ファイルフィールドに対して、REST API でファイルをアップロード・ダウンロードする操作は、多くのカスタマイズで必要になります。しかし、ファイル操作には通常のレコード CRUD とは異なる手順が必要で、ファイルキーという概念を理解する必要があります。
この記事では、kintone REST API でのファイル操作を、kintone 内の JavaScript カスタマイズと Node.js 環境の両方から解説します。
ファイル操作の基本的な流れ
kintone のファイル操作は、以下の 2 段階で行います。
アップロードの流れ
- ファイルアップロード API でファイルをアップロードし、
fileKey(ファイルキー)を取得する - レコードの追加・更新 API で、添付ファイルフィールドに
fileKeyを指定して保存する
ダウンロードの流れ
- レコード取得 API で添付ファイルフィールドの情報(
fileKeyを含む)を取得する - ファイルダウンロード API で
fileKeyを指定してファイルの実データを取得する
ファイルキーは一時的な識別子です。アップロード API で取得したファイルキーは、同一リクエストセッション内でのみ有効で、3 日間使用されないと失効します。
ファイルのアップロード
kintone 内から利用する場合
kintone の JavaScript カスタマイズでは、XMLHttpRequest を使ってファイルをアップロードします。
/**
* kintone にファイルをアップロードし、ファイルキーを取得する
* @param { File | Blob } file - アップロードするファイル
* @param { string } [fileName] - ファイル名(Blobの場合は指定必須)
* @returns { Promise<string> } ファイルキー
*/
const uploadFile = (file, fileName) => {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.append('file', file, fileName || file.name);
const xhr = new XMLHttpRequest();
xhr.open('POST', kintone.api.url('/k/v1/file.json', true));
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onload = () => {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
resolve(response.fileKey);
} else {
reject(new Error(`ファイルアップロードに失敗しました: ${xhr.status}`));
}
};
xhr.onerror = () => reject(new Error('ネットワークエラーが発生しました'));
xhr.send(formData);
});
};
ファイルをアップロードしてレコードに添付する
取得したファイルキーを使って、レコードの添付ファイルフィールドに設定します。
(() => {
'use strict';
/**
* ファイルをアップロードし、新規レコードの添付ファイルフィールドに設定して保存する
* @param { File } file - アップロードするファイル
* @param { string | number } app - アプリID
*/
const uploadAndCreateRecord = async (file) => {
// Step 1: ファイルをアップロードしてファイルキーを取得
const fileKey = await uploadFile(file);
// Step 2: ファイルキーを指定してレコードを追加
const body = {
app: kintone.app.getId(),
record: {
添付ファイル: {
value: [{ fileKey }],
},
タイトル: {
value: file.name,
},
},
};
const response = await kintone.api(
kintone.api.url('/k/v1/record.json', true),
'POST',
body
);
console.log('レコードが作成されました:', response);
return response;
};
kintone.events.on('app.record.index.show', (event) => {
const headerSpace = kintone.app.getHeaderMenuSpaceElement();
// ファイル選択用のinput要素を作成
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.onchange = async (e) => {
const file = e.target.files[0];
if (!file) return;
try {
await uploadAndCreateRecord(file);
alert('ファイルをアップロードし、レコードを作成しました');
location.reload();
} catch (error) {
alert('アップロードに失敗しました');
console.error(error);
}
};
const button = document.createElement('button');
button.textContent = 'ファイルから登録';
button.onclick = () => fileInput.click();
headerSpace.append(button);
return event;
});
})();
既存レコードに添付ファイルを追加する
既にファイルが添付されているレコードにファイルを追加する場合は、既存のファイル情報を取得してから追加する必要があります。
/**
* 既存レコードにファイルを追加する
* @param { string | number } app - アプリID
* @param { string | number } id - レコードID
* @param { string } fieldCode - 添付ファイルフィールドのフィールドコード
* @param { File } file - 追加するファイル
*/
const appendFileToRecord = async (app, id, fieldCode, file) => {
// Step 1: 既存のレコードから現在の添付ファイル情報を取得
const getResponse = await kintone.api(
kintone.api.url('/k/v1/record.json', true),
'GET',
{ app, id }
);
const existingFiles = getResponse.record[fieldCode].value;
// Step 2: 新しいファイルをアップロード
const fileKey = await uploadFile(file);
// Step 3: 既存のファイルキー + 新しいファイルキーでレコードを更新
const updatedFiles = [
...existingFiles.map((f) => ({ fileKey: f.fileKey })),
{ fileKey },
];
await kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', {
app,
id,
record: {
[fieldCode]: { value: updatedFiles },
},
});
};
添付ファイルフィールドを更新する際、既存のファイルキーを含めずに更新すると、既存のファイルが削除されます。ファイルを追加する場合は、必ず既存のファイル情報もあわせて指定してください。
ファイルのダウンロード
kintone 内から利用する場合
kintone の JavaScript カスタマイズでは、XMLHttpRequest を使ってファイルをダウンロードします。
/**
* kintone からファイルをダウンロードする
* @param { string } fileKey - ファイルキー
* @returns { Promise<Blob> } ダウンロードしたファイルデータ
*/
const downloadFile = (fileKey) => {
return new Promise((resolve, reject) => {
const url = kintone.api.url('/k/v1/file.json', true) + `?fileKey=${fileKey}`;
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(`ファイルダウンロードに失敗しました: ${xhr.status}`));
}
};
xhr.onerror = () => reject(new Error('ネットワークエラーが発生しました'));
xhr.send();
});
};
ダウンロードしたファイルをブラウザで保存する
ダウンロードした Blob データをブラウザのダウンロードダイアログで保存する方法です。
/**
* Blob データをファイルとしてダウンロードする
* @param { Blob } blob - ダウンロードするデータ
* @param { string } fileName - 保存するファイル名
*/
const saveBlobAsFile = (blob, fileName) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.append(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
};
レコードの添付ファイルをダウンロードする完全な例
(() => {
'use strict';
kintone.events.on('app.record.detail.show', (event) => {
const record = event.record;
const files = record['添付ファイル'].value;
if (files.length === 0) return event;
const headerSpace = kintone.app.record.getHeaderMenuSpaceElement();
// 各ファイルのダウンロードボタンを設置
files.forEach((file) => {
const button = document.createElement('button');
button.textContent = `${file.name} をダウンロード`;
button.style.marginRight = '8px';
button.onclick = async () => {
try {
const blob = await downloadFile(file.fileKey);
saveBlobAsFile(blob, file.name);
} catch (error) {
alert('ダウンロードに失敗しました');
console.error(error);
}
};
headerSpace.append(button);
});
return event;
});
})();
Node.js 環境からの操作
@kintone/rest-api-client を使った場合
Node.js 環境では @kintone/rest-api-client を使うと簡潔に記述できます。
const { KintoneRestAPIClient } = require('@kintone/rest-api-client');
const fs = require('fs');
const path = require('path');
const client = new KintoneRestAPIClient({
baseUrl: 'https://your-domain.cybozu.com',
auth: { apiToken: 'your-api-token' },
});
// ファイルのアップロード
const uploadAndAttach = async (filePath, app) => {
const fileName = path.basename(filePath);
const fileData = fs.readFileSync(filePath);
// Step 1: ファイルアップロード
const { fileKey } = await client.file.uploadFile({
file: { name: fileName, data: fileData },
});
// Step 2: レコードに添付
const response = await client.record.addRecord({
app,
record: {
添付ファイル: { value: [{ fileKey }] },
タイトル: { value: fileName },
},
});
console.log('レコード作成完了:', response);
};
// ファイルのダウンロード
const downloadAttachment = async (app, recordId, fieldCode, outputDir) => {
// レコードを取得してファイル情報を取得
const { record } = await client.record.getRecord({ app, id: recordId });
const files = record[fieldCode].value;
for (const file of files) {
const fileData = await client.file.downloadFile({ fileKey: file.fileKey });
const outputPath = path.join(outputDir, file.name);
fs.writeFileSync(outputPath, Buffer.from(fileData));
console.log(`ダウンロード完了: ${outputPath}`);
}
};
添付ファイルフィールドのデータ構造
参考として、添付ファイルフィールドのレコードデータ構造を示します。
{
"添付ファイル": {
"type": "FILE",
"value": [
{
"contentType": "application/pdf",
"fileKey": "20260224abcdef1234",
"name": "報告書.pdf",
"size": "1048576"
},
{
"contentType": "image/png",
"fileKey": "20260224ghijkl5678",
"name": "スクリーンショット.png",
"size": "204800"
}
]
}
}
value 配列内の各オブジェクトには、contentType(MIME
タイプ)、fileKey、name(ファイル名)、size(バイト数の文字列)が含まれます。
まとめ
- kintone のファイル操作は「ファイルアップロード → ファイルキー取得 → レコード保存」の 2 段階で行う
- アップロードには
XMLHttpRequestとFormDataを使用する - 既存レコードにファイルを追加する場合は、既存のファイルキーもあわせて指定する必要がある
- ダウンロードは
responseType: 'blob'で取得し、URL.createObjectURLでブラウザに保存できる - Node.js 環境では
@kintone/rest-api-clientを使うと簡潔に記述できる