Showing posts with label API. Show all posts
Showing posts with label API. Show all posts

Saturday, April 30, 2016

HTTP/REST API Specifications

Now that I have the pleasure of designing new APIs to support both B2C and B2B use cases, my first thought is to standardize. In the case of APIs, I believe standards reduce the burden of maintenance and improve the ease of integration.

To that end, I sought to define guidelines for all operations. These are not new or novel, but I need these to set shared expectations with my team. And we start with a few core principles:

  1. Follow REST conventions for CRUD operations
  2. Use JSON in all request and response bodies (Content-Type: application/json)...
  3. Except where binary content is involved (Content-Type: multipart/form-data)

REST conventions


Striving to KISS:

Error response body


Success responses will contain appropriate data for the request, but all error response bodies look alike. At least structurally, having only one field.

  • Array<Error> errors - An array of any errors encountered while executing the operation. This field is always present for an error state (any non-200 HTTP status).


Each errors element has the following fields:

  • int code - "for programmatic consumption" (ref Braintree)
  • String message - "for human consumption" (ref Braintree)
  • String component - Whatever we're blaming for the error

Wednesday, June 18, 2014

Rails directories for Heroku Connect

Heroku Connect is a new add-on offering that simplifies data synchronization between Heroku apps and Salesforce. At its core, Heroku Connect periodically syncs selected objects and fields between Salesforce and Heroku. While the demo Rails app provided by Heroku gives a solid recommendation for extending ActiveRecord::Base to create an analog for models in the Heroku Connect database, some gaps still existed in terms of how to best set up your Rails app and define your classes.

After some experimentation, I decided on the following setup for my app:

  • Heroku Connect model paths: app/models/heroku_connect/schema_name/table_name.rb
  • HerokuConnectRecord::Base
  • Autoload lib modules and classes

I'll explain the setup in more detail below, but quick question: How would you set up your Rails app directories for Heroku Connect?

Heroku Connect model paths


All models in your Rails app by default go in the app/models/ directory. Rails knows to autoload models stored in the models/ directory, and as a result it seemed to reason that Heroku Connect models should go in the same directory. But a namespace is needed to prevent conflicts between regular Rails models and Heroku Connect models. And moreover, what if you have multiple Heroku Connect databases in play?

My implementation addresses this by first moving Heroku Connect models into its own namespace a la the heroku_connect/ directory. Next, different Heroku Connect databases can be split by the schema name or some other unique identifier for each database.

Examples of Heroku Connect model class paths, assuming the schema name "salesforce"
sObject NameClass NameModel Path
Car__cHerokuConnect::Salesforce::Car__capp/models/heroku_connect/salesforce/car__c.rb
OpportunityLineItemHerokuConnect::Salesforce::OpportunityLineItemapp/models/heroku_connect/salesforce/opportunity_line_item.rb
AssessmentPeriod__cHerokuConnect::Salesforce::AssessmentPeriod__capp/models/heroku_connect/salesforce/assessment_period__c.rb

Note: For custom object models, the double-underscores can be written as-is in the name of the .rb file. To be more technical, use the String.underscore method in irb to derive the expected name of the model's .rb file. For example, JointVenture__c would become "joint_venture__c.rb", and Lazy_Boy__c would become "lazy_boy__c.rb".

HerokuConnectRecord::Base


Heroku recommends extending ActiveRecord::Base to create a base for all Heroku Connect models. I thought that instead of calling my base class SalesforceBase, I would call it HerokuConnectRecord::Base to be mimic the naming convention for ActiveRecord::Base. While there's no direct need for this to get going, I figured I would adopt this convention in case I need to extend other Active__ modules or classes down the road for Heroku Connect.

All that's needed to set up this class is the following code, placed within lib/heroku_connect_record/base.rb:

module HerokuConnectRecord
  class Base < ActiveRecord::Base
    self.abstract_class = true
    establish_connection ENV['DATABASE_URL']
  end
end

All Heroku Connect module classes would then extend this class, as in:

module HerokuConnect
  module Salesforce
    class Car__c < HerokuConnectRecord::Base
      self.table_name = "salesforce.car__c"
    end
  end
end

Autoload lib modules and classes


Finally, to autoload HerokuConnectRecord::Base (and potentially future custom classes for Heroku Connect), I adopted ifyouseewendy's recommendation to add the following line to config/application.rb:

