<commit_before>#  HyperResource - a self-inflating client for hypermedia APIs

## About

HyperResource is a client library for hypermedia web services.  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 
<a href="http://stateless.co/hal_specification.html" target="_blank">
HAL+JSON hypermedia format</a>, with support for
other hypermedia formats planned.

## Quick Tour

Set up API connection:

```ruby
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.

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

What'd we get back?

```ruby
api.deserialized_response
# => { 'message' => 'Welcome to the Example.com API',
#      'version' => 1,
#      '_links' => {
#        'self' => {'href' => '/'},
#        'users' => {'href' => '/users{?email,last_name}', 'templated' => true},
#        'forums' => {'href' => '/forums{?title}', 'templated' => true}
#      }
#    }
```

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

```ruby
jdoe_user = api.users(email: "<EMAIL>").first
# => #<HyperResource:0x12312312 ...>
```

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

First, the `users` link was
added as a method on the `api` object at the time the resource was
loaded with `api.get`.

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>").first
api.get.users(email: "<EMAIL>").first
api.get.links.users(email: "<EMAIL>").first
api.get.links['users'].where(email: "<EMAIL>").first
api.get.links['users'].where(email: "<EMAIL>").get.first
api.get.links['users'].where(email: "<EMAIL>").get.objects.first[1][0]
```

## GET, POST, PUT, and DELETE

In addition to `.get`, HyperResource provides `.create`, `.update`, and 
`.delete` methods track their HTTP counterparts.

```ruby
new_user = api.users.create(:email => '<EMAIL>',
                            :first_name => 'New',
                            :last_name => 'Guy')

new_user.first_name = '<NAME>'
new_user.update

new_user.delete
```

## Fake Real World Example

Now let's put it together, with our theoretical API.
Let's say Johnny ran his mouth in the
'Politics' forum one particular day and somehow managed to piss off the
entire Internet.  Let's try and satisfy the DDoSing horde by
amending his tone.

```ruby
forum = api.forums(title: 'Politics').first
jdoe_user.comments(date: '2013-04-01', forum: forum.href).each do |comment|
  comment.text = "OMG PUPPIES!!"
  comment.update
end
```

## Extending Data Types

If an API is returning data type information as part of the response --
and it really should be -- 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.

```ruby
class ExampleAPI < HyperResource
  class User < ExampleAPI
    def full_name
      first_name + ' ' + last_name
    end
  end
end

api.namespace = ExampleApi

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

user.full_name
# => "<NAME>"
```

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

## 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 `deserialized_response` (the response
as a `Hash`) as is possible at the time.

## Compatibility and Dependencies

HyperResource requires the 
<a href="https://github.com/hannesg/uri_template" target="_blank">uri_template</a>
and <a href="https://github.com/lostisland/faraday" target="_blank">Faraday</a>
gems.  

HyperResource is tested to support MRI Ruby 1.8.7 to present, and JRuby
in 1.8 mode or above.  Thanks,
<a href="https://travis-ci.org/gamache/hyperresource" target="_blank">
Travis CI!</a>

## Authorship and License

Copyright 2013 <NAME>,
[<EMAIL>](mailto:<EMAIL>).

If you got this far, you
should probably follow me on Twitter.  [@gamache](https://twitter.com/gamache)

Released under the MIT License.  See LICENSE.txt.<commit_msg>converted links in README to HTML<commit_after>#  HyperResource - a self-inflating client for hypermedia APIs

## About

HyperResource is a client library for hypermedia web services.  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 
<a href="http://stateless.co/hal_specification.html" target="_blank">
HAL+JSON hypermedia format</a>, with support for
other hypermedia formats planned.

## Quick Tour

Set up API connection:

```ruby
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.

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

What'd we get back?

```ruby
api.deserialized_response
# => { 'message' => 'Welcome to the Example.com API',
#      'version' => 1,
#      '_links' => {
#        'self' => {'href' => '/'},
#        'users' => {'href' => '/users{?email,last_name}', 'templated' => true},
#        'forums' => {'href' => '/forums{?title}', 'templated' => true}
#      }
#    }
```

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

```ruby
jdoe_user = api.users(email: "<EMAIL>").first
# => #<HyperResource:0x12312312 ...>
```

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

First, the `users` link was
added as a method on the `api` object at the time the resource was
loaded with `api.get`.

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>").first
api.get.users(email: "<EMAIL>").first
api.get.links.users(email: "<EMAIL>").first
api.get.links['users'].where(email: "<EMAIL>").first
api.get.links['users'].where(email: "<EMAIL>").get.first
api.get.links['users'].where(email: "<EMAIL>").get.objects.first[1][0]
```

## GET, POST, PUT, and DELETE

In addition to `.get`, HyperResource provides `.create`, `.update`, and 
`.delete` methods track their HTTP counterparts.

```ruby
new_user = api.users.create(:email => '<EMAIL>',
                            :first_name => 'New',
                            :last_name => 'Guy')

new_user.first_name = '<NAME>'
new_user.update

new_user.delete
```

## Fake Real World Example

Now let's put it together, with our theoretical API.
Let's say Johnny ran his mouth in the
'Politics' forum one particular day and somehow managed to piss off the
entire Internet.  Let's try and satisfy the DDoSing horde by
amending his tone.

```ruby
forum = api.forums(title: 'Politics').first
jdoe_user.comments(date: '2013-04-01', forum: forum.href).each do |comment|
  comment.text = "OMG PUPPIES!!"
  comment.update
end
```

## Extending Data Types

If an API is returning data type information as part of the response --
and it really should be -- 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.

```ruby
class ExampleAPI < HyperResource
  class User < ExampleAPI
    def full_name
      first_name + ' ' + last_name
    end
  end
end

api.namespace = ExampleApi

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

user.full_name
# => "<NAME>"
```

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

## 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 `deserialized_response` (the response
as a `Hash`) as is possible at the time.

## Compatibility and Dependencies

HyperResource requires the 
<a href="https://github.com/hannesg/uri_template" target="_blank">uri_template</a>
and <a href="https://github.com/lostisland/faraday" target="_blank">Faraday</a>
gems.  

HyperResource is tested to support MRI Ruby 1.8.7 to present, and JRuby
in 1.8 mode or above.  Thanks,
<a href="https://travis-ci.org/gamache/hyperresource" target="_blank">
Travis CI!</a>

## Authorship and License

Copyright 2013 <NAME>,
<a href="mailto:<EMAIL>" target="_blank"><EMAIL></a>.

If you got this far, you should probably follow me on Twitter.
<a href="https://twitter.com/gamache" target="_blank">@gamache</a>

Released under the MIT License.  See LICENSE.txt.
{'fraction_non_alphanumeric': 0.13126469205453692, 'fraction_numerical': 0.008086506817113304, 'mean_word_length': 4.052731591448931, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 101, 'https://': 14, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2156470', 'n_tokens_mistral': 3414, 'n_tokens_neox': 3202, 'n_words': 1168}