Created
July 24, 2012 21:52
-
-
Save steveklabnik/3172911 to your computer and use it in GitHub Desktop.
Hypermedia Proxy pattern in JSON
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is based on an idea from Jon Moore. | |
# see https://gist.github.com/1478637 for his original XHTML version | |
require 'net/http' | |
require 'open-uri' | |
require 'json' | |
require 'pp' | |
# A simple get request should not require this much boilerplate. | |
def fetch_data(uri) | |
uri = URI(uri) | |
req = Net::HTTP::Get.new(uri.request_uri) | |
# we should really be using a json profile, but I didn't bother for this simple example. | |
req['Accept'] = "application/json" | |
res = Net::HTTP.start(uri.host, uri.port) {|http| | |
http.request(req) | |
} | |
JSON.parse(res.body) | |
end | |
class Status | |
attr_accessor :self_rel, :id | |
def initialize(opts={}) | |
@id = opts['id'] | |
@name = opts['name'] | |
@self_rel = opts['links'].find{|link| link['rel'] == "self"}['href'] | |
end | |
def name | |
@name || begin | |
fetch_data(self_rel)['name'] | |
end | |
end | |
end | |
puts "getting partial representation" | |
# this will make 4 queries: one for the root, and one for each status | |
data = fetch_data("http://localhost:9292/partial") | |
statuses = data.collect {|datum| Status.new(datum) } | |
statuses.each do |status| | |
puts status.name | |
end | |
puts "getting full representation" | |
# this will make one query: one for the root | |
data = fetch_data("http://localhost:9292/full") | |
statuses = data.collect {|datum| Status.new(datum) } | |
statuses.each do |status| | |
puts status.name | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'bundler' | |
Bundler.require | |
require './hypermedia_proxy_pattern' | |
run HypermediaProxyPattern |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source :rubygems | |
gem 'sinatra' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HypermediaProxyPattern < Sinatra::Base | |
enable :inline_templates | |
get '/' do | |
erb :index | |
end | |
get '/full' do | |
content_type 'application/json' | |
erb :full | |
end | |
get '/partial' do | |
content_type 'application/json' | |
erb :partial | |
end | |
get '/status/:id' do | |
content_type 'application/json' | |
@id = params[:id] | |
erb :status | |
end | |
end | |
__END__ | |
@@ index | |
Hello, world! | |
@@ full | |
[ | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/1" | |
} | |
], | |
"id": 1, | |
"name": "name1" | |
}, | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/2" | |
} | |
], | |
"id": 2, | |
"name": "name2" | |
}, | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/3" | |
} | |
], | |
"id": 3, | |
"name": "name3" | |
} | |
] | |
@@ partial | |
[ | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/1" | |
} | |
], | |
"id": 1 | |
}, | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/2" | |
} | |
], | |
"id": 2 | |
}, | |
{ | |
"links": [ | |
{ | |
"rel": "self", | |
"href": "http://localhost:9292/status/3" | |
} | |
], | |
"id": 3 | |
} | |
] | |
@@ status | |
{ | |
"links":[ | |
{"rel":"self", "href":"http://<%= request.host %>:<%= request.port %>/status/3"} | |
], | |
"id":<%= @id %>, | |
"name":"name<%= @id %>" | |
} |
Neat!
A simple get request should not require this much boilerplate.
The net APIs have always felt kinds gross and Java-ish to me. Well, not as gross as Java, but... they could be so much more elegant. Which is why I always end up writing wrappers for Net::HTTP if I'm not using a gem that abstracts it.
Totally. I wanted to keep as few deps as possible.
What, you don't want include HTTParty
in ALL THE THINGS? 😃
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The next.soundcloud.com backbone.js front end follows the same pattern.