Interface for invoking Salesforce.com REST calls over SSL with OAUTH authentication. This interface is designed to simplify the interaction between mbed devices and salesforce.com web services.

Dependencies:   HTTPClient-SSL MbedJSONValue

Dependents:   StatusReporter

Files at this revision

API Documentation at this revision

Comitter:
ansond
Date:
Tue Sep 23 05:40:18 2014 +0000
Parent:
8:47db53cd5884
Child:
10:845ea6d00b65
Commit message:
updates for create,read,update,delete methods

Changed in this revision

SalesforceInterface.cpp Show annotated file Show diff for this revision Revisions of this file
SalesforceInterface.h Show annotated file Show diff for this revision Revisions of this file
--- a/SalesforceInterface.cpp	Mon Sep 22 04:28:02 2014 +0000
+++ b/SalesforceInterface.cpp	Tue Sep 23 05:40:18 2014 +0000
@@ -1,5 +1,7 @@
 /* Copyright C2014 ARM, MIT License
  *
+ * Author: Doug Anson (doug.anson@arm.com)
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  * and associated documentation files the "Software", to deal in the Software without restriction,
  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
@@ -50,10 +52,9 @@
      this->m_http_status = HTTP_OK;
      this->m_http_response_code = -1;
      RESET_BUFFER(this->m_http_redirection_url);
-     RESET_BUFFER(this->m_salesforce_id);
      memset(this->m_salesforce_api,0,SALESFORCE_API_VERSION_LENGTH);
      strcpy(this->m_salesforce_api,SALESFORCE_API_VERSION);
-     this->resetOauthToken();
+     this->resetSalesforceID();
  }
  
  // destructor
@@ -96,7 +97,7 @@
  
  // reset our oauth token
  void SalesforceInterface::resetOauthToken() {
-     //DEBUG("resetting OAUTH token...");
+     DEBUG("resetting OAUTH token...");
      this->m_oauth_token.valid              = false;
      this->m_oauth_token.id                 = "";
      this->m_oauth_token.issued_at          = "";
@@ -104,6 +105,7 @@
      this->m_oauth_token.instance_url       = "";
      this->m_oauth_token.signature          = "";
      this->m_oauth_token.access_token       = "";
+     if (this->http() != NULL) this->http()->oauthToken(NULL);
  }
  
  // fill our oauth token
@@ -130,37 +132,64 @@
  }
  
  // is our OAUTH token valid?
- bool SalesforceInterface::validOauthToken() {         
+ bool SalesforceInterface::validOauthToken(bool fetch) {         
     // make sure we have a valid OAUTH Token
-    this->checkAndGetOauthToken();
-    
-    // TODO: we currently only return fill status. Later we may want to check dates too...
+    this->checkAndGetOauthToken(fetch);
     return this->m_oauth_token.valid; 
  }
+ 
+ // reset our salesforce ID and OAUTH tokens
+ void SalesforceInterface::resetSalesforceID() {
+     this->resetOauthToken();
+     RESET_BUFFER(this->m_salesforce_id);
+ }
 
  // do we have a valid salesforce.com ID?
- bool SalesforceInterface::haveSalesforceID() {
+ bool SalesforceInterface::haveSalesforceID(bool fetch) {
      if (this->m_salesforce_id != NULL && strlen(this->m_salesforce_id) > 0) return true;
+     if (fetch) {
+        this->logger()->log("No Salesforce ID found... fetching...");
+        this->getSalesforceID();
+        return this->haveSalesforceID(false);
+     }
      return false;
  }
  
  // check and get our OAUTH token
- void SalesforceInterface::checkAndGetOauthToken() {
+ void SalesforceInterface::checkAndGetOauthToken(bool fetch) {
      DEBUG("checking for valid OAUTH token...");
-     if (this->m_oauth_token.valid == false) {
-         // re-initialize token
-         this->resetOauthToken();
-         
-         // get our Token
+     
+     // reset the token structure for sanity...
+     if (this->m_oauth_token.valid == false) this->resetOauthToken();   
+     
+     // should go fetch our token if we dont have one?
+     // just pass through if we already have a token
+     if (this->m_oauth_token.valid == true) {
+        DEBUG("valid OAUTH token found.");
+     }
+     else if (this->m_oauth_token.valid == false && fetch == true) {
+         // get our OAUTH token
+         DEBUG("No OAUTH token found. Acquiring OAUTH token...");
          ALLOC_BUFFER(output_buffer);
          char *token = this->getOauthToken(output_buffer,MAX_BUFFER_LENGTH);
-         
-         // fill
-         this->fillOauthToken(token);
-         return;
+         if (token != NULL && strlen(token) > 0) {
+            // fill
+            DEBUG("Saving OAUTH token...");
+            this->fillOauthToken(token);
+            return;
+         }
+         else {
+             // unable to get the token (reset for sanity)
+             this->logger()->log("error in acquiring OAUTH token http_code=%d status=%d",this->httpResponseCode(),this->httpStatus());
+             this->resetOauthToken();
+         }
      }
-     DEBUG("valid OAUTH token found.");
- }
+     
+     // else report that we dont have a token
+     else {
+         this->logger()->log("No OAUTH token found (fetch=false).");
+     }
+ }  
  
  //
  // get OAUTH2 Token - taken from here: 
@@ -192,8 +221,8 @@
          this->m_http_status = this->http()->post(SF_OAUTH_TOKEN_URL,input,&output);
 
          // check the result and return the token
-         if (this->m_http_status == HTTP_OK) return output_buffer;
-         this->logger()->log("oauth invocation failed. URL: %s",SF_OAUTH_TOKEN_URL);
+         if (this->httpStatus() == HTTP_OK || this->httpResponseCode() == 200) return output_buffer;
+         this->logger()->log("acquire oauth FAILED. URL: %s http_code=%d status=%d",SF_OAUTH_TOKEN_URL,this->httpResponseCode(),this->httpStatus());
      }
      else {
          // no credentials
@@ -203,9 +232,9 @@
  }
  
  // Salesforce.com: Get our ID
- char *SalesforceInterface::getSalesforceID() {
+ char *SalesforceInterface::getSalesforceID(bool fetch) {
     // proceed only if we have a valid OAUTH Token
-    if (this->validOauthToken() == true) {
+    if (this->validOauthToken(fetch) == true) {
         // pull the ID from salesforce
         RESET_BUFFER(this->m_salesforce_id);
         char *id = this->invoke(this->oauth()->id.c_str(),this->m_salesforce_id,MAX_BUFFER_LENGTH);
@@ -225,7 +254,7 @@
  char *SalesforceInterface::query(char *query_str,char *output_buffer,int output_buffer_length) {
      // first we have to ensure that we have valid salesforce ID
      if (this->haveSalesforceID()) {        
-        // get the QUERY URL
+        // get the query url
         ALLOC_BUFFER(url);
         char *sf_url = this->getSalesforceURL("query",url,MAX_BUFFER_LENGTH);
         if (sf_url != NULL && strlen(sf_url) > 0) {
@@ -259,29 +288,240 @@
      return NULL;
  }
  
+ // CREATE: a field in Salesforce.com
+ MbedJSONValue SalesforceInterface::createField(char *object_name,MbedJSONValue &field) { 
+    ALLOC_BUFFER(output_buffer);
+    char *reply = this->createField(object_name,(char *)field.serialize().c_str(),output_buffer,MAX_BUFFER_LENGTH);
+    MbedJSONValue response;
+    if (reply != NULL && strlen(reply) > 0) parse(response,reply);
+    return response;
+ }
+
+ // READ: a specific field in Salesforce.com
+ MbedJSONValue SalesforceInterface::readField(char *object_name,char *object_id) {
+    ALLOC_BUFFER(output_buffer);
+    char *reply = this->readField(object_name,object_id,output_buffer,MAX_BUFFER_LENGTH);
+    MbedJSONValue response;
+    if (reply != NULL && strlen(reply) > 0) parse(response,reply);
+    return response; 
+ }
+
+ // UPDATE: a specific field in Salesforce.com
+ bool SalesforceInterface::updateField(char *object_name,char *object_id,MbedJSONValue &field) {
+    return this->updateField(object_name,object_id,(char *)field.serialize().c_str());
+ }
+ 
+ // CREATE: a field in Salesforce.com
+ char *SalesforceInterface::createField(char *object_name,char *json_data,char *output_buffer,int output_buffer_length) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && json_data != NULL && strlen(json_data) > 0 && output_buffer != NULL && output_buffer_length > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // DEBUG
+                DEBUG("createField: URL: %s  DATA: %s",str_url.c_str(),json_data);
+                
+                // now invoke with POST with JSON data type
+                return this->invoke(str_url.c_str(),json_data,strlen(json_data)+1,output_buffer,output_buffer_length);
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("createField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("createField: error - invalid or NULL parameters...");
+     }
+     return NULL;
+ }
+
+ // READ: a specific field in Salesforce.com
+ char *SalesforceInterface::readField(char *object_name,char *object_id,char *output_buffer,int output_buffer_length) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && object_id != NULL && strlen(object_id) > 0 && output_buffer != NULL && output_buffer_length > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // DEBUG
+                DEBUG("readField: URL: %s",str_url.c_str());
+                
+                // now invoke with GET with JSON data type
+                return this->invoke(str_url.c_str(),output_buffer,output_buffer_length);
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("readField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("readField: error - invalid or NULL parameters...");
+     }
+     return NULL;
+ }
+
+ // UPDATE: a specific field in Salesforce.com
+ bool SalesforceInterface::updateField(char *object_name,char *object_id,char *json_data) {  
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && json_data != NULL && strlen(json_data) > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // HTTPClient does not support PATCH, so we have to use POST with a special added parameter
+                str_url += "?_HttpMethod=PATCH";
+                
+                // DEBUG
+                DEBUG("updateField: URL: %s DATA: %s",str_url.c_str(),json_data);
+                
+                // now invoke with POST with JSON data type
+                ALLOC_SML_BUFFER(output_buffer);
+                char *reply = this->invoke(str_url.c_str(),json_data,strlen(json_data)+1,output_buffer,MAX_SMALL_BUFFER_LENGTH);
+                
+                // DEBUG
+                DEBUG("updateField: http status=%d",this->httpResponseCode());
+                
+                // return our status
+                if (this->httpResponseCode() == 204) return true;
+                return false;
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("updateField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("updateField: error - invalid or NULL parameters...");
+     }
+     return false;  
+ }
+  
+ // DELETE: a specific field in Salesforce.com
+ bool SalesforceInterface::deleteField(char *object_name,char *object_id) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && object_id != NULL && strlen(object_id) > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // DEBUG
+                DEBUG("deleteField: URL: %s",str_url.c_str());
+                
+                // now invoke with DELETE 
+                ALLOC_SML_BUFFER(output_buffer);
+                char *reply = this->invoke(str_url.c_str(),output_buffer,MAX_SMALL_BUFFER_LENGTH,DELETE);
+                
+                // DEBUG
+                DEBUG("deleteField: http status=%d",this->httpResponseCode());
+                
+                // return our status
+                if (this->httpResponseCode() == 204) return true;
+                return false;
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("deleteField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("deleteField: error - invalid or NULL parameters...");
+     }
+     return false;
+ }
+ 
  // Salesforce.com Invoke: defaults to GET
- char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_len) { 
-    return this->invoke(url,NUM_TYPES,NULL,0,output_buffer,output_buffer_len,GET); 
+ char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_length) { 
+    return this->invoke(url,output_buffer,output_buffer_length,GET); 
+ }
+ 
+ // Salesforce.com Invoke: GET or DELETE with simple output
+ char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_length,HttpVerb verb) { 
+    char *response = NULL;
+    switch(verb) {
+        case GET:
+        case DELETE:
+            // GET and DELETE only require an output buffer...
+            response = this->invoke(url,NUM_TYPES,NULL,0,output_buffer,output_buffer_length,verb); 
+            break;
+        default:
+            // wrong verb for this call interface...
+            this->logger()->log("invoke: invalid call: must be either GET or DELETE verb if only output buffer is provided");
+            break;
+    }
+    return response;
  }
  
  // Salesforce.com Invoke: defaults to POST with JSON input data type                                                  
- char *SalesforceInterface::invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len) { 
-    return this->invoke(url,JSON,input_data,input_data_len,output_buffer,output_buffer_len); 
+ char *SalesforceInterface::invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length) { 
+    return this->invoke(url,JSON,input_data,input_data_len,output_buffer,output_buffer_length); 
  }
  
  // Salesforce.com Invoke: defaults to POST with variable input data type                                                  
- char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len) { 
-    return this->invoke(url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,POST); 
+ char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length) { 
+    return this->invoke(url,input_type,input_data,input_data_len,output_buffer,output_buffer_length,POST); 
  }
  
  // Salesforce.com Invoke: full fidelity method
- char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len,const HttpVerb verb) {     
+ char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length,const HttpVerb verb) {     
      // initialize our invocation status and response code
      this->m_http_response_code = -1;
      this->m_http_status = HTTP_ERROR;
                  
      // param check: make sure that we at least have an output buffer and URL
-     if (url != NULL && strlen(url) > 0 && output_buffer != NULL && output_buffer_len > 0) {         
+     if (url != NULL && strlen(url) > 0 && output_buffer != NULL && output_buffer_length > 0) {         
         // proceed only if we have a valid OAUTH Token
         if (this->validOauthToken() == true) {                  
             // use OAUTH headers
@@ -292,30 +532,30 @@
             this->http()->setLocationBuf((char *)this->m_http_redirection_url,MAX_BUFFER_LENGTH);
 
             // create our output/response buffer
-            HTTPText output(output_buffer,output_buffer_len);
+            HTTPText output(output_buffer,output_buffer_length);
             
             // now make the HTTP(S) request
             switch(verb) {
                 case GET:
-                    DEBUG("invoking(GET) URL: %s...",url);
+                    DEBUG("invoke (GET) URL: %s...",url);
                     this->m_http_status = this->http()->get(url,&output);
                     this->m_http_response_code = this->http()->getHTTPResponseCode();
                     break;
                 case DELETE:
-                    DEBUG("invoking(DEL) URL: %s...",url);
+                    DEBUG("invoke (DEL) URL: %s...",url);
                     this->m_http_status = this->http()->del(url,&output);
                     this->m_http_response_code = this->http()->getHTTPResponseCode();
                     break;
                 case POST:
                     if (input_data != NULL && input_data_len > 0) {
                         if (input_type == JSON) {
-                            DEBUG("invoking(POST-JSON) URL: %s...",url);
+                            DEBUG("invoke (POST-JSON) URL: %s...",url);
                             HTTPJson input_json((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->post(url,input_json,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
                         }
                         else {
-                            DEBUG("invoking(POST-TEXT) URL: %s...",url);
+                            DEBUG("invoke (POST-TEXT) URL: %s...",url);
                             HTTPText input_text((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->post(url,input_text,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
@@ -329,13 +569,13 @@
                 case PUT:
                     if (input_data != NULL && input_data_len > 0) {
                         if (input_type == JSON) {
-                            DEBUG("invoking(PUT-JSON) URL: %s...",url);
+                            DEBUG("invoke (PUT-JSON) URL: %s...",url);
                             HTTPJson input_json((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->put(url,input_json,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
                         }
                         else {
-                            DEBUG("invoking(PUT-TEXT) URL: %s...",url);
+                            DEBUG("invoke (PUT-TEXT) URL: %s...",url);
                             HTTPText input_text((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->put(url,input_text,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
@@ -367,7 +607,7 @@
          // do we have any redirections?
          if (this->httpResponseCode() == 302 /* REDIRECT */ && strlen(this->m_http_redirection_url) > 0) {
             // we have a redirect - so reset the output buffer
-            memset(output_buffer,0,output_buffer_len);
+            memset(output_buffer,0,output_buffer_length);
             
             // we have to make a copy of the redirection URL - this is because the subsequent invoke() will wipe our current one clean
             ALLOC_BUFFER(redirect_url);
@@ -375,7 +615,7 @@
                         
             // repeat with the redirection URL      
             DEBUG("invoke: redirecting to: %s",redirect_url);  
-            return this->invoke((const char *)redirect_url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,verb);
+            return this->invoke((const char *)redirect_url,input_type,input_data,input_data_len,output_buffer,output_buffer_length,verb);
          }
          else if (this->httpResponseCode() == 302 /* REDIRECT */) {
             // error - got a redirect but have no URL
@@ -385,7 +625,7 @@
      }
           
      // return the response in the output buffer
