@whoj/boxdk
v1.0.0-beta.8
Published
Typed version of [Box Clientside SDK]
Downloads
321
Readme
@whoj/boxdk
Typed version of Box Clientside SDK
Installation
pnpm add @whoj/boxdk # npm i @whoj/boxdk
Getting Started
Currently the root of the Box Clientside SDK contains a BasicBoxClient
property and a PersistentBoxClient
property that contains Managers for interacting with the Box REST API.
To initialize the SDK, use the following:
import BoxSdk from '@whoj/boxdk';
const box = new BoxSdk();
Access Token Details
Once you have the base SDK object, you can call the BasicBoxClient
or PersistentBoxClient
constructor for calling Box APIs within a clientside application.
For building on Box Platform with App Users this would be an individual's access token. You should never pass the Enterprise token to the client for any reason.
The Box Clientside SDK does not handle any authentication and only accepts an access token. Authentication should be handled with your application server, a serverless API gateway and lambda service, a service like Okta or Auth0, or some combination of these.
BasicBoxClient
The BoxSdk
object can create a new BasicBoxClient
. When creating a new BasicBoxClient
, you can pass in several options in a configuration object.
The most common setting you'll use when creating a BasicBoxClient
is an access token.
var client = new box.BasicBoxClient({accessToken: "1234554321"});
PersistentBoxClient
You can register a callback accessTokenHandler function with the PersistentBoxClient
type if you have your own API endpoint to generate App User tokens. You should only use the PersistentBoxClient
if you can create an API endpoint for generating Box App User tokens that is inaccessible to unauthorized users.
To create your own service for generating App User tokens, you can utilize an identity provider service like Auth0 for example. Auth0 has a service called webtask that you can write a secured lambda microservice that can generate a Box App User token using Auth0's id_token to secure the API endpoint webtask provides.
Additionally, Auth0 has a guide for implementing similar microservices within AWS and AWS Lambda.
Auth0 is not a requirement for this SDK and is only listed to give an example. Any identity provider service that can aid in securing your own REST API for generating Box App User tokens should be sufficient.
The BoxSdk
object can create a new PersistentBoxClient
. You can register a function that returns a Promise or callback function that resolves to an access token and keep your PersistentBoxClient
authorized to make calls to the Box API.
Examples of Valid accessTokenHandlers
function returnNewAccessToken(cb) {
$.ajax({
url: "http://localhost:3000/userToken",
method: "GET",
headers: { "Authorization": "Bearer identitfyTokenFrom3rdParyIdentityProvider" },
})
.done(function (data) {
cb(null, data);
});
}
function returnAccessTokenReturnsPromise() {
return new Promise(function (resolve, reject) {
$.ajax({
url: "http://localhost:3000/userToken",
method: "GET",
headers: { "Authorization": "Bearer identitfyTokenFrom3rdParyIdentityProvider" },
dataType: 'json'
})
.done(function (data) {
resolve(data);
});
});
}
//Angular Service Example
//boxTokenService.js
//Used to register your secure token endpoint for retrieving new tokens on expiration.
//Utilizing Auth0's idToken for endpoint authentication.
(function () {
'use strict';
angular
.module('authApp')
.service('boxTokenSerivce', ['$q', '$http', 'APP_CONFIG', BoxTokenService]);
function BoxTokenService($q, $http, APP_CONFIG) {
this.getAccessToken = function () {
var deferred = $q.defer();
var idToken = localStorage.getItem(APP_CONFIG.VARIABLES.AUTH0_ID_TOKEN_STORAGE_KEY);
$http({
url: APP_CONFIG.VARIABLES.BOX_REFRESH_TOKEN_URL,
type: 'GET',
headers: { Authorization: 'Bearer ' + idToken }
})
.then(function (response) {
deferred.resolve(response.data);
}, function (response) {
deferred.reject(response);
});
return deferred.promise;
}
}
})();
//boxApiService.js
//Used to create PersistentBoxClients and register your function to retrieve new tokens on expiration.
(function () {
'use strict';
angular
.module('authApp')
.service('boxApiService', BoxApiService);
BoxApiService.$inject = ['$q', '$http', 'boxTokenSerivce', 'APP_CONFIG'];
function BoxApiService($q, $http, boxToken, APP_CONFIG) {
var box = new BoxSdk();
this.persistentBoxClient = function () {
//You can overwrite the built-in SDK httpService and Promise objects with Angular's services.
//With this configuration, $scope will update from within the deferred .then methods returned by the SDK.
return new box.PersistentBoxClient({ accessTokenHandler: boxToken.getAccessToken, httpService: $http, Promise: $q });
};
this.persistentBoxClientOptionsOnly = function () {
return new box.PersistentBoxClient({ accessTokenHandler: boxToken.getAccessToken, noRequestMode: true });
}
}
})();
Register accessTokenHandler
with a PersistentBoxClient
After defining your accessTokenHandler
, you can register the handler function with the PersistentBoxClient
.
var box = new BoxSdk();
var persistClient = new box.PersistentBoxClient({ accessTokenHandler: returnAccessTokenReturnsPromise });
Please note, if you are utilizing a callback function as in returnNewAccessToken
, you'll need to set the callback
flag to true:
var box = new BoxSdk();
var persistClient = new box.PersistentBoxClient({ accessTokenHandler: returnNewAccessToken, isCallback: true });
Before issuing an API call, the SDK will now make sure your access token is not expired and will refresh your token using this accessTokenHandler function if the access token is expired.
Change Storage Option
By default, the PersistentBoxClient
detects if HTML5 storage is available, and if so, uses localStorage
to keep a token in browser cache to avoid making unnecessary AJAX calls.
You can change the storage option to sessionStorage
with the following flag:
var box = new BoxSdk();
var persistClient = new box.PersistentBoxClient({ accessTokenHandler: returnAccessTokenReturnsPromise, storage: "sessionStorage" });
Modes
Additionally, you can set the BasicBoxClient
and PersistentBoxClient
to perform in a few different modes.
noRequestMode
var client = new box.BasicBoxClient({accessToken: "1234554321", noRequestMode: true});
If you enable noRequestMode
, the SDK will not process your method calls as actual AJAX requests and will instead format an options
object according to the values within the SDK and the parameters you pass to each managers methods. The options
object is returned directly from the method.
You can then use the returned options
values with another HTTP service such as Angular's $http if needed or preferred.
Example:
var box = new BoxSdk();
var client = new box.BasicBoxClient({accessToken: "1234554321", noRequestMode: true});
var options = client.folders.get({ id: "0"});
/*
The options object will contain these values:
{
headers:
{
Authorization: "Bearer 1MVXXj333PepuMVOWLT8wRUZU3Z2G9Pv"
},
method: "GET",
url: "https://api.box.com/2.0/folders/0"
}
*/
simpleMode
var client = new box.BasicBoxClient({accessToken: "1234554321", simpleMode: true});
If you enable simpleMode
, the SDK will not process any validation against objects sent on calls requiring an options.body.
httpService
var client = new box.PersistentBoxClient({ httpService: $http });
You can change what service completes the AJAX HTTP requests completed by the SDK. Typically, this is useful for a framework like Angular.
Promise
var client = new box.PersistentBoxClient({ Promise: $q });
You can change what service creates the Promises used by the SDK. Typically, this is useful for a framework like Angular.
Configuration for Angular 1
Before instantiating any of the Box clients within the Box SDK, you'll need access to $http
. You'll also need $q
if working with the PersistentBoxClient
.
To use the PersistentBoxClient
and emit changes to $scope
, use the following configuration:
var persistClient = new box.PersistentBoxClient({ accessTokenHandler: boxToken.getAccessToken, httpService: $http, Promise: $q });
To use the BasicBoxClient
and emit changes to $scope
, use the following configuration:
var client = new box.BasicBoxClient({accessToken: "1234554321", httpService: $http});
Verbosity
verbose
var client = new box.BasicBoxClient({accessToken: "1234554321", verbose: true});
If you enable verbose
, the SDK will output some debug messages to the browser console.
Example Usage
Simple Upload
var accessToken = "1234";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
form.onsubmit = function (event) {
event.preventDefault();
uploadButton.innerHTML = 'Uploading...';
var files = fileSelect.files;
var formData = new FormData();
formData.append(files[0].name, files[0]);
formData.append('parent_id', '0');
boxClient.files.upload({ body: formData })
.then(function (file) {
var newFile = file;
})
.catch(function (err) {
console.log(err);
});
}
Get Root Folder
var accessToken = "1234";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
boxClient.folders.get({ id: "0", params: {fields: "name,item_collection"} })
.then(function (folder) {
var rootFolder = folder;
var id = folder.id;
})
.catch(function (err) {
console.log(err);
});
Create New Folder
var accessToken = "1234";
var rootFolderId = "0";
var folderName = "New Folder";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
boxClient.folders.create({ parent: { id: rootFolderId }, name: folderName })
.then(function (folder) {
var newFolder = folder;
})
.catch(function (err) {
console.log(err);
});
Get File Info
var accessToken = "1234";
var fileId = "8675309";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
boxClient.files.get({id: fileId})
.then(function (file) {
var file = file;
})
.catch(function (err) {
console.log(err);
});
Get Comment Info
var accessToken = "1234";
var commentId = "42";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
boxClient.comments.get({id: commentId})
.then(function (comment) {
var comment = comment;
})
.catch(function (err) {
console.log(err);
});
Get Preview Link for File
var accessToken = "1234";
var fileId = "8675309";
var boxClient = new box.BasicBoxClient({ accessToken: accessToken });
boxClient.files.getEmbedLink({ id: fileId })
.then(function (url) {
var file = url;
});
.catch(function (err) {
console.log(err);
});
Create Metadata on File
var accessToken = "1234";
var fileId = "8675309";
//scope is an optional parameter you can use in the object.
//If not set, scope will default to "enterprise".
var scope = "enterprise";
var box = new BoxSdk();
var client = new box.BasicBoxClient({ accessToken: accessToken });
client.metadata.createFileMetadata({
fileId: fileId,
scope: scope,
body: {
lineOfBusiness: "commercial"
},
templateKey: "customer"
})
Upload New Version and Rename File
var accessToken = "1234";
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
form.onsubmit = function(event){
event.preventDefault();
uploadButton.innerHTML = 'Uploading...';
var files = fileSelect.files;
var formData = new FormData();
var box = new BoxSdk();
var client = new box.BasicBoxClient({accessToken: accessToken});
var formData = new FormData();
formData.append('file', files[0]);
formData.append('id', '335561149042');
formData.append('attributes', '{"name": "newlaser.jpg"}');
client.files.uploadNewFileVersion({ body: formData })
.then(file => console.log(file))
.catch(e => console.log(e));
}
Upload with Preflight and MD5 check
Please note: This method has not undergone signficant testing. Please use at your own risk.
var accessToken = "1234";
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
form.onsubmit = function(event){
event.preventDefault();
uploadButton.innerHTML = 'Uploading...';
var files = fileSelect.files;
var formData = new FormData();
var box = new BoxSdk();
var client = new box.BasicBoxClient({accessToken: accessToken});
formData.append('files', files[0], files[0].name);
formData.append('parent_id', '0');
client.files.uploadWithPreflightAndMd5({
body: formData,
name: files[0].name,
file: files[0],
parent: { id: "0"},
size: files[0].size
})
.then(function (file) {
var newFile = file;
})
.catch(function (err) {
console.log(err);
});
}
Upload New Version with Preflight and MD5 check
Please note: This method has not undergone signficant testing. Please use at your own risk.
var accessToken = "1234";
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
form.onsubmit = function(event){
event.preventDefault();
uploadButton.innerHTML = 'Uploading...';
var files = fileSelect.files;
var formData = new FormData();
var box = new BoxSdk();
var client = new box.BasicBoxClient({accessToken: accessToken});
formData.append('files', files[0], files[0].name);
formData.append('parent_id', '0');
formData.append('id', '204457430882');
client.files.uploadNewFileVersionWithPreflightAndMd5({
body: formData,
name: files[0].name,
file: files[0],
parent: { id: "0"},
size: files[0].size
})
.then(function (file) {
var newFile = file;
})
.catch(function (err) {
console.log(err);
});
Upload File Greater than 50MB with Chunking
Please note: This method has not undergone signficant testing. Please use at your own risk.
var accessToken = "1234";
// Must be an HTML5 File object
var file = new File([], "test.iso");
var box = new BoxSdk();
// Uses XHR to perform chunked upload
var client = new box.BasicBoxClient({ accessToken: accessToken });
// If you want to use Angular services for chunked upload, you must include both the Angular HTTP service and the Angular Promise service:
var client = new box.PersistentBoxClient({ accessTokenHandler: accessTokenHandler, httpService: $http, Promise: $q });
// Cancel an upload by firing this event:
var abortEvt = new Event("boxChunkedUploadAbortUpload");
dispatchEvent(abortEvt);
client.files.chunkedUpload({
file: file,
name: "test.iso",
parentFolder: { id: "0" },
listeners: {
// Register a listener for receiving a percentage of SHA1 processed parts and uploaded parts
handleProgressUpdates: function (e) {
console.log("Progress captured...");
console.log("Percentage processed: ");
console.log(e.detail.progress.percentageProcessed);
console.log("Percentage uploaded: ");
console.log(e.detail.progress.percentageUploaded);
},
// Starting event fired after cancelling work is complete
getIsCancellingNotification: function (e) {
console.log("Started cancelling!");
console.log(e.detail.progress)
},
// Finish event fired after cancelling work is complete
getIsCancelledNotification: function (e) {
console.log("Finished cancelling!");
console.log(e.detail.progress)
},
// Register a listener for a failure event
getFailureNotification: function (e) {
console.log("Failed!");
console.log(e.detail.progress.didFail)
},
// Register a listener for a success event
getSuccessNotification: function (e) {
console.log("Success!");
console.log(e.detail.progress.didSucceed)
},
// Register a listener for when the upload process starts
getStartNotification: function (e) {
console.log("Upload started!");
console.log(e.detail.progress.didStart)
},
// Register a listener for when a commit has a retry needed
getFileCommitRetryNotification: function (e) {
console.log("File commit retry needed!");
},
// Register a listener for when all parts are uploaded and the entire file is committed to Box
getFileCommitNotification: function (e) {
console.log("File committed!");
console.log(e.detail.progress.didFileCommit)
},
// Register a listener for the completion event -- with either a success or failure outcome
getCompletedNotification: function (e) {
console.log("Upload completed!");
console.log(e.detail.progress.isComplete)
}
}
})
.then(function (fileCollection) {
console.log(fileCollection);
});
Upload New Version of a File Greater than 50MB with Chunking
Please note: This method has not undergone signficant testing. Please use at your own risk.
// Must be an HTML5 File object
var file = new File([], "test.iso");
var fileId = "8675309";
var box = new BoxSdk();
// Uses XHR to perform chunked upload
var client = new box.BasicBoxClient({ accessToken: accessToken });
// If you want to use Angular services for chunked upload, you must include both the Angular HTTP service and the Angular Promise service:
var client = new box.PersistentBoxClient({ accessTokenHandler: accessTokenHandler, httpService: $http, Promise: $q });
// chunkedUploadNewFileVersion uses the same upload abort event as chunkedUpload
var abortEvt = new Event("boxChunkedUploadAbortUpload");
dispatchEvent(abortEvt);
client.files.chunkedUploadNewFileVersion({
file: uploadedFile,
name: uploadedFile.name,
id: fileId,
listeners: {
handleProgressUpdates: function (e) {
console.log("Progress captured...");
console.log("Percentage processed: ");
console.log(e.detail.progress.percentageProcessed);
console.log("Percentage uploaded: ");
console.log(e.detail.progress.percentageUploaded);
},
getIsCancellingNotification: function (e) {
console.log("Started cancelling!");
console.log(e.detail.progress)
},
getIsCancelledNotification: function (e) {
console.log("Finished cancelling!");
console.log(e.detail.progress)
},
getFailureNotification: function (e) {
console.log("Failed!");
console.log(e.detail.progress.didFail)
},
getSuccessNotification: function (e) {
console.log("Success!");
console.log(e.detail.progress.didSucceed)
},
getStartNotification: function (e) {
console.log("Upload started!");
console.log(e.detail.progress.didStart)
},
getFileCommitRetryNotification: function (e) {
console.log("File commit retry needed!");
console.log(e.detail.progress);
},
getFileCommitNotification: function (e) {
console.log("File committed!");
console.log(e.detail.progress.didFileCommit)
},
getSessionCreatedNotification: function (e) {
console.log("Session created!");
console.log(e.detail.progress.didSessionStart)
},
getCompletedNotification: function (e) {
console.log("Upload completed!");
console.log(e.detail.progress.isComplete)
}
}
});
Chain Upload New File Version on Upload File for a File Greater than 50MB with Chunking
Please note: This method has not undergone signficant testing. Please use at your own risk.
// Must be an HTML5 File object
var file = new File([], "test.iso");
var fileId = "8675309";
var box = new BoxSdk();
// Uses XHR to perform chunked upload
var client = new box.BasicBoxClient({ accessToken: accessToken });
// If you want to use Angular services for chunked upload, you must include both the Angular HTTP service and the Angular Promise service:
var client = new box.PersistentBoxClient({ accessTokenHandler: accessTokenHandler, httpService: $http, Promise: $q });
client.files.chunkedUpload({
file: uploadedFile,
name: uploadedFile.name,
parentFolder: { id: "0" },
listeners: {
handleProgressUpdates: function (e) {
console.log("Progress captured...");
console.log("Percentage processed: ");
console.log(e.detail.progress.percentageProcessed);
console.log("Percentage uploaded: ");
console.log(e.detail.progress.percentageUploaded);
},
getIsCancellingNotification: function (e) {
console.log("Started cancelling!");
console.log(e.detail.progress)
},
getIsCancelledNotification: function (e) {
console.log("Finished cancelling!");
console.log(e.detail.progress)
},
getFailureNotification: function (e) {
console.log("Failed!");
console.log(e.detail.progress.didFail)
},
getSuccessNotification: function (e) {
console.log("Success!");
console.log(e.detail.progress.didSucceed)
},
getStartNotification: function (e) {
console.log("Upload started!");
console.log(e.detail.progress.didStart)
},
getFileCommitNotification: function (e) {
console.log("File committed!");
console.log(e.detail.progress.didFileCommit)
},
getSessionCreatedNotification: function (e) {
console.log("Session created!");
console.log(e.detail.progress.didSessionStart)
},
getCompletedNotification: function (e) {
console.log("Upload completed!");
console.log(e.detail.progress.isComplete)
}
}
})
.then(function (resp) {
// Uploads file if there is no name conflict in this folder.
// Otherwise, a 409 error is thrown due to a file conflict.
})
.catch(function (e) {
if (e.status === 409) {
var fileId;
if (e.data && e.data.context_info && e.data.context_info.conflicts && e.data.context_info.conflicts.id) {
fileId = e.data.context_info.conflicts.id;
} else if (e.response && e.response.context_info && e.response.context_info.conflicts && e.response.context_info.conflicts.id) {
fileId = e.response.context_info.conflicts.id;
}
if (fileId) {
// Try to upload the file as a new version of the existing file
return client.files.chunkedUploadNewFileVersion({
file: uploadedFile,
name: uploadedFile.name,
id: fileId
});
}
}
})
.then(function (resp) {
if (resp) {
console.log("Uploaded new file version");
console.log(resp);
}
});