API with Rabl and API versioning

I started playing around with RABL and here is what I came up with:

Support for versioning via case statement in new views/bookmarks/index.rabl:

collection @bookmarks, :root => "bookmarks"

case params[:apiversion]
when "0.4"
attributes :id
else

default 'current' api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4
{"bookmarks":[{"bookmark":{"id":2}},{"bookmark":{"id":5}},{"bookmark":{"id":4}},{"bookmark":{"id":1}},{"bookmark":{"id":3}}]}

http://192.168.1.46:3000/bookmarks.json
{"bookmarks":[{"bookmark":{"id":2,"name":"active","query":"last_report > &quot;35 minutes ago&quot; and (status.applied > 0 or status.restarted > 0)"}},{"bookmark":{"id":5,"name":"disabled","query":"status.enabled = false"}},{"bookmark":{"id":4,"name":"error","query":"last_report > &quot;35 minutes ago&quot; and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)"}},{"bookmark":{"id":1,"name":"eventful","query":"eventful = true"}},{"bookmark":{"id":3,"name":"out of sync","query":"last_report < &quot;30 minutes ago&quot; and status.enabled = true"}}]}

Its trivial to get this working. Took about 5 minutes. I haven't found a way to list all attributes but I have a feeling it will not be necessary in most cases.

Attached is a patch to implement what I coded already. I don't expect it to be merged into develop but just to serve as an example.
I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001

··· From: Corey Osman Date: Mon, 30 Apr 2012 22:23:10 -0700 Subject: [PATCH] Added view based json renderering using rabl

Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json 
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

> I started playing around with RABL and here is what I came up with:
>
>
> Support for versioning via case statement in new
> views/bookmarks/index.rabl:
>
> collection @bookmarks, :root => "bookmarks"
>
> case params[:apiversion]
> when "0.4"
> attributes :id
> else
> # default 'current' api
> attributes :id, :query, :name
> end
>
> http://192.168.1.46:3000/bookmarks.json?apiversion=0.4
>
> {"bookmarks":[{"bookmark":{"id":2}},{"bookmark":{"id":5}},{"bookmark":{"id":4}},{"bookmark":{"id":1}},{"bookmark":{"id":3}}]}
>
>
> http://192.168.1.46:3000/bookmarks.json
>
> {"bookmarks":[{"bookmark":{"id":2,"name":"active","query":"last_report > &quot;35 minutes ago&quot; and (status.applied > 0 or status.restarted > 0)"}},{"bookmark":{"id":5,"name":"disabled","query":"status.enabled = false"}},{"bookmark":{"id":4,"name":"error","query":"last_report > &quot;35 minutes ago&quot; and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)"}},{"bookmark":{"id":1,"name":"eventful","query":"eventful = true"}},{"bookmark":{"id":3,"name":"out of sync","query":"last_report < &quot;30 minutes ago&quot; and status.enabled = true"}}]}
>
>
> Its trivial to get this working. Took about 5 minutes. I haven't found a way to list all attributes but I have a feeling it will not be necessary in most cases.
>
> I agree that it pretty easy writing down the controllers themself.

I was wondering what you were thinking about the following approach
http://freelancing-gods.com/posts/versioning_your_ap_is for api namespace
and versioning.

I also think that its probably better to have separate classes for the API
(per version) in the long run.

Ohad

··· On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman wrote:

Attached is a patch to implement what I coded already. I don’t expect it to be merged into develop but just to serve as an example.

I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb
b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl
b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb
    b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

> I started playing around with RABL and here is what I came up with:
>
>
Rabl looks really powerful, and it looks like it might fit our
requirements, I think we should give this a try.

what I would like to have is both

  1. api versioning
  2. rabl views
  3. auto generated documentation

@Inecas do you see any conflict between 2 and 3 ?

thanks!
Ohad

··· On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman wrote:

Support for versioning via case statement in new
views/bookmarks/index.rabl:

collection @bookmarks, :root => “bookmarks”

case params[:apiversion]
when "0.4"
attributes :id
else

default ‘current’ api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4

{“bookmarks”:[{“bookmark”:{“id”:2}},{“bookmark”:{“id”:5}},{“bookmark”:{“id”:4}},{“bookmark”:{“id”:1}},{“bookmark”:{“id”:3}}]}

http://192.168.1.46:3000/bookmarks.json

{“bookmarks”:[{“bookmark”:{“id”:2,“name”:“active”,“query”:“last_report > “35 minutes ago” and (status.applied > 0 or status.restarted > 0)”}},{“bookmark”:{“id”:5,“name”:“disabled”,“query”:“status.enabled = false”}},{“bookmark”:{“id”:4,“name”:“error”,“query”:“last_report > “35 minutes ago” and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)”}},{“bookmark”:{“id”:1,“name”:“eventful”,“query”:“eventful = true”}},{“bookmark”:{“id”:3,“name”:“out of sync”,“query”:“last_report < “30 minutes ago” and status.enabled = true”}}]}

Its trivial to get this working. Took about 5 minutes. I haven’t found a way to list all attributes but I have a feeling it will not be necessary in most cases.

Attached is a patch to implement what I coded already. I don’t expect it to be merged into develop but just to serve as an example.

