🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

knack-api-helper

Package Overview
Dependencies
Maintainers
1
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knack-api-helper - npm Package Compare versions

Comparing version
2.2.6
to
2.3.0
+270
-1
browser.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.KnackAPI = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
//Import custom fetch library
const _fetch = require('@callum.boase/fetch');
//Use native browser FormData if in browser, or require('form-data') if in Nodejs
if(inBrowser()) {
FormData = window.FormData;
} else {
var FormData = require('form-data');
}
//Helper function to check if we are in the browser
function inBrowser(){
try {
window.fetch;
return true
} catch (err){
return false;
}
}
//The main knack-api-helper
function KnackAPI(config) {

@@ -313,2 +333,251 @@

// Helper function to check that a Filestream (for file uploads) is readable
// This is a way to check if the file exists & has a size among other things
this.checkStreamReadable = async function(stream) {
if (!stream) {
throw new Error('No stream provided to check');
}
// For browser File/Blob objects, just check size exists
if (inBrowser()) {
if (stream.size === undefined) {
throw new Error('Invalid or inaccessible stream: no size property found');
}
return true;
}
// For Node.js ReadStream or other readable streams
if (stream.readable) {
try {
await new Promise((resolve, reject) => {
const cleanup = () => {
stream.removeListener('readable', onReadable);
stream.removeListener('error', onError);
};
const onReadable = () => {
cleanup();
// Reset stream position
stream.unshift(stream.read(1));
resolve(true);
};
const onError = (error) => {
cleanup();
reject(new Error(`Invalid or inaccessible stream: ${error.message}`));
};
stream.once('readable', onReadable);
stream.once('error', onError);
});
return true;
} catch (err) {
throw new Error(`Error accessing stream: ${err.message}`);
}
}
throw new Error('Provided stream is not readable');
};
// Helper function to check filestreams and prepare for upload to Knack
this.uploadFilePrep = async function(settings = {uploadType, fileStream, fileName, helperData, retries}) {
// Check that uplaodType is either 'file' or 'image'
if (!settings.uploadType || (settings.uploadType !== 'file' && settings.uploadType !== 'image')) {
throw new Error('you must specify the uploadType ("file" or "image") when running uploadFile or uploadFiles');
}
// Validate the presence of fileStream
if (!settings.fileStream) {
throw new Error('uploadFile requires a fileStream to be provided');
}
// Make sure the filestream is an object with a readable or blob-like structure
if (typeof settings.fileStream !== 'object' || (!settings.fileStream.readable && !settings.fileStream.size)) {
throw new Error('uploadFile requires fileStream to be a readable stream or a Blob/File-like object');
}
// Verify stream is readable
await this.checkStreamReadable(settings.fileStream);
// Check if fileName is provided and is a string
if (!settings.fileName) {
throw new Error('uploadFile requires a fileName to be provided');
}
if (typeof settings.fileName !== 'string') {
throw new Error('uploadFile requires fileName to be a string');
}
// Check for the presence of a file extension
if (!settings.fileName.includes('.') || settings.fileName.split('.').pop() === settings.fileName) {
throw new Error('uploadFile requires fileName to include a file extension');
}
// Prepare the form data for file upload
let formData = new FormData();
formData.append("files", settings.fileStream, settings.fileName);
//Construct headers
const headers = {
'X-Knack-REST-API-Key': 'knack',
'X-Knack-Application-ID': config.applicationId,
}
//Manually add formData info to the headers if in nodejs
if(!inBrowser()) {
Object.assign(headers, formData.getHeaders());
}
//Determine the url, based on whether we are uploading a file or image
let url;
if(settings.uploadType === 'image') {
url = `${this.urlBase}/applications/${config.applicationId}/assets/image/upload`;
} else {
url = `${this.urlBase}/applications/${config.applicationId}/assets/file/upload`;
}
// Construct the request object for _fetch
const req = {
url,
options: {
method: 'POST',
body: formData,
headers: headers,
},
retries: this.getRetries(settings.retries),
helperData: settings.helperData
};
return req;
};
this.uploadFile = async function(settings = {uploadType, fileStream, fileName, helperData, retries}) {
const req = await this.uploadFilePrep(settings);
const response = await _fetch.one(req);
return {
response,
uploadedFileId: response.json?.id,
}
};
this.uploadFiles = async function(settings = {filesToUpload: [{uploadType, fileStream, fileName}], helperData, retries, progressCbs}) {
const filesToUpload = settings.filesToUpload;
//Validate data
if (!filesToUpload) {
throw new Error('uploadFiles requires a value for filesToUpload (an array of objects {fileStream, fileName})');
}
if (!Array.isArray(filesToUpload)) {
throw new Error('uploadFiles requires filesToUpload to be an array');
}
if (filesToUpload.length === 0) {
throw new Error('uploadFiles requires filesToUpload to contain at least one item {fileStream, fileName}');
}
//Build the requests to upload files
const requests = [];
for (const file of filesToUpload) {
const request = await this.uploadFilePrep({
uploadType: file.uploadType,
fileStream: file.fileStream,
fileName: file.fileName,
helperData: settings.helperData,
retries: settings.retries
});
requests.push(request);
}
const progressCbs = this.progressCbsSetup(settings);
// Run the requests
const results = await _fetch.many({requests, delayMs: 125, progressCbs});
// Extract helpful information from the results
// We break from the standard many results format here to improve usability
// In a future release, other many methods will be updated to use this format
const summary = this.tools.manyResultsReport.calc(results);
const allSucceeded = summary.rejected === 0;
const uploadedFileIds = results.map(result => result.value?.json?.id);
return {
results,
summary,
allSucceeded,
uploadedFileIds
}
};
// Helper to prep for uploadFileFromInput and uploadFilesFromInput
this.uploadFileFromInputPrep = function (fileInput) {
//This method is only valid in the browser
if (inBrowser() === false) {
throw new Error('uploadFileFromInput and uploadFilesFromInput methods are only valid if running knack-api-helper in the browser. Use uploadFile() instead.');
}
// Validate the presence of fileInput
if (!fileInput) {
throw new Error('uploadFileFromInput requires a fileInput to be provided');
}
// Check fileInput is an object with a files property
if (!fileInput.files) {
throw new Error('uploadFileFromInput requires fileInput to have a files property');
}
// Validate there's at least one file and it has a size
if (fileInput.files.length === 0) {
throw new Error('uploadFileFromInput: no files found in fileInput. Could not continue');
}
const files = fileInput.files;
// Check if each file has a size
for (let i = 0; i < files.length; i++) {
const file = files[i];
// Check for file size
if (!file.size) {
throw new Error(`uploadFileFromInput: file (index ${i}) has no size. Could not continue`);
}
}
return files;
};
// Modify existing uploadFileFromInput to use the new prep function
this.uploadFileFromInput = async function (settings = { uploadType, fileInput, helperData, retries }) {
const files = this.uploadFileFromInputPrep(settings.fileInput);
const file = files[0];
// Create a FormData object and append the file
const formData = new FormData();
formData.append('fileStream', file, file.name);
//Upload the file to Knack servers
return await this.uploadFile({
uploadType: settings.uploadType,
fileStream: formData.get('fileStream'),
fileName: file.name,
helperData: settings.helperData,
retries: settings.retries
});
};
// Add new uploadFilesFromInput function
this.uploadFilesFromInput = async function (settings = { uploadType, fileInput, helperData, retries, progressCbs }) {
const files = this.uploadFileFromInputPrep(settings.fileInput);
const filesToUpload = Array.from(files).map(file => ({
fileStream: file,
fileName: file.name,
uploadType: settings.uploadType
}));
return await this.uploadFiles({
filesToUpload,
helperData: settings.helperData,
retries: settings.retries,
progressCbs: settings.progressCbs
});
};
this.tools = {

@@ -459,3 +728,3 @@ progressBar: {

module.exports = KnackAPI;
},{"@callum.boase/fetch":2}],2:[function(require,module,exports){
},{"@callum.boase/fetch":2,"form-data":3}],2:[function(require,module,exports){
//Only load node-fetch in nodeJs environment

@@ -462,0 +731,0 @@ //If we're running this file in browser, we'll use the browser's fetch API which is built-in

+16
-7
# Knack-api-helper CHANGELOG
## 2022/04/26 Version 2.2.4 -> 2.2.5 -> 2.2.6
## 2024/12/17 Version 2.2.6 -> 2.3.0
* Added new methods for file uploads
* `uploadFile()`
* `uploadFiles()`
* `uploadFileFromInput()`
* `uploadFilesFromInput()`
* All other methods are unchanged. No breaking changes.
* Fix incorrect dates in the changelog (all dates were listed as 2022 despite some changes beeing from 2023 and 2024)
## 2024/04/26 Version 2.2.4 -> 2.2.5 -> 2.2.6
* Updated mistake in readme for `putMany()`
* Skipped 2.2.5 due to unpublishing version 2.2.5 from NPM due to publishing mistake.
## 2022/01/29 Version 2.2.3 -> 2.2.4
## 2024/01/29 Version 2.2.3 -> 2.2.4
* Added new method getFromReportView() the enables getting data from report view (when using view-based auth)
* Refactored knack-api-helper.js to support this, but there are no functionality changes to existing methods (get, post, put, delete, getMany, postMany, putMany, deleteMany, login, remoteLogin, validateSession)
## 2022/09/16 Version 2.2.2 -> 2.2.3
## 2023/09/16 Version 2.2.2 -> 2.2.3
* Fixed browser build (browser loadable file). Otherwise unchanged
## 2022/09/11 Version 2.2.1 -> 2.2.2
## 2023/09/11 Version 2.2.1 -> 2.2.2
* Added MIT license file.
## 2022/09/11 - Version 2.2.0 -> 2.2.1
## 2023/09/11 - Version 2.2.0 -> 2.2.1
* Updated the readme to fix error in instructions for loading knack-api-helper into Knack javascript area.
## 2022/08/29 - Version 2.1.5 -> 2.2.0
## 2023/08/29 - Version 2.1.5 -> 2.2.0
* Added `validateSession()` method (see readme for details)
## 2022/05/08 - Version 2.1.4 -> 2.1.5
## 2023/05/08 - Version 2.1.4 -> 2.1.5
* Updated readme.md with more documentation and examples

@@ -25,0 +34,0 @@

@@ -0,3 +1,23 @@

//Import custom fetch library
const _fetch = require('@callum.boase/fetch');
//Use native browser FormData if in browser, or require('form-data') if in Nodejs
if(inBrowser()) {
FormData = window.FormData;
} else {
var FormData = require('form-data');
}
//Helper function to check if we are in the browser
function inBrowser(){
try {
window.fetch;
return true
} catch (err){
return false;
}
}
//The main knack-api-helper
function KnackAPI(config) {

@@ -312,2 +332,251 @@

// Helper function to check that a Filestream (for file uploads) is readable
// This is a way to check if the file exists & has a size among other things
this.checkStreamReadable = async function(stream) {
if (!stream) {
throw new Error('No stream provided to check');
}
// For browser File/Blob objects, just check size exists
if (inBrowser()) {
if (stream.size === undefined) {
throw new Error('Invalid or inaccessible stream: no size property found');
}
return true;
}
// For Node.js ReadStream or other readable streams
if (stream.readable) {
try {
await new Promise((resolve, reject) => {
const cleanup = () => {
stream.removeListener('readable', onReadable);
stream.removeListener('error', onError);
};
const onReadable = () => {
cleanup();
// Reset stream position
stream.unshift(stream.read(1));
resolve(true);
};
const onError = (error) => {
cleanup();
reject(new Error(`Invalid or inaccessible stream: ${error.message}`));
};
stream.once('readable', onReadable);
stream.once('error', onError);
});
return true;
} catch (err) {
throw new Error(`Error accessing stream: ${err.message}`);
}
}
throw new Error('Provided stream is not readable');
};
// Helper function to check filestreams and prepare for upload to Knack
this.uploadFilePrep = async function(settings = {uploadType, fileStream, fileName, helperData, retries}) {
// Check that uplaodType is either 'file' or 'image'
if (!settings.uploadType || (settings.uploadType !== 'file' && settings.uploadType !== 'image')) {
throw new Error('you must specify the uploadType ("file" or "image") when running uploadFile or uploadFiles');
}
// Validate the presence of fileStream
if (!settings.fileStream) {
throw new Error('uploadFile requires a fileStream to be provided');
}
// Make sure the filestream is an object with a readable or blob-like structure
if (typeof settings.fileStream !== 'object' || (!settings.fileStream.readable && !settings.fileStream.size)) {
throw new Error('uploadFile requires fileStream to be a readable stream or a Blob/File-like object');
}
// Verify stream is readable
await this.checkStreamReadable(settings.fileStream);
// Check if fileName is provided and is a string
if (!settings.fileName) {
throw new Error('uploadFile requires a fileName to be provided');
}
if (typeof settings.fileName !== 'string') {
throw new Error('uploadFile requires fileName to be a string');
}
// Check for the presence of a file extension
if (!settings.fileName.includes('.') || settings.fileName.split('.').pop() === settings.fileName) {
throw new Error('uploadFile requires fileName to include a file extension');
}
// Prepare the form data for file upload
let formData = new FormData();
formData.append("files", settings.fileStream, settings.fileName);
//Construct headers
const headers = {
'X-Knack-REST-API-Key': 'knack',
'X-Knack-Application-ID': config.applicationId,
}
//Manually add formData info to the headers if in nodejs
if(!inBrowser()) {
Object.assign(headers, formData.getHeaders());
}
//Determine the url, based on whether we are uploading a file or image
let url;
if(settings.uploadType === 'image') {
url = `${this.urlBase}/applications/${config.applicationId}/assets/image/upload`;
} else {
url = `${this.urlBase}/applications/${config.applicationId}/assets/file/upload`;
}
// Construct the request object for _fetch
const req = {
url,
options: {
method: 'POST',
body: formData,
headers: headers,
},
retries: this.getRetries(settings.retries),
helperData: settings.helperData
};
return req;
};
this.uploadFile = async function(settings = {uploadType, fileStream, fileName, helperData, retries}) {
const req = await this.uploadFilePrep(settings);
const response = await _fetch.one(req);
return {
response,
uploadedFileId: response.json?.id,
}
};
this.uploadFiles = async function(settings = {filesToUpload: [{uploadType, fileStream, fileName}], helperData, retries, progressCbs}) {
const filesToUpload = settings.filesToUpload;
//Validate data
if (!filesToUpload) {
throw new Error('uploadFiles requires a value for filesToUpload (an array of objects {fileStream, fileName})');
}
if (!Array.isArray(filesToUpload)) {
throw new Error('uploadFiles requires filesToUpload to be an array');
}
if (filesToUpload.length === 0) {
throw new Error('uploadFiles requires filesToUpload to contain at least one item {fileStream, fileName}');
}
//Build the requests to upload files
const requests = [];
for (const file of filesToUpload) {
const request = await this.uploadFilePrep({
uploadType: file.uploadType,
fileStream: file.fileStream,
fileName: file.fileName,
helperData: settings.helperData,
retries: settings.retries
});
requests.push(request);
}
const progressCbs = this.progressCbsSetup(settings);
// Run the requests
const results = await _fetch.many({requests, delayMs: 125, progressCbs});
// Extract helpful information from the results
// We break from the standard many results format here to improve usability
// In a future release, other many methods will be updated to use this format
const summary = this.tools.manyResultsReport.calc(results);
const allSucceeded = summary.rejected === 0;
const uploadedFileIds = results.map(result => result.value?.json?.id);
return {
results,
summary,
allSucceeded,
uploadedFileIds
}
};
// Helper to prep for uploadFileFromInput and uploadFilesFromInput
this.uploadFileFromInputPrep = function (fileInput) {
//This method is only valid in the browser
if (inBrowser() === false) {
throw new Error('uploadFileFromInput and uploadFilesFromInput methods are only valid if running knack-api-helper in the browser. Use uploadFile() instead.');
}
// Validate the presence of fileInput
if (!fileInput) {
throw new Error('uploadFileFromInput requires a fileInput to be provided');
}
// Check fileInput is an object with a files property
if (!fileInput.files) {
throw new Error('uploadFileFromInput requires fileInput to have a files property');
}
// Validate there's at least one file and it has a size
if (fileInput.files.length === 0) {
throw new Error('uploadFileFromInput: no files found in fileInput. Could not continue');
}
const files = fileInput.files;
// Check if each file has a size
for (let i = 0; i < files.length; i++) {
const file = files[i];
// Check for file size
if (!file.size) {
throw new Error(`uploadFileFromInput: file (index ${i}) has no size. Could not continue`);
}
}
return files;
};
// Modify existing uploadFileFromInput to use the new prep function
this.uploadFileFromInput = async function (settings = { uploadType, fileInput, helperData, retries }) {
const files = this.uploadFileFromInputPrep(settings.fileInput);
const file = files[0];
// Create a FormData object and append the file
const formData = new FormData();
formData.append('fileStream', file, file.name);
//Upload the file to Knack servers
return await this.uploadFile({
uploadType: settings.uploadType,
fileStream: formData.get('fileStream'),
fileName: file.name,
helperData: settings.helperData,
retries: settings.retries
});
};
// Add new uploadFilesFromInput function
this.uploadFilesFromInput = async function (settings = { uploadType, fileInput, helperData, retries, progressCbs }) {
const files = this.uploadFileFromInputPrep(settings.fileInput);
const filesToUpload = Array.from(files).map(file => ({
fileStream: file,
fileName: file.name,
uploadType: settings.uploadType
}));
return await this.uploadFiles({
filesToUpload,
helperData: settings.helperData,
retries: settings.retries,
progressCbs: settings.progressCbs
});
};
this.tools = {

@@ -314,0 +583,0 @@ progressBar: {

{
"name": "knack-api-helper",
"version": "2.2.6",
"version": "2.3.0",
"description": "Methods for interacting with the Knack API using both view-based and object-based authentication",

@@ -8,3 +8,3 @@ "main": "knack-api-helper.js",

"test": "echo \"Error: no test specified\" && exit 1",
"build": "browserify --ignore node-fetch --standalone KnackAPI knack-api-helper.js > browser.js"
"build": "browserify --ignore node-fetch --ignore form-data --standalone KnackAPI knack-api-helper.js > browser.js"
},

@@ -25,4 +25,5 @@ "repository": {

"dependencies": {
"@callum.boase/fetch": "^1.5.0"
"@callum.boase/fetch": "^1.5.0",
"form-data": "^4.0.0"
}
}
+352
-0

@@ -792,1 +792,353 @@ # KnackAPI

## File uploads
Uploading a file or image to Knack involves two steps:
1. **Upload the file/image to Knack servers.** After uploading, the response will contain a file ID such as `675fafbf3cfc88031b154795`.
2. **Create or update a Knack record**, using the ID of the file/image field as the value for a file or image field.
For more information on how Knack handle file uploads, refer to the [Knack File/Image Uploads Documentation](https://docs.knack.com/docs/fileimage-uploads).
Knack-api-helper requires this 2-step process but adds methods to make it easier.
The API calls to upload files to Knack servers have similar behaviour to the standard CRUD API calls listed above, including auto-retry when sensible.
There are 4 methods available for file uploads. These are:
* `uploadFile()` (usually for Node.js code, upload single file to Knack servers)
* `uploadFiles()` (usually for Node.js code, upload multiple files to Knack servers)
* `uploadFileFromInput()` (for client-side code only, upload single file from an HTML file input)
* `uploadFilesFromInput()` (for client-side code only, upload multiple files from an HTML file input)
All 4 methods share common parameters, as listed below:
### Common parameters for file upload API calls
| Parameter | Type | Required? | Auth type applies to | Details |
| --- | --- | --- | --- | --- |
| helperData | object | No | Both | Any arbritrary object you want to include with the API call. This will get returned to you when you receive the response to the API call.<br><br> Useful for tracking data about the request that wouldn't ordinarily be easy to understand from the data received back from the API call. |
| retries | integar >= 0 | No | Both | The number of times to retry the API call/s on failure, if the error code indicates that a retry might fix the error ([see above](#auto-retry-and-delay-between-retries)). Defaults to 5 if no value is provided. |
### uploadFile()
Upload a single file to Knack servers. This method is most helpful for usage in Node.js code or similar, where you have a file stored locally that you want to upload. However, it could be adapted for use in the browser environment too.
**Parameters:**
* The common parameters for file upload API calls plus:
| Parameter | Type | Required? | Auth type applies to | Details |
|----|----|----|----|----|
| uploadType | String | Yes | Both | Type of field you're uploading to, either `'file'` or `'image'`. |
| fileStream | Stream | Yes | Both | A readable stream of the file to upload. |
| fileName | String | Yes | Both | The name of the file to upload, including extension (eg `example.png`) |
#### uploadFile example (Node.js environment)
```javascript
const KnackAPI = require('../knack-api-helper.js');
const fs = require('fs');
const path = require('path');
async function uploadFileTest() {
//Assuming there's a file stored in the same directory this is running called example.png
//Extract the necessary information from the file and create a file stream
const filePath = path.join(__dirname, 'example.png');
const fileStream = fs.createReadStream(filePath);
const fileName = path.basename(filePath);
try {
//Initialise knack-api-helper
const knackAPI = new KnackAPI({
auth: 'view-based', // You could also use object-based auth
applicationId: "YOUR-APPLICATION-ID",
//No need for userToken or login when uploading files.
});
//Upload the file to Knack servers
const { uploadedFileId, response } = await knackAPI.uploadFile({
uploadType: 'file',//Or 'image'
fileStream,
fileName
});
console.log('Upload successful. Here is the file ID to save to your Knack record: ', uploadedFileId);
// Create a new record in Knack with the file attached
// This example uses a publicly accessible form, but you could also use a login protected one if you pass a userToken or run login first
// You could also use object-based auth if knackAPI was initialised with auth: 'object-based'
const newRecordResponse = await knackAPI.post({
scene: 'scene_7',
view: 'view_6',
body: {
field_23: uploadedFileId, //Assuming field_23 is a file or image field in your Knack database
field_25: 'Hello', //Any other value(s) you want to fill
}
})
console.log('Added new record', newRecordResponse);
} catch (error) {
console.error(error);
}
}
//Run the function defined above
uploadFileTest();
```
### uploadFiles()
Upload multiple files to Knack servers. As for `uploadFile`, this method is most helpful for usage in Node.js code or similar, where you have files stored locally that you want to upload. However, it could be adapted for use in the browser environment.
**Parameters:**
* The common parameters for file upload API calls plus:
| Parameter | Type | Required? | Auth type applies to | Details |
|----|----|----|----|----|
| filesToUpload | Array of objects | Yes | Both | An array of objects, 1 per file to upload, containing parameters `uploadType` (string: 'file' or 'image'), `fileStream` (a readable stream of the file to upload) and `fileName` (string eg `example.png`) |
#### uploadFiles() example (Node.js Environment)
```javascript
const KnackAPI = require('../knack-api-helper.js');
const fs = require('fs');
const path = require('path');
async function uploadFilesTest() {
//Assuming there's are files stored in the same directory this is running called example..png, example2.png, example3.png
//Extract the necessary information from the file and create a file stream
const filePaths = [
path.join(__dirname, 'example.png'),
path.join(__dirname, 'example2.png'),
path.join(__dirname, 'example3.png'),
]
const filesToUpload = filePaths.map(filePath => {
return {
uploadType: 'file',//Or 'image'
fileStream: fs.createReadStream(filePath),
fileName: path.basename(filePath)
}
});
try {
// Initialise knack-api-helper
const knackAPI = new KnackAPI({
auth: 'view-based',
applicationId: "YOUR-APPLICATION-ID",
//No need for userToken or login when uploading files.
});
//Upload the file to Knack servers
const { results, uploadedFileIds, allSucceeded, summary } = await knackAPI.uploadFiles({
filesToUpload
});
if (!allSucceeded) {
console.error('At least one file failed to upload. Here is a summary of the results:', summary);
console.log(results);
} else {
console.log('All files uploaded successfully. Here are the IDs of uploaded files to append to Knack records');
console.log(uploadedFileIds);
}
// Create one record in Knack per uploaded file
// With the uploaded file attached to the record
// This example uses a publicly accessible scene and view, but you can also use a login-protected one if you run the login method first
// You could also use object-based auth if knackAPI was initialised with auth: 'object-based'
const records = uploadedFileIds.map(uploadedFileId => {
return {
field_23: uploadedFileId, //Assuming field_23 is a file or image field in your Knack database
field_25: 'Hello', //Any other value(s) you want to fill
}
});
// Run the POST request to create the records in Knack
const newRecordResponses = await knackAPI.postMany({
scene: 'scene_7',
view: 'view_6',
records
})
// Check if all records were added successfully
if (newRecordResponses.summary.rejected > 0) {
console.error('Some records failed to post. Here is a summary of the results:', newRecordResponses.summary);
} else {
console.log('All records added successfully', newRecordResponses);
}
} catch (err) {
// Handle any other errors
// Errors from uploadFiles and postMany will NOT reach here
console.error(err);
}
}
uploadFilesTest();
```
### uploadFileFromInput()
Upload a single file from an HTML file input on a webpage to Knack servers. This method is ONLY for use in the browser environment eg in javascript code running on a webpage or a Knack page.
Since this method is for client-side (browser) code, we strongly recommend initialising knack-api-helper with view-based authentication to avoid exposing your API key to the public.
**Parameters:**
* The common parameters for file upload API calls plus:
| Parameter | Type | Required? | Auth type applies to | Details |
|----|----|----|----|----|
| uploadType | String | Yes | Both | Type of upload, either `'file'` or `'image'`.|
| fileInput | HTMLElement | Yes | Both | The HTML file input element containing the file. The first uploaded file (index 0) will be used so we recommend that the file input is configured to only allow selecting a single file. |
#### uploadFileFromInput() Example (Browser Environment)
The example below uses plain HTML and javascript to create a form with a file input and a submit button. When the form is submitted, the file is uploaded to Knack servers and a new record is created with the file attached.
This code could be adapted to use jquery instead of plain javascript, as is more conventional when writing code to use within a Knack app.
```html
<!--HTML for a basic form with a file input (single select) and a submit button -->
<form id="fileUploadForm">
<input type="file" id="fileInput" name="file">
<button type="submit">Upload File</button>
</form>
<!-- Javascript to process form submit: upload file and create a new Knack record with it attached file -->
<script>
document.getElementById('fileUploadForm').addEventListener('submit', async function (e) {
e.preventDefault();
try {
// Initialize the KnackAPI with your configuration
const knackAPI = new KnackAPI({
auth: 'view-based',
applicationId: "YOUR-APPLICATION-ID",
// No need for userToken or login when uploading files.
});
// Select the fileInput in the form
const myFileInput = document.getElementById('fileInput');
// Run the API call to upload file to Knack server
const { response, uploadedFileId } = await knackAPI.uploadFileFromInput({
uploadType: 'file', // Or 'image'
fileInput: myFileInput
});
console.log('File uploaded successfully. Here is the ID to save to your Knack record:', uploadedFileId);
// Create a new record in Knack with the file attached
// This example uses a publicly accessible form, but you could also use a login protected one if you pass a userToken
// when initialising knackAPI or run the login method first
const newRecordResponse = await knackAPI.post({
scene: 'scene_7',
view: 'view_6',
body: {
field_23: uploadedFileId, // Assuming field_23 is a file or image field in your Knack database
field_25: 'Hello', // Any other value(s) you want to fill
}
});
console.log('Added new record', newRecordResponse);
} catch (error) {
console.error('File upload or record creation failed:', error);
}
});
</script>
```
### uploadFilesFromInput()
Upload multiple files from an HTML file input to Knack servers. As for `uploadFileFromInput`, this method is ONLY for use in the browser environment eg in javascript code running on a webpage or a Knack page.
Since this method is for client-side (browser) code, we strongly recommend initialising knack-api-helper with view-based authentication to avoid exposing your API key to the public.
**Parameters:**
* The common parameters for file upload API calls plus:
| Parameter | Type | Required? | Auth type applies to | Details |
|----|----|----|----|----|
| uploadType | String | Yes | Both | Type of upload, either `'file'` or `'image'`.|
| fileInput | HTMLElement | Yes | Both | The HTML file input element containing the file/s to upload. All files from the file input will be uploaded so you can configure it to accept multiple files. |
**Important note:** different to `uploadFiles()`, it's not possible in `uploadFilesFromInput()` to specify a different `uploadType` per file. Instead, we specify one `uploadType` for all files found in the `fileInput`.
#### uploadFilesFromInput() Example (Browser Environment)
```html
<!-- A basic form with a file input that allows multiple selection, and a submit button -->
<form id="fileUploadForm">
<input type="file" id="fileInput" name="file" multiple>
<button type="submit">Upload Multiple Files</button>
</form>
<!-- Javascript to process form submit: upload files and create new Knack records for each file -->
<script>
document.getElementById('fileUploadForm').addEventListener('submit', async function (e) {
e.preventDefault();
try {
// Initialize the KnackAPI with your configuration
const knackAPI = new KnackAPI({
auth: 'view-based',
applicationId: "YOUR-APPLICATION-ID",
// No need for userToken or login when uploading files.
});
// Select the fileInput in the form
const myFileInput = document.getElementById('fileInput');
// Run the API call to upload files to Knack servers
const { response, uploadedFileIds, allSucceeded, summary } = await knackAPI.uploadFilesFromInput({
uploadType: 'file', // Or 'image'
fileInput: myFileInput
});
// Check if all files were uploaded successfully
if (allSucceeded) {
console.log('All files uploaded successfully. Here are the IDs to save to your Knack records:', uploadedFileIds);
} else {
console.error('Some files failed to upload. Here is a summary of the results:', summary);
}
// Create one record in Knack per uploaded file
// This example uses a publicly accessible form, but you could also use a login protected one if you pass a userToken
// when initialising knackAPI or run the login method first
const records = uploadedFileIds.map(uploadedFileId => {
return {
field_23: uploadedFileId, // Assuming field_23 is a file or image field in your Knack database
field_25: 'Hello', // Any other value(s) you want to fill
};
});
const newRecordResponses = await knackAPI.postMany({
scene: 'scene_7',
view: 'view_6',
records
});
// Check if all records were added successfully
if (newRecordResponses.summary.rejected > 0) {
console.error('Some records failed to post. Here is a summary of the results:', newRecordResponses.summary);
} else {
console.log('All records added successfully', newRecordResponses);
}
} catch (err) {
console.error('Something went wrong', err);
}
});
</script>
```