-     if (this->httpStatus() == HTTP_OK) return output_buffer;
+     if (this->httpStatus() == HTTP_OK || this->httpStatus() == HTTP_REDIRECT) return output_buffer;
      else this->logger()->log("invocation failed with HTTP error code=%d status=%d",this->httpResponseCode(),this->httpStatus());
      return NULL;
  }
@@ -463,4 +703,4 @@
             line.insert( pos, newString );
         }
     }
-} 
\ No newline at end of file
+ }
\ No newline at end of file
--- a/SalesforceInterface.h	Mon Sep 22 04:28:02 2014 +0000
+++ b/SalesforceInterface.h	Tue Sep 23 05:40:18 2014 +0000
@@ -1,5 +1,7 @@
 /* Copyright C2014 ARM, MIT License
  *
+ * Author: Doug Anson (doug.anson@arm.com)
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  * and associated documentation files the "Software", to deal in the Software without restriction,
  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
@@ -78,7 +80,7 @@
      string access_token;
  } OauthToken;
         
- // This class provides an interface into the REST-based Salesforce.com APIs
+ // SalesforceInterface provides an API into the REST-based Salesforce.com Force APIs
  class SalesforceInterface {
     private:
         ErrorHandler    *m_logger;
@@ -104,26 +106,56 @@
         void setCredentials(char *username,char *password,char *client_id,char *client_secret);
         
         // get our ID structure from Salesforce
-        char *getSalesforceID();
-        bool haveSalesforceID();
+        char *getSalesforceID(bool fetch = true);
+        
+        // force the interface to re-acquire the OAUTH token and salesforce ID
+        void resetSalesforceID();
         
         // set/get our salesforce API version
         void setSalesforceAPIVersion(int version);
         void setSalesforceAPIVersion(char *version);
         char *getSalesforceAPIVersion();
         
-        // QUERY: into Salesforce.com
+        // SQL QUERY: into Salesforce.com
         char *query(char *query_str,char *output_buffer,int output_buffer_length);
-                     
+ 
+        // CREATE: a field in Salesforce.com
+        MbedJSONValue createField(char *object_name,MbedJSONValue &field);
+        
+        // READ: a specific field in Salesforce.com
+        MbedJSONValue readField(char *object_name,char *object_id);
+        
+        // UPDATE: a specific field in Salesforce.com
+        bool updateField(char *object_name,char *object_id,MbedJSONValue &field);
+        
+        // DELETE: a specific field in Salesforce.com
+        bool deleteField(char *object_name,char *object_id);
+        
+        // HTTP Error code access
+        int httpResponseCode();
+                      
+ protected: 
+        // do we have a valid salesforce ID and OAUTH token?
+        bool haveSalesforceID(bool fetch = true);
+
+        // CREATE: a field in Salesforce.com
+        char *createField(char *object_name,char *json_data,char *output_buffer,int output_buffer_length);
+        
+        // READ: a specific field in Salesforce.com
+        char *readField(char *object_name,char *object_id,char *output_buffer,int output_buffer_length);
+        
+        // UPDATE: a specific field in Salesforce.com
+        bool updateField(char *object_name,char *object_id,char *json_data);
+                            
         // raw invocation of REST calls into Salesforce.com
-        char *invoke(const char *url,char *output_buffer,int output_buffer_len);                                                                                                        // defaults to GET
-        char *invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len);                                                        // defaults to POST with JSON input data type                                                                              // defaults to GET
-        char *invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len);                        // defaults to POST with variable input data type
-        char *invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len,const HttpVerb verb);    // full fidelity method
- 
- private:       
+        char *invoke(const char *url,char *output_buffer,int output_buffer_length);                                                                                                        // defaults to GET
+        char *invoke(const char *url,char *output_buffer,int output_buffer_length,HttpVerb verb);                                                                                          // GET or DELETE with simple output
+        char *invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length);                                                        // defaults to POST with JSON input data type
+        char *invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length);                        // defaults to POST with variable input data type
+        char *invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length,const HttpVerb verb);    // full fidelity method
+      
         // get our OAUTH Token
-        void checkAndGetOauthToken();
+        void checkAndGetOauthToken(bool fetch = true);
         char *getOauthToken(char *output_buffer,int output_buffer_length);
      
         // convenience accessors
@@ -131,17 +163,16 @@
         HTTPClient *http();
         OauthToken *oauth();
         HTTPResult httpStatus();
-        int httpResponseCode();
         
         // internal checkers
         bool haveCreds();
         void resetOauthToken();
         void fillOauthToken(char *token);
-        bool validOauthToken();
+        bool validOauthToken(bool fetch = true);
         
         // get the specified URL from our Salesforce ID
         char *getSalesforceURL(char *key,char *url_buffer,int url_buffer_length);
-        
+       
         // simple char array replacement (modifies input string!)
         void replace(char *str,char orig_char,char new_char);