I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb
b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl
b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb
    b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

Seems like a lot of work on top of the fact that will still need to use view templates.

I watched this and it appears that is very similar to the flying sphinx article if not better.
http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true

If I am reading correct we will need to replicate every controller for each version of the api. How would this even scale with foreman version 1.60? Are we going to have 10 different versions of each controller? Seems kinda crazy.

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

··· On Jun 3, 2012, at 11:50 PM, Ohad Levy wrote:

On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman corey@logicminds.biz wrote:
I started playing around with RABL and here is what I came up with:

Support for versioning via case statement in new views/bookmarks/index.rabl:

collection @bookmarks, :root => “bookmarks”

case params[:apiversion]
when "0.4"
attributes :id
else

default ‘current’ api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4
{“bookmarks”:[{“bookmark”:{“id”:2}},{“bookmark”:{“id”:5}},{“bookmark”:{“id”:4}},{“bookmark”:{“id”:1}},{“bookmark”:{“id”:3}}]}

http://192.168.1.46:3000/bookmarks.json
{“bookmarks”:[{“bookmark”:{“id”:2,“name”:“active”,“query”:“last_report > “35 minutes ago” and (status.applied > 0 or status.restarted > 0)”}},{“bookmark”:{“id”:5,“name”:“disabled”,“query”:“status.enabled = false”}},{“bookmark”:{“id”:4,“name”:“error”,“query”:“last_report > “35 minutes ago” and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)”}},{“bookmark”:{“id”:1,“name”:“eventful”,“query”:“eventful = true”}},{“bookmark”:{“id”:3,“name”:“out of sync”,“query”:“last_report < “30 minutes ago” and status.enabled = true”}}]}

Its trivial to get this working. Took about 5 minutes. I haven’t found a way to list all attributes but I have a feeling it will not be necessary in most cases.
I agree that it pretty easy writing down the controllers themself.

I was wondering what you were thinking about the following approach http://freelancing-gods.com/posts/versioning_your_ap_is for api namespace and versioning.

I also think that its probably better to have separate classes for the API (per version) in the long run.

Ohad

Attached is a patch to implement what I coded already. I don’t expect it to be merged into develop but just to serve as an example.
I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json 
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

Hi,

If the old versions are depreciated and removed later, one don't have
to keep so many versions. But having at least two versions (old and
new) seems quite useful, giving the user time for save migration of
their scripts to the new one.

– Ivan

··· On Jun 4, 9:22 am, Corey Osman wrote: > Seems like a lot of work on top of the fact that will still need to use view templates. > > I watched this and it appears that is very similar to the flying sphinx article if not better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true > > If I am reading correct we will need to replicate every controller for each version of the api. How would this even scale with foreman version 1.60? Are we going to have 10 different versions of each controller? Seems kinda crazy.

Old controllers could also be shared until new version requires a
change. So the only true replication would at the routes.rb level,
which is not so bad, since problem with replication comes when you
need to change something. But since the old API version is not going
to change, it doesn't hurt so much.

– Ivan

··· On Jun 4, 9:52 am, iNecas wrote: > On Jun 4, 9:22 am, Corey Osman wrote: > > > Seems like a lot of work on top of the fact that will still need to use view templates. > > > I watched this and it appears that is very similar to the flying sphinx article if not better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true > > > If I am reading correct we will need to replicate every controller for each version of the api. How would this even scale with foreman version 1.60? Are we going to have 10 different versions of each controller? Seems kinda crazy. > > Hi, > > If the old versions are depreciated and removed later, one don't have > to keep so many versions. But having at least two versions (old and > new) seems quite useful, giving the user time for save migration of > their scripts to the new one. > > -- Ivan

> Seems like a lot of work on top of the fact that will still need to use view
> templates.
>
>
>
> I watched this and it appears that is very similar to the flying sphinx
> article if not better.
> http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true
>
> If I am reading correct we will need to replicate every controller for each
> version of the api. How would this even scale with foreman version 1.60?
> Are we going to have 10 different versions of each controller? Seems kinda
> crazy.

I haven't reviewed the links, I'm thinking we only need to cut a new
API version when we make a backward incompatible change. IE: If someone
is pinned to an API version we can extend it, and add features to it
without cutting a new version, if we don't break their existing
integrations. Does that change the work?

··· On Mon, Jun 4, 2012 at 3:22 AM, Corey Osman wrote:

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

On Jun 3, 2012, at 11:50 PM, Ohad Levy wrote:

On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman corey@logicminds.biz wrote:

I started playing around with RABL and here is what I came up with:

Support for versioning via case statement in new
views/bookmarks/index.rabl:

collection @bookmarks, :root => “bookmarks”

case params[:apiversion]
when "0.4"
attributes :id
else

default ‘current’ api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4

{“bookmarks”:[{“bookmark”:{“id”:2}},{“bookmark”:{“id”:5}},{“bookmark”:{“id”:4}},{“bookmark”:{“id”:1}},{“bookmark”:{“id”:3}}]}

http://192.168.1.46:3000/bookmarks.json

