README.md
Harpy
======
[![Build Status](https://travis-ci.org/TalentBox/harpy.png?branch=master)](https://travis-ci.org/TalentBox/harpy)
[![Code Climate](https://codeclimate.com/github/TalentBox/harpy.png)](https://codeclimate.com/github/TalentBox/harpy)
Client for REST API with HATEOAS
Dependencies
------------
* Ruby >= 2.4.
* gem "typhoeus", ">= 0.6.5"
* gem "activesupport", ">= 5.2.0"
* gem "activemodel", ">= 5.2.0"
* gem "hash-deep-merge", ">= 0.1.1"
Usage
-----
* Set entry_point url:
Harpy.entry_point_url = "http://localhost"
* Include `Harpy::Resource` in your model:
class MyModel
include Harpy::Resource
end
# Mass assignment
model = MyModel.new "firstname" => "Anthony", "lastname" => "Stark"
model.attributes = {"company" => "Stark Enterprises"}
model.firstname # => "Anthony"
model.company # => "Stark Enterprises"
# Because model is not persisted you can read any attribute, allowing
# to use form_for on new resources to which the client doesn't know the
# existing attributes yet
model.email # => nil
# Fetch by url
MyModel.from_url "http://localhost/mymodel/1"
# => instance of MyModel with attributes filled in on 200
# => nil on 404
# => raises Harpy::ClientTimeout on timeout
# => raises Harpy::ClientError on Curl error
# => raises Harpy::InvalidResponseCode on other response codes
# Fetch multiple by url in parallel
MyModel.from_url ["http://localhost/mymodel/1", "http://localhost/mymodel/2"]
# Get index
MyModel.search
# will call GET http://localhost/mymodel given the following entry_point response:
{
"link": [
{"rel": "my_model", "href": "http://localhost/mymodel"}
]
}
# => return an array of MyModel instances on 200
# => raises Harpy::ClientTimeout on timeout
# => raises Harpy::ClientError on Curl error
# => raises Harpy::InvalidResponseCode on other response codes
# Search by first_name
MyModel.search :firstname => "Anthony" # GET http://localhost/mymodel?firstname=Anthony
# Create (POST)
model = MyModel.new "firstname" => "Anthony"
model.save # POST http://localhost/mymodel with {"firstname":"Anthony"}
# Get an existing resource by url:
model = MyModel.from_url "http://localhost/mymodel/1"
# if the service returns the following response:
{
"firstname": "Anthony",
"lastname": null,
"urn": "urn:mycompany:mymodel:1"
"link" => [
{"rel" => "self", "href" => "http://localhost/mymodel/1"},
{"rel" => "accounts", "href" => "http://localhost/mymodel/1/accounts"}
]
}
# we can then do:
model.firstname # => "Anthony"
model.link "self" # => "http://localhost/mymodel/1"
model.link :accounts # => "http://localhost/mymodel/1/accounts"
# Update (PUT) requires resource to have both urn and link to self
model.attributes = {"firstname" => "Tony"}
model.save # PUT http://localhost/mymodel/1
# The resource is persisted once it has an urn:
model.persisted? # => true
# If persisted you can no longer read undefined attributes:
model.lastname # => nil
model.email # => will raise NoMethodError
* To find a resource by id you need to define `.urn`:
class MyModel
include Harpy::Resource
def self.urn(id)
"urn:mycompany:mymodel:#{id}"
end
end
model = MyModel.from_id 1 # will GET http://localhost/urn:mycompany:mymodel:1
# expecting a permanent redirect (301) to follow or not found (404)
* Rel name to search for in entry_point when getting index can be overridden:
class MyCustomModel
include Harpy::Resource
def self.resource_name
"custom_model"
end
end
* or you can use `.with_url(url)` for getting index of nested resources:
class Account
include Harpy::Resource
def users
User.with_url(link "user") do
User.search
end
end
end
class User
include Harpy::Resource
end
* you can override `#url_collection` to create nested resources:
class Account
include Harpy::Resource
end
class User
include Harpy::Resource
attr_accessor :account
def url_collection
account ? account.link("user") : super
end
end
* Fetch multiple resources in parallel:
class FirstModel
include Harpy::Resource
end
class SecondModel
include Harpy::Resource
end
Harpy::Resource.from_url({
FirstModel => ["http://localhost/firstmodel/1", "http://localhost/firstmodel/2"],
SecondModel => ["http://localhost/secondmodel/1"],
})
# => {FirstModel => [...], SecondModel => [...]}
License
-------
harpy is Copyright © 2011 TalentBox SA. It is free software, and may be redistributed under the terms specified in the LICENSE file.