Here, we will explain how to use the functionalities the CloudRail SI node.js SDK provides.

We assume you have already installed the library, if not, have a look at Installation.

The code samples that come with each function description assume that a service that implements the respective interface has already been instantiated.

If you want to run the code samples refer to Services to find instructions on how to instantiate your service and then come back here.

General

In order to understand what functionality which service offers we need to understand the concept of interfaces and implementing services.

CloudRail SI's services all implement one or multiple of the following interfaces:

Name What is does Implementing services
Cloud Storage Upload, download, copy, delete, move, create and get information about files and/or folders in a CloudStorage provider Dropbox, Google Drive, OneDrive, OneDrive Business, Box, Egnyte
Business Cloud Storage Upload and download files, create and delete buckets, list buckets and files, get information about files Amazon S3, Microsoft Azure, Backblaze, Rackspace
Social Profile Retrieve information about a user, including an identifier to realize "Login with ..." Facebook, GitHub, Google+, LinkedIn, Slack, Twitter, Windows Live, Yahoo, Instagram
Social Interaction Get a user's connections and post updates Facebook, FacebookPage, Twitter
Payment Manage charges, refunds and subscriptions of clients who make payments with their credit card to an account on the respective service PayPal, Stripe
Email Programmatically send text/HTML emails to one or many addresses Mailjet, SendGrid
SMS Programmatically send SMS to phones Twilio, Nexmo
Points of Interest Get a list of points of interest in around a given location in a certain radius filtered by search terms and/or categories Google Places, Foursquare, Yelp

Each interface comes with a set of functionalities and implementing that interface implies that the respective service supports all the functionality from that interface.

Interfaces

Cloud Storage

Introduction

The CloudStorage interface bundles functionality around interaction with cloud storage providers. Its main challenge consists in abstracting about how files and folders are referenced. For the sake of easy usage, we have chosen paths over identifiers. This means every file and folder will be referenced by its full path starting at the root folder for all the functions in this interface.

For example, /TestFolder/UserData.csv refers to a file called UserData.csv residing in the TestFolder folder which in turn is located at root.

Implementing services

Function Overview

Did not find the function you need? Try Advanced Request!

Functions

Upload

Declaration
/**
 * Uploads a file to a cloud storage, error is set if the path is invalid,
 * the parent path does not exist, the stream is null or the size negative
 *
 * @param filePath The path where to store the file from the root folder
 * and including the name, e.g /myFolder/myFile.jpg
 *
 * @param stream A stream from which the file can be read
 *
 * @param size The size in bytes of the data that can be read from the stream
 *
 * @param overwrite If true, an existing file with the same path will be
 * overwritten (its contents updated), if false the presence of a file with
 * the same name will cause an error
 */
upload:(
    filePath:string,
    stream:stream.Readable,
    size:number,
    overwrite:boolean,
    callback?:(error:Error) => void
) => void;
Example
// Loads a file from the working directory and uploads it
let fileStream = fs.createReadStream("UserData.csv");
let size = fs.statSync("UserData.csv").size;

cs.upload("/TestFolder/Data.csv", fileStream, size, false, (err) => {
    if (err) throw err;
    console.log("Upload successfully finished");
});

Download

Declaration
/**
 * Downloads a file from a cloud storage, error is set if the file is
 * not found or the path invalid
 *
 * @param filePath The path to the file from the root folder and including
 * the name, e.g /myFolder/myFile.jpg
 *
 * @return A stream from which the file can be read
 */
download:(
	filePath:string,
	callback:(error:Error, stream:stream.Readable) => void
) => void;
Example
// Downloads a file to the working directory
let fileStream = fs.createWriteStream("UserData.csv");

cs.download("/TestFolder/Data.csv", (err, stream) => {
    if (err) throw err;
    stream.pipe(fileStream);
});

Check Existence

Declaration
/**
 * Checks if a given path already exists on a user's cloud storage.
 *
 * @param path The path that shall be checked.
 *
 * @return True if the file / folder exists, false otherwise.
 */
exists:(
	filePath:string,
	callback:(error:Error, exists:boolean) => void
) => void;
Example
cs.exists("/TestFolder/Data.csv", (err, exists) => {
    if (err) throw err;

    if (exists) console.log("File exists");
    else console.log("File does not exist");
});

Create Folder

Declaration
/**
 * Creates a folder at the given path, error is set if the path is
 * invalid or the parent path does not exist
 *
 * @param folderPath The path to the folder from the root folder and
 * including the name, e.g. /myNewFolder
 */
createFolder:(
    folderPath:string,
    callback?:(error:Error) => void
) => void;
Example
// Creates a new folder at the root
cs.createFolder("/NewFolder", (err) => {
    if (err) throw err;
    console.log("Folder successfully created");
});

Copy

Declaration
/**
 * Copies a file from one path in the cloud storage to another, error
 * is set if one of the paths is invalid, the source path or the parent
 * destination path does not exist
 *
 * @param sourcePath The path of the origin file from the root folder
 * and including the name
 *
 * @param destinationPath The path of the destination file from the root
 * folder and including the name
 */
copy:(
    sourcePath:string,
    destinationPath:string,
    callback?:(error:Error) => void
) => void;
Example
cs.copy("/SourceFolder/file.jpg", "/DestFolder/file.jpg", (err) => {
    if (err) throw err;
    console.log("File is now in two folders");
});

Delete

Declaration
/**
* Deletes a file or folder from the cloud storage, error is set if
* the path is invalid or does not exist
*
* @param filePath The path to the file to be deleted from the root folder
* and including the name
*/
delete:(
    filePath:string,
    callback?:(error:Error) => void
) => void;
Example
cs.delete("/DestFolder/file.jpg", (err) => {
    if (err) throw err;
    console.log("File is now deleted");
});

Move

Declaration
/**
 * Moves a file or a folder in the cloud storage, error is set if one
 * of the paths is invalid, the source path or the parent destination path
 * does not exist
 *
 * @param sourcePath The path to the file which should be moved from the root
 * folder and including the name
 *
 * @param destinationPath The path to move the file to from the root folder
 * and including the name
 */
move:(
    sourcePath:string,
    destinationPath:string,
    callback?:(error:Error) => void
) => void;
Example
cs.move("/SourceFolder/file.jpg", "/DestFolder/file.jpg", (err) => {
    if (err) throw err;
    console.log("File is now in a different folder");
});

Get Metadata

Declaration
/**
 * Gets metadata about the file/folder, error is set if the path is invalid or
 * does not exist. Also if getting metadata from root ("/") is attempted!
 *
 * @param filePath The path to the file from the root folder and including the
 * name
 *
 * @return A container for metadata
 */