{“bookmarks”:[{“bookmark”:{“id”:2,“name”:“active”,“query”:“last_report >
“35 minutes ago” and (status.applied > 0 or status.restarted >
0)”}},{“bookmark”:{“id”:5,“name”:“disabled”,“query”:“status.enabled =
false”}},{“bookmark”:{“id”:4,“name”:“error”,“query”:“last_report > “35
minutes ago” and (status.failed > 0 or status.failed_restarts > 0 or
status.skipped >
0)”}},{“bookmark”:{“id”:1,“name”:“eventful”,“query”:“eventful =
true”}},{“bookmark”:{“id”:3,“name”:“out of sync”,“query”:“last_report < “30
minutes ago” and status.enabled = true”}}]}

Its trivial to get this working. Took about 5 minutes. I haven’t found a
way to list all attributes but I have a feeling it will not be necessary in
most cases.

I agree that it pretty easy writing down the controllers themself.

I was wondering what you were thinking about the following approach
http://freelancing-gods.com/posts/versioning_your_ap_is for api namespace
and versioning.

I also think that its probably better to have separate classes for the API
(per version) in the long run.

Ohad

Attached is a patch to implement what I coded already. I don’t expect it
to be merged into develop but just to serve as an example.

I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our
api code for a new version we can just create a new case to support the
previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb
b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl
b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb
    b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

It appears we have a plan then.

  1. JSON serialization via RABL at the view layer
  2. Versioning via this method: http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true
  3. API Documentation for each version of the controller via restapi

If were all in agreement about this plan I can kickstart the "new" api by finishing up the bookmarks controller using the plan above. Then we can tackle a new controller as time permits.

Anybody wanting to use the new api method would have to call http://oreman/api/hosts.json (assuming version string is added to the header). Otherwise the old api call would still be available.

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

··· On Jun 4, 2012, at 2:03 AM, iNecas wrote:

Old controllers could also be shared until new version requires a
change. So the only true replication would at the routes.rb level,
which is not so bad, since problem with replication comes when you
need to change something. But since the old API version is not going
to change, it doesn’t hurt so much.

– Ivan

On Jun 4, 9:52 am, iNecas neca...@gmail.com wrote:

On Jun 4, 9:22 am, Corey Osman co...@logicminds.biz wrote:

Seems like a lot of work on top of the fact that will still need to use view templates.

I watched this and it appears that is very similar to the flying sphinx article if not better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true

If I am reading correct we will need to replicate every controller for each version of the api. How would this even scale with foreman version 1.60? Are we going to have 10 different versions of each controller? Seems kinda crazy.

Hi,

If the old versions are depreciated and removed later, one don’t have
to keep so many versions. But having at least two versions (old and
new) seems quite useful, giving the user time for save migration of
their scripts to the new one.

– Ivan

> Seems like a lot of work on top of the fact that will still need to
> use view templates.
>
>
>
> I watched this and it appears that is very similar to the flying
> sphinx article if not better.
> http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true
>
> If I am reading correct we will need to replicate every controller for
> each version of the api. How would this even scale with foreman
> version 1.60? Are we going to have 10 different versions of each
> controller? Seems kinda crazy.
>
>
An API version isn't necessary the same as the API of the program. And
if it changes too much, we could deprecate some parts of the old API,
hence making a major version change of the API if we use semantic
versioning (we should).

>
> Corey Osman
> corey@logicminds.biz <mailto:corey@logicminds.biz>
>
> Green IT and Datacenter Automation Specialist
>
>
>
>
>
>>
>>
>>
>> I started playing around with RABL and here is what I came up with:
>>
>>
>> Support for versioning via case statement in new
>> views/bookmarks/index.rabl:
>>
>> collection @bookmarks, :root => "bookmarks"
>>
>> case params[:apiversion]
>> when "0.4"
>> attributes :id
>> else
>> # default 'current' api
>> attributes :id, :query, :name
>> end
>>
>> http://192.168.1.46:3000/bookmarks.json?apiversion=0.4
>>
>> {"bookmarks":[{"bookmark":{"id":2}},{"bookmark":{"id":5}},{"bookmark":{"id":4}},{"bookmark":{"id":1}},{"bookmark":{"id":3}}]}
>>
>> http://192.168.1.46:3000/bookmarks.json
>>
>> {"bookmarks":[{"bookmark":{"id":2,"name":"active","query":"last_report> &quot;35 minutes ago&quot; and (status.applied> 0 or status.restarted> 0)"}},{"bookmark":{"id":5,"name":"disabled","query":"status.enabled = false"}},{"bookmark":{"id":4,"name":"error","query":"last_report> &quot;35 minutes ago&quot; and (status.failed> 0 or status.failed_restarts> 0 or status.skipped> 0)"}},{"bookmark":{"id":1,"name":"eventful","query":"eventful = true"}},{"bookmark":{"id":3,"name":"out of sync","query":"last_report< &quot;30 minutes ago&quot; and status.enabled = true"}}]}
>>

I kind of like this behavior for some objects, but that inconsistent in
the current API.
Do you think it we could add some parameter to have the full objects
instead of just a few fields describing them in listings ?

