Created
January 30, 2015 15:49
-
-
Save eterps/88746530d7fd7c847146 to your computer and use it in GitHub Desktop.
REST/hypermedia webservice in Ruby using Webmachine, Webmachine linking and Roar for HAL/JSON support
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 'webmachine/adapters/rack' | |
require_relative 'webservice' | |
run Webservice.adapter |
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
Feature: Artists | |
Scenario: Get information about the artist Radiohead | |
Given these albums: | |
| artist | album | | |
| Radiohead | Pablo Honey | | |
| Radiohead | OK Computer | | |
When the client provides the header "Accept: application/hal+json" | |
And the client does a GET request to "/artist/Radiohead" | |
Then the response should be HAL JSON: | |
"""json | |
{ | |
"_links": { | |
"self": { | |
"href": "/artist/Radiohead" | |
}, | |
"albums": [ | |
{ | |
"href": "/album/Pablo Honey" | |
}, | |
{ | |
"href": "/album/OK Computer" | |
} | |
] | |
}, | |
"name": "Radiohead" | |
} | |
""" | |
Scenario: Add a new artist | |
Given the client provides the header "Content-Type: application/json" | |
When the client does a POST request to "/artists" with the following data: | |
"""json | |
{ | |
"name": "Led Zeppelin" | |
} | |
""" | |
Then the status code should be "201" (Created) | |
And the Location header should be "http://example.org/artist/Led Zeppelin" | |
And this artist should exist: | |
| name | | |
| Led Zeppelin | | |
Scenario: List all artists | |
Given the client provides the header "Accept: application/hal+json" | |
When the client does a GET request to "/artists" | |
Then the response should be HAL JSON: | |
"""json | |
{ | |
"_links": { | |
"self": { | |
"href": "/artists" | |
}, | |
"artists": [ | |
{ | |
"href": "/artist/Radiohead" | |
}, | |
{ | |
"href": "/artist/Led Zeppelin" | |
} | |
] | |
} | |
} | |
""" |
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 Artist | |
attr_accessor :name, :albums | |
def initialize(name: name, albums: albums) | |
@name, @albums = name, albums | |
end | |
end | |
class Album | |
attr_accessor :name | |
def initialize(name: name) | |
@name = name | |
end | |
end | |
module ArtistRepresenter | |
include Roar::JSON::HAL | |
include BaseRepresenter | |
links(:albums) {|n| rel n, :albums } | |
property :name | |
end | |
module ArtistsRepresenter | |
include Roar::JSON::HAL | |
include BaseRepresenter | |
links(:artists) {|n| rel n, :artists } | |
end | |
class ArtistResource < BaseResource | |
def relations | |
{ | |
self: {href: url_for(ArtistResource, name: @artist.name)}, | |
albums: @artist.albums.map{|n| {href: url_for(AlbumResource, name: n.name)}} | |
} | |
end | |
def resource_exists? | |
@artist = DB.artists.find{|n| n.name == request.path_info[:name]} | |
end | |
private | |
def to_json | |
@artist.extend(ArtistRepresenter).to_json(rel: relations) | |
end | |
end | |
class ArtistsResource < BaseResource | |
def relations | |
{ | |
self: {href: url_for(ArtistsResource)}, | |
artists: @artists.map{|n| {href: url_for(ArtistResource, name: n.name)}} | |
} | |
end | |
def resource_exists? | |
@artists = DB.artists | |
end | |
def finish_request | |
return unless request.method == 'POST' | |
response.headers['Location'] += url_for(ArtistResource, name: @artist.name)[1..-1] | |
end | |
def allowed_methods; %w(GET POST) end | |
def post_is_create?; true end | |
def create_path; '' end | |
private | |
def from_json | |
@artist = Artist.new | |
@artist.extend(ArtistRepresenter).from_json(request.body.to_s) | |
@artists << @artist | |
end | |
def to_json | |
extend(ArtistsRepresenter).to_json | |
end | |
end | |
class AlbumResource < BaseResource | |
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 'roar/json/hal' | |
require 'webmachine' | |
require 'webmachine-linking' | |
module BaseRepresenter | |
include Roar::JSON::HAL | |
def rel(rels, id) | |
return relations[id] unless rels.include?(:rel) | |
rels[:rel][id] | |
end | |
link(:self) {|n| rel n, :self } | |
end | |
class BaseResource < Webmachine::Resource | |
include Webmachine::Linking::Resource::LinkHelpers | |
def content_types_accepted; [['application/json', :from_json]] end | |
def content_types_provided; [['application/hal+json', :to_json]] end | |
end | |
module DB | |
class << self | |
attr_accessor :artists | |
def artists | |
@artists ||= [] | |
end | |
end | |
end | |
require_relative 'resources' | |
Webmachine.application.routes do | |
add ['artist', :name], ArtistResource | |
add ['album', :name], AlbumResource | |
add ['artists'], ArtistsResource | |
end | |
Webmachine.application.inject_resource_url_provider | |
Webservice = Webmachine.application |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment