Implemented connect, disconnect, and getConnections on UsergridClient
diff --git a/helpers/build.js b/helpers/build.js
index 5f5f8c9..8c7ed82 100644
--- a/helpers/build.js
+++ b/helpers/build.js
@@ -14,7 +14,8 @@
             config.baseUrl,
             options.client.orgId,
             options.client.appId,
-            options.type, (_.isString(options.uuidOrName) ? options.uuidOrName : "")
+            options.type,
+            _.isString(options.uuidOrName) ? options.uuidOrName : ""
         )
     },
     GET: function(client, args) {
@@ -26,7 +27,7 @@
         client.GET(query, optionalCallback)
         client.GET({
             query: query, // takes precedence
-            type: type, // required only if query not defined
+            type: type, // required if query not defined
             uuid: uuid, // will be set to nameOrUuid on init (priority)
             name: name, // will be set to nameOrUuid on init (if no uuid specified)
             nameOrUuid: nameOrUuid // the definitive key for name or uuid
@@ -39,7 +40,8 @@
             method: 'GET'
         }
 
-        if (_.isObject(args[0]) && !_.isFunction(args[0]) && !(args[0] instanceof UsergridQuery)) {
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
             _.assign(options, args[0])
         }
 
@@ -68,7 +70,7 @@
         client.PUT({
             *entity = alias to body*
             query: query, // takes precedence over type/body
-            type: type, // required only if query not defined
+            type: type, // required if query not defined
             body: bodyObject or bodyObjectOrEntity, // if includes type, type will be inferred from body
             *uuid, name* = alias to nameOrUuid*
             nameOrUuid: nameOrUuid // the definitive key for name or uuid
@@ -81,7 +83,8 @@
             method: 'PUT'
         }
 
-        if (_.isObject(args[0]) && !_.isFunction(args[0]) && !(args[0] instanceof UsergridEntity) && !(args[0] instanceof UsergridQuery)) {
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
             _.assign(options, args[0])
         }
 
@@ -104,7 +107,6 @@
 
         return options
     },
-
     POST: function(client, args) {
 
         /* POST supports the following constructor patterns:
@@ -114,7 +116,7 @@
         client.POST(entityOrEntities, optionalCallback)
         client.POST({
             *entity, entities = alias to body*
-            type: type, // required if type is not inferred
+            type: type, // required
             body: bodyObjectOrArray or entityOrEntities, // if the first entity includes type, type will be inferred from body
         }, optionalCallback)
 
@@ -125,21 +127,22 @@
             method: 'POST'
         }
 
-        if (_.isObject(args[0]) && !_.isFunction(args[0]) && !(args[0] instanceof UsergridEntity)) {
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
             _.assign(options, args[0])
         }
 
-        options.callback = helpers.cb(_.last(args.filter(_.isFunction)))    
+        options.callback = helpers.cb(_.last(args.filter(_.isFunction)))
 
         options.body = _.first([options.entities, options.entity, options.body, args[1], args[0]].filter(function(property) {
             return _.isArray(property) && _.isObject(property[0]) && !_.isFunction(property[0]) || _.isObject(property) && !_.isFunction(property)
         }))
-        
+
         if (typeof options.body !== 'object') {
             throw new Error('"body" parameter is required when making a POST request')
         }
 
-        options.body = _.isArray(options.body) ? options.body : [options.body]        
+        options.body = _.isArray(options.body) ? options.body : [options.body]
         options.type = _.first([options.type, args[0], options.body[0].type].filter(_.isString))
 
         return options
@@ -154,7 +157,7 @@
         client.DELETE({
             *uuid, name* = alias to nameOrUuid*
             uuidOrName: uuidOrName,
-            type: type, // required if type is not inferred
+            type: type, // required if query not defined
             query: query // takes precedence over type/uuid
         }, optionalCallback)
 
@@ -165,13 +168,13 @@
             method: 'DELETE'
         }
 
-        if (_.isObject(args[0]) && !_.isFunction(args[0]) && !(args[0] instanceof UsergridQuery)) {
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
             _.assign(options, args[0])
         }
 
         options.callback = helpers.cb(_.last(args.filter(_.isFunction)))
-
-        options.type = _.first([options.type, args[0]._type, args[0]].filter(_.isString))
+        options.type = _.first([options.type, ok(options).getIfExists('entity.type'), args[0]._type, args[0]].filter(_.isString))
         options.entity = _.first([options.entity, args[0]].filter(function(property) {
             return (property instanceof UsergridEntity)
         }))
@@ -186,5 +189,152 @@
         }
 
         return options
+    },
+    connection: function(client, args) {
+
+        /* connect supports the following constructor patterns:
+
+        client.connect(entity, "relationship", toEntity);
+        // POST entity.type/entity.uuid/"relationship"/toEntity.uuid
+
+        client.connect("type", <uuidOrName>, "relationship", <toUuid>);
+        // POST type/uuidOrName/relationship/toUuid
+
+        client.connect("type", <uuidOrName>, "relationship", "toType", "toName");
+        // POST type/uuidOrName/relationship/toType/toName
+
+        client.connect({
+            entity: { // or UsergridEntity
+                type: "type", 
+                uuidOrName: <uuidOrName>
+            },
+            relationship: "likes",
+            to: { // or UsergridEntity
+                "type": "(required if not using uuid)",
+                "uuidOrName": <uuidOrName>,
+                "name": "alias to uuidOrName" // if uuid not specified, requires "type"
+                "uuid": "alias to uuidOrName" 
+            }
+        );
+
+        disconnect supports the identical patters, but uses DELETE instead of POST; it is therefore a reference to this function
+
+        */
+
+        var options = {
+            entity: {},
+            to: {},
+            callback: helpers.cb(_.last(args.filter(_.isFunction)))
+        }
+
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
+            _.assign(options, args[0])
+        }
+
+        // handle DELETE using "from" preposition
+        if (_.isObject(options.from)) {
+            options.to = options.from
+        }
+
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && _.isString(args[1]) && _.isObject(args[2]) && !_.isFunction(args[2])) {
+            _.assign(options.entity, args[0])
+            options.relationship = _.first([options.relationship, args[1]].filter(_.isString))
+            _.assign(options.to, args[2])
+        } else {
+            options.entity.type = _.first([options.entity.type, args[0]].filter(_.isString))
+            options.relationship = _.first([options.relationship, args[2]].filter(_.isString))
+
+            // when using 'name', arg3 and arg4 must both be strings
+            options.to.type = _.isString(args[3]) && !_.isUuid(args[3]) && _.isString(args[4]) ? args[3] : undefined
+        }
+
+        options.entity.uuidOrName = _.first([options.entity.uuidOrName, options.entity.uuid, options.entity.name, args[1]].filter(_.isString))
+        options.to.uuidOrName = _.first([options.to.uuidOrName, options.to.uuid, options.to.name, args[4], args[3]].filter(_.isString))
+
+        if (!_.isString(options.entity.uuidOrName)) {
+            throw new Error('source entity "uuidOrName" is required when connecting or disconnecting entities')
+        }
+
+        if (!_.isString(options.to.uuidOrName)) {
+            throw new Error('target entity "uuidOrName" is required when connecting or disconnecting entities')
+        }
+
+        if (!_.isString(options.to.type) && !_.isUuid(options.to.uuidOrName)) {
+            throw new Error('target "type" (collection name) parameter is required connecting or disconnecting entities by name')
+        }
+
+        options.uri = urljoin(
+            config.baseUrl,
+            client.orgId,
+            client.appId,
+            _.isString(options.entity.type) ? options.entity.type : "",
+            _.isString(options.entity.uuidOrName) ? options.entity.uuidOrName : "",
+            options.relationship,
+            _.isString(options.to.type) ? options.to.type : "",
+            _.isString(options.to.uuidOrName) ? options.to.uuidOrName : ""
+        )
+
+        return options
+    },
+    getConnections: function(client, args) {
+        /* getConnections supports the following constructor patterns:
+
+        client.getConnections(direction, entity, "relationship");
+        // GET OUT: /entity.type/entity.uuid/connections/relationship
+        // GET IN: /entity.type/entity.uuid/connecting/relationship
+
+        client.getConnections(direction, "type", "<uuidOrName>", "relationship");
+        // GET OUT: /type/uuidOrName/connections/relationship
+        // GET IN: /type/uuidOrName/connecting/relationship
+
+        client.getConnections({
+            type: "type", // or inferred, if second argument is an entity
+            uuidOrName: "<uuidOrName>" // if entity not specified
+            relationship: "relationship",
+            direction: OUT or IN
+        );
+        // GET OUT: /entity.type/entity.uuid/connections/relationship
+        // GET IN: /entity.type/entity.uuid/connecting/relationship
+
+        */
+
+        var options = {
+            callback: helpers.cb(_.last(args.filter(_.isFunction)))
+        }
+
+        // if a preformatted options argument passed, assign it to options
+        if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
+            _.assign(options, args[0])
+        } else if (_.isObject(args[1]) && !_.isFunction(args[1])) {
+            _.assign(options, args[1])
+        }
+
+        options.direction = _.first([options.direction, args[0]].filter(function(d) {
+            return (d === "IN" || d === "OUT")
+        }))
+        options.relationship = _.first([options.relationship, args[3], args[2]].filter(_.isString))
+        options.uuidOrName = _.first([options.uuidOrName, options.uuid, options.name, args[2]].filter(_.isString))
+        options.type = _.first([options.type, args[1]].filter(_.isString))
+
+        if (!_.isString(options.type)) {
+            throw new Error('"type" (collection name) parameter is required when retrieving connections')
+        }
+
+        if (!_.isString(options.uuidOrName)) {
+            throw new Error('target entity "uuidOrName" is required when retrieving connections')
+        }
+
+        options.uri = urljoin(
+            config.baseUrl,
+            client.orgId,
+            client.appId,
+            _.isString(options.type) ? options.type : "",
+            _.isString(options.uuidOrName) ? options.uuidOrName : "",
+            options.direction === "IN" ? "connecting" : "connections",
+            options.relationship
+        )
+
+        return options
     }
 }
\ No newline at end of file
diff --git a/lib/client.js b/lib/client.js
index 611bda3..ad82cd1 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -3,6 +3,7 @@
 var UsergridRequest = require('./request'),
     request = require('request'),
     helpers = require('../helpers'),
+    UsergridResponse = require('./response'),
     UsergridAppAuth = require('./appAuth'),
     UsergridUserAuth = require('./userAuth'),
     UsergridUser = require('./user'),
@@ -51,96 +52,132 @@
     })
 }
 
-UsergridClient.prototype.GET = function() {
-    return new UsergridRequest(helpers.build.GET(this, Array.prototype.slice.call(arguments)))
-}
+UsergridClient.prototype = {
+    GET: function() {
+        return new UsergridRequest(helpers.build.GET(this, Array.prototype.slice.call(arguments)))
+    },
+    PUT: function() {
+        return new UsergridRequest(helpers.build.PUT(this, Array.prototype.slice.call(arguments)))
+    },
+    POST: function() {
+        return new UsergridRequest(helpers.build.POST(this, Array.prototype.slice.call(arguments)))
+    },
+    DELETE: function() {
+        return new UsergridRequest(helpers.build.DELETE(this, Array.prototype.slice.call(arguments)))
+    },
+    connections: {
+        DIRECTION_IN: "IN",
+        DIRECTION_OUT: "OUT"
+    },
+    connect: function() {
+        var options = helpers.build.connection(this, Array.prototype.slice.call(arguments))
+        request({
+            uri: options.uri,
+            headers: helpers.userAgent,
+            method: 'POST',
+            json: true
+        }, function(error, response) {
+            var usergridResponse = new UsergridResponse(response)
+            options.callback(error, usergridResponse, usergridResponse.entities)
+        })
+    },
+    disconnect: function(options, callback) {
+        var options = helpers.build.connection(this, Array.prototype.slice.call(arguments))
+        request({
+            uri: options.uri,
+            headers: helpers.userAgent,
+            method: 'DELETE',
+            json: true
+        }, function(error, response) {
+            var usergridResponse = new UsergridResponse(response)
+            options.callback(error, usergridResponse, usergridResponse.entities)
+        })
+    },
+    getConnections: function(options, callback) {
+        var options = helpers.build.getConnections(this, Array.prototype.slice.call(arguments))
+        request({
+            uri: options.uri,
+            headers: helpers.userAgent,
+            method: 'GET',
+            json: true
+        }, function(error, response) {
+            var usergridResponse = new UsergridResponse(response)
+            options.callback(error, usergridResponse, usergridResponse.entities)
+        })
+    },
+    setAppAuth: function(options) {
+        this.appAuth = (typeof options === 'string') ? _.values(arguments) : options
+    },
+    authenticateApp: function(options, callback) {
+        var self = this
+        callback = helpers.cb(callback || options)
 
-UsergridClient.prototype.PUT = function() {
-    return new UsergridRequest(helpers.build.PUT(this, Array.prototype.slice.call(arguments)))
-}
+        options = (options instanceof UsergridAppAuth) ? options : self.appAuth || new UsergridAppAuth(options)
 
-UsergridClient.prototype.POST = function() {
-    return new UsergridRequest(helpers.build.POST(this, Array.prototype.slice.call(arguments)))
-}
-
-UsergridClient.prototype.DELETE = function() {
-    return new UsergridRequest(helpers.build.DELETE(this, Array.prototype.slice.call(arguments)))
-}
-
-UsergridClient.prototype.setAppAuth = function(options) {
-    this.appAuth = (typeof options === 'string') ? _.values(arguments) : options
-}
-
-UsergridClient.prototype.authenticateApp = function(options, callback) {
-    var self = this
-    callback = helpers.cb(callback || options)
-
-    options = (options instanceof UsergridAppAuth) ? options : self.appAuth || new UsergridAppAuth(options)
-
-    if (!(options instanceof UsergridAppAuth)) {
-        throw new Error('App auth context was not defined when attempting to call .authenticateApp()')
-    } else if (!options.clientId || !options.clientSecret) {
-        throw new Error('authenticateApp() failed because clientId or clientSecret are missing')
-    }
-
-    options.type = 'token'
-    options.client = self
-    request({
-        uri: helpers.build.url(options),
-        headers: helpers.userAgent,
-        body: {
-            grant_type: 'client_credentials',
-            client_id: options.clientId,
-            client_secret: options.clientSecret
-        },
-        method: 'POST',
-        json: true
-    }, function(error, response, body) {
-        if (self.appAuth && response.statusCode === 200) {
-            self.appAuth.token = body.access_token
-            self.appAuth.expiry = helpers.time.expiry(body.expires_in)
-            self.appAuth.tokenTtl = body.expires_in
+        if (!(options instanceof UsergridAppAuth)) {
+            throw new Error('App auth context was not defined when attempting to call .authenticateApp()')
+        } else if (!options.clientId || !options.clientSecret) {
+            throw new Error('authenticateApp() failed because clientId or clientSecret are missing')
         }
-        callback(error, response, body.access_token)
-    })
-}
 
-UsergridClient.prototype.authenticateUser = function(options, callback) {
-    var self = this
-    callback = helpers.cb(callback || options)
+        options.type = 'token'
+        options.client = self
+        request({
+            uri: helpers.build.url(options),
+            headers: helpers.userAgent,
+            body: {
+                grant_type: 'client_credentials',
+                client_id: options.clientId,
+                client_secret: options.clientSecret
+            },
+            method: 'POST',
+            json: true
+        }, function(error, response, body) {
+            if (self.appAuth && response.statusCode === 200) {
+                self.appAuth.token = body.access_token
+                self.appAuth.expiry = helpers.time.expiry(body.expires_in)
+                self.appAuth.tokenTtl = body.expires_in
+            }
+            callback(error, response, body.access_token)
+        })
+    },
+    authenticateUser: function(options, callback) {
+        var self = this
+        callback = helpers.cb(callback || options)
 
-    if (!options.username && !options.email && !options.password) {
-        throw new Error('authenticateUser() failed because username/email and password are missing')
-    } else if (!options.password) {
-        throw new Error('authenticateUser() failed because password is missing')
-    }
-
-    options.type = 'token'
-    options.client = self
-    request({
-        uri: helpers.build.url(options),
-        headers: helpers.userAgent,
-        body: options.username ? {
-            grant_type: 'password',
-            username: options.username,
-            password: options.password
-        } : {
-            grant_type: 'password',
-            email: options.email,
-            password: options.password
-        },
-        method: 'POST',
-        json: true
-    }, function(error, response, body) {
-        if (response.statusCode === 200) {
-            self.currentUser = new UsergridUser(body.user)
-            self.currentUser.auth = new UsergridUserAuth(body.user)
-            self.currentUser.auth.token = body.access_token
-            self.currentUser.auth.expiry = helpers.time.expiry(body.expires_in)
-            self.currentUser.auth.tokenTtl = body.expires_in
+        if (!options.username && !options.email && !options.password) {
+            throw new Error('authenticateUser() failed because username/email and password are missing')
+        } else if (!options.password) {
+            throw new Error('authenticateUser() failed because password is missing')
         }
-        callback(error, response, body.access_token)
-    })
+
+        options.type = 'token'
+        options.client = self
+        request({
+            uri: helpers.build.url(options),
+            headers: helpers.userAgent,
+            body: options.username ? {
+                grant_type: 'password',
+                username: options.username,
+                password: options.password
+            } : {
+                grant_type: 'password',
+                email: options.email,
+                password: options.password
+            },
+            method: 'POST',
+            json: true
+        }, function(error, response, body) {
+            if (response.statusCode === 200) {
+                self.currentUser = new UsergridUser(body.user)
+                self.currentUser.auth = new UsergridUserAuth(body.user)
+                self.currentUser.auth.token = body.access_token
+                self.currentUser.auth.expiry = helpers.time.expiry(body.expires_in)
+                self.currentUser.auth.tokenTtl = body.expires_in
+            }
+            callback(error, response, body.access_token)
+        })
+    }
 }
 
 module.exports = UsergridClient
\ No newline at end of file
diff --git a/lib/request.js b/lib/request.js
index edd0860..2a8160a 100644
--- a/lib/request.js
+++ b/lib/request.js
@@ -10,8 +10,8 @@
 var UsergridRequest = function(options) {
     options.callback = helpers.cb(options.callback)
 
-    if (typeof options.type !== 'string') {
-        throw new Error('"type" (or "collection") parameter is required when making a request')
+    if (!_.isString(options.type)) {
+        throw new Error('"type" (collection name) parameter is required when making a request')
     }
 
     var headers = helpers.userAgent
@@ -21,7 +21,6 @@
             authorization: util.format("Bearer %s", options.client.appAuth.token)
         })
     }
-
     request(helpers.build.url(options), {
         headers: headers,
         body: options.body,
@@ -32,7 +31,8 @@
             limit: options.query._limit
         } : undefined
     }, function(error, response) {
-        options.callback(error, new UsergridResponse(response))
+        var usergridResponse = new UsergridResponse(response)
+        options.callback(error, usergridResponse, usergridResponse.entities)
     })
 
 }
