<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>GetMoreFromCoding</title>
 <link href="http://yacc.github.com/atom.xml" rel="self"/>
 <link href="http://yacc.github.com"/>
 <updated>2013-03-11T18:57:51-07:00</updated>
 <id>http://yacc.github.com</id>
 <author>
   <name>Yacin Bahi</name>
   <email>yacin@sensr.net</email>
 </author>

 
 <entry>
   <title>Revenue Tracking With Stripe</title>
   <link href="http://yacc.github.com/2013/02/27/revenue-tracking-with-stripe"/>
   <updated>2013-02-27T00:00:00-08:00</updated>
   <id>http://yacc.github.com/2013/02/27/revenue-tracking-with-stripe</id>
   <content type="html"></content>
 </entry>
 
 <entry>
   <title>Lean Software Startup Tool Chain</title>
   <link href="http://yacc.github.com/2013/02/27/lean-software-startup-tool-chain"/>
   <updated>2013-02-27T00:00:00-08:00</updated>
   <id>http://yacc.github.com/2013/02/27/lean-software-startup-tool-chain</id>
   <content type="html">&lt;p&gt;redmine github&lt;/p&gt;

&lt;p&gt;rails: * secret http://stackoverflow.com/questions/5132152/when-you-have-secret-key-in-your-project-how-can-pushing-to-github-be-possible&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Stripe For Recurring Billing</title>
   <link href="http://yacc.github.com/2013/02/18/stripe-for-recurring-billing"/>
   <updated>2013-02-18T00:00:00-08:00</updated>
   <id>http://yacc.github.com/2013/02/18/stripe-for-recurring-billing</id>
   <content type="html"></content>
 </entry>
 
 <entry>
   <title>For Blogging Less Is More</title>
   <link href="http://yacc.github.com/2013/02/18/for-blogging-less-is-more"/>
   <updated>2013-02-18T00:00:00-08:00</updated>
   <id>http://yacc.github.com/2013/02/18/for-blogging-less-is-more</id>
   <content type="html"></content>
 </entry>
 
 <entry>
   <title>API design</title>
   <link href="http://yacc.github.com/coding/2013/02/18/api-design"/>
   <updated>2013-02-18T00:00:00-08:00</updated>
   <id>http://yacc.github.com/coding/2013/02/18/api-design</id>
   <content type="html">&lt;h2&gt;What are some elements of good api design ?&lt;/h2&gt;&lt;p&gt;
This post presents a collection of principles I followed when developing the &lt;a href='https://sensr.net'&gt;Sensr.net API&lt;/a&gt;, you can learn more about the sensr.net APIs by reading our &lt;a href='http://yacc.github.com/sensrapi-tutorials/'&gt;tutorial.&lt;/a&gt;. This is the first of several posts that will cover some of the aspects presented here.
&lt;/p&gt;&lt;p&gt;
I'm going to go over some of the basics of API design and illustrate some of the points with example implementation in Ruby on Rails.
If you're on a Rack stack, note that a nice alternative to implementing an API from the ground up is to go with &lt;a href='https://github.com/intridea/grape'&gt;Grape&lt;/a&gt;, an opinionated micro-framework for creating REST-like APIs in Ruby.
&lt;ol&gt;
	&lt;li&gt;Maintainability: api must be easy to test and the code easy to understand.&lt;/li&gt;
	&lt;li&gt;Version: support multiple version&lt;/li&gt;
	&lt;li&gt;Authentication: restrict access to private resources.&lt;/li&gt;
	&lt;li&gt;Extendability: must be easy to add new API calls as new resources become available.&lt;/li&gt;
	&lt;li&gt;Predictability: avoid surprising developers even if it means not following best pratices.&lt;/li&gt;
	&lt;li&gt;Documentation: up-to-date and extensive documentation.&lt;/li&gt;
	&lt;li&gt;Throtling&lt;/li&gt;
	&lt;li&gt;Generating SDKs&lt;/li&gt;
&lt;/ol&gt;	
&lt;/p&gt;&lt;h2&gt;Maintainability and code structure&lt;/h2&gt;
&lt;p&gt;How do you organize your code so the API is easy to maintain ? I needed a little more control than what &lt;a href='https://github.com/intridea/grape'&gt;Grape&lt;/a&gt; was offering me, so intead I went for a Presenter pattern. The &lt;a href='http://www.amazon.com/gp/product/0321127420'&gt;presenter pattern&lt;/a&gt; is a way to compose a single unified object that can be utilized to properly output data for a specific purpose. This implementaiton yields flexibility, customization, and testability instead of ActiveRecord&amp;#8217;s as_json rigidity. We basicaly setup presenters for our models and utilize them in our controllers to provide the desired structure of our JSON responses.&lt;/p&gt;
&lt;h3&gt;Code structure&lt;/h3&gt;
&lt;p&gt;Our code is now organized this way, for all version of the api, every model has a corresponding presenter and controller. This leads to a code that is nicely organized. Here, I&amp;#8217;m adding a namespace to distinguish between internal API &amp;#8216;/i/v3/&amp;#8217; calls and user level ones &amp;#8216;/u/v3/&amp;#8217;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;app&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;models&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
          &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;camera&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
&lt;span class='n'&gt;app&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;controllers&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;u&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;v3&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;base_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
                    &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;users_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
                    &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;cameras_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
               &lt;span class='sr'&gt;/i/&lt;/span&gt;&lt;span class='n'&gt;v3&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;base_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
                    &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;users_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
