Ananke¶ ↑
Ananke is a DSL that extends the functionality of Sinatra for easy creation of Restful Services and Resources:
#myapp.rb require 'sinatra/base' require 'sinatra/ananke' resource :user do all do [{:id => ] end end
Install the gem and run with:
gem install ananke ruby myapp.rb
All Users
http://localhost:4567/user
One User
http://localhost:4567/user/1
REST Resources¶ ↑
‘route` defines a complete Resource, and constructs Sinatra Routes based on what’s available in it’s respective Repository. Routes are:
get '/name/?' -> Repository::Capitalize(name).all get '/name/id' -> Repository::Capitalize(name).one(id) post '/name' -> Repository::Capitalize(name).new(data) put '/name/id' -> Repository::Capitalize(name).edit(id, data) delete '/name/id' -> Repository::Capitalize(name).delete(id)
Repositories¶ ↑
The Default Repository can be changed:
ananke.default_repository = 'MyRepository'
HyperMedia¶ ↑
Linked¶ ↑
route :user do id :id linked :computer end module Repository module User def self.one(id) [Return User for User Id] end def self.computer_id_list(id) [Return an array of single value id's] end end end
Repository Method:
[ResourceRepository].[linked name]_id_list
Routes Available/Registered:
/user/:id
Output:
{ user: { user_id: "1" name: "One" } links: [ { rel: "self" uri: "/user/1" }, { rel: "computer" uri: "/computer/2" } ] }
The Respository for User needs to have a method that returns an array of id’s for use in the HyperMedia links. The link to Self uses this method. The output will be something like this:
Link To and Route For¶ ↑
route :user do id :id link_to :car end route :car do id :id route_for :user end module Repository module User def self.one(id) [Return User for User Id] end end module Car def self.user(id) [Return List of Cars for User Id] end end end
Routes Available/Registered:
/user/:id /car/user/:id
Output:
{ user: { user_id: "1" name: "One" } links: [ { rel: "self" uri: "/user/1" }, { rel: "computer" uri: "/computer/user/1" } ] }
This way of linking solves a lot of problems, and can also be used for searching support. route_for supports an optional 2nd parameter to specify the type of request it must register for:
route :car do id :id route_for :user, :post end
The Called Repository can also have multiple input paramaters:
def some_method(id, name, email) ... end
will need an incoming Request with these paramaters:
id, name, email
Media Type¶ ↑
The REST media type can be built up:
required :name optional :country
Exposing the Media Type is on the cards.
Validation¶ ↑
Validation can be added on any field by providing arguments after a field declaration:
required :name, :length => 4
This will cause the paramater to be validated against the method defined in Ananke::Rules. Custom Rules can be added to the module and provided as arguments. Current Default included rules are:
length(min)
Validation Methods are Invoked in the Ananke::Rules context, and has access to a class variable named value, which holds the value for the currently valuated Parameter.
To Add a Custom Rule:
rule :name, do value == [expected] ? nil : 'Not Expected Value' end required :name, :name
or
module Ananke module Rules def validate_name value == [expected] ? nil : 'Not Expected Value' end end end required :name, :name
or Advanced
module Ananke module Rules def validate_name(extra) value == [expected using extra] ? nil : 'Not Expected Value' end end end required :name, :name => extra
Future¶ ↑
A short list of future development:
- Refactor! - Return Value Strategy - Resource Exposes Media Type - Lots more `bullet-proofing` - ETag Support