Skip to content

Commit

Permalink
Initial commit of Nutshell API JSON-RPC wrapper + examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Dzombak committed Mar 2, 2011
0 parents commit 25f76e1
Show file tree
Hide file tree
Showing 5 changed files with 398 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
temp/
195 changes: 195 additions & 0 deletions NutshellApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<?php

/**
* @class NutshellApi
* @brief Easy access to the Nutshell JSON-RPC API
*
* This class is instantiated with a username and API key. Once it has been
* instantiated, the call() method is used to make calls to the Nutshell API.
*
* Rather than using call(), you can also call any Nutshell API methods on
* this class. For example, rather than calling
* @code
* $api->call('getContact', $params);
* @endcode
* you can call
* @code
* $api->getContact($params);
* @endcode
*
* Calls made using this class are synchronous - the method blocks until the
* request is completed.
*
* Requires PHP 5.0+ and the CURL and JSON modules.
* CURL: http://php.net/manual/en/book.curl.php
* JSON Module: http://pecl.php.net/package/json
*
* @version 0.1
* @date March 2, 2011
*/

class NutshellApi {
const ENDPOINT_DISCOVER_URL = 'http://api.nutshell.com/v1/json';
protected $curl = NULL;

/**
* Initializes the API access class. Takes care of endpoint discovery.
*
* @param string $username
* @param string $apiKey
* @throws NutshellApiException if either parameter is invalid
*/
function __construct($username, $apiKey) {
if (!is_string($username) || !is_string($apiKey)) {
throw new NutshellApiException('You must specify a username and API key.');
}
if (strpos($username, '@') === FALSE) {
throw new NutshellApiException('Username is not a valid email address.');
}
if (strlen($apiKey) <= 12) {
throw new NutshellApiException('API key is not long enough to be a valid key.');
}

$endpoint = $this->_getApiEndpointForUser($username);
$authHeader = base64_encode($username . ':' . $apiKey);

$this->curl = curl_init($endpoint);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Authorization: Basic '.$authHeader));
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->curl, CURLOPT_POST, true);
curl_setopt($this->curl, CURLOPT_HEADER, false);
}

function __destruct() {
if ($this->curl) {
curl_close($this->curl);
}
}

/**
* Calls a Nutshell API method
*
* See call() for detailed specs.
*
* @return array
* @throws NutshellApiException
*/
public function __call($name, $args) {
return $this->call($name, isset($args[0]) ? $args[0] : NULL);
}

/**
* Calls a Nutshell API method.
*
* Returns the result from that call or, if there was an error on the server,
* throws an exception.
*
* @param string $method
* @param array|null $params
* @return array
* @throws NutshellApiException
*/
public function call($method, array $params = NULL) {
if ($this->curl === NULL) {
throw new NutshellApiException('Nutshell API uninitialized; perhaps the constructor failed?');
}
if ($params === NULL) {
$params = array();
}
if (!is_string($method)) {
throw new NutshellApiException("Invalid method '$method'");
} else if (!is_array($params)) {
throw new NutshellApiException('$params must be an array');
}

$payload = array(
'method' => $method,
'params' => $params,
'id' => $this->_generateRequestId(),
);

curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->json_encode($payload));
$fullResult = curl_exec($this->curl);
if (curl_errno($this->curl)) {
throw new NutshellApiException('Curl error #' . curl_errno($this->curl) . ' during API call: '. curl_error($this->curl));
}
$fullResult = $this->json_decode($fullResult);

if ($fullResult->error !== NULL) {
throw new NutshellApiException('API Error: ' . $fullResult->error->message, $fullResult->error->code, $fullResult->error->data);
}

return $fullResult->result;
}

/**
* Finds the appropriate API endpoint for the given user.
*
* Info on endpoint discovery: http://nutshell.com/api/endpoint-discovery.html
*
* @param string $username
* @return string API endpoint
* @throws NutshellApiException
*/
protected function _getApiEndpointForUser($username) {
$payload = array(
'method' => 'getApiForUsername',
'params' => array('username' => $username),
'id' => $this->_generateRequestId(),
);

$curl = curl_init(self::ENDPOINT_DISCOVER_URL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $this->json_encode($payload));
curl_setopt($curl, CURLOPT_HEADER, false);
$result = curl_exec($curl);
if (curl_errno($curl)) {
throw new NutshellApiException('Curl error #' . curl_errno($curl) . ' while finding endpoint: '. curl_error($curl));
}
curl_close($curl);

$decoded = $this->json_decode($result);
return 'https://' . $decoded->result->api . '/api/v1/json';
}