>> Its trivial to get this working. Took about 5 minutes. I haven't found a way to list all attributes but I have a feeling it will not be necessary in most cases.
>>
>> I agree that it pretty easy writing down the controllers themself.
>>
>> I was wondering what you were thinking about the following approach
>> http://freelancing-gods.com/posts/versioning_your_ap_is for api
>> namespace and versioning.
>>
>> I also think that its probably better to have separate classes for
>> the API (per version) in the long run.
>>
>> Ohad
>>
>> Attached is a patch to implement what I coded already. I don't expect it to be merged into develop but just to serve as an example.
>>
>> I believe the apiversion could also be passed in the header.
>>
>> What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.
>>
>>
>> From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00
>> 2001 <tel:2001>
>> From: Corey Osman <corey@ogicminds.biz <mailto:corey@ogicminds.biz>>
>> Date: Mon, 30 Apr 2012 <tel:2012> 22:23:10 -0700
>> Subject: [PATCH] Added view based json renderering using rabl
>>
>> —
>> Gemfile | 2 ±
>> app/controllers/bookmarks_controller.rb | 5 +++±
>> app/views/bookmarks/index.rabl | 10 ++++++++++
>> config/initializers/rabl_init.rb | 19 +++++++++++++++++++
>> 4 files changed, 34 insertions(+), 2 deletions(-)
>> create mode 100644 app/views/bookmarks/index.rabl
>> create mode 100644 config/initializers/rabl_init.rb
>>
>> diff --git a/Gemfile b/Gemfile
>> index 1ab5b7c…bf5f789 100644
>> — a/Gemfile
>> +++ b/Gemfile
>> @@ -12,7 +12,7 @@ gem 'scoped_search', '>= 2.3.7'
>> gem 'net-ldap'
>> gem "safemode", "~> 1.0.1"
>> gem 'uuidtools'
>> -
>> +gem 'rabl'
>> local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
>> if File.file?(local_gemfile)
>> self.instance_eval(Bundler.read_file(local_gemfile))
>> diff --git a/app/controllers/bookmarks_controller.rb
>> b/app/controllers/bookmarks_controller.rb
>> index ba4a723…4bf1a68 100644
>> — a/app/controllers/bookmarks_controller.rb
>> +++ b/app/controllers/bookmarks_controller.rb
>> @@ -6,7 +6,10 @@ class BookmarksController < ApplicationController
>>
>> respond_to do |format|
>> format.html
>> - format.json { render :json => @bookmarks }
>> + # Before RAPL
>> + #format.json { render :json => @bookmarks }
>> + # After RAPL
>> + format.json
>> end
>> end
>>
>> diff --git a/app/views/bookmarks/index.rabl
>> b/app/views/bookmarks/index.rabl
>> new file mode 100644
>> index 0000000…aaa9827
>> — /dev/null
>> +++ b/app/views/bookmarks/index.rabl
>> @@ -0,0 +1,10 @@
>> +collection @bookmarks, :root => "bookmarks"
>> +
>> +
>> +case params[:apiversion]
>> + when "0.4"
>> + attributes :id
>> + else
>> + # default 'current' api
>> + attributes :id, :query, :name
>> + end
>> diff --git a/config/initializers/rabl_init.rb
>> b/config/initializers/rabl_init.rb
>> new file mode 100644
>> index 0000000…96df777
>> — /dev/null
>> +++ b/config/initializers/rabl_init.rb
>> @@ -0,0 +1,19 @@
>> +# config/initializers/rabl_init.rb
>> +Rabl.configure do |config|
>> + # Commented as these are defaults
>> + # config.cache_all_output = false
>> + # config.cache_sources = false
>> + # config.escape_all_output = false
>> + # config.json_engine = nil # Any multi_json engines
>> + # config.msgpack_engine = nil # Defaults to ::MessagePack
>> + # config.bson_engine = nil # Defaults to ::BSON
>> + # config.plist_engine = nil # Defaults to ::Plist::Emit
>> + config.include_json_root = true
>> + # config.include_msgpack_root = true
>> + # config.include_bson_root = true
>> + # config.include_plist_root = true
>> + # config.include_xml_root = false
>> + # config.enable_json_callbacks = false
>> + # config.xml_options = { :dasherize => true, :skip_types =>
>> false }
>> + # config.view_paths = []
>> +end
>> –
>> 1.7.1
>>
>>
>>
>> Corey Osman
>> corey@logicminds.biz <mailto:corey@logicminds.biz>
>> 678-348-0582 (Pacific Time)
>>
>> Green IT and Datacenter Automation Specialist
>>
>>
>>
>>
>>
>

Florent Castelli
Software engineer

··· On 04/06/2012 09:22, Corey Osman wrote: > On Jun 3, 2012, at 11:50 PM, Ohad Levy wrote: >> On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman > > wrote:

> Seems like a lot of work on top of the fact that will still need to use
> view templates.
>
>
>
> I watched this and it appears that is very similar to the flying sphinx
> article if not better.
> http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true
>
yes, this is the same approach it seems.

>
> If I am reading correct we will need to replicate every controller for
> each version of the api. How would this even scale with foreman version
> 1.60? Are we going to have 10 different versions of each controller?
> Seems kinda crazy.
>
no, I dont think we would support so many different versions at the same
time, no one said that API version has to match each release of foreman.

