• Stars
    star
    304
  • Rank 136,431 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 11 years ago
  • Updated about 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A self-inflating Ruby client for hypermedia APIs. Not under active development.

HyperResource Build Status

HyperResource is a Ruby client library for hypermedia web services.

HyperResource makes using a hypermedia API feel like calling plain old methods on plain old objects.

It is usable with no configuration other than API root endpoint, but also allows incoming data types to be extended with Ruby code.

HyperResource supports the HAL+JSON hypermedia format, with support for Siren and other hypermedia formats planned.

For more insight into HyperResource's goals and design, read the paper!

Hypermedia in a Nutshell

Hypermedia APIs return a list of hyperlinks with each response. These links, each of which has a relation name or "rel", represent everything you can do to, with, or from the given response. They are URLs which can take arguments. The consumer of the hypermedia API uses these links to access the API's entire functionality.

A primary advantage to hypermedia APIs is that a client library can write itself based on the hyperlinks coming back with each response. This removes both the chore of writing a custom client library in the first place, and also the process of pushing client updates to your users.

HyperResource Philosophy

An automatically-generated library can and should feel as comfortable as a custom client library. Hypermedia brings many promises, but this is one we can deliver on.

If you're an API user, HyperResource will help you consume a hypermedia API with short, direct, elegant code. If you're an API designer, HyperResource is a great default client, or a smart starting point for a rich SDK.

Link-driven APIs are the future, and proper tooling can make it The Jetsons instead of The Road Warrior.

Install It

Nothing special is required, just: gem install hyperresource

HyperResource works on Ruby 1.8.7 to present, and JRuby in 1.8 mode or above.

HyperResource uses the uri_template and Faraday gems.

Use It - Zero Configuration

Set up API connection:

api = HyperResource.new(root: 'https://api.example.com',
                        headers: {'Accept' => 'application/vnd.example.com.v1+json'},
                        auth: {basic: ['username', 'password']})
# => #<HyperResource:0xABCD1234 @root="https://api.example.com" @href="" @namespace=nil ... >

Now we can get the API's root resource, the gateway to everything else on the API.

api.get
# => #<HyperResource:0xABCD1234 @root="https://api.example.com" @href="" @namespace=nil ... >

What'd we get back?

api.body
# => { 'message' => 'Welcome to the Example.com API',
#      'version' => 1,
#      '_links' => {
#        'curies' => [{
#          'name' => 'example',
#          'templated' => true,
#          'href' => 'https://api.example.com/rels/{rel}'
#        }],
#        'self' => {'href' => '/'},
#        'example:users' => {'href' => '/users{?email,last_name}', 'templated' => true},
#        'example:forums' => {'href' => '/forums{?title}', 'templated' => true}
#      }
#    }

Lovely. Let's find a user by their email.

jdoe_user = api.users(email: "[email protected]").first
# => #<HyperResource:0x12312312 ...>

HyperResource has performed some behind-the-scenes expansions here.

First, the example:users link was added to the api object at the time the resource was loaded with api.get. And since the link rel has a CURIE prefix, HyperResource will allow a shortened version of its name, users.

Then, calling first on the users link followed the link and loaded it automatically.

Finally, calling first on the resource containing one set of embedded objects -- like this one -- delegates the method to .objects.first, which returns the first object in the resource.

Here are some equivalent expressions to the above. HyperResource offers a very short, expressive syntax as its primary interface, but you can always fall back to explicit syntax if you like or need to.

api.users(email: "[email protected]").first
api.get.users(email: "[email protected]").first
api.get.links.users(email: "[email protected]").first
api.get.links['users'].where(email: "[email protected]").first
api.get.links['users'].where(email: "[email protected]").get.first
api.get.links['users'].where(email: "[email protected]").get.objects.first[1][0]

Use It - ActiveResource-style

If an API is returning data type information as part of the response, then we can assign those data types to ruby classes so that they can be extended.

For example, in our hypothetical Example API above, a user object is returned with a custom media type bearing a 'type=User' modifier. We will extend the User class with a few convenience methods.

class ExampleAPI < HyperResource
  self.root = 'https://api.example.com'
  self.headers = {'Accept' => 'application/vnd.example.com.v1+json'}
  self.auth = {basic: ['username', 'password']}

  class User < ExampleAPI
    def full_name
      first_name + ' ' + last_name
    end
  end
end

api = ExampleApi.new

user = api.users.where(email: '[email protected]').first
# => #<ExampleApi::User:0xffffffff ...>

user.full_name
# => "John Doe"

Don't worry if your API uses some other mechanism to indicate resource data type; you can override the .get_data_type method and implement your own logic.

Configuration for Multiple Hosts

HyperResource supports the concept of different APIs connected in one ecosystem by providing a mechanism to scope configuration parameters by a URL mask. This allows a simple way to provide separate authentication, headers, etc. to different services which link to each other.

As a toy example, consider two servers. http://localhost:12345/ returns:

{ "name": "Server One",
  "_links": {
    "self":       {"href": "http://localhost:12345/"},
    "server_two": {"href": "http://localhost:23456/"}
  }
}