getMetadata:(
    filePath:string,
    callback:(error:Error, metadata:CloudMetaData) => void
) => void;

type CloudMetaData = {
    path:string, // The whole path
    name:string, // The name
    size:number, // Size in bytes
    folder:boolean, // True for folders, false for files
    modifiedAt:number, // Timestamp of last modification in unix time
    imageMetaData?:ImageMetaData // Information about an image, may not be present
};

type ImageMetaData = {
    height:number, // Image height in pixels
    width:number // Image width in pixels
};
Example
cs.getMetadata("/SourceFolder/file.jpg", (err, metadata) => {
    if (err) throw err;
    console.log("File size is " + metadata.size);
});

Get Children

Declaration
/**
 * Gets the metadata of this folder's children, error is set if the path is
 * invalid or does not exist.
 *
 * @param folderPath The path to the file from the root folder and including
 * the name
 *
 * @return A list of containers for metadata
 */
getChildren:(
    folderPath:string,
    callback:(error:Error, children:CloudMetaData[]) => void
) => void;

type CloudMetaData = {
    path:string, // The whole path
    name:string, // The name
    size:number, // Size in bytes
    folder:boolean, // True for folders, false for files
    modifiedAt:number, // Timestamp of last modification in unix time
    imageMetaData?:ImageMetaData // Information about an image, may not be present
};

type ImageMetaData = {
    height:number, // Image height in pixels
    width:number // Image width in pixels
};
Example
cs.getChildren("/SourceFolder", (err, children) => {
    if (err) throw err;
    for (let child of children) {
        console.log(child.name + " is in /SourceFolder");
    }
});

Get Children Page

Declaration
/**
 * Gets the metadata of this folder's children in chunks, error is set if the path is
 * invalid or does not exist.
 * Returns an empty array if offset or limit get out of bounds of existing children.
 *
 * @param folderPath The path to the file from the root folder and including the name
 * @param offset The offset for the children
 * @param limit The amount of children returned
 *
 * @return A list of containers for metadata
 */
getChildrenPage:(
    folderPath:string,
    offset:number,
    limit:number,
    callback:(error:Error, children:CloudMetaData[]) => void
) => void;

type CloudMetaData = {
    path:string, // The whole path
    name:string, // The name
    size:number, // Size in bytes
    folder:boolean, // True for folders, false for files
    modifiedAt:number, // Timestamp of last modification in unix time
    imageMetaData?:ImageMetaData // Information about an image, may not be present
};

type ImageMetaData = {
    height:number, // Image height in pixels
    width:number // Image width in pixels
};
Example
cs.getChildrenPage("/SourceFolder", 0, 10, (err, children) => {
    if (err) throw err;
    console.log("Successfully retrieved the first 10 children");
});

Create Share Link

Declaration
/**
 * Creates a share link, the permission is only to 'view' and download the file/folder
 *
 * @param path the path to the file/folder which the link to will be created
 *
 * @return The url as a string
 */
createShareLink:(
    path:string,
    callback:(error:Error, link:string) => void
) => void;
Example
cs.getShareLink((err, link) => {
    if (err) throw err;
    console.log("The link to share this file is " + link);
});

Get Space

Declaration
/**
 *
 * @return The total space in bytes and the used space
 */
getAllocation:(
    callback:(error:Error, allocation:SpaceAllocation) => void
) => void;

type SpaceAllocation = {
    total:number, // Total space on the cloud storage provider for this user in bytes
    used:number // Used space in bytes
}
Example
cs.getAllocation((err, allocation) => {
    if (err) throw err;
    console.log("This user uses " + ((allocation.used / allocation.total) * 100) + " % of their space");
});

Get Thumbnail

Declaration
/**
 *
 * @return A thumbnail of the picture
 */
getThumbnail:(
    callback:(error:Error, thumbnail:stream.Readable) => void
) => void;
Example
cs.getThumbnail((err, thumbnail) => {
    if (err) throw err;
    // Do something with the stream
});

Get User's Login Identifier

Declaration
/**
 * @return The currently logged in user's login identifier (name/email/...)
 */
getUserLogin:(
    callback:(error:Error, identifier:string) => void
) => void;
Example
cs.getUserLogin((err, identifier) => {
    if (err) throw err;
    console.log("User ID is " + identifier);
});

Get User's Name

Declaration
/**
 * @return The currently logged in user's (full) name
 */
getUserName:(
    callback:(error:Error, name:string) => void
) => void;
Example
cs.getUserName((err, name) => {
    if (err) throw err;
    console.log("User name is " + name);
});

Explicit Login

Declaration
/**
 * Optional! Explicitly triggers user authentication.
 * Allows better control over the authentication process.
 * Optional because all methods that require prior authentication will
 * trigger it automatically, unless this method has been called before.
 */
login:(
    callback?:(error:Error) => void
) => void;
Example
cs.login((err) => {
    if (err) throw err;
    console.log("User is now logged in");
});

Explicit Logout

Declaration
/**
 * Optional! Revokes the current authentication.
 */
logout:(
    callback?:(error:Error) => void
) => void;
Example
cs.logout((err) => {
    if (err) throw err;
    console.log("User is now logged out");
});

Resume Login

Declaration
/**
 * Loads/restores execution state from RedirectReceiver's second argument
 * and continues the login. Main use case are server applications with
 * multiple instances.
 *
 * @param executionState The saved execution state now to be restored
 */
resumeLogin:(
    executionState:string,
    callback?:(error:Error) => void
) => void;
Example

See Example


Save As String

Declaration
/**
 * A method to retrieve the data from a service that is intended for
 * persistent storage
 *
 * @return The data of the service that should be stored persistently,
 * e.g. access credentials
 */
saveAsString:() => string;
Example
// Assume cs and cs2 are both instances of the same service
// cs already has a logged in user and cs2 is freshly created
let data = cs.saveAsString();
cs2.loadAsString(data);
// Now cs2 has the same user logged in as cs

Load As String

Declaration
/**
 * Loads/restores data saved by saveAsString() into the service
 *
 * @param savedData The persistent data that was stored
 */
loadAsString:(savedData:string) => void;
Example
// Assume cs and cs2 are both instances of the same service
// cs already has a logged in user and cs2 is freshly created
let data = cs.saveAsString();
cs2.loadAsString(data);
// Now cs2 has the same user logged in as cs

Business Cloud Storage

Introduction

This is a common interface for Bucket based Cloud Storage Services. Instead of organizing files in nested folders, they reside in a bucket.

Implementing services

Function Overview

Functions

List Buckets

Declaration
/**
 * Get a list of all buckets within your account.
 *
 * @return List of buckets. This might be an empty list if there are no buckets.
 */