but it does seems like the right way forward, I'll read more about rabl.

thanks!
Ohad

··· On Mon, Jun 4, 2012 at 10:22 AM, Corey Osman wrote:

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

On Jun 3, 2012, at 11:50 PM, Ohad Levy wrote:

On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman corey@logicminds.biz wrote:

I started playing around with RABL and here is what I came up with:

Support for versioning via case statement in new
views/bookmarks/index.rabl:

collection @bookmarks, :root => “bookmarks”

case params[:apiversion]
when "0.4"
attributes :id
else

default ‘current’ api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4

{“bookmarks”:[{“bookmark”:{“id”:2}},{“bookmark”:{“id”:5}},{“bookmark”:{“id”:4}},{“bookmark”:{“id”:1}},{“bookmark”:{“id”:3}}]}

http://192.168.1.46:3000/bookmarks.json

{“bookmarks”:[{“bookmark”:{“id”:2,“name”:“active”,“query”:“last_report > “35 minutes ago” and (status.applied > 0 or status.restarted > 0)”}},{“bookmark”:{“id”:5,“name”:“disabled”,“query”:“status.enabled = false”}},{“bookmark”:{“id”:4,“name”:“error”,“query”:“last_report > “35 minutes ago” and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)”}},{“bookmark”:{“id”:1,“name”:“eventful”,“query”:“eventful = true”}},{“bookmark”:{“id”:3,“name”:“out of sync”,“query”:“last_report < “30 minutes ago” and status.enabled = true”}}]}

Its trivial to get this working. Took about 5 minutes. I haven’t found a way to list all attributes but I have a feeling it will not be necessary in most cases.

I agree that it pretty easy writing down the controllers themself.

I was wondering what you were thinking about the following approach
http://freelancing-gods.com/posts/versioning_your_ap_is for api namespace
and versioning.

I also think that its probably better to have separate classes for the API
(per version) in the long run.

Ohad

Attached is a patch to implement what I coded already. I don’t expect it to be merged into develop but just to serve as an example.

I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb
b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl
b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb
    b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

>
>
>
>> I started playing around with RABL and here is what I came up with:
>>
>>
> Rabl looks really powerful, and it looks like it might fit our
> requirements, I think we should give this a try.
>
> what I would like to have is both
> 1. api versioning
> 2. rabl views
> 3. auto generated documentation
>
> thinking of this a bit further, it seems like we would have all of the
info to generate dynamically ruby binding to the api, what do you guys
think?

Ohad

··· On Mon, Jun 4, 2012 at 11:01 AM, Ohad Levy wrote: > On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman wrote:

@Inecas do you see any conflict between 2 and 3 ?

thanks!
Ohad

Support for versioning via case statement in new
views/bookmarks/index.rabl:

collection @bookmarks, :root => “bookmarks”

case params[:apiversion]
when "0.4"
attributes :id
else

default ‘current’ api

attributes :id, :query, :name
end

http://192.168.1.46:3000/bookmarks.json?apiversion=0.4

{“bookmarks”:[{“bookmark”:{“id”:2}},{“bookmark”:{“id”:5}},{“bookmark”:{“id”:4}},{“bookmark”:{“id”:1}},{“bookmark”:{“id”:3}}]}

http://192.168.1.46:3000/bookmarks.json

{“bookmarks”:[{“bookmark”:{“id”:2,“name”:“active”,“query”:“last_report > “35 minutes ago” and (status.applied > 0 or status.restarted > 0)”}},{“bookmark”:{“id”:5,“name”:“disabled”,“query”:“status.enabled = false”}},{“bookmark”:{“id”:4,“name”:“error”,“query”:“last_report > “35 minutes ago” and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)”}},{“bookmark”:{“id”:1,“name”:“eventful”,“query”:“eventful = true”}},{“bookmark”:{“id”:3,“name”:“out of sync”,“query”:“last_report < “30 minutes ago” and status.enabled = true”}}]}

Its trivial to get this working. Took about 5 minutes. I haven’t found a way to list all attributes but I have a feeling it will not be necessary in most cases.

Attached is a patch to implement what I coded already. I don’t expect it to be merged into develop but just to serve as an example.

I believe the apiversion could also be passed in the header.

What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version.

From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 00:00:00 2001
From: Corey Osman corey@ogicminds.biz
Date: Mon, 30 Apr 2012 22:23:10 -0700
Subject: [PATCH] Added view based json renderering using rabl


Gemfile | 2 ±
app/controllers/bookmarks_controller.rb | 5 +++±
app/views/bookmarks/index.rabl | 10 ++++++++++
config/initializers/rabl_init.rb | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 app/views/bookmarks/index.rabl
create mode 100644 config/initializers/rabl_init.rb

diff --git a/Gemfile b/Gemfile
index 1ab5b7c…bf5f789 100644
— a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem ‘scoped_search’, '>= 2.3.7’
gem 'net-ldap’
gem “safemode”, "~> 1.0.1"
gem ‘uuidtools’