And http://localhost:23456/ returns:

{ "name": "Server Two",
  "_links": {
    "self":       {"href": "http://localhost:23456/"},
    "server_one": {"href": "http://localhost:12345/"}
  }
}

The following configuration would ensure proper namespacing of the two servers' response objects:

class APIEcosystem < HyperResource
  self.config(
    "localhost:12345" => {"namespace" => "ServerOneAPI"},
    "localhost:23456" => {"namespace" => "ServerTwoAPI"}
  )
end

root_one = APIEcosystem.new(root: ‘http://localhost:12345’).get
root_one.name      # => ‘Server One’
root_one.url       # => ‘http://localhost:12345’
root_one.namespace # => ServerOneAPI

root_two = root_one.server_two.get
root_two.name      # => ‘Server Two’
root_two.url       # => ‘http://localhost:23456’
root_two.namespace # => ServerTwoAPI

Fuzzy matching of URL masks is provided by the FuzzyURL gem; check there for full documentation of URL mask syntax.

Error Handling

HyperResource raises a HyperResource::ClientError on 4xx responses, and HyperResource::ServerError on 5xx responses. Catch one or both (HyperResource::ResponseError). The exceptions contain as much of cause (internal exception which led to this one), response (Faraday::Response object), and body (the decoded response as a Hash) as is possible at the time.

Contributors

Many thanks to the people who've sent pull requests and improved this code:

Authorship and License

Copyright 2013-2015 Pete Gamache, [email protected].

Released under the MIT License. See LICENSE.txt.

If you got this far, you should probably follow me on Twitter. @gamache

More Repositories

1

jsonxf

JSON Transformer. A fast pretty-printer and minimizer, written in Rust.
Rust
64
star
2

blehm

The source code to Duane Blehm's three Macintosh games
Pascal
41
star
3

fuzzyurl.ex

An Elixir library for non-strict parsing, manipulation, and wildcard matching of URLs.
Elixir
20
star
4

DSt

DSt is a lightweight JavaScript library for HTML5 DOM Storage (localStorage). Ancient and unsupported!
JavaScript
17
star
5

fuzzyurl.rb

A Ruby Gem for non-strict parsing, manipulation, and wildcard matching of URLs.
Ruby
13
star
6

freedom_formatter

NEW OWNER, NEW HOME: https://github.com/marcandre/freedom_formatter
Elixir
12
star
7

fuzzyurl

Ruby/Elixir/JS libraries for non-strict parsing, manipulation, and wildcard matching of URLs.
12
star
8

json_patch_elixir

An Elixir implementation of the JSON Patch format, described in RFC 6902.
Elixir
10
star
9

beeradvocate

An unofficial, slapdash Ruby Gem for scraping beer information from BeerAdvocate.com.
Ruby
5
star
10

brick

Brick is a scoreboard website for the November Games.
HTML
5
star
11

uber.ex

An Elixir library for the UBER hypermedia format.
Elixir
4
star
12

fuzzyurl.js

A JavaScript library for non-strict parsing, manipulation, and wildcard matching of URLs.
JavaScript
4
star
13

ets_deque

A fast and efficient double-ended queue (deque) in Elixir, using ETS as the backing store.
Elixir
4
star
14

advent2019

Advent of Code 2019 solutions in Prolog.
Prolog
3
star
15

imagewriter

Prints black and white PNG graphics on Apple Imagewriter and ImageWriter II printers
Ruby
3
star
16

canobie

A scavenger hunt checklist app.
Elixir
3
star
17

advent2016

Advent of Code solutions in Elixir -- http://adventofcode.com/
Elixir
2
star
18

tumblr-feedeater

Render a Tumblr feed as HTML
JavaScript
2
star
19

cretin

the CD Ripper, Encoder and Tagger with an Inoffensive Name
Perl
2
star
20

EIT

Clan EIT Elite Scoreboard!!!! Nethack scoreboard software for awesome doods
Perl
2
star
21

arduinbros

A port of rainbros (dicks + lolcat) to the Arduino µC and GOLDELOX OLED display.
Arduino
1
star
22

harmonydawn

HTML
1
star
23

Schlitz-BBS

Schlitz BBS is yesterday's messageboard software, today. Now with 55% less godawful.
Perl
1
star
24

gamache.org

gamache.org
1
star
25

gamache.github.io

Jekyll site
CSS
1
star
26

dci

dci is a console RPN scientific calculator, an improved /usr/bin/dc for engineers.
Perl
1
star
27

missingships

missingships.com site code
Ruby
1
star
28

boozeepoque

boozeepoque.com site code
Haml
1
star
29

flac2lame

Create properly-tagged MP3s from properly-tagged FLACs.
Ruby
1
star
30

gunyoki

NetHack tournament server software
Ruby
1
star
31

coolingtowers

Cooling Towers website
JavaScript
1
star
32

advent2021

Advent of Code 2021 solutions in Elixir
Elixir
1
star
33

epice

Epice is a minimal Ruby wrapper for the SPICE circuit emulator.
Ruby
1
star
34

typeahead

1
star