&lt;span class='n'&gt;app&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;presenter&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;u&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;v3&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;base_presenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;
                    &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;users_presenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;                     
                    &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;cameras_presenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;                     
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Base Controllers&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s take a look at our controllers first. All controllers inherit from a base controller. The base controller has two purposes, encapsulate behavior common to all controllers and -very important- expose a description of the resources available, we will use this later for documentation.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;U&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='ss'&gt;V3&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:BaseController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;  
  &lt;span class='n'&gt;respond_to&lt;/span&gt; &lt;span class='ss'&gt;:json&lt;/span&gt;
  &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:current_user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:current_tenant&lt;/span&gt;
  
  &lt;span class='c1'&gt;# this is used for API discovery and documentation&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;resources&lt;/span&gt;
    &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:json&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ResourcesPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;description&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;users&lt;/span&gt;
    &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:text&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;UserPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;description&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;cameras&lt;/span&gt;
    &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:text&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;CameraPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;description&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Controllers&lt;/h3&gt;
&lt;p&gt;Now a resource controller is fairly straighforward. It has a before_filter to validate the token and inherits from the base controller. You&amp;#8217;ll notice that the code is well scoped and versionned. The resource is either looked up by query paramaters or in the case of the user as the owner of the API session token. Once the resource is loaded, we just call instantiate the resource presenter and call &amp;#8216;render :json&amp;#8217; on it.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;U&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='ss'&gt;V3&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:UsersController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;BaseController&lt;/span&gt;

  &lt;span class='n'&gt;before_filter&lt;/span&gt; &lt;span class='ss'&gt;:set_resource_owner_by_oauth_token&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;  &lt;span class='ss'&gt;:except&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:register&lt;/span&gt;
  &lt;span class='n'&gt;oauth_required&lt;/span&gt; &lt;span class='ss'&gt;:scope&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:except&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:register&lt;/span&gt;
  
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;me&lt;/span&gt;
    &lt;span class='n'&gt;logger&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;info&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;[API Client: &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;oauth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;client&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;] with scope &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;oauth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;scope&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; and tenant  [&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;oauth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;identity&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;]&amp;quot;&lt;/span&gt;
    &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:json&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;UserPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='ss'&gt;:status&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:ok&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Base api presenter&lt;/h3&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ApiPresenter&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;resource&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;{})&lt;/span&gt;
    &lt;span class='vi'&gt;@options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;test?&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;build?&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;development?&lt;/span&gt; 
      &lt;span class='vi'&gt;@basepath&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;https://sensrapi.dev&amp;#39;&lt;/span&gt;
    &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;staging?&lt;/span&gt;
      &lt;span class='vi'&gt;@basepath&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;https://api.stagingserver.com&amp;#39;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='vi'&gt;@basepath&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;https://api.sensr.net&amp;#39;&lt;/span&gt;          
    &lt;span class='k'&gt;end&lt;/span&gt;    
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;User presenter&lt;/h3&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;U&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='ss'&gt;V3&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:UserPresenter&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApiPresenter&lt;/span&gt;
  &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='kp'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;{})&lt;/span&gt;
    &lt;span class='k'&gt;super&lt;/span&gt;
    &lt;span class='vi'&gt;@user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;description&lt;/span&gt;
    &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;root&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/app/assets/resources/u_v3_users.json&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;https://api.sensr.net&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@basepath&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;as_json&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;{})&lt;/span&gt;
    &lt;span class='vi'&gt;@options&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;data&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='ss'&gt;:user&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='ss'&gt;:id&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;:email&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;:name&lt;/span&gt;  &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='ss'&gt;:urls&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='ss'&gt;:cancel&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@basepath&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/u/v3/users/&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/cancel&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;:update&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@basepath&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/u/v3/users/&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/update&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;:my_cameras&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@basepath&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/u/v3/cameras/owned&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;:my_clips&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@basepath&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;/u/v3/clips/owned&amp;quot;&lt;/span&gt;      &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='vi'&gt;@options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:include&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:cameras&lt;/span&gt;
      &lt;span class='n'&gt;data&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='o'&gt;][&lt;/span&gt;&lt;span class='ss'&gt;:cameras&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;cameras&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;collect&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;camera&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='ss'&gt;U&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:V3&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;CameraPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;camera&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='ss'&gt;:include&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:ftp_user&lt;/span&gt;&lt;span class='p'&gt;})&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='n'&gt;data&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
     
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Versionning&lt;/h2&gt;&lt;p&gt;
Some of the principles I followed when developing our API
&lt;ol&gt;
	&lt;li&gt;Always include a version when releasing an API.&lt;/li&gt;
	&lt;li&gt;Developers must specify a version when calling the API&lt;/li&gt;
	&lt;li&gt;Specify the version with a 'v' prefix (ex: /u/v3/cameras.json)&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;&lt;p&gt;
As a developer, I like seeing the version of the api on the URL rather than in the HTTP header.
With the code structure and the namespacing introduced above in the presenters and the controller, we can now release new versions of our API along side the old ones. We can apply our namescoping to our models, controllers, presenters, and specs.
&lt;/p&gt;
&lt;p&gt;I will talk about the other aspects of API desing in follow-up posts.&lt;/p&gt;</content>
 </entry>
 
 
</feed>