Backblaze B2 Node.js Library
A customizable B2 client for Node.js:
- Uses axios. You can control the axios instance at the request level (see
axios
and axiosOverride
config arguments) and at the global level (see axios
config argument at instantiation) so you can use any axios feature. - Automatically retries on request failure. You can control retry behaviour using the
retries
argument at instantiation.
Usage
This library uses promises, so all actions on a B2
instance return a promise in the following pattern:
b2.instanceFunction(arg1, arg2).then(
successFn(response) { ... },
errorFn(err) { ... }
);
Basic Example
const B2 = require('backblaze-b2');
const b2 = new B2({
applicationKeyId: 'applicationKeyId',
applicationKey: 'applicationKey'
});
async function GetBucket() {
try {
await b2.authorize();
let response = await b2.getBucket({ bucketName: 'my-bucket' });
console.log(response.data);
} catch (err) {
console.log('Error getting bucket:', err);
}
}
Response Object
Each request returns an object with:
How it works
Each action (see reference below) takes arguments and constructs an axios request. You can add additional axios options at the request level using:
- The
axios
argument (object): each property in this object is added to the axios request object only if it does not conflict with an existing property. - The
axiosOverride
argument (object): each property in this object is added to the axios request object by overriding conflicting properties, if any. Don't use this unless you know what you're doing! - Both
axios
and axiosOverride
work by recursively merging properties, so if you pass axios: { headers: { 'your-custom-header': 'header-value' } }
, the entire headers object will not be overridden - each header property (your-custom-header
) will be compared.
Reference
const B2 = require('backblaze-b2');
const b2 = new B2({
applicationKeyId: 'applicationKeyId',
applicationKey: 'applicationKey',
axios: {
},
retry: {
retries: 3
}
});
const common_args = {
axios: {
timeout: 30000
},
axiosOverride: {
}
}
b2.authorize({
});
b2.createBucket({
bucketName: 'bucketName',
bucketType: 'bucketType'
});
b2.deleteBucket({
bucketId: 'bucketId'
});
b2.listBuckets({
});
b2.getBucket({
bucketName: 'bucketName',
bucketId: 'bucketId'
});
b2.updateBucket({
bucketId: 'bucketId',
bucketType: 'bucketType'
});
b2.getUploadUrl({
bucketId: 'bucketId'
});
b2.uploadFile({
uploadUrl: 'uploadUrl',
uploadAuthToken: 'uploadAuthToken',
fileName: 'fileName',
contentLength: 0,
mime: '',
data: 'data',
hash: 'sha1-hash',
info: {
key1: 'value',
key2: 'value'
},
onUploadProgress: (event) => {} || null
});
b2.listFileNames({
bucketId: 'bucketId',
startFileName: 'startFileName',
maxFileCount: 100,
delimiter: '',
prefix: ''
});
b2.listFileVersions({
bucketId: 'bucketId',
startFileName: 'startFileName',
startFileId: 'startFileId',
maxFileCount: 100
});
b2.listParts({
fileId: 'fileId',
startPartNumber: 0,
maxPartCount: 100,
});
b2.hideFile({
bucketId: 'bucketId',
fileName: 'fileName'
});
b2.getFileInfo({
fileId: 'fileId'
});
b2.getDownloadAuthorization({
bucketId: 'bucketId',
fileNamePrefix: 'fileNamePrefix',
validDurationInSeconds: 'validDurationInSeconds',
b2ContentDisposition: 'b2ContentDisposition'
});
b2.downloadFileByName({
bucketName: 'bucketName',
fileName: 'fileName',
responseType: 'arraybuffer',
onDownloadProgress: (event) => {} || null
});
b2.downloadFileById({
fileId: 'fileId',
responseType: 'arraybuffer',
onDownloadProgress: (event) => {} || null
});
b2.deleteFileVersion({
fileId: 'fileId',
fileName: 'fileName'
});
b2.startLargeFile({
bucketId: 'bucketId',
fileName: 'fileName'
});
b2.getUploadPartUrl({
fileId: 'fileId'
});
b2.uploadPart({
partNumber: 'partNumber',
uploadUrl: 'uploadUrl',
uploadAuthToken: 'uploadAuthToken',
data: Buffer
hash: 'sha1-hash',
onUploadProgress: (event) => {} || null,
contentLength: 0,
});
b2.finishLargeFile({
fileId: 'fileId',
partSha1Array: [partSha1Array]
});
b2.cancelLargeFile({
fileId: 'fileId'
});
b2.createKey({
capabilities: [
'readFiles',
b2.KEY_CAPABILITIES.READ_FILES,
],
keyName: 'my-key-1',
validDurationInSeconds: 3600,
bucketId: 'bucketId',
namePrefix: 'prefix_',
});
b2.deleteKey({
applicationKeyId: 'applicationKeyId',
});
b2.listKeys({
maxKeyCount: 10,
startApplicationKeyId: '...',
});
Uploading Large Files Example
To upload large files, you should split the file into parts (between 5MB and 5GB) and upload each part seperately.
First, you initiate the large file upload to get the fileId:
let response = await b2.startLargeFile({ bucketId, fileName });
let fileId = response.data.fileId;
Then, to upload parts, you request at least one uploadUrl
and use the response to
upload the part with uploadPart
. The url and token returned by getUploadPartUrl()
are valid for 24 hours or until uploadPart()
fails, in which case you should request
another uploadUrl
to continue. You may utilize multiple uploadUrl
s in parallel to
achieve greater upload throughput.
If you are unsure whether you should use multipart upload, refer to the recommendedPartSize
value returned by a call to authorize()
.
let response = await b2.getUploadPartUrl({ fileId });
let uploadURL = response.data.uploadUrl;
let authToken = response.data.authorizationToken;
response = await b2.uploadPart({
partNumber: parNum,
uploadUrl: uploadURL,
uploadAuthToken: authToken,
data: buf
});
Then finish the uploadUrl:
let response = await b2.finishLargeFile({
fileId,
partSha1Array: parts.map(buf => sha1(buf))
})
If an upload is interrupted, the fileId can be used to get a list of parts
which have already been transmitted. You can then send the remaining
parts before finally calling b2.finishLargeFile()
.
let response = await b2.listParts({
fileId,
startPartNumber: 0,
maxPartCount: 1000
})
Changes
See the CHANGELOG for a history of updates.
Upgrading from 0.9.x to 1.0.x
For this update, we've switched the back end HTTP request library from request
to axios
as it has better Promise and progress support built in. However, there are a couple changes that will break your code and ruin your day. Here are the changes:
- The Promise resolution has a different data structure. Where previously, the request response data was the root object in the promise resolution (
res
), this data now resides in res.data
. - In v0.9.12, we added request progress reporting via the third parameter to
then()
. Because we are no longer using the same promise library, this functionality has been removed. However, progress reporting is still available by passing a callback function into the b2.method()
that you're calling. See the documentation below for details. - In v0.9.x,
b2.downloadFileById()
accepted a fileId
parameter as a String or Number. As of 1.0.0, the first parameter is now expected to be a plain Object of arguments.
Contributing
Contributions, suggestions, and questions are welcome. Please review the contributing guidelines for details.
Authors and Contributors
- Yakov Khalinsky (@yakovkhalinsky)
- Ivan Kalinin (@IvanKalinin) at Isolary
- Brandon Patton (@crazyscience) at Isolary
- C. Bess (@cbess)
- Amit (@Amit-A)
- Zsombor Paróczi (@realhidden)
- Oden (@odensc)