Skip to content

TalentBox/harpy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Harpy

Build Status Code Climate

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.