This is a thin Javascript client for Draftable's document comparison API.
It wraps the available endpoints, and handles authentication and signing for you.
The library is available on npm as @draftable/compare-api.
See the full API documentation for an introduction to the API, usage notes, and other references.
-
Sign up for free at api.draftable.com to get your credentials.
-
npm install @draftable/compare-api -
Instantiate the client:
const client = require('@draftable/compare-api').client(<yourAccountId>, <yourAuthToken>); const comparisons = client.comparisons; -
Start creating comparisons:
comparisons.create({ left: { source: 'https://api.draftable.com/static/test-documents/code-of-conduct/left.pdf', fileType: 'pdf', }, right: { source: 'https://api.draftable.com/static/test-documents/code-of-conduct/right.rtf', fileType: 'rtf', }, }).then(function(comparison) { console.log("Comparison created:", comparison); # This generates a signed viewer URL that can be used to access the private comparison. # By default, the URL will expire in 30 minutes. See the documentation for `signedViewerURL(...)`. console.log("Viewer URL (expires in 30 min):", comparisons.signedViewerURL(comparison.identifier)); });
-
All API requests return Promises.
- Successful API calls that return data will resolve to
Comparisonobjects with the parsed data. - Successful calls that return no data (e.g. a
DELETErequest) resolve tonull. - Calls that fail for any reason will reject the Promise, with an
Errorobject describing what went wrong.
- Successful API calls that return data will resolve to
-
API requests should always succeed in production. Errors only occur upon network failures, invalid data, or invalid authentication.
@draftable/compare-api exports a single function, client(accountId: string, authToken: string).
Call it to create a Client for your API account.
At present, Client has a single property, comparisons, that yields a ComparisonsClient that manages the comparisons for your API account.
So, we'll assume you set things up as follows:
const comparisons = require('@draftable/compare-api').client(<yourAccountId>, <yourAuthToken>).comparisons;
ComparisonsClient provides getAll() and get(identifier: string).
getAll()returns aPromisethat resolves to a list of all your comparisons, ordered from newest to oldest. This is a potentially expensive operation.get(identifier: string)returns aPromisethat resolves to a singleComparisonobject, or rejects if there isn't a comparison with that identifier.
Comparison objects have the following properties:
identifier: astringgiving the identifier.left,right: objects giving information about each side, containing:fileType: the file extension.sourceURL(optional): if the file was specified as a URL, this is astringgiving that URL.displayName(optional): astringgiving the display name, if one was given.
publiclyAccessible: abooleangiving whether the comparison is public, or requires authentication to view.creationTime: aDategiving when the comparison was created.expiryTime(optional): if the comparison will expire, aDategiving the expiry time.ready:booleanindicating whether the comparison is ready for display.
If a Comparison is ready (i.e. it has been processed and is ready for display), it will have the following additional properties:
readyTime:Dategiving the time the comparison became ready.failed:booleanindicating whether the comparison succeeded or failed.errorMessage(only present iffailed): provides the developer with the reason the comparison failed.
comparisons.get('<identifier>').then(function(comparison) {
const privateOrPublic = comparison.publiclyAccessible ? "private" : "public";
const readyOrNot = comparison.ready ? "ready" : "not ready yet";
console.log("Comparison '" + comparison.identifier + "' (" + privateOrPublic + ") is " + readyOrNot + ".");
if (comparison.ready) {
const secondsElapsed = Math.round((comparison.readyTime - comparison.creationTime) / 1000);
console.log("The comparison took " + secondsElapsed + " seconds.");
if (comparison.failed) {
console.log("The comparison failed. Error message: " + comparison.errorMessage);
}
}
});
ComparisonsClient provides destroy(identifier: string), which attempts to delete the comparison with that identifier.
It returns a Promise that resolves (with no return value) on success, and rejects with an error message if no comparison with that identifier exists.
comparisons.getAll().then(function(comparisons) {
console.log("Deleting oldest 10 comparisons.");
const deleteStartIndex = Math.max(0, comparisons.length - 10);
for (let i = deleteStartIndex; i < comparisons.length; ++i) {
const identifier = comparisons[i].identifier;
comparisons.destroy(identifier).then(function() {
console.log("Comparison '" + identifier + "' deleted.");
});
}
});
ComparisonsClient provides create(options), which returns a Promise that resolves to a newly created Comparison object.
options should contain:
left,right: objects describing the left and right files.identifier(optional): the identifier to use for the comparison.- If specified, the identifier can't clash with an existing comparison.
- If left unspecified, the API will automatically generate one for you.
publiclyAccessible(optional): whether the comparison is publicly accessible.- Defaults to
falseif unspecified. Iftrue, then the comparison viewer can be accessed by anyone, without authentication. - See the full API documentation for details.
- Defaults to
expires(optional): a time at which the comparison will be automatically deleted.- Can be specified as a
Dateobject, or astringthatDate.parsecan understand. - If specified, the time must be in the future.
- If unspecified, the comparison will never expire.
- Can be specified as a
options.left and options.right should contain:
source: either abuffergiving the file data, or astringgiving a full URL from which Draftable will download the file.- For instance,
{source: fs.readFileSync('path/to/file')}or{source: 'https://example.com/path/to/file'}.
- For instance,
fileType: the type of the file, specified by the file extension.- The following file types are supported:
- PDF:
pdf - Word:
docx,docm,doc,rtf - PowerPoint:
pptx,pptm,ppt
- PDF:
- If you provide the incorrect file type, the comparison will fail.
- The following file types are supported:
displayName(optional): astringthat gives a name for the file to show in the comparison.
const identifier = comparisons.generateIdentifier(); # Generates a unique identifier.
comparisons.create({
identifier: identifier,
left: {
source: 'https://domain.com/left.pdf',
fileType: 'pdf',
displayName: 'document.pdf',
},
right: {
source: fs.readFileSync('path/to/right/file.docx'),
fileType: 'docx',
displayName: 'document (revised).docx',
},
# 'publiclyAccessible' is omitted, because we only want to let authenticated users view the comparison.
# Comparison expires 30 minutes into the future. (Date.now() is in milliseconds since the UNIX epoch.)
expires: new Date(Date.now() + 1000 * 60 * 30),
}).then(function(comparison) {
console.log("Created comparison:", comparison);
# This generates a signed viewer URL that can be used to access the private comparison for the next 30 minutes.
# At that time, both the URL and the comparison will expire. (Signed URLs default to expiring in 30 minutes.)
console.log("Viewer URL (expires in 30 min):", comparisons.signedViewerURL(comparison.identifier));
});
Comparisons are displayed using a viewer URL. See the section on displaying comparisons in the full API documentation for details.
Viewer URLs are generated with the following methods:
-
comparisons.publicViewerURL(identifier: string, wait?: boolean)- Viewer URL for a public comparison with the given
identifier. - If
waitisfalseor unspecified, the viewer will show an error if no such comparison exists. - If
waitistrue, the viewer will wait for a comparison with the givenidentifierto exist (potentially displaying a loading animation forever).
- Viewer URL for a public comparison with the given
-
comparisons.signedViewerURL(identifier: string, valid_until?: Date | string, wait?: boolean)- Gets a signed viewer URL for a comparison with the given
identifier. (The signature is an HMAC based on your credentials.) - If
waitistrue, the viewer will wait forever for a comparison with the givenidentifierto exist. valid_untilgives when the link will expire. It's specified as aDateor astringthatDate.parsecan understand.valid_untildefaults to 30 minutes in the future, which is more than enough time for a user to have loaded the page.
- Gets a signed viewer URL for a comparison with the given
####### Example usage
const identifier = comparisons.generateIdentifier()
# Start uploading our request in the background.
comparisons.create({left: {...}, right: {...}});
# Immediately give the user a view link to use, that displays a loading animation while we're creating the comparison.
# The URL is valid for 30 minutes, the default amount of time.
const viewerURL = comparisons.signedViewerURL(identifier, undefined, true);
console.log(viewerURL);
comparisons.generateIdentifier()generates a random unique identifier for you to use.
All of the source code has Flow type annotations (flowtype.org).
The published package has typing information in dist/flow.
If you're using Flow, add the following to your .flowconfig to enable type checking:
[libs]
<PROJECT_ROOT>/node_modules/@draftable/compare-api/dist/flow
The lack of support for streams when uploading files is a known issue. This is a limitation that emerges from the lightweight request library we use, needle.
If this causes you issues, consider adapting the code, or contact us at [email protected] as we may be able to help.
We chose not to support browsers, as it's hazardous to be sharing your credentials with any users of your software.
If you find yourself needing to use the API from in a browser context, contact us at [email protected] for pointers. You'll likely want to use more advanced authentication than just passing your auth token into requests made in the browser.