config.autoload_paths += %W(#{config.root}/lib)

Wednesday, April 30, 2014

Custom Button connection.js: INVALID_SESSION_ID

After deploying a custom button from a sandbox to Production, I noticed that the button stopped working. Puzzled, I opened the Web Console in Firefox to find the following error message: INVALID_SESSION_ID.

I was not doing anything special with sforce.connection.sessionId in my code. All the button does is {!REQUIRESCRIPT('/soap/ajax/30.0/connection.js')} and move on to query and update the database. The same code was working fine in my sandbox still, so I figured the next best thing would be to actually look at sessionId to see what's wrong.

At first glance, sessionId looked like a perfectly fine mess of characters that are reasonable for a Session ID value.

00DG0000000krVL!ARQAQP3vNkwdt8OU3WVIjlAwQvWtGcFcIjWq.0jb7A5wYNljj6Oog50.wDma4uUiB.PeDMqx1mLwkMyGj78gyMGLRLGTxic1

Then, I compared sessionId to the sid cookie, and I noticed that the two values were very different.

00DG0000000krVL!ARQAQLWR697R.eqoAy4178kYPxh2kJGv6BOpv_wsHc6KBjY6UPY01.Rfncn6WAMS2klSm.gLvDOWicNKujfE4smTPBLJvyS5

Refreshing the page in my browser did nothing for the problem. The same two values consistently appeared, and the INVALID_SESSION_ID error consistently broke my code.

Finally, the fix was implemented in the form of additional JavaScript in a static resource. This resource, added using REQUIRESCRIPT() after connection.js, simply maps the cookies in the current document and then stores the sid value in sforce.connection.sessionId. The addition of this step resolved the INVALID_SESSION_ID error as far as I could tell.

Has anyone else ever encountered this issue, in Spring '14 or earlier? I feel like I've stumbled upon a bug, because as far as I know connection.js used in a custom button should not need this kind of "initialization".

Sunday, March 16, 2014

3 Ways to Tell What Version of Salesforce You're Using

Your out-of-the-box Salesforce experience is typically driven by two attributes: your Salesforce edition and the version (i.e., which release) of your org.

The edition (e.g., Enterprise Edition, Developer Edition) is readily identified by examining your browser's title bar or running a query: SELECT Id, Name, OrganizationType FROM Organization

But finding the version is a bit trickier, with no "official" method to reference. You can try one of the three methods below:
  • Switch to one of the standard, out-of-the-box apps (e.g., Sales), and look at the app logo

  • Create or edit a formula field, and look for the largest API version in the $Api object

  • Generate an Enterprise WSDL (Setup > Build > Develop > API) and look for the SOAP service endpoint location

You can convert the API version number into a release using the assumptions that Salesforce pushes three releases a year (Winter, Spring, Summer) and that each release corresponds to a new major version number. For example, we know that Winter '14 is API version 29.0. This means that 28.0 is Summer '13, and 30.0 will be Spring '14.

Monday, February 17, 2014

AJAX Toolkit 29.0 Home Page Component

For orgs trying to push the limits of the standard Home tab in Salesforce, using JavaScript is essential. However, trying to pull in the AJAX Toolkit is not as easy as adding a merge field to a new home page component, because merge fields don't work here. Fortunately, making an assumption about where the toolkit resides allows us to create a home page component that's equivalent to {!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}.

This 1-minute video shows you how to create the component and add it to your home page layout, using the sample code from "Home Page Component: AJAX Toolkit 29.0". The only real "trick" that's needed to make the component work is to extract the session ID cookie and pass it to the sforce object.

Now all of your home page components can be Ajax-enabled.

Tuesday, December 3, 2013

Deploying Destructive Changes Using Workbench

Sometimes, especially in the case of custom Apex or Visualforce, a Salesforce admin or developer needs to delete components from an org. However, Salesforce's user-friendly change sets feature does not allow admins to propagate component deletions. The only semi-automated alternative to performing these deletions, especially in production orgs, is to leverage the metadata API.

Fortunately, with the availability of Workbench on Developer Force, the steps required for deploying destructive changes (that delete components) are pretty simple:

  1. Create a package.xml file
  2. Create a destructiveChanges.xml file
  3. Bundle the two files together in a .zip file
  4. Deploy the .zip package using Workbench

As you can see from this sample .zip package, the files are fairly simple and straightforward. Multiple types of metadata can be removed with a single package.

The exact steps for deploying using Workbench 29.0.1 are:
  1. Open the migration menu, then click Deploy
  2. Click Browse... and select the .zip package file
  3. Mark the "Rollback On Error" checkbox
  4. Mark the "Single Package" checkbox
  5. Mark the "Run All Tests" checkbox
  6. Click Next
  7. Review the deployment options, then click Deploy

The results, successful or otherwise, will be displayed in Workbench for you to review once the deployment process is complete.