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