+gem 'rabl’
local_gemfile = File.dirname(FILE) + "/Gemfile.local.rb"
if File.file?(local_gemfile)
self.instance_eval(Bundler.read_file(local_gemfile))
diff --git a/app/controllers/bookmarks_controller.rb
b/app/controllers/bookmarks_controller.rb
index ba4a723…4bf1a68 100644
— a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -6,7 +6,10 @@ class BookmarksController < ApplicationController

respond_to do |format|
  format.html
  •  format.json { render :json => @bookmarks }
    
  •  # Before RAPL
    
  •  #format.json { render :json => @bookmarks }
    
  •  # After RAPL
    
  •  format.json
    
    end
    end

diff --git a/app/views/bookmarks/index.rabl
b/app/views/bookmarks/index.rabl
new file mode 100644
index 0000000…aaa9827
— /dev/null
+++ b/app/views/bookmarks/index.rabl
@@ -0,0 +1,10 @@
+collection @bookmarks, :root => “bookmarks”
+
+
+case params[:apiversion]

  • when “0.4”
  • attributes :id
  • else
  • default ‘current’ api

  • attributes :id, :query, :name
  • end
    diff --git a/config/initializers/rabl_init.rb
    b/config/initializers/rabl_init.rb
    new file mode 100644
    index 0000000…96df777
    — /dev/null
    +++ b/config/initializers/rabl_init.rb
    @@ -0,0 +1,19 @@
    +# config/initializers/rabl_init.rb
    +Rabl.configure do |config|
  • Commented as these are defaults

  • config.cache_all_output = false

  • config.cache_sources = false

  • config.escape_all_output = false

  • config.json_engine = nil # Any multi_json engines

  • config.msgpack_engine = nil # Defaults to ::MessagePack

  • config.bson_engine = nil # Defaults to ::BSON

  • config.plist_engine = nil # Defaults to ::Plist::Emit

  • config.include_json_root = true
  • config.include_msgpack_root = true

  • config.include_bson_root = true

  • config.include_plist_root = true

  • config.include_xml_root = false

  • config.enable_json_callbacks = false

  • config.xml_options = { :dasherize => true, :skip_types => false }

  • config.view_paths = []

+end

1.7.1

Corey Osman
corey@logicminds.biz
678-348-0582 (Pacific Time)

Green IT and Datacenter Automation Specialist

Are we dropping YAML? RABL seems to only support JSON and XLM?

Thanks,
Brian

··· On Mon, Jun 4, 2012 at 12:33 PM, Corey Osman wrote: > It appears we have a plan then. > > 1. JSON serialization via RABL at the view layer > 2. Versioning via this > method: http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true > 3. API Documentation for each version of the controller via restapi > > > If were all in agreement about this plan I can kickstart the "new" api by > finishing up the bookmarks controller using the plan above. Then we can > tackle a new controller as time permits. > > Anybody wanting to use the new api method would have to call > http://oreman/api/hosts.json (assuming version string is added to the > header). Otherwise the old api call would still be available. > > > > Corey Osman > corey@logicminds.biz > > Green IT and Datacenter Automation Specialist > > > > > On Jun 4, 2012, at 2:03 AM, iNecas wrote: > > Old controllers could also be shared until new version requires a > change. So the only true replication would at the routes.rb level, > which is not so bad, since problem with replication comes when you > need to change something. But since the old API version is not going > to change, it doesn't hurt so much. > > -- Ivan > > On Jun 4, 9:52 am, iNecas wrote: > > On Jun 4, 9:22 am, Corey Osman wrote: > > > Seems like a lot of work on top of the fact that will still need to use view > templates. > > > I watched this and it appears that is very similar to the flying sphinx > article if not > better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true > > > If I am reading correct we will need to replicate every controller for each > version of the api. How would this even scale with foreman version 1.60? > Are we going to have 10 different versions of each controller? Seems kinda > crazy. > > > Hi, > > > If the old versions are depreciated and removed later, one don't have > > to keep so many versions. But having at least two versions (old and > > new) seems quite useful, giving the user time for save migration of > > their scripts to the new one. > > > -- Ivan > >

Brain,

Afaik, YAML would still be supported. RABL just makes it easier for JSON/XML. Whatever method foreman currently uses for YAML output will still be the same going forward unless RABL adds YAML support.

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

··· On Jun 4, 2012, at 9:48 AM, Brian Gupta wrote:

Are we dropping YAML? RABL seems to only support JSON and XLM?

Thanks,
Brian

On Mon, Jun 4, 2012 at 12:33 PM, Corey Osman corey@logicminds.biz wrote:

It appears we have a plan then.

  1. JSON serialization via RABL at the view layer
  2. Versioning via this
    method: http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true
  3. API Documentation for each version of the controller via restapi

If were all in agreement about this plan I can kickstart the “new” api by
finishing up the bookmarks controller using the plan above. Then we can
tackle a new controller as time permits.

Anybody wanting to use the new api method would have to call
http://oreman/api/hosts.json (assuming version string is added to the
header). Otherwise the old api call would still be available.

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

On Jun 4, 2012, at 2:03 AM, iNecas wrote:

Old controllers could also be shared until new version requires a
change. So the only true replication would at the routes.rb level,
which is not so bad, since problem with replication comes when you
need to change something. But since the old API version is not going
to change, it doesn’t hurt so much.