diff --git a/tests/lib/client.test.js b/tests/lib/client.test.js
index 09995fe..c1196d1 100644
--- a/tests/lib/client.test.js
+++ b/tests/lib/client.test.js
@@ -1,6 +1,7 @@
 'use strict'
 
 var should = require('should'),
+    urljoin = require('url-join'),
     config = require('../../helpers').config,
     UsergridClient = require('../../lib/client'),
     UsergridEntity = require('../../lib/entity'),
@@ -496,6 +497,281 @@
     })
 })
 
+describe('connect()', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    var response,
+        client = new UsergridClient(),
+        query = new UsergridQuery(config.test.collection).eq('name', 'testNameOne').or.eq('name', 'testNameTwo').asc('name')
+
+    before(function(done) {
+        // Create the entities we're going to use for connections
+        client.POST(config.test.collection, [{
+            "name": "testNameOne"
+        }, {
+            "name": "testNameTwo"
+        }], function() {
+            client.GET(query, function(err, usergridResponse) {
+                response = usergridResponse
+                done()
+            })
+        })
+    })
+
+    it('should connect entities by passing UsergridEntity objects as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "foos"
+
+        client.connect(entity1, relationship, entity2, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.first.metadata.connecting[relationship].should.equal(urljoin(
+                    "/",
+                    config.test.collection,
+                    entity1.uuid,
+                    relationship,
+                    entity2.uuid,
+                    "connecting",
+                    relationship
+                ))
+                done()
+            })
+        })
+    })
+
+    it('should connect entities by passing source type, source uuid, and target uuid as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "bars"
+
+        client.connect(entity1.type, entity1.uuid, relationship, entity2.uuid, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.first.metadata.connecting[relationship].should.equal(urljoin(
+                    "/",
+                    config.test.collection,
+                    entity1.uuid,
+                    relationship,
+                    entity2.uuid,
+                    "connecting",
+                    relationship
+                ))
+                done()
+            })
+        })
+    })
+
+    it('should connect entities by passing source type, source name, target type, and target name as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "bazzes"
+
+        client.connect(entity1.type, entity1.name, relationship, entity2.type, entity2.name, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.first.metadata.connecting[relationship].should.equal(urljoin(
+                    "/",
+                    config.test.collection,
+                    entity1.uuid,
+                    relationship,
+                    entity2.uuid,
+                    "connecting",
+                    relationship
+                ))
+                done()
+            })
+        })
+    })
+
+    it('should connect entities by passing a preconfigured options object', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var options = {
+            entity: entity1,
+            relationship: "quxes",
+            to: entity2
+        }
+
+        client.connect(options, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, options.relationship, function(err, usergridResponse) {
+                usergridResponse.first.metadata.connecting[options.relationship].should.equal(urljoin(
+                    "/",
+                    config.test.collection,
+                    entity1.uuid,
+                    options.relationship,
+                    entity2.uuid,
+                    "connecting",
+                    options.relationship
+                ))
+                done()
+            })
+        })
+    })
+
+    it('should fail to connect entities when specifying target name without type', function() {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        should(function() {
+            client.connect(entity1.type, entity1.name, "test", entity2.name, function(err, usergridResponse) {})
+        }).throw()
+    })
+})
+
+describe('getConnections()', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    var response,
+        client = new UsergridClient(),
+        query = new UsergridQuery(config.test.collection).eq('name', 'testNameOne').or.eq('name', 'testNameTwo').asc('name')
+
+    before(function(done) {
+        client.GET(query, function(err, usergridResponse) {
+            response = usergridResponse
+            done()
+        })
+    })
+
+    it('should get an entity\'s outbound connections', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "foos"
+
+        client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+            usergridResponse.first.metadata.connecting[relationship].should.equal(urljoin(
+                "/",
+                config.test.collection,
+                entity1.uuid,
+                relationship,
+                entity2.uuid,
+                "connecting",
+                relationship
+            ))
+            done()
+        })
+    })
+
+    it('should get an entity\'s inbound connections', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "foos"
+
+        client.getConnections(client.connections.DIRECTION_IN, entity2, relationship, function(err, usergridResponse) {
+            usergridResponse.first.metadata.connections[relationship].should.equal(urljoin(
+                "/",
+                config.test.collection,
+                entity2.uuid,
+                "connecting",
+                entity1.uuid,
+                relationship
+            ))
+            done()
+        })
+    })
+})
+
+describe('disconnect()', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    var response,
+        client = new UsergridClient(),
+        query = new UsergridQuery(config.test.collection).eq('name', 'testNameOne').or.eq('name', 'testNameTwo').asc('name')
+
+    before(function(done) {
+        client.GET(query, function(err, usergridResponse) {
+            response = usergridResponse
+            done()
+        })
+    })
+
+    it('should disconnect entities by passing UsergridEntity objects as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "foos"
+
+        client.disconnect(entity1, relationship, entity2, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.entities.should.be.an.Array().with.lengthOf(0)
+                done()
+            })
+        })
+    })
+
+    it('should disconnect entities by passing source type, source uuid, and target uuid as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "bars"
+
+        client.disconnect(entity1.type, entity1.uuid, relationship, entity2.uuid, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.entities.should.be.an.Array().with.lengthOf(0)
+                done()
+            })
+        })
+    })
+
+    it('should disconnect entities by passing source type, source name, target type, and target name as parameters', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var relationship = "bazzes"
+
+        client.disconnect(entity1.type, entity1.name, relationship, entity2.type, entity2.name, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, relationship, function(err, usergridResponse) {
+                usergridResponse.entities.should.be.an.Array().with.lengthOf(0)
+                done()
+            })
+        })
+    })
+
+    it('should disconnect entities by passing a preconfigured options object', function(done) {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        var options = {
+            entity: entity1,
+            relationship: "quxes",
+            to: entity2
+        }
+
+        client.disconnect(options, function(err, usergridResponse) {
+            usergridResponse.statusCode.should.equal(200)
+            client.getConnections(client.connections.DIRECTION_OUT, entity1, options.relationship, function(err, usergridResponse) {
+                usergridResponse.entities.should.be.an.Array().with.lengthOf(0)
+                done()
+            })
+        })
+    })
+
+    it('should fail to disconnect entities when specifying target name without type', function() {
+        var entity1 = response.first
+        var entity2 = response.last
+
+        should(function() {
+            client.disconnect(entity1.type, entity1.name, "test", entity2.name, function(err, usergridResponse) {})
+        }).throw()
+    })
+})
+
 describe('authenticateApp()', function() {
 
     this.slow(_slow)
@@ -613,7 +889,7 @@
 
     it('client.currentUser should have an email', function() {
         client.currentUser.should.have.property('email')
-    })    
+    })
 
     it('client.currentUser and client.currentUser.auth should not store password', function() {
         client.currentUser.should.not.have.property('password')