/**
* Generates a random JSON request ID
*
* @return string
*/
protected function _generateRequestId() {
return substr(md5(rand()), 0, 8);
}

/**
* Encodes object in JSON
*
* Can be overridden to support PHP installations without built-in JSON support.
*/
protected function json_encode($x) {
return json_encode($x);
}

/**
* Decodes object from JSON
*
* Can be overridden to support PHP installations without built-in JSON support.
*/
protected function json_decode($x) {
return json_decode($x);
}
}

class NutshellApiException extends Exception {
protected $data;

public function __construct($message, $code = 0, $data = NULL) {
parent::__construct($message, $code);
$this->data = $data;
}

public function getData() {
return $this->data;
}
}
105 changes: 105 additions & 0 deletions examples/create.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env php
<?php

// Configuration:
$apiKey = 'YOUR API KEY HERE';
$username = 'user@example.com';
// End of configuration

require_once('../NutshellApi.php');
$api = new NutshellApi($username, $apiKey);

/**
* Example: creating an account, contact, and lead
*
* We will create a new contact, then add a new account associated with that contact,
* then finally create a new lead involving that account/contact.
*
* Relevant documentation:
* http://www.nutshell.com/api/detail/class_nut___api___core.html
*/

// Create a new contact and save its ID to $newContactId
$params = array(
'contact' => array(
'name' => 'Joan Smith',
'phone' => array(
'734-555-9090',
'cell' => '734-555-6711',
),
'email' => array(
'jsmith@example.com',
'blackberry' => 'jsmith@att.blackberry.com',
),
),
);
$newContact = $api->call('newContact', $params);
$newContactId = $newContact->id;

// Create a new account that includes the contact we just added
$params = array(
'account' => array(
'name' => 'Arbor Medical LLC',
'industryId' => 1,
'url' => array(
'http://example.com',
'http://suppliers.example.com',
),
'phone' => array(
'734-234-9990',
),
'contacts' => array(
array(
'id' => $newContactId,
'relationship' => 'Purchasing Manager'
),
),
'address' => array(
'office' => array(
'address_1' => '220 Depot St',
'city' => 'Ann Arbor',
'state' => 'MI',
'postalCode' => '48104',
),
),
),
);
$newAccount = $api->newAccount($params);
$newAccountId = $newAccount->id;

// Finally, create a lead that includes the account we just added
$params = array(
'lead' => array(
'primaryAccount' => array('id' => $newAccountId),
'confidence' => 70,
'market' => array('id' => 1),
'contacts' => array(
array(
'relationship' => 'First Contact',
'id' => $newContactId,
),
),
'products' => array(
array(
'relationship' => '',
'quantity' => 15,
'price' => array(
'currency_shortname' => 'USD',
'amount' => 1000,
),
'id' => 4,
),
),
'sources' => array(
array('id' => 2),
),
'assignee' => array(
'entityType' => 'Teams',
'id' => 1000,
),
),
);
$result = $api->newLead($params);
var_dump($result);

echo "\n";
61 changes: 61 additions & 0 deletions examples/edit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env php
<?php

// Configuration:
$apiKey = 'YOUR API KEY HERE';
$username = 'user@example.com';
// End of configuration

require_once('../NutshellApi.php');
$api = new NutshellApi($username, $apiKey);

/**
* Example: editing a lead
*
* We will add a contact and change the confidence for a lead.
* To keep the existing contacts, we need to include them in our request.
*
* Relevant documentation:
* http://nutshell.com/api/retrieving-editing.html
* http://www.nutshell.com/api/revs-etags.html
*/

// Get the lead so we have an up-to-date rev and the current contacts array
$leadId = 1600;
$params = array( 'leadId' => $leadId );
$oldLead = $api->call('getLead', $params);
$rev = $oldLead->rev;
$oldContacts = $oldLead->contacts;

// Build new contacts array containing the old contacts plus the one we want to add
$contacts = array();
foreach ($oldContacts as $contact) {
$contacts[] = array(
'id' => $contact-> id,
'relationship' => $contact->relationship,
'entityType' => 'Contacts',
// entityType is required for updating multivalue keys when editing a lead.
// this requirement will be removed in a future API release.
);
}
$contacts[] = array(
'relationship' =>'additional contact',
'id' => 17,
'entityType' => 'Contacts',
// entityType is required for updating multivalue keys when editing a lead.
// this requirement will be removed in a future API release.
);

// edit the lead
$params = array(
'leadId' => $leadId,
'rev' => $rev,
'lead' => array(
'confidence' => 75,
'contacts' => $contacts,
),
);
$result = $api->editLead($params);
var_dump($result);

echo "\n";
Loading

0 comments on commit 25f76e1

Please sign in to comment.