– Ivan

On Jun 4, 9:52 am, iNecas neca...@gmail.com wrote:

On Jun 4, 9:22 am, Corey Osman co...@logicminds.biz wrote:

Seems like a lot of work on top of the fact that will still need to use view
templates.

I watched this and it appears that is very similar to the flying sphinx
article if not
better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true

If I am reading correct we will need to replicate every controller for each
version of the api. How would this even scale with foreman version 1.60?
Are we going to have 10 different versions of each controller? Seems kinda
crazy.

Hi,

If the old versions are depreciated and removed later, one don’t have

to keep so many versions. But having at least two versions (old and

new) seems quite useful, giving the user time for save migration of

their scripts to the new one.

– Ivan

>
>
>
>
>
>
> I started playing around with RABL and here is what I came up
> with:
>
>
> Rabl looks really powerful, and it looks like it might fit our
> requirements, I think we should give this a try.
>
> what I would like to have is both
> 1. api versioning
> 2. rabl views
> 3. auto generated documentation
>
> thinking of this a bit further, it seems like we would have all of the
> info to generate dynamically ruby binding to the api, what do you guys
> think?
>
> Ohad
>
> @Inecas do you see any conflict between 2 and 3 ?
>
2 and 3 doesn't conflict at all. The rails-restapi tool is more about
describing the intputs (verb, path and params) and it relies on examples
for the description of the response. Rabl completes this. There would be
also possible to use that dsl Rabl use to reuse it for documentation
purposes as well.

– Ivan

··· On 06/04/2012 10:14 AM, Ohad Levy wrote: > On Mon, Jun 4, 2012 at 11:01 AM, Ohad Levy > wrote: > On Mon, Jun 4, 2012 at 4:49 AM, Corey Osman > <corey@logicminds.biz > wrote: > > > thanks! > Ohad > > > Support for versioning via case statement in new > views/bookmarks/index.rabl: > > collection @bookmarks, :root => "bookmarks" > > case params[:apiversion] > when "0.4" > attributes :id > else > # default 'current' api > attributes :id, :query, :name > end > > http://192.168.1.46:3000/bookmarks.json?apiversion=0.4 > > {"bookmarks":[{"bookmark":{"id":2}},{"bookmark":{"id":5}},{"bookmark":{"id":4}},{"bookmark":{"id":1}},{"bookmark":{"id":3}}]} > > http://192.168.1.46:3000/bookmarks.json > > {"bookmarks":[{"bookmark":{"id":2,"name":"active","query":"last_report> \"35 minutes ago\" and (status.applied> 0 or status.restarted> 0)"}},{"bookmark":{"id":5,"name":"disabled","query":"status.enabled = false"}},{"bookmark":{"id":4,"name":"error","query":"last_report> \"35 minutes ago\" and (status.failed> 0 or status.failed_restarts> 0 or status.skipped> 0)"}},{"bookmark":{"id":1,"name":"eventful","query":"eventful = true"}},{"bookmark":{"id":3,"name":"out of sync","query":"last_report< \"30 minutes ago\" and status.enabled = true"}}]} > > Its trivial to get this working. Took about 5 minutes. I haven't found a way to list all attributes but I have a feeling it will not be necessary in most cases. > > Attached is a patch to implement what I coded already. I don't expect it to be merged into develop but just to serve as an example. > > I believe the apiversion could also be passed in the header. > > What do you guys think? Seems easy enough. Anytime we have to fork our api code for a new version we can just create a new case to support the previous version. > > > From 1a563e39c566d6e8bdbdbd12cb480df90ff2dfff Mon Sep 17 > 00:00:00 2001 > From: Corey Osman > > Date: Mon, 30 Apr 2012 22:23:10 -0700 > Subject: [PATCH] Added view based json renderering using rabl > > --- > Gemfile | 2 +- > app/controllers/bookmarks_controller.rb | 5 ++++- > app/views/bookmarks/index.rabl | 10 ++++++++++ > config/initializers/rabl_init.rb | 19 +++++++++++++++++++ > 4 files changed, 34 insertions(+), 2 deletions(-) > create mode 100644 app/views/bookmarks/index.rabl > create mode 100644 config/initializers/rabl_init.rb > > diff --git a/Gemfile b/Gemfile > index 1ab5b7c..bf5f789 100644 > --- a/Gemfile > +++ b/Gemfile > @@ -12,7 +12,7 @@ gem 'scoped_search', '>= 2.3.7' > gem 'net-ldap' > gem "safemode", "~> 1.0.1" > gem 'uuidtools' > - > +gem 'rabl' > local_gemfile = File.dirname(__FILE__) + "/Gemfile.local.rb" > if File.file?(local_gemfile) > self.instance_eval(Bundler.read_file(local_gemfile)) > diff --git a/app/controllers/bookmarks_controller.rb > b/app/controllers/bookmarks_controller.rb > index ba4a723..4bf1a68 100644 > --- a/app/controllers/bookmarks_controller.rb > +++ b/app/controllers/bookmarks_controller.rb > @@ -6,7 +6,10 @@ class BookmarksController < ApplicationController > > respond_to do |format| > format.html > - format.json { render :json => @bookmarks } > + # Before RAPL > + #format.json { render :json => @bookmarks } > + # After RAPL > + format.json > end > end > > diff --git a/app/views/bookmarks/index.rabl > b/app/views/bookmarks/index.rabl > new file mode 100644 > index 0000000..aaa9827 > --- /dev/null > +++ b/app/views/bookmarks/index.rabl > @@ -0,0 +1,10 @@ > +collection @bookmarks, :root => "bookmarks" > + > + > +case params[:apiversion] > + when "0.4" > + attributes :id > + else > + # default 'current' api > + attributes :id, :query, :name > + end > diff --git a/config/initializers/rabl_init.rb > b/config/initializers/rabl_init.rb > new file mode 100644 > index 0000000..96df777 > --- /dev/null > +++ b/config/initializers/rabl_init.rb > @@ -0,0 +1,19 @@ > +# config/initializers/rabl_init.rb > +Rabl.configure do |config| > + # Commented as these are defaults > + # config.cache_all_output = false > + # config.cache_sources = false > + # config.escape_all_output = false > + # config.json_engine = nil # Any multi\_json engines > + # config.msgpack_engine = nil # Defaults to ::MessagePack > + # config.bson_engine = nil # Defaults to ::BSON > + # config.plist_engine = nil # Defaults to ::Plist::Emit > + config.include_json_root = true > + # config.include_msgpack_root = true > + # config.include_bson_root = true > + # config.include_plist_root = true > + # config.include_xml_root = false > + # config.enable_json_callbacks = false > + # config.xml_options = { :dasherize => true, :skip_types > => false } > + # config.view_paths = [] > +end > -- > 1.7.1 > > > > Corey Osman > corey@logicminds.biz > 678-348-0582 (Pacific Time) > > Green IT and Datacenter Automation Specialist > > > > > >

