<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jeff Douglas - Technology, Coding and Bears... OH MY!</title>
	<atom:link href="http://ec2.jeffdouglas.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://ec2.jeffdouglas.com</link>
	<description>Get your head out of your #@! and into the clouds!</description>
	<lastBuildDate>Tue, 01 May 2012 13:28:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Build a Command Line App for Force.com with Ruby &amp; Thor</title>
		<link>http://ec2.jeffdouglas.com/2012/05/01/forcedotcom-cli/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=forcedotcom-cli</link>
		<comments>http://ec2.jeffdouglas.com/2012/05/01/forcedotcom-cli/#comments</comments>
		<pubDate>Tue, 01 May 2012 13:17:33 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4520</guid>
		<description><![CDATA[Over at CloudSpokes we write a lot of ruby code (CloudSpokes.com runs on Heroku in Ruby with Database.com as the backend) for debugging, data migration, utilities and more. We typically just write a quick ruby class and run it from the command line to execute the script. However, I thought it might be cooler to [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F05%2F01%2Fforcedotcom-cli%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F05%2F01%2Fforcedotcom-cli%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/05/thor.png" rel="lightbox[4520]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/05/thor-203x300.png" alt="" title="thor" width="175"  class="alignleft size-medium wp-image-4553" /></a>Over at <a href="http://www.cloudspokes.com">CloudSpokes</a> we write a lot of ruby code (CloudSpokes.com runs on Heroku in Ruby with <a href="http://www.database.com">Database.com</a> as the backend) for debugging, data migration, utilities and more. We typically just write a quick ruby class and run it from the command line to execute the script. However, I thought it might be cooler to write a cli for Force.com that I could distribute to the team. </p>
<p>So if you know a little ruby, the process isn&#8217;t that difficult. All you need is the <a href="https://github.com/heroku/databasedotcom">databasedoctom gem</a> and <a href="https://github.com/wycats/thor">thor</a>, a simple  tool for building self-documenting command line utilities in ruby. You then write your ruby code in the .thor file and execute if from the command line as you would any other cli.</p>
<p>So here are the available commands for the cli via thor&#8217;s help command. Feel free to <a href="https://github.com/jeffdonthemic/Force.com-Command-Line">fork the code at github</a>.</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/05/commandline.png" rel="lightbox[4520]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/05/commandline.png" alt="" title="commandline" width="347" height="125" class="alignnone size-full wp-image-4524" /></a></p>
<p>This video walks you through the functionality, setup and code for the cli in case you want more detail. The main code is below after the jump.</p>
<p><a href="http://www.youtube.com/watch?v=b3YV2Fj84yQ&#038;fmt=18">http://www.youtube.com/watch?v=b3YV2Fj84yQ</a></p>
<p>Assuming you have ruby installed, you need to install the databasedotcom and thor gems. It&#8217;s very trivial and the instructions are available from their respective github repos. With thor, you can pass parameters to each task and setup method options. So for instance, in the thor file below, each task has an optional &#8216;-c&#8217; switch where you specify the connection file to load thus making it easy to connect to different orgs. If you omit the switch, the default databasedotcom.yml file is loaded. </p>
<div id="gist-2567190" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;databasedotcom&#39;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="k">class</span> <span class="nc">Utils</span> <span class="o">&lt;</span> <span class="no">Thor</span></div><div class='line' id='LC4'>&nbsp;&nbsp;</div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="n">desc</span> <span class="s2">&quot;query SOQL&quot;</span><span class="p">,</span> <span class="s2">&quot;runs a soql query and displays the value of each record&#39;s &#39;name&#39; field&quot;</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="n">method_option</span> <span class="ss">:config_file</span><span class="p">,</span> <span class="ss">:type</span> <span class="o">=&gt;</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;databasedotcom.yml&quot;</span><span class="p">,</span> </div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:aliases</span> <span class="o">=&gt;</span> <span class="s2">&quot;-c&quot;</span><span class="p">,</span> <span class="ss">:desc</span> <span class="o">=&gt;</span> <span class="s2">&quot;The name of the file containing the connection parameters.&quot;</span>  </div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">query</span><span class="p">(</span><span class="n">soql</span><span class="p">)</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span> <span class="o">=</span> <span class="n">authenticate</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config_file</span><span class="o">]</span><span class="p">)</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># execute the soql and iterate over the results to output the name</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="n">soql</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">r</span><span class="o">|</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">puts</span> <span class="n">r</span><span class="o">.</span><span class="n">Name</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC14'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC15'>&nbsp;&nbsp;</div><div class='line' id='LC16'>&nbsp;&nbsp;<span class="n">desc</span> <span class="s2">&quot;export SOQL FIELDS FILE&quot;</span><span class="p">,</span> <span class="s2">&quot;runs a soql query and exports the specified </span></div><div class='line' id='LC17'><span class="s2">    comma separated list of fields to a comma separated file&quot;</span></div><div class='line' id='LC18'>&nbsp;&nbsp;<span class="n">method_option</span> <span class="ss">:config_file</span><span class="p">,</span> <span class="ss">:type</span> <span class="o">=&gt;</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;databasedotcom.yml&quot;</span><span class="p">,</span> </div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:aliases</span> <span class="o">=&gt;</span> <span class="s2">&quot;-c&quot;</span><span class="p">,</span> <span class="ss">:desc</span> <span class="o">=&gt;</span> <span class="s2">&quot;The name of the file containing the connection parameters.&quot;</span></div><div class='line' id='LC20'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">export</span><span class="p">(</span><span class="n">soql</span><span class="p">,</span> <span class="n">fields</span><span class="p">,</span> <span class="n">file</span><span class="p">)</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span> <span class="o">=</span> <span class="n">authenticate</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config_file</span><span class="o">]</span><span class="p">)</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># query for records</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">records</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="n">soql</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># open the file to write (probably local directory)</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span> </div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># interate over the records</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">records</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">r</span><span class="o">|</span> </div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># create a single line with all field values specified</span></div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">line</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fields</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">field</span><span class="o">|</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">line</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="nb">eval</span><span class="p">(</span><span class="s2">&quot;r.</span><span class="si">#{</span><span class="n">field</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span><span class="si">}</span><span class="s2">,&quot;</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span> </div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># write each line to the csv file       </span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">f</span><span class="o">.</span><span class="n">puts</span>  <span class="s2">&quot;</span><span class="si">#{</span><span class="n">line</span><span class="si">}</span><span class="se">\n</span><span class="s2">&quot;</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span> </div><div class='line' id='LC37'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC38'>&nbsp;&nbsp;</div><div class='line' id='LC39'>&nbsp;&nbsp;<span class="n">desc</span> <span class="s2">&quot;describe OBJECT&quot;</span><span class="p">,</span> <span class="s2">&quot;displays the describe info for a particular object&quot;</span></div><div class='line' id='LC40'>&nbsp;&nbsp;<span class="n">method_option</span> <span class="ss">:config_file</span><span class="p">,</span> <span class="ss">:type</span> <span class="o">=&gt;</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;databasedotcom.yml&quot;</span><span class="p">,</span> </div><div class='line' id='LC41'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:aliases</span> <span class="o">=&gt;</span> <span class="s2">&quot;-c&quot;</span><span class="p">,</span> <span class="ss">:desc</span> <span class="o">=&gt;</span> <span class="s2">&quot;The name of the file containing the connection parameters.&quot;</span></div><div class='line' id='LC42'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">describe</span><span class="p">(</span><span class="n">object</span><span class="p">)</span></div><div class='line' id='LC43'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span> <span class="o">=</span> <span class="n">authenticate</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config_file</span><span class="o">]</span><span class="p">)</span></div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># call describe on the object by name</span></div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">sobject</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">describe_sobject</span><span class="p">(</span><span class="n">object</span><span class="p">)</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># output the results -- not very useful (frowny face)</span></div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">puts</span> <span class="n">sobject</span></div><div class='line' id='LC48'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC49'>&nbsp;&nbsp;</div><div class='line' id='LC50'>&nbsp;&nbsp;<span class="n">desc</span> <span class="s2">&quot;get_token&quot;</span><span class="p">,</span> <span class="s2">&quot;retreives an access token&quot;</span></div><div class='line' id='LC51'>&nbsp;&nbsp;<span class="n">method_option</span> <span class="ss">:config_file</span><span class="p">,</span> <span class="ss">:type</span> <span class="o">=&gt;</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;databasedotcom.yml&quot;</span><span class="p">,</span> </div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:aliases</span> <span class="o">=&gt;</span> <span class="s2">&quot;-c&quot;</span><span class="p">,</span> <span class="ss">:desc</span> <span class="o">=&gt;</span> <span class="s2">&quot;The name of the file containing the connection parameters.&quot;</span></div><div class='line' id='LC53'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">get_token</span></div><div class='line' id='LC54'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span> <span class="o">=</span> <span class="n">authenticate</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config_file</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">oauth_token</span></div><div class='line' id='LC55'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">puts</span> <span class="s2">&quot;Access token: </span><span class="si">#{</span><span class="n">client</span><span class="si">}</span><span class="s2">&quot;</span></div><div class='line' id='LC56'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'>&nbsp;&nbsp;<span class="n">desc</span> <span class="s2">&quot;show_config&quot;</span><span class="p">,</span> <span class="s2">&quot;display the salesforce connection properties&quot;</span></div><div class='line' id='LC59'>&nbsp;&nbsp;<span class="n">method_option</span> <span class="ss">:config_file</span><span class="p">,</span> <span class="ss">:type</span> <span class="o">=&gt;</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;databasedotcom.yml&quot;</span><span class="p">,</span> </div><div class='line' id='LC60'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:aliases</span> <span class="o">=&gt;</span> <span class="s2">&quot;-c&quot;</span><span class="p">,</span> <span class="ss">:desc</span> <span class="o">=&gt;</span> <span class="s2">&quot;The name of the file containing the connection parameters.&quot;</span></div><div class='line' id='LC61'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">show_config</span></div><div class='line' id='LC62'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">config</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">.</span><span class="n">load_file</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config_file</span><span class="o">]</span><span class="p">)</span></div><div class='line' id='LC63'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">puts</span> <span class="n">config</span></div><div class='line' id='LC64'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC65'>&nbsp;&nbsp;</div><div class='line' id='LC66'>&nbsp;&nbsp;<span class="kp">private</span> </div><div class='line' id='LC67'>&nbsp;&nbsp;</div><div class='line' id='LC68'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="n">file_name</span><span class="p">)</span></div><div class='line' id='LC69'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># load the configuration file with connection parameters</span></div><div class='line' id='LC70'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">config</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">.</span><span class="n">load_file</span><span class="p">(</span><span class="n">file_name</span><span class="p">)</span></div><div class='line' id='LC71'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># init the databasedotcom gem with the specified yml config file</span></div><div class='line' id='LC72'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span> <span class="o">=</span> <span class="no">Databasedotcom</span><span class="o">::</span><span class="no">Client</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">file_name</span><span class="p">)</span>    </div><div class='line' id='LC73'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># pass the credentials to authenticate</span></div><div class='line' id='LC74'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">client</span><span class="o">.</span><span class="n">authenticate</span> <span class="ss">:username</span> <span class="o">=&gt;</span> <span class="n">config</span><span class="o">[</span><span class="s1">&#39;username&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">:password</span> <span class="o">=&gt;</span> <span class="n">config</span><span class="o">[</span><span class="s1">&#39;password&#39;</span><span class="o">]</span></div><div class='line' id='LC75'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="n">client</span></div><div class='line' id='LC76'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC77'>&nbsp;&nbsp;</div><div class='line' id='LC78'><span class="k">end</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2567190/998992fc527da43a96ed42ea3157db38592d03a5/gistfile1.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2567190#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a>
            <a href="https://gist.github.com/2567190">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>The connection file is a simple yml file containing the parameters specified by the databasedotcom gem. You can have as many connection files as you would like to for production, developer and sandbox orgs and easily load different files using the &#8216;-c&#8217; switch. For instance, to run the query task against the org specified in the sandbox.yml file you would run:</p>
<div style="font-family: courier;padding-bottom:20px;padding-left:15px">thor utils:query &#8216;select id, name from account limie 10&#8242; -c &#8216;sandbox.yml&#8217;</div>
<div id="gist-2567200" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>client_id: YOUR-CLIENT-ID</div><div class='line' id='LC2'>client_secret: YOUR-CLIENT-SECRET</div><div class='line' id='LC3'>host: test.salesforce.com</div><div class='line' id='LC4'>debugging: false</div><div class='line' id='LC5'>username: YOUR-USERNAME</div><div class='line' id='LC6'>password: YOUR-PASSWORD</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2567200/bf869587b91367de5e1899f4268b81f03fb5614b/gistfile1.txt" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2567200#file_gistfile1.txt" style="float:right;margin-right:10px;color:#666">gistfile1.txt</a>
            <a href="https://gist.github.com/2567200">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/05/01/forcedotcom-cli/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Node.js Demo with Force.com REST API, OAuth &amp; Express</title>
		<link>http://ec2.jeffdouglas.com/2012/04/27/node-js-demo-with-force-com-rest-api-oauth-express/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=node-js-demo-with-force-com-rest-api-oauth-express</link>
		<comments>http://ec2.jeffdouglas.com/2012/04/27/node-js-demo-with-force-com-rest-api-oauth-express/#comments</comments>
		<pubDate>Fri, 27 Apr 2012 15:00:49 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4502</guid>
		<description><![CDATA[We&#8217;ve been working with Node.js quite a bit at CloudSpokes but I hadn&#8217;t done anything with Force.com and Node.js using their REST API; we&#8217;ve mostly been using our own API. So I thought I would give it a spin and see what it would take to write a small demo app using Node.js, the Force.com [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F27%2Fnode-js-demo-with-force-com-rest-api-oauth-express%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F27%2Fnode-js-demo-with-force-com-rest-api-oauth-express%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>We&#8217;ve been working with Node.js quite a bit at <a href="http://www.cloudspokes.com">CloudSpokes</a> but I hadn&#8217;t done anything with Force.com and Node.js using their REST API; we&#8217;ve mostly been using our own API. So I thought I would give it a spin and see what it would take to write a small demo app using Node.js, the Force.com REST API, OAuth, Express and Jade for templating.</p>
<p>As it turns  out it wasn&#8217;t that difficult. Salesforce.com has done most of the work writing the REST and OAuth pieces. </p>
<p>So initially I started woking from <a href="https://twitter.com/#!/joshbirk">Josh Birk</a>&#8216;s <a href="https://github.com/joshbirk/FDC-NODEJS-HEROKU">FDC-NODEJS-HEROKU</a> repo (don&#8217;t use this btw). I should have known from the beginning not to use this as the code hadn&#8217;t been updated in 9 months. Anyway a spent some time over the weekend getting it to work with Express, adding some middleware and rewriting some stuff. Once I finally got it working, I emailed Josh with a question and he informed me that the code was outdated and not to you use it. </p>
<p>Being the cool guy that Josh is, he pointed me to <a href="https://twitter.com/#!/dcarroll">Dave Carroll</a>&#8216;s <a href="https://github.com/dcarroll/rest4dbdotcom">rest4dbdotcom</a> repo for the latest and greatest code. This is definitely the repo you want to watch.</p>
<p>So I put together a small demo that allows you to authorize access to an org, get a list of accounts, create new accounts and update existing ones. </p>
<p><strong>Here&#8217;s the link to the <a href="https://node-sfdc-demo.herokuapp.com/">live application on heroku</a> and the <a href="https://github.com/jeffdonthemic/Node-Force.com-REST-Demo">github repo with the code</a> for your forking pleasure.</strong></p>
<p><a href="http://www.youtube.com/watch?v=3KE4XkNOzgA&#038;fmt=18">http://www.youtube.com/watch?v=3KE4XkNOzgA</a></p>
<p>Most of the logic for the application is in the main app.js file (below) and you can see that it&#8217;s pretty straight forward. We set some configuration parameters for OAuth, configure the middleware, create the server and then define the routes that we can call. </p>
<div id="gist-2508492" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><br/></div><div class='line' id='LC2'><span class="cm">/**</span></div><div class='line' id='LC3'><span class="cm"> * Module dependencies.</span></div><div class='line' id='LC4'><span class="cm"> */</span></div><div class='line' id='LC5'><span class="kd">var</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;express&#39;</span><span class="p">)</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">routes</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./routes&#39;</span><span class="p">)</span></div><div class='line' id='LC7'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">rest</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./rest.js&#39;</span><span class="p">)</span></div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">oauth</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./oauth.js&#39;</span><span class="p">)</span></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;url&#39;</span><span class="p">);</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="cm">/**</span></div><div class='line' id='LC12'><span class="cm"> * Setup some environment variables (heroku) with defaults if not present</span></div><div class='line' id='LC13'><span class="cm"> */</span></div><div class='line' id='LC14'><span class="kd">var</span> <span class="nx">port</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PORT</span> <span class="o">||</span> <span class="mi">3001</span><span class="p">;</span> <span class="c1">// use heroku&#39;s dynamic port or 3001 if localhost</span></div><div class='line' id='LC15'><span class="kd">var</span> <span class="nx">cid</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">CLIENT_ID</span> <span class="o">||</span> <span class="s2">&quot;YOUR-REMOTE-ACCESS-CONSUMER-KEY&quot;</span><span class="p">;</span></div><div class='line' id='LC16'><span class="kd">var</span> <span class="nx">csecr</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">CLIENT_SECRET</span> <span class="o">||</span> <span class="s2">&quot;YOUR-REMOTE-ACCESS-CONSUMER-SECRET&quot;</span><span class="p">;</span></div><div class='line' id='LC17'><span class="kd">var</span> <span class="nx">lserv</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">LOGIN_SERVER</span> <span class="o">||</span> <span class="s2">&quot;https://login.salesforce.com&quot;</span><span class="p">;</span></div><div class='line' id='LC18'><span class="kd">var</span> <span class="nx">redir</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">REDIRECT_URI</span> <span class="o">||</span> <span class="s2">&quot;http://localhost:&quot;</span> <span class="o">+</span> <span class="nx">port</span> <span class="o">+</span> <span class="s2">&quot;/token&quot;</span><span class="p">;</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'><span class="cm">/**</span></div><div class='line' id='LC21'><span class="cm"> * Middleware to call identity service and attach result to session</span></div><div class='line' id='LC22'><span class="cm"> */</span></div><div class='line' id='LC23'><span class="kd">function</span> <span class="nx">idcheck</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="k">return</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// Invoke identity service if we haven&#39;t got one or access token has </span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// changed since we got it</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">session</span> <span class="o">||</span> <span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">identity</span> <span class="o">||</span> <span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">identity_check</span> <span class="o">!=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">oauth</span><span class="p">.</span><span class="nx">access_token</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">identity</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">identity</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">identity_check</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">oauth</span><span class="p">.</span><span class="nx">access_token</span><span class="p">;</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">next</span><span class="p">();</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span>          </div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span> <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">next</span><span class="p">();</span>      </div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC37'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC38'><span class="p">}</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'><span class="cm">/**</span></div><div class='line' id='LC41'><span class="cm"> * Create the server</span></div><div class='line' id='LC42'><span class="cm"> */</span></div><div class='line' id='LC43'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span></div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">express</span><span class="p">.</span><span class="nx">cookieParser</span><span class="p">(),</span></div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">express</span><span class="p">.</span><span class="nx">session</span><span class="p">({</span> <span class="nx">secret</span><span class="o">:</span> <span class="nx">csecr</span> <span class="p">}),</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">express</span><span class="p">.</span><span class="nx">query</span><span class="p">(),</span></div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">oauth</span><span class="p">.</span><span class="nx">oauth</span><span class="p">({</span></div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">clientId</span><span class="o">:</span> <span class="nx">cid</span><span class="p">,</span></div><div class='line' id='LC49'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">clientSecret</span><span class="o">:</span> <span class="nx">csecr</span><span class="p">,</span></div><div class='line' id='LC50'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">loginServer</span><span class="o">:</span> <span class="nx">lserv</span><span class="p">,</span></div><div class='line' id='LC51'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">redirectUri</span><span class="o">:</span> <span class="nx">redir</span><span class="p">,</span></div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}),</span></div><div class='line' id='LC53'>&nbsp;&nbsp;<span class="nx">idcheck</span><span class="p">()</span></div><div class='line' id='LC54'><span class="p">);</span></div><div class='line' id='LC55'><br/></div><div class='line' id='LC56'><span class="cm">/**</span></div><div class='line' id='LC57'><span class="cm"> * Configuration the server</span></div><div class='line' id='LC58'><span class="cm"> */</span></div><div class='line' id='LC59'><span class="nx">app</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span></div><div class='line' id='LC60'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;views&#39;</span><span class="p">,</span> <span class="nx">__dirname</span> <span class="o">+</span> <span class="s1">&#39;/views&#39;</span><span class="p">);</span></div><div class='line' id='LC61'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;view engine&#39;</span><span class="p">,</span> <span class="s1">&#39;jade&#39;</span><span class="p">);</span></div><div class='line' id='LC62'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">bodyParser</span><span class="p">());</span></div><div class='line' id='LC63'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">methodOverride</span><span class="p">());</span></div><div class='line' id='LC64'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">app</span><span class="p">.</span><span class="nx">router</span><span class="p">);</span></div><div class='line' id='LC65'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="nx">__dirname</span> <span class="o">+</span> <span class="s1">&#39;/public&#39;</span><span class="p">));</span></div><div class='line' id='LC66'><span class="p">});</span></div><div class='line' id='LC67'><br/></div><div class='line' id='LC68'><span class="nx">app</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="s1">&#39;development&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(){</span></div><div class='line' id='LC69'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">errorHandler</span><span class="p">({</span> <span class="nx">dumpExceptions</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">showStack</span><span class="o">:</span> <span class="kc">true</span> <span class="p">}));</span></div><div class='line' id='LC70'><span class="p">});</span></div><div class='line' id='LC71'><br/></div><div class='line' id='LC72'><span class="nx">app</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="s1">&#39;production&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(){</span></div><div class='line' id='LC73'>&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">errorHandler</span><span class="p">());</span></div><div class='line' id='LC74'><span class="p">});</span></div><div class='line' id='LC75'><br/></div><div class='line' id='LC76'><span class="cm">/**</span></div><div class='line' id='LC77'><span class="cm"> * Routes</span></div><div class='line' id='LC78'><span class="cm"> */</span></div><div class='line' id='LC79'><br/></div><div class='line' id='LC80'>&nbsp;<span class="c1">// &#39;home&#39; page</span></div><div class='line' id='LC81'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="nx">routes</span><span class="p">.</span><span class="nx">index</span><span class="p">);</span></div><div class='line' id='LC82'><br/></div><div class='line' id='LC83'><span class="c1">// list of accounts - see routes/index.js for more info</span></div><div class='line' id='LC84'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/accounts&#39;</span><span class="p">,</span> <span class="nx">routes</span><span class="p">.</span><span class="nx">accounts</span><span class="p">);</span></div><div class='line' id='LC85'><br/></div><div class='line' id='LC86'><span class="c1">// form to create a new account</span></div><div class='line' id='LC87'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/accounts/new&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC88'>&nbsp;&nbsp;<span class="c1">// call describe to dynamically generate the form fields</span></div><div class='line' id='LC89'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;Account&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC90'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;new&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;New Account&#39;</span><span class="p">,</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span> <span class="p">})</span></div><div class='line' id='LC91'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC92'><span class="p">});</span></div><div class='line' id='LC93'><br/></div><div class='line' id='LC94'><span class="c1">// create the account in salesforce</span></div><div class='line' id='LC95'><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/accounts/create&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC96'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">create</span><span class="p">(</span><span class="s2">&quot;Account&quot;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">account</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">results</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC97'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">results</span><span class="p">.</span><span class="nx">success</span> <span class="o">==</span> <span class="kc">true</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC98'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/accounts/&#39;</span><span class="o">+</span><span class="nx">results</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span></div><div class='line' id='LC99'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span></div><div class='line' id='LC100'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC101'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC102'><span class="p">});</span></div><div class='line' id='LC103'><br/></div><div class='line' id='LC104'><span class="c1">// display the account</span></div><div class='line' id='LC105'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/accounts/:id&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC106'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">retrieve</span><span class="p">(</span><span class="s1">&#39;Account&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC107'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;show&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;Account Details&#39;</span><span class="p">,</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span> <span class="p">});</span></div><div class='line' id='LC108'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC109'><span class="p">});</span></div><div class='line' id='LC110'><br/></div><div class='line' id='LC111'><span class="c1">// form to update an existing account</span></div><div class='line' id='LC112'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/accounts/:id/edit&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC113'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">retrieve</span><span class="p">(</span><span class="s1">&#39;Account&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC114'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;edit&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;Edit Account&#39;</span><span class="p">,</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span> <span class="p">});</span></div><div class='line' id='LC115'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC116'><span class="p">});</span></div><div class='line' id='LC117'><br/></div><div class='line' id='LC118'><span class="c1">// update the account in salesforce</span></div><div class='line' id='LC119'><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/accounts/:id/update&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC120'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">update</span><span class="p">(</span><span class="s2">&quot;Account&quot;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">account</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">results</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC121'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/accounts/&#39;</span><span class="o">+</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span></div><div class='line' id='LC122'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span></div><div class='line' id='LC123'>&nbsp;&nbsp;<span class="p">});</span>  </div><div class='line' id='LC124'><span class="p">});</span></div><div class='line' id='LC125'><br/></div><div class='line' id='LC126'><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="kd">function</span><span class="p">(){</span></div><div class='line' id='LC127'>&nbsp;&nbsp;<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Express server listening on port %d in %s mode&quot;</span><span class="p">,</span> </div><div class='line' id='LC128'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">app</span><span class="p">.</span><span class="nx">address</span><span class="p">().</span><span class="nx">port</span><span class="p">,</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">.</span><span class="nx">env</span><span class="p">);</span></div><div class='line' id='LC129'><span class="p">});</span></div><div class='line' id='LC130'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2508492/469a0a4ee4494d87275b7685676ca7e00e60aab1/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2508492#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2508492">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>I did make a small change for the &#8220;/accounts&#8221; route in app.js. You&#8217;ll notice that it delegates to routes/index.js and contains no actual code. When your node application start getting more complex and larger, you&#8217;ll want to refactor the code out of app.js and into their own routes to make life easier.</p>
<div id="gist-2508501" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// only needed if calling the rest api from this file (accounts route)</span></div><div class='line' id='LC2'><span class="kd">var</span> <span class="nx">rest</span> <span class="o">=</span> <span class="nx">rest</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./../rest.js&#39;</span><span class="p">);</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="cm">/*</span></div><div class='line' id='LC5'><span class="cm"> * GET home page.</span></div><div class='line' id='LC6'><span class="cm"> */</span></div><div class='line' id='LC7'><span class="nx">exports</span><span class="p">.</span><span class="nx">index</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;index&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;Salesforce.com Node.js REST Demo&#39;</span> <span class="p">})</span></div><div class='line' id='LC9'><span class="p">};</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="cm">/*</span></div><div class='line' id='LC12'><span class="cm"> * GET list of accounts - for larger apps, you may want to separate</span></div><div class='line' id='LC13'><span class="cm"> * code into different routes for ease of maintenance and logic. </span></div><div class='line' id='LC14'><span class="cm"> * Prevents app.js from becoming huge!</span></div><div class='line' id='LC15'><span class="cm"> */</span></div><div class='line' id='LC16'><span class="nx">exports</span><span class="p">.</span><span class="nx">accounts</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC17'>&nbsp;&nbsp;<span class="nx">rest</span><span class="p">.</span><span class="nx">api</span><span class="p">(</span><span class="nx">req</span><span class="p">).</span><span class="nx">query</span><span class="p">(</span><span class="s2">&quot;select id, name from account limit 10&quot;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&quot;accounts&quot;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s1">&#39;Accounts&#39;</span><span class="p">,</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span><span class="p">,</span> <span class="nx">user</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">identity</span> <span class="p">}</span> <span class="p">);</span></div><div class='line' id='LC19'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC20'><span class="p">};</span></div><div class='line' id='LC21'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2508501/bb829d3d35d0e5235b4e7a61e95c039f57482752/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2508501#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2508501">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/04/27/node-js-demo-with-force-com-rest-api-oauth-express/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Guest Blogger on Amazon&#8217;s Web Services Blog</title>
		<link>http://ec2.jeffdouglas.com/2012/04/11/guest-blogger-aws/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=guest-blogger-aws</link>
		<comments>http://ec2.jeffdouglas.com/2012/04/11/guest-blogger-aws/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 20:54:56 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[AWS]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4485</guid>
		<description><![CDATA[So yesterday I was a guest blogger on Amazon&#8217;s Web Services blog highlighting the results of our CloudSpokes challenge Build an #Awesome Demo with Amazon DynamoDB. We featured 5 applications built by the CloudSpokes community with DynamoDB including videos, demo URLs and source code. Check out the AWS post for the full details: CloudSpokes Coding [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F11%2Fguest-blogger-aws%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F11%2Fguest-blogger-aws%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2009/09/logo_aws.gif" rel="lightbox[4485]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2009/09/logo_aws.gif" alt="" title="logo_aws" width="164" height="60" class="alignleft size-full wp-image-1353" /></a> So yesterday I was a guest blogger on Amazon&#8217;s Web Services blog highlighting the results of our CloudSpokes challenge <a href="http://www.cloudspokes.com/challenges/1362">Build an #Awesome Demo with Amazon DynamoDB</a>. We featured 5 applications built by the <a href="http://www.cloudspokes.com">CloudSpokes</a> community with DynamoDB including videos, demo URLs and source code. </p>
<p>Check out the AWS post for the full details:</p>
<p><a href="http://aws.typepad.com/aws/2012/04/cloudspokes-coding-challenge-build-a-dynamodb-demo.html">CloudSpokes Coding Challenge Winners &#8211; Build a DynamoDB Demo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/04/11/guest-blogger-aws/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convert a Related List to a Comma Separated List</title>
		<link>http://ec2.jeffdouglas.com/2012/04/10/convert-a-related-list-to-a-comma-separated-list/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=convert-a-related-list-to-a-comma-separated-list</link>
		<comments>http://ec2.jeffdouglas.com/2012/04/10/convert-a-related-list-to-a-comma-separated-list/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 14:49:02 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4466</guid>
		<description><![CDATA[Sure, picklists and (sometimes) multi-select picklists are a great way to store data for Salesforce.com objects but related list are much more powerful and flexible. Here&#8217;s a great little trick to keep the power of related objects but still have the ease of use of a quasi-picklist for reporting, creating formulas, displaying values to users, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F10%2Fconvert-a-related-list-to-a-comma-separated-list%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F04%2F10%2Fconvert-a-related-list-to-a-comma-separated-list%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Sure, picklists and (sometimes) multi-select picklists are a great way to store data for Salesforce.com objects but related list are much more powerful and flexible. Here&#8217;s a great little trick to keep the power of related objects but still have the ease of use of a quasi-picklist for reporting, creating formulas, displaying values to users, external applications (iterating through a collection to display a comma separated list is tiresome!), etc.</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/04/csv-list.png" rel="lightbox[4466]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/04/csv-list.png" alt="" title="csv-list" width="500"  class="aligncenter size-full wp-image-4467" /></a></p>
<p>The use case is that Accounts can operate in many regions so we need a way to tie Accounts and Regions together. Typically you would create a new custom object (i.e., a junction object) with a master-detail relationship to Account and a master-detail relationship to Region. This allows you to map multiple Accounts to multiple Regions. </p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/04/cvs-list-erd.png" rel="lightbox[4466]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/04/cvs-list-erd.png" alt="" title="cvs-list-erd" width="500"  class="aligncenter size-full wp-image-4477" /></a></p>
<p>However, for ease of use, let&#8217;s put a single textarea field on the Account object and show the names of the regions as a simple comma separated list of values. We do this by creating a trigger that updates the Account each time the junction object (Account_Region__c) records are inserted, updated or deleted.</p>
<p>The trigger below fires whenever an Account_Region__c records is inserted, updated or deleted and simply passes the IDs for the Accounts that are affected to the AccountRegionTriggerHandler class for processing.</p>
<div id="gist-2351453" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>trigger AccountRegionTrigger on Account<span class="nb">_</span>Region<span class="nb">__</span>c (after delete, after insert, after update) <span class="nb">{</span></div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;// fires after both insert and update</div><div class='line' id='LC4'>&nbsp;&nbsp;if((Trigger.isInsert || Trigger.isUpdate) <span class="nb">&amp;&amp;</span> Trigger.isAfter)<span class="nb">{</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;// find the ids of all accounts that were affected</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;Id&gt; accountIds = new Set&lt;Id&gt;();</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;for (Account<span class="nb">_</span>Region<span class="nb">__</span>c ar : [select Id, Account<span class="nb">__</span>c from Account<span class="nb">_</span>Region<span class="nb">__</span>c </div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where Id IN :Trigger.newMap.keySet()])</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountIds.add(ar.Account<span class="nb">__</span>c);</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;// process the accounts  </div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;AccountRegionTriggerHandler.ProcessRegionsAsync(accountIds);</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>&nbsp;&nbsp;// fires when records are deleted. may want to do undelete also?</div><div class='line' id='LC17'>&nbsp;&nbsp;<span class="nb">}</span> else if(Trigger.isDelete <span class="nb">&amp;&amp;</span> Trigger.isAfter)<span class="nb">{</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;// find the ids of all accounts that were affected</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;Id&gt; accountIds = new Set&lt;Id&gt;();</div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;for (ID id : Trigger.oldMap.keySet())</div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountIds.add(Trigger.oldMap.get(id).Account<span class="nb">__</span>c);</div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;// process the accounts</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;AccountRegionTriggerHandler.ProcessRegionsAsync(accountIds);</div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'>&nbsp;&nbsp;<span class="nb">}</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'><span class="nb">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2351453/0937140d27107e78d4f0372e4301a274936bf7b0/gistfile1.tex" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2351453#file_gistfile1.tex" style="float:right;margin-right:10px;color:#666">gistfile1.tex</a>
            <a href="https://gist.github.com/2351453">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>The AccountRegionTriggerHandler does all of the heaving lifting. For the Accounts in context, it queries for all of the Regions for each account, builds a comma separated list of region names and then updates the accounts with this list of regions.</p>
<div id="gist-2351458" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>public with sharing class AccountRegionTriggerHandler {</div><div class='line' id='LC2'>&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;@future </div><div class='line' id='LC4'>&nbsp;&nbsp;public static void ProcessRegionsAsync(Set&lt;ID&gt; accountIds){</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;// holds a map of the account id and comma separated regions to build</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;Id, String&gt; accountRegionMap = new Map&lt;Id, String&gt;();</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;// get ALL of the regions for all affected accounts so we can build</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account_Region__c&gt; accountRegions = [select id, Account__c, </div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Region__r.Name from Account_Region__c </div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where Account__c IN :accountIds order by Region__r.Name];</div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;for (Account_Region__c ar : accountRegions) {</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!accountRegionMap.containsKey(ar.Account__c)) {</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// if the key (account) doesn&#39;t exist, add it with region name</div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegionMap.put(ar.Account__c,ar.Region__r.Name);</div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// if the key (account) already exist, add &quot;, region-name&quot;</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegionMap.put(ar.Account__c,accountRegionMap.get(ar.Account__c) + </div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;, &#39; + ar.Region__r.Name);</div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;}</div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;// get the account that were affected</div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account&gt; accounts = [select id from Account where Id IN :accountIds];</div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;// add the comma separated list of regions</div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;for (Account a : accounts)</div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.Regions__c = accountRegionMap.get(a.id);</div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;// update the accounts</div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;update accounts;</div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC35'>&nbsp;&nbsp;}  </div><div class='line' id='LC36'>&nbsp;&nbsp;</div><div class='line' id='LC37'>}</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2351458/d7592085bec85871cf552317bcd53c6d9bbc83bb/gistfile1.cls" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2351458#file_gistfile1.cls" style="float:right;margin-right:10px;color:#666">gistfile1.cls</a>
            <a href="https://gist.github.com/2351458">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>And finally, here&#8217;s the unit tests for the trigger handler.</p>
<div id="gist-2351461" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>@isTest</div><div class='line' id='LC2'>private class Test_AccountRegionTriggerHandler {</div><div class='line' id='LC3'>&nbsp;&nbsp;</div><div class='line' id='LC4'>&nbsp;&nbsp;static List&lt;Region__c&gt; regions = new List&lt;Region__c&gt;();</div><div class='line' id='LC5'>&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;static {</div><div class='line' id='LC7'>&nbsp;&nbsp;</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;// insert some regions</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;Region__c r1 = new Region__c(name=&#39;Region 1&#39;);</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;Region__c r2 = new Region__c(name=&#39;Region 2&#39;);</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;Region__c r3 = new Region__c(name=&#39;Region 3&#39;);</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;Region__c r4 = new Region__c(name=&#39;Region 4&#39;);</div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;regions.add(r1);</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;regions.add(r2);</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;regions.add(r3);</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;regions.add(r4);</div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;insert regions;</div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;}</div><div class='line' id='LC20'>&nbsp;&nbsp;</div><div class='line' id='LC21'>&nbsp;&nbsp;private static void testInsertRecords() {</div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account&gt; accounts = new List&lt;Account&gt;();</div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account_Region__c&gt; accountRegions = new List&lt;Account_Region__c&gt;();</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;// insert some accounts</div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;Account a1 = new Account(name=&#39;Account 1&#39;);</div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;Account a2 = new Account(name=&#39;Account 2&#39;);</div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;accounts.add(a1);</div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;accounts.add(a2);</div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;insert accounts;</div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;Test.startTest();</div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(0).Id));</div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(1).Id));</div><div class='line' id='LC37'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a2.Id, Region__c=regions.get(2).Id));</div><div class='line' id='LC38'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a2.Id, Region__c=regions.get(3).Id));</div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC40'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert accountRegions;</div><div class='line' id='LC41'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC42'>&nbsp;&nbsp;&nbsp;&nbsp;Test.stopTest();</div><div class='line' id='LC43'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;// since async, check for the accounts AFTER tests stop</div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account&gt; updatedAccounts = [select id, name, regions__c from account where id IN :accounts];</div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(&#39;Region 1, Region 3&#39;,updatedAccounts.get(0).Regions__c);</div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(&#39;Region 2, Region 4&#39;,updatedAccounts.get(1).Regions__c);</div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC49'>&nbsp;&nbsp;}</div><div class='line' id='LC50'>&nbsp;&nbsp;</div><div class='line' id='LC51'>&nbsp;&nbsp;private static void testDeleteRecords() {</div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC53'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account&gt; accounts = new List&lt;Account&gt;();</div><div class='line' id='LC54'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account_Region__c&gt; accountRegions = new List&lt;Account_Region__c&gt;();</div><div class='line' id='LC55'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC56'>&nbsp;&nbsp;&nbsp;&nbsp;// insert an account</div><div class='line' id='LC57'>&nbsp;&nbsp;&nbsp;&nbsp;Account a1 = new Account(name=&#39;Account 1&#39;);</div><div class='line' id='LC58'>&nbsp;&nbsp;&nbsp;&nbsp;accounts.add(a1);</div><div class='line' id='LC59'>&nbsp;&nbsp;&nbsp;&nbsp;insert accounts;</div><div class='line' id='LC60'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC61'>&nbsp;&nbsp;&nbsp;&nbsp;Test.startTest();</div><div class='line' id='LC62'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC63'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(0).Id)); </div><div class='line' id='LC64'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(1).Id));</div><div class='line' id='LC65'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(2).Id));</div><div class='line' id='LC66'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accountRegions.add(new Account_Region__c(Account__c=a1.Id, Region__c=regions.get(3).Id));</div><div class='line' id='LC67'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC68'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert accountRegions;</div><div class='line' id='LC69'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC70'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// now delete a record</div><div class='line' id='LC71'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete accountRegions.get(3);</div><div class='line' id='LC72'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC73'>&nbsp;&nbsp;&nbsp;&nbsp;Test.stopTest();</div><div class='line' id='LC74'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC75'>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Account&gt; updatedAccounts = [select id, name, regions__c from account where id IN :accounts];</div><div class='line' id='LC76'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(&#39;Region 1, Region 2, Region 3&#39;,updatedAccounts.get(0).Regions__c);</div><div class='line' id='LC77'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC78'>&nbsp;&nbsp;}</div><div class='line' id='LC79'>&nbsp;&nbsp;</div><div class='line' id='LC80'>}</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2351461/21c6aa1c11f3ba7193bf2cdbb9db946629d1f26d/gistfile1.cls" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2351461#file_gistfile1.cls" style="float:right;margin-right:10px;color:#666">gistfile1.cls</a>
            <a href="https://gist.github.com/2351461">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>A couple of caveats:</p>
<ol>
<li>Since textarea fields only hold 255 characters, this may not be the best approach for extremely long lists of values.
<li>You may want give profiles read-only access to the field holding the list of values so that they cannot edit it. The trigger runs in system mode so that it has read-write access to this field.
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/04/10/convert-a-related-list-to-a-comma-separated-list/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Build an API with Node.js, Express, MongoDB and Cloud Foundry</title>
		<link>http://ec2.jeffdouglas.com/2012/03/25/build-an-api-with-node-js-express-mongodb-and-cloud-foundry/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=build-an-api-with-node-js-express-mongodb-and-cloud-foundry</link>
		<comments>http://ec2.jeffdouglas.com/2012/03/25/build-an-api-with-node-js-express-mongodb-and-cloud-foundry/#comments</comments>
		<pubDate>Mon, 26 Mar 2012 00:53:54 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Cloud Foundry]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4440</guid>
		<description><![CDATA[I was finalist in the LinkedIn Hackday hackathon last November with my &#8220;Mobile Chow Finder&#8221; app using jQuery Mobile, Database.com and Ruby on Rails on Heroku. I really liked the Chow Finder use case but wanted to make it more of a finished application; not just something I threw together in a matter of hours. [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F25%2Fbuild-an-api-with-node-js-express-mongodb-and-cloud-foundry%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F25%2Fbuild-an-api-with-node-js-express-mongodb-and-cloud-foundry%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/11/chow-finder1.png" rel="lightbox[4440]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/11/chow-finder1-150x150.png" alt="" title="chow-finder1" width="150" height="150" class="alignleft size-thumbnail wp-image-4266" /></a>I was <a href="http://veterans2011.linkedin.com/#gallery">finalist in the LinkedIn Hackday hackathon</a> last November with my &#8220;Mobile Chow Finder&#8221; app using jQuery Mobile, Database.com and Ruby on Rails on Heroku. I really liked the Chow Finder use case but wanted to make it more of a finished application; not just something I threw together in a matter of hours. So I decided to start off by writing an API with Node.js and MongoDB and host it on Cloud Foundry. I&#8217;m going to build a website running off that API with something like Sinatra or Rails. I also want to eventually build HTML5, Android and iOS applications running off this API too. </p>
<p>So I put together a video of the initial process of building the API. It&#8217;s definitely a work in progress. You can <a href="https://github.com/jeffdonthemic/Chow-Finder-API">clone the code from this repo</a> if you find it useful. It assumes that you have <a href="http://nodejs.org/#download">Node.js</a>, <a href="http://www.mongodb.org/display/DOCS/Quickstart">MongoDB</a>, <a href="http://expressjs.com/guide.html">Express</a> and the Cloud Foundry <a href="http://start.cloudfoundry.com/tools/vmc/installing-vmc.html">Command-Line Interface</a> (vmc) installed.</p>
<p><a href="http://www.youtube.com/watch?v=3AKaGShTHpo&#038;fmt=18">http://www.youtube.com/watch?v=3AKaGShTHpo</a></p>
<p>The API has the following methods around two objects: locations and facilities.</p>
<p>GET	/locations	&#8211; returns a list of locations<br />
GET	/locations/:id &#8212; returns a location<br />
POST	/locations	&#8211; creates a location<br />
GET	/locations/favorites	&#8211; returns list of favorite locations for a user<br />
POST	/locations/favorites	&#8211; creates a new favorite for a user<br />
GET	/locations/:id/facilities &#8212; returns a list of facilities for a location<br />
POST	/locations/:id/facilities &#8212; creates a new facility for a location<br />
GET	/locations/:id/facilities/:id &#8212; returns a facility<br />
PUT	/locations/:id/facilities/:id &#8212; updates a facility</p>
<p>You can <a href="https://github.com/jeffdonthemic/Chow-Finder-API/blob/master/app.js">check out code for app.js on github</a>, but most of the interesting stuff is around the connection to MongoDB and the code for the actual methods. </p>
<p>Once you installed the <a href="https://github.com/christkv/node-mongodb-native">MongoDB native Node.js driver</a>, you just need to create your connection to either your localhost or Mongo running on Cloud Foundry in app.js. </p>
<div id="gist-2201777" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">if</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">VCAP_SERVICES</span><span class="p">){</span></div><div class='line' id='LC2'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">env</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">VCAP_SERVICES</span><span class="p">);</span></div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">mongo</span> <span class="o">=</span> <span class="nx">env</span><span class="p">[</span><span class="s1">&#39;mongodb-1.8&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;credentials&#39;</span><span class="p">];</span></div><div class='line' id='LC4'><span class="p">}</span></div><div class='line' id='LC5'><span class="k">else</span><span class="p">{</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">mongo</span> <span class="o">=</span> <span class="p">{</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;hostname&quot;</span><span class="o">:</span><span class="s2">&quot;localhost&quot;</span><span class="p">,</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;port&quot;</span><span class="o">:</span><span class="mi">27017</span><span class="p">,</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;username&quot;</span><span class="o">:</span><span class="s2">&quot;&quot;</span><span class="p">,</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;password&quot;</span><span class="o">:</span><span class="s2">&quot;&quot;</span><span class="p">,</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;name&quot;</span><span class="o">:</span><span class="s2">&quot;&quot;</span><span class="p">,</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;db&quot;</span><span class="o">:</span><span class="s2">&quot;db&quot;</span></div><div class='line' id='LC13'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC14'><span class="p">}</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><span class="kd">var</span> <span class="nx">generate_mongo_url</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">){</span></div><div class='line' id='LC17'>&nbsp;&nbsp;<span class="nx">obj</span><span class="p">.</span><span class="nx">hostname</span> <span class="o">=</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">hostname</span> <span class="o">||</span> <span class="s1">&#39;localhost&#39;</span><span class="p">);</span></div><div class='line' id='LC18'>&nbsp;&nbsp;<span class="nx">obj</span><span class="p">.</span><span class="nx">port</span> <span class="o">=</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">port</span> <span class="o">||</span> <span class="mi">27017</span><span class="p">);</span></div><div class='line' id='LC19'>&nbsp;&nbsp;<span class="nx">obj</span><span class="p">.</span><span class="nx">db</span> <span class="o">=</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">db</span> <span class="o">||</span> <span class="s1">&#39;test&#39;</span><span class="p">);</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'>&nbsp;&nbsp;<span class="k">if</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">username</span> <span class="o">&amp;&amp;</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">password</span><span class="p">){</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="s2">&quot;mongodb://&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">username</span> <span class="o">+</span> <span class="s2">&quot;:&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">password</span> <span class="o">+</span> <span class="s2">&quot;@&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">hostname</span> <span class="o">+</span> <span class="s2">&quot;:&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">port</span> <span class="o">+</span> <span class="s2">&quot;/&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">db</span><span class="p">;</span></div><div class='line' id='LC23'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="k">else</span><span class="p">{</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="s2">&quot;mongodb://&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">hostname</span> <span class="o">+</span> <span class="s2">&quot;:&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">port</span> <span class="o">+</span> <span class="s2">&quot;/&quot;</span> <span class="o">+</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">db</span><span class="p">;</span></div><div class='line' id='LC26'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC27'><span class="p">}</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'><span class="kd">var</span> <span class="nx">mongourl</span> <span class="o">=</span> <span class="nx">generate_mongo_url</span><span class="p">(</span><span class="nx">mongo</span><span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201777/b174b4eb940c339a5989a2542e2058bf6968a717/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201777#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201777">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Now the API itself. What&#8217;s great about Node and Mongo are that they both talk JSON. So in this method, we POST some JSON and simply insert it into the &#8216;locations&#8217; collection.</p>
<div id="gist-2201789" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// creates a location in the &#39;locations&#39; collection</span></div><div class='line' id='LC2'><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/v.1/locations&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">connect</span><span class="p">(</span><span class="nx">mongourl</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">conn</span><span class="p">){</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">conn</span><span class="p">.</span><span class="nx">collection</span><span class="p">(</span><span class="s1">&#39;locations&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">coll</span><span class="p">){</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">coll</span><span class="p">.</span><span class="nx">insert</span><span class="p">(</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span> <span class="p">{</span><span class="nx">safe</span><span class="o">:</span><span class="kc">true</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Content-Type&quot;</span><span class="o">:</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Access-Control-Allow-Origin&quot;</span><span class="o">:</span> <span class="s2">&quot;*&quot;</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">));</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC13'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC14'>&nbsp;<span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201789/a372c6ec5ac830f4751c22eb2f453d13a28af061/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201789#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201789">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>To return all of the locations in the collection, we issue the find() command which returns a cursor object to the callback which is passed to the responses as an array of documents.</p>
<div id="gist-2201793" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// returns list of locations</span></div><div class='line' id='LC2'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/v.1/locations&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">connect</span><span class="p">(</span><span class="nx">mongourl</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">conn</span><span class="p">){</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">conn</span><span class="p">.</span><span class="nx">collection</span><span class="p">(</span><span class="s1">&#39;locations&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">coll</span><span class="p">){</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">coll</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">cursor</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">cursor</span><span class="p">.</span><span class="nx">toArray</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">items</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Content-Type&quot;</span><span class="o">:</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Access-Control-Allow-Origin&quot;</span><span class="o">:</span> <span class="s2">&quot;*&quot;</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">items</span><span class="p">));</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC16'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201793/f296f46231e728fbfabc21f7490dbfe6b62c2310/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201793#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201793">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>To return a specific location (as a document) from Mongo, we use the findOne() command and pass in the location&#8217;s id from the URL.</p>
<div id="gist-2201797" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// returns a specific location by id</span></div><div class='line' id='LC2'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/v.1/locations/:location_id&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">ObjectID</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">ObjectID</span><span class="p">;</span></div><div class='line' id='LC5'>&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">connect</span><span class="p">(</span><span class="nx">mongourl</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">conn</span><span class="p">){</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">conn</span><span class="p">.</span><span class="nx">collection</span><span class="p">(</span><span class="s1">&#39;locations&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">coll</span><span class="p">){</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">coll</span><span class="p">.</span><span class="nx">findOne</span><span class="p">({</span><span class="s1">&#39;_id&#39;</span><span class="o">:</span><span class="k">new</span> <span class="nx">ObjectID</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">location_id</span><span class="p">)},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nb">document</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Content-Type&quot;</span><span class="o">:</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Access-Control-Allow-Origin&quot;</span><span class="o">:</span> <span class="s2">&quot;*&quot;</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nb">document</span><span class="p">));</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC16'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC17'>&nbsp;&nbsp;</div><div class='line' id='LC18'><span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201797/167365f0e43afcb823e6805b2664c5ddb862708b/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201797#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201797">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>To create a facility for a location, we POST the entire JSON for the facility and then add the id for the parent location from the URL before inserting it into the collection.</p>
<div id="gist-2201803" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// creates a new facility for a location</span></div><div class='line' id='LC2'><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/v.1/locations/:location_id/facilities&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC3'>&nbsp;&nbsp;</div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="c1">// add the location id to the json</span></div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">facility</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">;</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="nx">facility</span><span class="p">[</span><span class="s1">&#39;location&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">location_id</span><span class="p">;</span></div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">connect</span><span class="p">(</span><span class="nx">mongourl</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">conn</span><span class="p">){</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">conn</span><span class="p">.</span><span class="nx">collection</span><span class="p">(</span><span class="s1">&#39;facilities&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">coll</span><span class="p">){</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">coll</span><span class="p">.</span><span class="nx">insert</span><span class="p">(</span> <span class="nx">facility</span><span class="p">,</span> <span class="p">{</span><span class="nx">safe</span><span class="o">:</span><span class="kc">true</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Content-Type&quot;</span><span class="o">:</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Access-Control-Allow-Origin&quot;</span><span class="o">:</span> <span class="s2">&quot;*&quot;</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">facility</span><span class="p">));</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC18'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'><span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201803/75ccdbb2af8a99335712ffc652f7d94980608bff/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201803#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201803">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>The last method updates a facility document with the findAndModify() method. The method finds the facility by id and updates the data PUT in the JSON payload. </p>
<div id="gist-2201808" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c1">// updates a facility</span></div><div class='line' id='LC2'><span class="nx">app</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="s1">&#39;/v.1/locations/:location_id/facilities/:facility_id&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">ObjectID</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">ObjectID</span><span class="p">;</span></div><div class='line' id='LC5'>&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongodb&#39;</span><span class="p">).</span><span class="nx">connect</span><span class="p">(</span><span class="nx">mongourl</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">conn</span><span class="p">){</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">conn</span><span class="p">.</span><span class="nx">collection</span><span class="p">(</span><span class="s1">&#39;facilities&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">coll</span><span class="p">){</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">coll</span><span class="p">.</span><span class="nx">findAndModify</span><span class="p">({</span><span class="s1">&#39;_id&#39;</span><span class="o">:</span><span class="k">new</span> <span class="nx">ObjectID</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">facility_id</span><span class="p">)},</span> <span class="p">[[</span><span class="s1">&#39;name&#39;</span><span class="p">,</span><span class="s1">&#39;asc&#39;</span><span class="p">]],</span> <span class="p">{</span> <span class="nx">$set</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span> <span class="p">},</span> <span class="p">{},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nb">document</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Content-Type&quot;</span><span class="o">:</span> <span class="s2">&quot;application/json&quot;</span><span class="p">,</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;Access-Control-Allow-Origin&quot;</span><span class="o">:</span> <span class="s2">&quot;*&quot;</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nb">document</span><span class="p">));</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC16'>&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2201808/3e55fecf199b0386192edeb950a82e0298f5b0f5/gistfile1.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2201808#file_gistfile1.js" style="float:right;margin-right:10px;color:#666">gistfile1.js</a>
            <a href="https://gist.github.com/2201808">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/03/25/build-an-api-with-node-js-express-mongodb-and-cloud-foundry/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing Unit Tests for v24 Apex REST Services</title>
		<link>http://ec2.jeffdouglas.com/2012/03/21/writing-unit-tests-for-v24-apex-rest-services/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=writing-unit-tests-for-v24-apex-rest-services</link>
		<comments>http://ec2.jeffdouglas.com/2012/03/21/writing-unit-tests-for-v24-apex-rest-services/#comments</comments>
		<pubDate>Wed, 21 Mar 2012 11:42:05 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4417</guid>
		<description><![CDATA[With the Spring &#8217;12 release, salesforce.com made some great enhancements to Apex REST services (v24): Apex REST automatically provides the REST request and response in your Apex REST methods via a static RestContext object. You no longer need to declare a RestRequest or RestResponse parameter in your method. User-defined types are now allowed as Apex [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F21%2Fwriting-unit-tests-for-v24-apex-rest-services%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F21%2Fwriting-unit-tests-for-v24-apex-rest-services%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>With the Spring &#8217;12 release, salesforce.com made some <a href="http://developer.force.com/releases/release/Spring12/apex+rest+updates">great enhancements</a> to Apex REST services (v24):</p>
<ul>
<li>Apex REST automatically provides the REST request and response in your Apex REST methods via a static RestContext object. You no longer need to declare a RestRequest or RestResponse parameter in your method.
<li>User-defined types are now allowed as Apex REST parameter types.
<li>Apex REST methods are now supported in managed and unmanaged packages.
<li>The order of elements in the JSON or XML response data no longer has to match the Apex REST method parameter order.</ul>
<p>My favorite is the user-defined types. My REST services can now pass back a wrapper class with error messages along with the actual data. Here&#8217;s what my new REST service looks like:</p>
<div id="gist-2146052" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nd">@RestResource</span><span class="o">(</span><span class="n">urlMapping</span><span class="o">=</span><span class="err">&#39;</span><span class="o">/</span><span class="n">v</span><span class="o">.</span><span class="mi">9</span><span class="o">/</span><span class="n">member</span><span class="o">/*/</span><span class="n">results</span><span class="o">/*</span><span class="err">&#39;</span><span class="o">)</span> </div><div class='line' id='LC2'><span class="n">global</span> <span class="n">with</span> <span class="n">sharing</span> <span class="kd">class</span> <span class="nc">MemberRestSvc</span> <span class="o">{</span></div><div class='line' id='LC3'>&nbsp;</div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="nd">@HttpGet</span> </div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="n">global</span> <span class="kd">static</span> <span class="n">ReturnClass</span> <span class="nf">doGet</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC6'>&nbsp;&nbsp;</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">String</span><span class="o">[]</span> <span class="n">uriKeys</span> <span class="o">=</span> <span class="n">RestContext</span><span class="o">.</span><span class="na">request</span><span class="o">.</span><span class="na">requestURI</span><span class="o">.</span><span class="na">split</span><span class="o">(</span><span class="sc">&#39;/&#39;</span><span class="o">);</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// get the member name from the uri</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">String</span> <span class="n">memberName</span> <span class="o">=</span> <span class="n">uriKeys</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">uriKeys</span><span class="o">.</span><span class="na">size</span><span class="o">()-</span><span class="mi">3</span><span class="o">);</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do awesome programming stuff here &amp; catch any exceptions</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">try</span> <span class="o">{</span></div><div class='line' id='LC13'>&nbsp;&nbsp;</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">List</span><span class="o">&lt;</span><span class="n">Contact</span><span class="o">&gt;</span> <span class="n">contacts</span> <span class="o">=</span> <span class="o">[</span><span class="n">Select</span> <span class="n">Id</span> <span class="n">From</span> <span class="n">Contact</span> <span class="n">where</span> <span class="n">member_name__c</span> <span class="o">=</span> <span class="o">:</span><span class="n">memberName</span><span class="o">];</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="k">new</span> <span class="nf">ReturnClass</span><span class="o">(</span><span class="err">&#39;</span><span class="kc">true</span><span class="err">&#39;</span><span class="o">,</span> <span class="err">&#39;</span><span class="n">Query</span> <span class="n">executed</span> <span class="n">successfully</span><span class="o">.</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">contacts</span><span class="o">);</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="k">new</span> <span class="nf">ReturnClass</span><span class="o">(</span><span class="err">&#39;</span><span class="kc">false</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">(),</span> <span class="kc">null</span><span class="o">);</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>&nbsp;&nbsp;<span class="n">global</span> <span class="kd">class</span> <span class="nc">ReturnClass</span> <span class="o">{</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">global</span> <span class="n">String</span> <span class="n">success</span><span class="o">;</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">global</span> <span class="n">String</span> <span class="n">message</span><span class="o">;</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">global</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Contact</span><span class="o">&gt;</span> <span class="n">records</span><span class="o">;</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">global</span> <span class="nf">ReturnClass</span><span class="o">(</span><span class="n">String</span> <span class="n">success</span><span class="o">,</span> <span class="n">String</span> <span class="n">message</span><span class="o">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Contact</span><span class="o">&gt;</span> <span class="n">records</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">this</span><span class="o">.</span><span class="na">success</span> <span class="o">=</span> <span class="n">success</span><span class="o">;</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">this</span><span class="o">.</span><span class="na">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">;</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">this</span><span class="o">.</span><span class="na">records</span> <span class="o">=</span> <span class="n">records</span><span class="o">;</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC35'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC37'><span class="o">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2146052/a821cec6a0a828606886cd8d7ee02c0da9944d61/gistfile1.java" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2146052#file_gistfile1.java" style="float:right;margin-right:10px;color:#666">gistfile1.java</a>
            <a href="https://gist.github.com/2146052">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>So now that I have my service written and running like a champ, I just need to write my unit tests. If I was writing the unit test with the <em><strong>previous API (v23)</strong></em>, I would write my unit test like:</p>
<div id="gist-2146168" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>@isTest</div><div class='line' id='LC2'>private class Test_MemberRestSvc {</div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>&nbsp;&nbsp;static {</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;// setup test data	</div><div class='line' id='LC6'>&nbsp;&nbsp;}</div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'>&nbsp;&nbsp;static testMethod void testDoGet() {</div><div class='line' id='LC9'>&nbsp;&nbsp;	    </div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;RestRequest req = new RestRequest(); </div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;RestResponse res = new RestResponse();</div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;// pass the req and resp objects to the method		 </div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;req.requestURI = &#39;https://cs9.salesforce.com/services/apexrest/v.9/member/me/results/today&#39;;  </div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;req.httpMethod = &#39;GET&#39;;</div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;MemberRestSvc.ReturnClass results = MemberRestSvc.doGet(req,res);</div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(&#39;true&#39;, results.success);</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(10, results.records.size());</div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;System.assertEquals(&#39;Query executed successfully.&#39;, results.message);</div><div class='line' id='LC22'>&nbsp;</div><div class='line' id='LC23'>&nbsp;&nbsp;}</div><div class='line' id='LC24'>&nbsp;&nbsp;</div><div class='line' id='LC25'>}</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2146168/3df29c5532169effc5a0a1ab60f9c1cf1bdc6af1/gistfile1.txt" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2146168#file_gistfile1.txt" style="float:right;margin-right:10px;color:#666">gistfile1.txt</a>
            <a href="https://gist.github.com/2146168">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Since v24 now includes a static RestContext object, testing is a little different as you no longer need to pass a Request and Response object to the method. I searched the <a href="http://www.salesforce.com/us/developer/docs/apexcode/index.htm">Apex docs</a> but there was no mention of writing unit tests. Pat Patterson has a <a href="http://blogs.developerforce.com/developer-relations/2012/02/quick-tip-public-restful-web-services-on-force-com-sites.html">good blog post</a> for Apex REST but no mention of unit testing either. </p>
<p>So I tried a few routes for an hour or so to no avail. I finally IM&#8217;d Pat and begged for help. I <a href="http://boards.developerforce.com/t5/REST-API-Integration/How-to-unit-test-v24-Apex-REST-classes/td-p/414759">posted the question on the Force.com Discussion Boards</a> and Pat went to work. However, before Pat could finish his investigation and provide a solution, <a href="http://boards.developerforce.com/t5/user/viewprofilepage/user-id/57763">Kartik</a> beat him to it (thanks!!).  </p>
<p>So here&#8217;s what the unit test looks like for a v24 Apex REST service. Notice that you pass a request and response object to the RestContext but that&#8217;s it. Doesn&#8217;t seem very intuitive?</p>
<div id="gist-2146160" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nd">@isTest</span></div><div class='line' id='LC2'><span class="kd">private</span> <span class="kd">class</span> <span class="nc">Test_MemberRestSvc</span> <span class="o">{</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="kd">static</span> <span class="o">{</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// setup test data	</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC7'><br/></div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="kd">static</span> <span class="n">testMethod</span> <span class="kt">void</span> <span class="nf">testDoGet</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;	    </div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">RestRequest</span> <span class="n">req</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RestRequest</span><span class="o">();</span> </div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">RestResponse</span> <span class="n">res</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RestResponse</span><span class="o">();</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">req</span><span class="o">.</span><span class="na">requestURI</span> <span class="o">=</span> <span class="err">&#39;</span><span class="nl">https:</span><span class="c1">//cs9.salesforce.com/services/apexrest/v.9/member/me/results/today&#39;;  </span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">req</span><span class="o">.</span><span class="na">httpMethod</span> <span class="o">=</span> <span class="err">&#39;</span><span class="n">GET</span><span class="err">&#39;</span><span class="o">;</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">RestContext</span><span class="o">.</span><span class="na">request</span> <span class="o">=</span> <span class="n">req</span><span class="o">;</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">RestContext</span><span class="o">.</span><span class="na">response</span> <span class="o">=</span> <span class="n">res</span><span class="o">;</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">MemberRestSvc</span><span class="o">.</span><span class="na">ReturnClass</span> <span class="n">results</span> <span class="o">=</span> <span class="n">MemberRestSvc</span><span class="o">.</span><span class="na">doGet</span><span class="o">();</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">System</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="err">&#39;</span><span class="kc">true</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">results</span><span class="o">.</span><span class="na">success</span><span class="o">);</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">System</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">10</span><span class="o">,</span> <span class="n">results</span><span class="o">.</span><span class="na">records</span><span class="o">.</span><span class="na">size</span><span class="o">());</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">System</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="err">&#39;</span><span class="n">Query</span> <span class="n">executed</span> <span class="n">successfully</span><span class="o">.</span><span class="err">&#39;</span><span class="o">,</span> <span class="n">results</span><span class="o">.</span><span class="na">message</span><span class="o">);</span></div><div class='line' id='LC23'>&nbsp;</div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC25'>&nbsp;&nbsp;</div><div class='line' id='LC26'><span class="o">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/2146160/23e307e4f42bf2cecb2023f85ef3943cb534a403/gistfile1.java" style="float:right;">view raw</a>
            <a href="https://gist.github.com/2146160#file_gistfile1.java" style="float:right;margin-right:10px;color:#666">gistfile1.java</a>
            <a href="https://gist.github.com/2146160">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/03/21/writing-unit-tests-for-v24-apex-rest-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Synchronizing Asynchronous Events in Salesforce.com</title>
		<link>http://ec2.jeffdouglas.com/2012/03/20/synchronizing-asynchronous-events-in-salesforce-com/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=synchronizing-asynchronous-events-in-salesforce-com</link>
		<comments>http://ec2.jeffdouglas.com/2012/03/20/synchronizing-asynchronous-events-in-salesforce-com/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 13:26:56 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4406</guid>
		<description><![CDATA[So the title is slightly dubious as you really can&#8217;t synchronize asynchronous events in salesforce.com. However, here&#8217;s a strategy to make asynchronous events more manageable. Don&#8217;t get me wrong, asynchronous events (Apex methods with the @future annotation) are awesome. You get higher limits, they fire when the platform has spare cycles and users don&#8217;t have [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F20%2Fsynchronizing-asynchronous-events-in-salesforce-com%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F03%2F20%2Fsynchronizing-asynchronous-events-in-salesforce-com%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><img alt="" src="http://i2.photobucket.com/albums/y48/risk07/sept05/synchro.jpg" class="alignleft" width="275" />So the title is slightly dubious as you really can&#8217;t synchronize asynchronous events in salesforce.com. However, here&#8217;s a strategy to make asynchronous events more manageable.</p>
<p>Don&#8217;t get me wrong, asynchronous events (Apex methods with the @future annotation) are awesome. You get higher limits, they fire when the platform has spare cycles and users don&#8217;t have to wait for processing to finish. However, if you use them liberally in your application, orchestrating them may become difficult.</p>
<p>So here&#8217;s the situation we ran into at <a href="http://www.cloudspokes.com">CloudSpokes</a> and how I finally solved the issue. I may be a bit slow but it took a few iterations. </p>
<p>So if you haven&#8217;t been to CloudSpokes (shame on you if you haven&#8217;t!!) we run development challenges for cash, prizes, badges and bragging right. A good majority of our challenges are Force.com related. So we run a challenge like <a href="http://www.cloudspokes.com/challenges/1374">Multiple Campaign Picker</a> and a number of developers submit solutions for the challenge. After the challenge closes for submissions, multiple judges score each developer&#8217;s submission. Here&#8217;s the problem: all of our scoring is done asynchronously. So when a judge submits a scorecard for a developer it is scored asynchronously. When all of the judges have submitted all of their scorecards for a developer, the developer is given a final score, again asynchronously. Then when all of the developers have been scored by all of the judges, the entire challenge is scored&#8230;. you guessed it, asynchronously.</p>
<p>The issue we were running into was that because of the asynchronous nature of the event processing the final scoring for the challenge was being done (occasionally) before that last developer was scored. At first I thought a simple sleep() would work at the beginning of the final challenging scoring. This would give the platform some time to score that final developer. However, as you know, there is no sleep() on Force.com as it would tie up valuable shared resources. </p>
<p>I then wrote batch job that I kicked off when the final developer was scored. The job was schedule to run in two minutes. That quickly hit the limit of scheduled tasks available and I didn&#8217;t really like the solution anyway. </p>
<p>Note: a queue in Force.com would be awesome in this circumstance and Taggart Matthiesen mentioned in a recent webinar that it is on the roadmap. (Be still my beating heart.) </p>
<p>So here&#8217;s the solution that I can up with. I went back to good &#8216;ole workflow. Never do programmatically what you can do declaratively, I always say. So I wrote a workflow that fires on the challenge object when the number of scored developers equals the number of developers participating. The workflow runs a time-dependent action that fires &#8220;0 Hours After Rule Trigger Date&#8221; and changes a picklist value. My trigger catches this change and fires the Apex code to score the entire challenge. Viola! Problem solved with point-and-click programming!</p>
<p>There are some limitations with this workflow method but they are minor. Time-based triggers don&#8217;t support minutes or seconds. I think the documentation states that they fire within an hour but I read on the developerforce boards once that it&#8217;s generally 15 minutes or so. I&#8217;ve noticed that most of ours fire around 5 minutes or so.</p>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/03/20/synchronizing-asynchronous-events-in-salesforce-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apex REST Service Not Found?</title>
		<link>http://ec2.jeffdouglas.com/2012/02/28/apex-rest-service-not-found/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=apex-rest-service-not-found</link>
		<comments>http://ec2.jeffdouglas.com/2012/02/28/apex-rest-service-not-found/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 17:32:55 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4401</guid>
		<description><![CDATA[I just deployed an Apex REST service to production and noticed something strange when trying to access it. When calling the URL with my Rails app, I received the error: &#8220;Could not find a match for URL /v.9/quickquiz/results/today&#8221;. Strange because the URL worked in my sandbox and there was no difference in the code. I [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F28%2Fapex-rest-service-not-found%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F28%2Fapex-rest-service-not-found%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I just deployed an Apex REST service to production and noticed something strange when trying to access it. When calling the URL with my Rails app, I received the error: &#8220;Could not find a match for URL /v.9/quickquiz/results/today&#8221;. Strange because the URL worked in my sandbox and there was no difference in the code. I tried with the Apigee Console with the same results. Hmmm&#8230;.</p>
<p>I was only able to access the URL <strong><em>after</em></strong> I &#8220;Ran All Tests&#8221; in the org. Check out the debug below. </p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/cs-website-—-ruby-—-108×36-1.png" rel="lightbox[4401]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/cs-website-—-ruby-—-108×36-1-300x95.png" alt="" title="cs-website — ruby — 108×36-1" width="300" height="95" class="alignnone size-medium wp-image-4403" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/02/28/apex-rest-service-not-found/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Node.js to Host Development Web Services</title>
		<link>http://ec2.jeffdouglas.com/2012/02/02/using-node-js-to-host-development-web-services/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=using-node-js-to-host-development-web-services</link>
		<comments>http://ec2.jeffdouglas.com/2012/02/02/using-node-js-to-host-development-web-services/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 11:54:53 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[CloudSpokes]]></category>
		<category><![CDATA[Heroku]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4357</guid>
		<description><![CDATA[One of the cool things about Node.js, besides the fact that it&#8217;s fast and scalable, is that it&#8217;s extremely easy to setup and get running. In a couple of minutes you can get a fully operational web server running with minimal code. I&#8217;ve been playing around with the Express library and it makes developing Node.js [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F02%2Fusing-node-js-to-host-development-web-services%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F02%2Fusing-node-js-to-host-development-web-services%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/node-logo.png" rel="lightbox[4357]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/node-logo.png" alt="" title="node-logo" width="175" height="55" class="alignleft size-full wp-image-4379" /></a>One of the cool things about <a href="http://nodejs.org/">Node.js</a>, besides the fact that it&#8217;s fast and scalable, is that it&#8217;s extremely easy to setup and get running. In a couple of minutes you can get a fully operational web server running with minimal code. I&#8217;ve been playing around with the <a href="http://expressjs.com/">Express</a> library and it makes developing Node.js app <strong>sooo</strong> much easier. It&#8217;s early but I&#8217;m really impressed with it so far. Check out <a href="http://expressjs.com/screencasts.html">this screencast</a> for a 5 minute overview.</p>
<p>One use case that we&#8217;ve come across is to use Node.js to mock up web services for development and testing. It&#8217;s easy to put together a small app the stubs out a return structure to get your POC up and running quickly. How many times have you wanted to test your Apex callouts but the web service wasn&#8217;t finished or stable yet? Now you can setup a quick Node.js app on Heroku that returns dummy data, develop your callouts and then switch to the production endpoint when available. This use case is extremely useful when developing mobile apps as you can run the Node.js server locally while developing with your simulator! (Another great idea from <a href="https://twitter.com/#!/iromin">Romin</a>).</p>
<p>We&#8217;ve found a really cool use case for Node.js at <a href="http://www.cloudspokes.com">CloudSpokes</a>.  Most of our challenges use some sort of backend datastore or API and this can become tedious when working on jQuery, Rails or HTML challenges where the developer really doesn&#8217;t care where the data comes from. Typically their first step in development is authenticating to the API which is a pain when all you really care about is the UI. Now with Node.js we&#8217;ve decoupled the frontend and backend requirements. We&#8217;ve made available a little Node.js app with resources that simply return JSON in the structure that they&#8217;d receive from actual calls to Database.com. They can modify the Node.js app to return different hashes or extend the app to simulate different calls if needed. Now the developers don&#8217;t have to worry about authenticating to Database.com and we don&#8217;t have to setup an org, enter dummy data and configurations and provide them access. Birds are chirping, the sun is shining and everyone is happy.</p>
<p>The source code for the CloudSpokes Node.js devserver is <a href="https://github.com/cloudspokes/cs-node-devserver">available at github</a> and you can <a href="http://node-demo-devserver.herokuapp.com/">run the app on heroku</a>.</p>
<p>James Ward has a <a href="http://www.jamesward.com/2011/06/21/getting-started-with-node-js-on-the-cloud/">great article about getting a Node.js app up and running on heroku</a>. It&#8217;s a little long if you are familiar with Heroku but it&#8217;s well worth the read. Make sure you don&#8217;t skip the section about configuring your app to listen on the port defined by Heroku&#8217;s environment variables.</p>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/02/02/using-node-js-to-host-development-web-services/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Welcome to CloudSpokes Rob Cheng!</title>
		<link>http://ec2.jeffdouglas.com/2012/02/02/welcome-to-cloudspokes-rob-cheng/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=welcome-to-cloudspokes-rob-cheng</link>
		<comments>http://ec2.jeffdouglas.com/2012/02/02/welcome-to-cloudspokes-rob-cheng/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 11:05:09 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4367</guid>
		<description><![CDATA[We just announced on the CloudSpokes blog that Rob Cheng has joined the team and will be heading up our CloudSpokes strategy. Rob came from salesforce.com where he was the Director of Force.com Platform Product Marketing and has also had stints at CollabNet and Borland. He actually has a really cool blog as well that [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F02%2Fwelcome-to-cloudspokes-rob-cheng%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fec2.jeffdouglas.com%2F2012%2F02%2F02%2Fwelcome-to-cloudspokes-rob-cheng%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/rob.jpeg" rel="lightbox[4367]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2012/02/rob-150x150.jpg" alt="" title="rob" width="150" height="150" class="alignleft size-thumbnail wp-image-4368" /></a>We just announced on the <a href="http://blog.cloudspokes.com/2012/02/welcome-to-newest-member-of-cloudspokes.html">CloudSpokes blog</a> that <a href="http://www.linkedin.com/in/robcheng">Rob Cheng</a> has joined the team and will be heading up our CloudSpokes strategy. Rob came from salesforce.com where he was the Director of Force.com Platform Product Marketing and has also had stints at CollabNet and Borland. He actually has a <a href="http://robcheng.wordpress.com/">really cool blog</a> as well that you should check out.</p>
<p>Personally, this is a great addition to the team and since Rob is focusing on partners, sponsors and strategy, this allows me to have more time to work with the community. A few less tasks on my plate.</p>
<p>The CloudSpokes platform and community is growing wickedly fast and Rob was badly needed. We will be adding more people to the team shortly. Are you interested? Drop me a line.</p>
]]></content:encoded>
			<wfw:commentRss>http://ec2.jeffdouglas.com/2012/02/02/welcome-to-cloudspokes-rob-cheng/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