listBuckets:(
    callback:(error:Error, buckets:Bucket[]) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
bcs.listBuckets((err, buckets) => {
    if (err) throw err;
    console.log("This account has " + buckets.length + " buckets");
});

Create Bucket

Declaration
/**
 * Creates a new empty bucket.
 *
 * @param name The name of the new bucket.
 * @return The newly created bucket.
 * @error IllegalArgumentError Is set if a bucket with the same name already exists.
 */
createBucket:(
    name:string,
    callback?:(error:Error, bucket:Bucket) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
bcs.createBucket("bucketname", (err, bucket) => {
    if (err) throw err;
    console.log("Bucket successfully created");
});

Delete Bucket

Declaration
/**
 * Deletes the specified bucket with all its content.
 *
 * @param bucket The bucket which will be deleted.
 * @error NotFoundError Is set if the bucket does not exist.
 */
deleteBucket:(
    bucket:Bucket,
    callback?:(error:Error) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
bcs.deleteBucket(bucket, (err) => {
    if (err) throw err;
    console.log("Bucket successfully deleted");
});

List Files

Declaration
/**
 * Get a list of files contained in the specified bucket.
 *
 * @param bucket The bucket containing the files.
 * @error NotFoundError Is set if the specified bucket does not exist.
 */
listFiles:(
    bucket:Bucket,
    callback:(error:Error, files:BusinessFileMetaData[]) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};

type BusinessFileMetaData = {
    fileName:string, // The file's name
    fileID:string, // The file's unique identifier, may equal the name or be null
    size:number, // The file's size in Bytes
    lastModified:number // The timestamp of the last modification in unix time
};
Example
bcs.listFiles(bucket, (err, files) => {
    if (err) throw err;
    console.log("The bucket named " + bucket.name + " has " + files.length + " files");
});

Upload File

Declaration
/**
 * Uploads a new file into a bucket or replaces the file if it is already present.
 *
 * @param bucket  The bucket into which the file shall be put.
 * @param name    The name of the file.
 * @param content The file content as a readable stream.
 * @param size    The amount of bytes that the file contains.
 */
uploadFile:(
    bucket:Bucket,
    name:string,
    content:stream.Readable,
    size:number,
    callback?:(error:Error) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
// Loads a file from the working directory and uploads it
let fileStream = fs.createReadStream("UserData.csv");
let size = fs.statSync("UserData.csv").size;

bcs.uploadFile(bucket, "Data.csv", fileStream, size, (err) => {
    if (err) throw err;
    console.log("Upload successfully finished");
});

Delete File

Declaration
/**
 * Deletes a file within a bucket.
 *
 * @param bucket   The bucket that contains the file.
 * @param fileName The name of the file.
 * @error NotFoundError Is set if there is no file with the given
 *                      name inside the bucket.
 */
deleteFile:(
    fileName:string,
    bucket:Bucket,
    callback?:(error:Error) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
bcs.deleteFile("Data.csv", bucket, (err) => {
    if (err) throw err;
    console.log("File successfully deleted");
});

Download File

Declaration
//**
 * Downloads a file from a bucket.
 *
 * @param bucket   The bucket which contains the file.
 * @param fileName The name of the file.
 * @return The content of the file as a readable stream.
 * @error NotFoundError Is set if there is no file with the given
 *                      name inside the bucket.
 */
downloadFile:(
    fileName:string,
    bucket:Bucket,
    callback:(error:Error, stream:stream.Readable) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};
Example
// Downloads a file to the working directory
let fileStream = fs.createWriteStream("UserData.csv");

bcs.downloadFile("Data.csv", bucket, (err, stream) => {
    if (err) throw err;
    stream.pipe(fileStream);
});

Get File Metadata

Declaration
/**
 * Get metadata of a file containing the name, the size and the last
 * modified date.
 *
 * @param bucket   The bucket where the file is located.
 * @param fileName The name of the file.
 */
getFileMetadata:(
    bucket:Bucket,
    fileName:string,
    callback:(error:Error, meta:BusinessFileMetaData) => void
) => void;

type Bucket = {
    name:string, // The bucket's name
    identifier:string // A unique identifier for the bucket
};

type BusinessFileMetaData = {
    fileName:string, // The file's name
    fileID:string, // The file's unique identifier, may equal the name or be null
    size:number, // The file's size in Bytes
    lastModified:number // The timestamp of the last modification in unix time
};
Example
bcs.getFileMetadata(bucket, "Data.csv", (err, meta) => {
    if (err) throw err;
    console.log("The file " + meta.name + " is " + meta.size / 1000 + " kilobytes big");
});

Social Profile

Introduction

The Profile interface is a common interface for Services that provide unique user identifiers and general user information.

With the getIdentifier function, "Login with ..." scenarios can be easily implemented: Whenever a user needs to login/signup, call the getIdentifier function of an instance of this interface. This will have the user login and then return a unique identifier for this user with this service. Use this to identify a user's account with your application.

All the other information might be present or not, depending on the service and how much information the user has filled out with the respective service. To avoid unnecessary requests, information is cached up to one minute.

Implementing services

Function Overview

Did not find the function you need? Try Advanced Request!

Functions

Get Identifier

Declaration
/**
 * @return A unique identifier for the authenticated user. All services
 * provide this value. Useful for "Login with ...". Prefixed with the
 * lowercased service name and a minus.
 */
getIdentifier:(
    callback:(error:Error, identifier:string) => void
) => void;
Example
profile.getIdentifier((err, identifier) => {
    if (err) throw err;
    console.log("User's unique identifier is " + identifier);
});

Get Full Name

Declaration
/**
 * @return The user's full name or null if not present
 */
getFullName:(
    callback:(error:Error, identifier:string) => void
) => void;
Example
profile.getFullName((err, name) => {
    if (err) throw err;
    console.log("User's full name is " + name);
});

Get Email

Declaration
/**
 * @return The user's email address or null if not present
 */
getEmail:(
    callback:(error:Error, identifier:string) => void
) => void;
Example
profile.getEmail((err, email) => {
    if (err) throw err;
    console.log("User's email address is " + email);
});

Get Gender

Declaration
/**
 * @return The user's gender, normalized to be one of "female", "male", "other"
 * or null if not present
 */
getGender:(
    callback:(error:Error, gender:string) => void
) => void;
Example
profile.getGender((err, gender) => {
    if (err) throw err;
    switch (gender) {
        case "female":
        case "male":
        case "other": console.log("Hello human");
    }
});

Get Description

Declaration
/**
 * @return The description the user has given themselves or null if not present
 */
getDescription:(
    callback:(error:Error, description:string) => void
) => void;
Example
profile.getDescription((err, description) => {
    if (err) throw err;
    console.log("User's description is " + description);
});

Get Date Of Birth

Declaration
/**
 * @return The date of birth in a special format of 3 numbers to achieve
 * locale-independence
 */
getDateOfBirth:(
    callback:(error:Error, dateOfBirth:DateOfBirth) => void
) => void;

type DateOfBirth = {
    day:number,
    month:number,
    year:number
};
Example
profile.getDateOfBirth((err, dateOfBirth) => {
    if (err) throw err;
    console.log("User's birth year is " + dateOfBirth.year);
});

Get Locale

Declaration
/**
 * @return The locale/language setting of the user, e.g. "en", "de" or null
 * if not present
 */
getLocale:(
    callback:(error:Error, locale:string) => void
) => void;
Example
profile.getLocale((err, locale) => {
    if (err) throw err;
    console.log("User's locale is " + locale);
});

Get Picture URL

Declaration
/**
 * @return The URL of the user's profile picture or null if not present
 */
getPictureURL:(
    callback:(error:Error, url:string) => void
) => void;
Example
profile.getPictureURL((err, url) => {
    if (err) throw err;
    console.log("User's picture can be retrieved from " + url);
});

Explicit Login

Declaration
/**
 * Optional! Explicitly triggers user authentication.
 * Allows better control over the authentication process.
 * Optional because all methods that require prior authentication will
 * trigger it automatically, unless this method has been called before.
 */
login:(
    callback?:(error:Error) => void
) => void;
Example
profile.login((err) => {
    if (err) throw err;
    console.log("User is now logged in");
});

Explicit Logout

Declaration
/**
 * Optional! Revokes the current authentication.
 */
logout:(
    callback?:(error:Error) => void
) => void;
Example
profile.logout((err) => {
    if (err) throw err;
    console.log("User is now logged out");
});

Resume Login

Declaration
/**
 * Loads/restores execution state from RedirectReceiver's second argument
 * and continues the login. Main use case are server applications with
 * multiple instances.
 *
 * @param executionState The saved execution state now to be restored
 */
resumeLogin:(
    executionState:string,
    callback?:(error:Error) => void
) => void;
Example

See Example


Save As String

Declaration
/**
 * A method to retrieve the data from a service that is intended for
 * persistent storage
 *
 * @return The data of the service that should be stored persistently,
 * e.g. access credentials
 */
saveAsString:() => string;
Example
// Assume profile and profile2 are both instances of the same service
// profile already has a logged in user and profile2 is freshly created
let data = profile.saveAsString();
profile2.loadAsString(data);
// Now profile2 has the same user logged in as profile

Load As String

Declaration
/**
 * Loads/restores data saved by saveAsString() into the service
 *
 * @param savedData The persistent data that was stored
 */
loadAsString:(savedData:string) => void;
Example
// Assume profile and profile2 are both instances of the same service
// profile already has a logged in user and profile2 is freshly created
let data = profile.saveAsString();
profile2.loadAsString(data);
// Now profile2 has the same user logged in as profile

Social Interaction

Introduction

This is a common interface for services that provide a set of social functionalities. Currently the functionalities are limited to receiving a list of user ids with which the currently logged in user has a connection to and who is also using your app and to post an update to a users timeline.

Implementing services

Function Overview

Functions

Get Connections

Declaration
/**
 * Retrieves a list of connection/friend/etc. IDs.
 * The IDs are compatible with those returned by Profile.getIdentifier()
 *
 * @return A (possibly empty) list of IDs
 */
getConnections:(
    callback:(error:Error, ids:string[]) => void
) => void;
Example
social.getConnections((err, ids) => {
    if (err) throw err;
    console.log("User has " ids.length + " connections");
});

Post Update

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc.
 * Throws an exception if the content is too long for the service instance.
 *
 * @param content The post's content
 */
postUpdate:(
    content:string,
    callback?:(error:Error) => void
) => void;
Example
social.postUpdate("Hello from CloudRail", (err) => {
    if (err) throw err;
    console.log("Update posted");
});

Post Image

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc posting an
 * image and a message.
 * Throws an exception if the message is too long for the service instance.
 *
 * @param message The message that shall be posted together with the image.
 * @param image Stream containing the image content.
 */
postImage:(
    message:string,
    image:stream.Readable,
    callback?:(error:Error) => void
) => void;
Example
let fileStream = fs.createReadStream("SampleImage.jpg");

social.postImage("Hello from CloudRail", fileStream, (err) => {
    if (err) throw err;
    console.log("Image posted");
});

Post Video

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc posting a
 * video and a message.
 * Throws an exception if the message is too long for the service instance.
 *
 * @param message The message that shall be posted together with the video.
 * @param video Stream containing the video content.
 * @param size The size of the video in bytes.
 * @param mimeType The mime type of the video, for instance video/mp4.
 */
postVideo:(
    message:string,
    video:stream.Readable,
    size:number,
    mimeType:string,
    callback?:(error:Error) => void
) => void;
Example
let fileStream = fs.createReadStream("SampleVideo.mp4");
let size = fs.statSync("SampleVideo.mp4").size;

social.postVideo("Hello from CloudRail", fileStream, size, "video/mp4", (err) => {
    if (err) throw err;
    console.log("Video posted");
});

Payment

Introduction

Payment is a common interface for services that allow you to collect payments from credit cards. It serves three main purposes: perform single charges, refund previously made charges and manage subscriptions. In order to properly test your integration, all services do provide some sort of testing environment and/or test values.

Implementing services

Function Overview

Functions

Create Charge

Declaration
/**
 * Charges a credit card and returns a charge resource.
 *
 * @param amount A positive integer in the smallest currency unit (e.g. cents)
 * representing how much to charge the credit card.
 *
 * @param currency A three-letter ISO code for currency.
 *
 * @param source The credit card to be charged.
 *
 * @return A charge resource representing the newly created payment.
 *
 * @error IllegalArgumentError if any of the parameters is null, amount is
 * less than 0 or currency is not a valid three-letter currency code.
 *
 * @error AuthenticationError if the provided credentials are invalid.
 *
 * @error HttpError if the communication with a services fails.
 * More detail is provided in the error message.
 */
createCharge:(
    amount:number,
    currency:string,
    source:CreditCard,
    callback:(error:Error, charge:Charge)
) => void;

type CreditCard = {
    cvc:string, // Card validation code
    expire_month:number, // Values between 1 and 12
    expire_year:number, // Four digit expiration data
    number:string,
    type:string, // Can have the following values: visa, mastercard, discover, amex
    firstName:string,
    lastName:string,
    address:Address
};

type Address = {
    country:string, // 2-letter ISO country code
    city:string, // City/Suburb/Town/Village
    state:string,
    line1:string, // Street address/PO Box/Company name
    line2:string, // Apartment/Suite/Unit/Building
    postalCode:string
};

type Charge = {
    id:string, // ID of the newly generated charge
    amount:string, // amount that was charged
    currency:string, // currency in which the amount was charged
    source:CreditCard, // credit card that was charged
    created:number, // timestamp of when the charge was created
    status:string, // current state of the charge. Possible values are: 'pending', 'succeeded' or 'failed'
    refunded:boolean // if the payment has been completely refunded or not
};
Example
let source = new cloudrail.types.CreditCard(
    null,
    6,
    2021,
    "xxxxxxxxxxxxxxxx",
    "visa",
    "<FirstName>",
    "<LastName>",
    null
);

payment.createCharge(500, "USD", source, (err, charge) => {
    if (err) throw err;
    switch (charge.status) {
        case "succeeded": console.log("Successfully charged 500$ directly"); break;
        case "failed": console.log("Charge failed"); break;
        case "pending": console.log("Charge still pending"); break;
    }
});

Get Charge

Declaration
/**
 * Returns information about an existing charge. Mostly used to get an update
 * on the status of the charge.
 *
 * @param id The ID of the charge.
 *
 * @return A charge resource for the provided ID.
 *
 * @error IllegalArgumentError if id is null.
 *
 * @error NotFoundError if there is now charge with that ID.
 *
 * @error AuthenticationError if the provided credentials are invalid.
 *
 * @error HttpError if the communication with a services fails.
 * More detail is provided in the error message.
 */
getCharge:(
    id:string,
    callback:(error:Error, charge:Charge) => void
) => void;

type Charge = {
    id:string, // ID of the newly generated charge
    amount:string, // amount that was charged
    currency:string, // currency in which the amount was charged
    source:CreditCard, // credit card that was charged
    created:number, // timestamp of when the charge was created
    status:string, // current state of the charge. Possible values are: 'pending', 'succeeded' or 'failed'
    refunded:boolean // if the payment has been completely refunded or not
};
Example
payment.getCharge("<ChargeID>", (err, charge) => {
    if (err) throw err;
    console.log("Charge has " + (charge.refunded ? "" : "not") + " been refunded");    
});

List Charges

Declaration
/**
 * Receive a list of charges within a specified timeframe.
 *
 * @param from Timestamp representing the start date for the list.
 *
 * @param to Timestamp representing the end date for the list.
 *
 * @param creditCard Optionally the credit card information so it can be listed
 * all the charges of this specific credit card.
 *
 * @return List of charge resources.
 *
 * @error IllegalArgumentError if from or to is null, from or to is less than 0,
 * from is greater than to or to is greater than
 * the current date.
 *
 * @error AuthenticationError if the provided credentials are invalid.
 *
 * @error HttpError if the communication with a services fails.
 * More detail is provided in the error message.
 */
listCharges:(
    from:number,
    to:number,
    creditCard:CreditCard,
    callback:(error:Error, charges:Charge[]) => void
) => void;

type CreditCard = {
    cvc:string, // Card validation code
    expire_month:number, // Values between 1 and 12
    expire_year:number, // Four digit expiration data
    number:string,
    type:string, // Can have the following values: visa, mastercard, discover, amex
    firstName:string,
    lastName:string,
    address:Address
};

type Address = {
    country:string, // 2-letter ISO country code
    city:string, // City/Suburb/Town/Village
    state:string,
    line1:string, // Street address/PO Box/Company name
    line2:string, // Apartment/Suite/Unit/Building
    postalCode:string
};

type Charge = {
    id:string, // ID of the newly generated charge
    amount:string, // amount that was charged
    currency:string, // currency in which the amount was charged
    source:CreditCard, // credit card that was charged
    created:number, // timestamp of when the charge was created
    status:string, // current state of the charge. Possible values are: 'pending', 'succeeded' or 'failed'
    refunded:boolean // if the payment has been completely refunded or not
};
Example
let current = (new Date()).getTime();
let aWeekAgo = current - 604800000;
payment.listCharges(aWeekAgo, current, null, (err, charges) => {
    if (err) throw err;
    console.log("There have been " + charges.length + " charges in the last week");
});

Completely Refund Charge

Declaration
/**
 * Refund a previously made charge.
 *
 * @param id The ID of the charge to be refunded.
 *
 * @return A refund resource.
 *
 * @error IllegalArgumentError error is set if id is null.
 *
 * @error NotFoundError error is set if there is now charge with that ID.
 *
 * @error AuthenticationError error is set if the provided credentials
 * are invalid.
 *
 * @error HttpError error is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
refundCharge:(
    id:string,
    callback:(error:Error, refund:Refund) => void
) => void;

type Refund = {
    amount:number, //  The amount that has been refunded
    chargeID:string, // Reference to the Charge that was refunded
    created:number, // Timestamp representing the creation time of this refund
    id:string, // The ID of the newly created refund
    state:string, // Can have the following values: 'pending', 'succeeded' or 'failed'.
    currency:string // The currency in which the refund was made
};
Example
payment.refundCharge("<ChargeID>", (err, refund) => {
    if (err) throw err;
    console.log("Refund has status " + refund.status);
});

Partially Refund Charge

Declaration
/**
 * Refund a specified amount from a previously made charge.
 *
 * @param id The ID of the charge to be refunded.
 *
 * @param amount The amount that shall be refunded.
 *
 * @return A refund resource.
 *
 * @error IllegalArgumentError Is set if any of the parameters is null or
 * lower/equals than 0.
 *
 * @error NotFoundError Is set if there is now charge with that ID.
 *
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
partiallyRefundCharge:(
    id:string,
    amount:number,
    callback:(error:Error, refund:Refund) => void
) => void;

type Refund = {
    amount:number, //  The amount that has been refunded
    chargeID:string, // Reference to the Charge that was refunded
    created:number, // Timestamp representing the creation time of this refund
    id:string, // The ID of the newly created refund
    state:string, // Can have the following values: 'pending', 'succeeded' or 'failed'.
    currency:string // The currency in which the refund was made
};
Example
payment.partiallyRefundCharge("<ChargeID>", 100, (err, refund) => {
    if (err) throw err;
    console.log("Partial refund has status " + refund.status);
});

Get Refund

Declaration
/**
 * Returns information about an existing refund. Mostly used to get an update
 * on the status of the refund.
 *
 * @param id The ID of the refund.
 *
 * @return A refund resource for the provided ID.
 *
 * @error IllegalArgumentError Is set if id is null.
 *
 * @error NotFoundError Is set if there is no refund with that ID.
 *
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
getRefund:(
    id:string,
    callback:(error:Error, refund:Refund) => void
) => void;

type Refund = {
    amount:number, //  The amount that has been refunded
    chargeID:string, // Reference to the Charge that was refunded
    created:number, // Timestamp representing the creation time of this refund
    id:string, // The ID of the newly created refund
    state:string, // Can have the following values: 'pending', 'succeeded' or 'failed'.
    currency:string // The currency in which the refund was made
};
Example
payment.getRefund("<ChargeID>", (err, refund) => {
    if (err) throw err;
    console.log("Refund was created at " + (new Date(refund.created)));
});

Get Refunds for Charge

Declaration
/**
 * Returns information about the refunds for a specific charge.
 *
 * @param id The ID of the charge.
 *
 * @return A refund resource for the provided charge.
 *
 * @error IllegalArgumentError Is set if id is null.
 *
 * @error NotFoundError Is set if there is now charge with that ID or the
 * charge has not been refunded.
 *      
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
getRefundsForCharge:(
    id:string,
    callback:(error:Error, refunds:Refund[]) => void
) => void;

type Refund = {
    amount:number, //  The amount that has been refunded
    chargeID:string, // Reference to the Charge that was refunded
    created:number, // Timestamp representing the creation time of this refund
    id:string, // The ID of the newly created refund
    state:string, // Can have the following values: 'pending', 'succeeded' or 'failed'.
    currency:string // The currency in which the refund was made
};
Example
payment.getRefundsForCharge("<ChargeID>", (err, refunds) => {
    if (err) throw err;
    console.log("The charge has " + refunds.length + " refunds associated");
});

Create Subscription Plan

Declaration
/**
 * Creates a subscription plan which is required to use subscription based payments.
 * The result of this method can be used together with 'createSubscription' in
 * order to subscribe someone to your subscription plan.
 *
 * @param name The name for the subscription plan.
 *
 * @param amount The amount that is charged on a regular basis. A positive integer
 * in the smallest currency unit (e.g. cents).
 *
 * @param currency A three-letter ISO code for currency.
 *
 * @param description A description for this subscription plan.
 *
 * @param interval Specifies the billing frequency together with interval_count.
 * Allowed values are: day, week, month or year.
 *      
 * @param interval_count Specifies the billing frequency together with interval.
 * For example: interval_count = 2 and interval = "week" -> Billed every two weeks.
 *
 * @return Returns the newly created subscription plan resource.
 *
 * @error IllegalArgumentError Is set if any of the parameters is null
 * or lower/equal than 0, currency is not a three-letter currency code, interval
 * is not one of the allowed values or amount is less/equal than 0.
 *
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
createSubscriptionPlan:(
    name:string,
    amount:number,
    currency:string,
    description:string,
    interval:string,
    interval_count:number,
    callback:(error:Error, plan:SubscriptionPlan) => void
) => void;

type SubscriptionPlan = {
    amount:number, // The amount that is charged on a regular basis
    created:number, // Timestamp representing the creation time of this subscription plan
    currency:string, // The currency in which the amount is charged
    description:string, // The description of the subscription plan
    id:string, // The ID of the subscription plan
    interval:string, // The billing interval. Can have the following values: 'day', 'week', 'month' or 'year'.
    interval_count:number, // The billing frequency
    name:string // The name of the subscription plan
};
Example
payment.createSubscriptionPlan(
    "My subscription plan",
    500,
    "USD",
    "Awesome subscription plan",
    "week",
    2,
    (err, plan) => {
        if (err) throw err;
        console.log("A new subscription plan has created and will charge every " + plan.interval_count + " " + plan.interval + "s");
    }
);

List Subscription Plans

Declaration
/**
 * Returns a list of all existing subscription plans.
 *
 * @return List of subscription plans.
 *
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
listSubscriptionPlans:(
    callback:(error:Error, plans:SubscriptionPlan[]) => void
) => void;

type SubscriptionPlan = {
    amount:number, // The amount that is charged on a regular basis
    created:number, // Timestamp representing the creation time of this subscription plan
    currency:string, // The currency in which the amount is charged
    description:string, // The description of the subscription plan
    id:string, // The ID of the subscription plan
    interval:string, // The billing interval. Can have the following values: 'day', 'week', 'month' or 'year'.
    interval_count:number, // The billing frequency
    name:string // The name of the subscription plan
};
Example
payment.listSubscriptionPlans((err, plans) => {
    if (err) throw err;
    console.log("You have " + plans.length + " subscription plans registered");
});

Create Subscription

Declaration
/**
 * Subscribes a new customer to an existing subscription plan.
 *
 * @param planID The ID of the subscription plan.
 *
 * @param name A name for the subscription.
 *
 * @param description A description for the subscription.
 *
 * @param creditCard The customer that shall be subscribed.
 *
 * @return The newly created subscription resource.
 *
 * @error IllegalArgumentError Is set if planID, name, description or
 * payer is null.
 *
 * @error NotFoundError Is set if there is no subscription plan with
 * the passed ID.
 *
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
createSubscription:(
    planID:string,
    name:string,
    description:string,
    creditCard:CreditCard,
    callback:(error:Error, subscription:Subscription) => void
) => void;

type CreditCard = {
    cvc:string, // Card validation code
    expire_month:number, // Values between 1 and 12
    expire_year:number, // Four digit expiration data
    number:string,
    type:string, // Can have the following values: visa, mastercard, discover, amex
    firstName:string,
    lastName:string,
    address:Address
};

type Subscription = {
    created:number, // Timestamp representing the time the subscription was created
    description:string, // The description of the subscription
    id:string, // The subscription ID
    lastCharge:number, // Timestamp representing the last time a charge was made
    name:string, // The name of the subscription
    nextCharge:number, // Timestamp representing the next time a charge will be made
    creditCard:CreditCard, // The credit card that will be charged on a regular basis
    state:string, // State of the subscription. Possible values are: 'active' and 'canceled'
    subscriptionPlanID:string // The ID of the subscription plan
};
Example
let source = new cloudrail.types.CreditCard(
    null,
    6,
    2021,
    "xxxxxxxxxxxxxxxx",
    "visa",
    "<FirstName>",
    "<LastName>",
    null
);

payment.createSubscription("<PlanID>", "My Subscription", "My Description", source, (err, subscription) => {
    if (err) throw err;
    console.log("Subscription created");
});

Cancel Subscription

Declaration
/**
 * Cancel an active subscription.
 *
 * @param id ID of the subscription that should be canceled.
 *
 * @error IllegalArgumentError Is set if id is null.
 *
 * @error NotFoundError Is set if there is no subscription with the provided ID.
 *      
 * @error AuthenticationError Is set if the provided credentials are invalid.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
cancelSubscription:(
    id:string,
    callback?:(error:Error) => void
) => void;
Example
payment.cancelSubscription("<SubscriptionID>", (err) => {
    if (err) throw err;
    console.log("Subscription cancelled");
});

SMS

Introduction

This is a common interface for Services that provide the possibility to programmatically send SMS, e.g. for signup confirmations.

Implementing services

Function Overview

Functions

Send SMS

Declaration
/**
 * Sends an SMS message
 *
 * @param fromName A alphanumeric sender id to identify/brand the sender. Only
 * works in some countries.
 *
 * @param toNumber The recipients phone number in E.164 format, e.g. +4912345678
 *
 * @param content The message content. Limited to 1600 characters, messages > 160
 * characters are sent and charged as multiple messages.
 */
sendSMS:(
    fromName:string,
    toNumber:string,
    content:string,
    callback?:(error:Error) => void
) => void;
Example
sms.sendSMS("CloudRail", "+4912345678", "Hello from CloudRail", (err) => {
    if (err) throw err;
    console.log("SMS successfully sent");
});

Email

Introduction

This is a common interface for Services that provide the possibility to programmatically send Emails, e.g. for signup confirmations.

Implementing services

Function Overview

Functions

Send Email

Declaration
/**
 * Sends an email
 *
 * @param fromAddress Mandatory. The sender email address. Must normally be
 * registered with the corresponding service.
 *
 * @param fromName Mandatory. The from name to be displayed to the recipient(s).
 *
 * @param toAddresses Mandatory. A list of recipient email addresses.
 *
 * @param subject Mandatory. The email's subject line.
 *
 * @param textBody The email's body plain text part. Either this and/or the htmlBody
 * must be specified.
 *
 * @param htmlBody The email's body HTML part. Either this and/or the textBody must
 * be specified.
 *
 * @param ccAddresses Optional. A list of CC recipient email addresses.
 *
 * @param bccAddresses Optional. A list of BCC recipient email addresses.
 */
sendEmail:(
    fromAddress:string,
    fromName:string,
    toAddresses:string[],
    subject:string,
    textBody:string,
    htmlBody:string,
    ccAddresses:string[],
    bccAddresses:string[],
    callback?:(error:Error) => void
) => void;
Example
email.sendEmail(
    "info@cloudrail.com",
    "CloudRail",
    ["foo@bar.com", "bar@foo.com"],
    "Welcome",
    "Hello from CloudRail",
    null,
    [],
    [],
    (err) => {
        if (err) throw err;
        console.log("Email successfully sent");
    }
);

Points of Interest

Introduction

This is a common interface for services that provide information about Points of Interest close to a given location. This location can be specified by passing latitude and longitude as well as a search radius. Furthermore, results can be limited by providing an optional search term or a list of categories.

Implementing services

Function Overview

Functions

Get Nearby POIs

Declaration
/**
 * Returns a list of POIs that are close to the passed location and filters them by
 * certain criteria.
 *
 * @param latitude The latitude of the target location.
 *
 * @param longitude The longitude of the target location.
 *
 * @param radius The search radius in metres. The maximum is 40,000 meters.
 *
 * @param searchTerm Optional search term that has to be matched.
 *
 * @param categories Optional list of categories. Available categories can be found
 * below.
 *
 * @return A list of POIs for the target location.
 *
 * @error IllegalArgumentError Is set if latitude, longitude or radius is null,
 * latitude or longitude is invalid, radius is greater than 40,000 metres or
 * one of the passed categories is unknown.
 *
 * @error AuthenticationError Is set if the passed credentials are invalid or
 * authorization fails for whatever reason.
 *
 * @error HttpError Is set if the communication with a services fails.
 * More detail is provided in the error message.
 */
getNearbyPOIs:(
    latitude:number,
    longtitude:number,
    radius:number,
    searchTerm:string,
    categories:string[],
    callback:(error:Error, pois:POI[]) => void
) => void;

type POI = {
    categories:string[], // List of categories that apply to this POI
    imageURL:string, // A URL that can be used to display an image for this POI
    location:Location, // A Location object containing the location of the POI
    name:string, // The name of the POI
    phone:string // The phone number if there is one
};

type Location = {
    longitude:number,
    latitude:number
};
Example
poi.getNearbyPOIs(49.4557091, 8.5279138, 3000, "Restaurant", null, (err, pois) => {
    if (err) throw err;
    console.log("There are " + pois.length + " points of interest with the keyword 'Restaurant' in a 3km radius around the given coordinates");
});

POI Categories

Use one or many of the below category keywords with the Points of Interest interface

  • airport
  • amusement_park
  • aquarium
  • bank
  • bar
  • beauty_salon
  • art_gallery
  • bakery
  • bicycle_store
  • book_store
  • bowling_alley
  • bus_station
  • cafe
  • car_dealer
  • car_rental
  • car_wash
  • casino
  • cemetery
  • church
  • clothing_store
  • convenience_store
  • courthouse
  • dentist
  • department_store
  • doctor
  • electronics_store
  • embassy
  • finance
  • fire_station
  • florist
  • food
  • funeral_home
  • furniture_store
  • gas_station
  • grocery_or_supermarket
  • gym
  • hardware_store
  • health
  • hindu_temple
  • hospital
  • jewelry_store
  • laundry
  • lawyer
  • library
  • locksmith
  • mosque
  • movie_theater
  • museum
  • night_club
  • parks
  • parking
  • pet_store
  • pharmacy
  • physiotherapist
  • police
  • post_office
  • real_estate_agency
  • restaurant
  • rv_park
  • school
  • shoe_store
  • shopping_mall
  • spa
  • stadium
  • synagogue
  • taxi_stand
  • train_station
  • travel_agency
  • university
  • veterinary_care
  • zoo

Advanced Request

The methods above are chosen to reflect most commonly used functionalities and thus those that all services implementing an interface have in common. It follows that the APIs of the services CloudRail integrates with offer more, service-specific functionality that is missing from CloudRail. To mitigate this, the advanced request functionality was introduced. It allows a developer to specify the raw HTTP request against an API and thus access all of its functionality. To be more than just another HTTP Client, CloudRail supports the developer by taking care of authentication and error checking.

Supported services

Currently, the advanced request function is present on all services implementing the CloudStorage interface and those implementing the Profile interface. More services will follow soon.

Example

We want to list all shared folders of a Dropbox account and know through the Dropbox API documentation that this functionality is supported by Dropbox (https://www.dropbox.com/developers/documentation/http/documentation#sharing-list_folders). Yet, it is not supported by the CloudRail Dropbox service so we use advanced request. The example assumes that you are already familiar with the installation and intialization of a CloudRail service integration.

// Initialize like usual
Settings.setKey([CloudRail key]);
const dropbox = new Dropbox([Credentials etc.]);

// Specify the URL of the Dropbox API endpoint, the base URL is prepended by default
let req = new AdvancedRequestSpecification("/sharing/list_folders");

// Set the HTTP request method to POST
req.setMethod("POST");

// Specify the body and let it be converted to JSON
req.setBodyStringifyJson({
    limit: 100
});

// Specify the headers
req.setHeaders({
    "Content-Type": "application/json"
});

// Execute the request, CloudRail will start the authentication flow if necessary
// and append the authorization header.
// The response is checked for errors.
dropbox.advancedRequest(req, (err, res) => {
    if (err) throw err;
    else {
        // Extract the parsed response body
        res.getBodyJsonParsed((err, obj) => {
            if (err) throw err;
            else {
                // Now you can work with the answer
                console.log("We have " + obj.entries.length + " shared folders");
            }
        });
    }
});

Specification

All supported services have an advancedRequest method:

advancedRequest:(specification: AdvancedRequestSpecification, callback: NodeCallback<AdvancedRequestResponse>) => void;

The AdvancedRequestSpecification looks like this:

class AdvancedRequestSpecification {

    /**
     * Constructs a new advanced request specification
     *
     * @param url The request's URL
     */
    constructor(url:string);

    /**
     * Specify the request's method, default is GET
     *
     * @param method The HTTP method
     */
    public setMethod(method:string):void;

    /**
     * Specify the body to sent with this request providing a readable stream
     *
     * @param body The request's body
     */
    public setBodyAsStream(body:stream.Readable):void;

    /**
     * Specify the body to sent with this request providing a string
     *
     * @param body The request's body
     */
    public setBodyAsString(body:string):void;

    /**
     * Specify the body to sent with this request providing an object that will be converted to JSON.
     *
     * @param body The request's body
     */
    public setBodyStringifyJson(body:any):void;

    /**
     * Specify the body to sent with this request providing an object that will be converted to XML.
     * The object has to have the following structure:
     *
     * @param body The request's body
     */
    public setBodyStringifyXml(body:XMLElement):void;

    /**
     * Specify the request's (additional) headers
     *
     * @param headers An object specifying headers
     */
    public setHeaders(headers:ObjectMap<string>):void;

    /**
     * Disable appending authorization information to the request
     */
    public disableAuthorization():void;

    /**
     * Disable checking the request's response for errors
     */
    public disableErrorChecking():void;

    /**
     * Disable appending the base URL
     */
    public disableBaseUrl():void;
}

The AdvancedRequestResponse looks like this:

class AdvancedRequestResponse {
    /**
     * Returns the response's body as a readable stream
     *
     * @return {stream.Readable} The response's body
     */
    public getBodyAsStream():stream.Readable;

    /**
     * Returns the response's body as a string
     *
     * @return {string} The response's body
     */
    public getBodyAsString(callback:NodeCallback<string>):void;

    /**
     * Returns the response's body as an object resulting from JSON parsing it.
     *
     * @return The response's body
     */
    public getBodyJsonParsed(callback:NodeCallback<any>):void;

    /**
     * Returns the response's body as an object resulting from XML parsing it.
     * The object has the following structure:
     *
     * @return The response's body
     */
    public getBodyXmlParsed(callback:NodeCallback<XMLElement>):void;

    /**
     * Returns the response headers as an object
     *
     * @return {ObjectMap<string>} The response's headers
     */
    public getHeaders():ObjectMap<string>;

    /**
     * Returns the response status code as a number
     *
     * @return {number} The response's status code
     */
    public getStatus():number;
}

where

type NodeCallback<T> = (err:Error, data?:T) => void;

type ObjectMap<T> = {[key:string]:T};

type XMLElement = {
    attributes: ObjectMap<string>,
    text: string,
    name: string,
    children: XMLElement[]
};

Limitations

The requests are facilitated by prepending a Base URL, adding authorization and doing error checking. This assumes similar behavior in those regards of all API methods. Yet sometimes, this is not the case. You might have to disable authentication and do it on your own, e.g. because insufficient scopes are requested. You might have to disable error checking or do additional checking because the defaults are wrong or not sufficient. You might have to disable prepeding the base URL because a certain API endpoint has a different one. Do read up on each service in the Services section to learn about what base URL is prepended, what authorization appending does and which errors are caught.

Redirect Receiver

A redirect receiver is a function with the following definition:

(
    url:string,
    currentState:string,
    callback:(error:Error, redirectedUrl:string) => void
) => void;

Its purpose is to customize a part of OAuth authorization that highly depends on the environment and can thus not be provided by the library. Accordingly it is only required by those services that use OAuth.

The function receives a url parameter as a string that points to a website that you're supposed to present to the user you want to get authorization from.

The currentState parameter is a string representation of the service's internal state. It can be used in specific scenarios to resume authorization in a place different from where it was initiated.

The callback parameter takes a url string parameter and you should call it with the service's redirect once you receive it.

For testing or when the Node application is purely local (no server), you can get a preconfigured redirect receiver from the SDK itself, e.g.:

const cloudrail = require("cloudrail-si");

let cs = new cloudrail.services.Dropbox(
    cloudrail.RedirectReceivers.getLocalAuthenticator(port),
    "[clientId]",
    "[clientSecret]",
    "http://localhost:" + port,
    "state"
);

This implementation will use a temporary sever on localhost on the specified port (choose any free port) and the local standard browser to complete OAuth. This is to get you started quickly, but cannot be used on a server serving clients that need to authenticate.

If you are using the electron framework we have got you covered because there is a preconfigured redirect receiver as well, e.g.:

const cloudrail = require("cloudrail-si");
const {BrowserWindow} = require("electron").remote;
const redirectUrl = "[some valid redirect URL registered in your Dropbox app]";

let cs = new cloudrail.services.Dropbox(
    cloudrail.RedirectReceivers.getElectronAuthenticator(BrowserWindow, redirectUrl),
    "[clientId]",
    "[clientSecret]",
    redirectUrl,
    "state"
);

This implementation will open an electron window to do OAuth.

It is strongly recommended to have a look at the Examples to understand how it works.

License Key

In order to use the CloudRail SI Node.js SDK you need to put a license key.

CloudRail provides a developer portal which offers usage insights for the SDKs and allows you to generate license keys.

It's free to sign up and generate a key.

Head over to https://developers.cloudrail.com to get an account and a key.