I've pushed an api branch to my github as a basic structure that supports

  1. api versioning
  2. rabl support
  3. 'auto discovery'

the 3 options is aimed towards the api being able to tell you what are the
possible actions from any given point.

for example, if you query the root of the api - get /api
{
"Links": {
"bookmarks": "/api/bookmarks",
"status": "/api/status"
}
}

then you could query /api/status or /api/bookmarks

then when querying /api/bookmarks you would get
[
{
"bookmark": {
"id": 6,
"public": true,
"name": "build",
"edit_url": "http://0.0.0.0:3000/bookmarks/build/edit",
"user": {
"name": "Admin User",
"login": "admin",
"email": "root@tlv.redhat.com"
},
"controller": "hosts",
"query": "build = false"
}
},
{
"bookmark": {
"id": 5,
"public": true,

we could extend this a lot, and this could help a lot with users who

  1. dont know the api
  2. client side implementations that can relay on asking foreman rather then
    hardcoding the possible options.

what do you think?

Ohad

··· On Mon, Jun 4, 2012 at 8:33 PM, Corey Osman wrote:

Brain,

Afaik, YAML would still be supported. RABL just makes it easier for
JSON/XML. Whatever method foreman currently uses for YAML output will
still be the same going forward unless RABL adds YAML support.

Corey Osman
corey@logicminds.biz

Green IT and Datacenter Automation Specialist

On Jun 4, 2012, at 9:48 AM, Brian Gupta wrote:

Are we dropping YAML? RABL seems to only support JSON and XLM?

Thanks,
Brian

On Mon, Jun 4, 2012 at 12:33 PM, Corey Osman corey@logicminds.biz wrote:

It appears we have a plan then.

  1. JSON serialization via RABL at the view layer

  2. Versioning via this

method:
http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true

  1. API Documentation for each version of the controller via restapi

If were all in agreement about this plan I can kickstart the “new” api by

finishing up the bookmarks controller using the plan above. Then we can

tackle a new controller as time permits.

Anybody wanting to use the new api method would have to call

http://oreman/api/hosts.json (assuming version string is added to the

header). Otherwise the old api call would still be available.

Corey Osman

corey@logicminds.biz

Green IT and Datacenter Automation Specialist

On Jun 4, 2012, at 2:03 AM, iNecas wrote:

Old controllers could also be shared until new version requires a

change. So the only true replication would at the routes.rb level,

which is not so bad, since problem with replication comes when you

need to change something. But since the old API version is not going

to change, it doesn’t hurt so much.

– Ivan

On Jun 4, 9:52 am, iNecas neca...@gmail.com wrote:

On Jun 4, 9:22 am, Corey Osman co...@logicminds.biz wrote:

Seems like a lot of work on top of the fact that will still need to use
view

templates.

I watched this and it appears that is very similar to the flying sphinx

article if not

better.http://railscasts.com/episodes/350-rest-api-versioning?autoplay=true

If I am reading correct we will need to replicate every controller for each

version of the api. How would this even scale with foreman version 1.60?

Are we going to have 10 different versions of each controller? Seems
kinda

crazy.

Hi,

If the old versions are depreciated and removed later, one don’t have

to keep so many versions. But having at least two versions (old and

new) seems quite useful, giving the user time for save migration of

their scripts to the new one.

– Ivan