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
Comparison
objects with the parsed data. - Successful calls that return no data (e.g. a
DELETE
request) resolve tonull
. - Calls that fail for any reason will reject the Promise, with an
Error
object 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 aPromise
that resolves to a list of all your comparisons, ordered from newest to oldest. This is a potentially expensive operation.get(identifier: string)
returns aPromise
that resolves to a singleComparison
object, or rejects if there isn't a comparison with that identifier.
Comparison
objects have the following properties:
identifier
: astring
giving 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 astring
giving that URL.displayName
(optional): astring
giving the display name, if one was given.
publiclyAccessible
: aboolean
giving whether the comparison is public, or requires authentication to view.creationTime
: aDate
giving when the comparison was created.expiryTime
(optional): if the comparison will expire, aDate
giving the expiry time.ready
:boolean
indicating 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
:Date
giving the time the comparison became ready.failed
:boolean
indicating 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
false
if 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
Date
object, or astring
thatDate.parse
can 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 abuffer
giving the file data, or astring
giving 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): astring
that 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
wait
isfalse
or unspecified, the viewer will show an error if no such comparison exists. - If
wait
istrue
, the viewer will wait for a comparison with the givenidentifier
to 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
wait
istrue
, the viewer will wait forever for a comparison with the givenidentifier
to exist. valid_until
gives when the link will expire. It's specified as aDate
or astring
thatDate.parse
can understand.valid_until
defaults 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.