# Plaza

_Because rest areas are more fun with a service plaza_

Plaza is a client side gem that works with [RestArea][1] to provide an ActiveRecord like experience
in dealing with a JSON rest API. Plaza uses [Virtus][2] and [Faraday][3] under the hood to access a
json api, so most things that work with those projects will also work with Plaza.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'plaza'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install plaza

## Usage

### Creating a Plaza Model

Rest API backed plaza models can be created like any other class, here's an example

```ruby
require 'plaza'

class Thing
  include Plaza::RestfulModel

  attribute :name, String
  attribute :amajig_id, Integer

  has_many :amabobs, 'Amajing'   # 1
end
```

**Note 1**: Valid: plural symbols: `:amabobs`, classes: `MyModule::Amabob`, strings: `'MyModule::Amabob'`

See [Virtus][2] for more information on configuring attributes.

### Configuring Plaza

At some point before you use a Plaza model, you need to configure Plaza, at the bare minimum you
need to tell plaza the base url to use for the rest_area api. You can optionally configure the
logger, cache store, and faraday middleware that plaza models will use.

```ruby
Plaza.configure do
  base_url    'http://www.example.com/rest' # Required
  logger      Logger.new(STDOUT)            # Default
  cache_store MemoryStore.new               # Default, recommend `Rails.cache` for rails apps
  use         Faraday::SomeMiddleware       # Add faraday middleware useing use
end
```

#### Cache Store

The store where cached responses are stored, for rails apps we recommend that you just set this
to `Rails.cache`. Plaza uses [Faraday Http Cache][4] for caching, refer to their documentation for
more information on what the store can be.

#### Faraday Middleware

Becasue Plaza works on top of [Faraday][3], you can optionaly add additional middleware to Plaza using the
`use` keyword inside the `Plaza.configure` block

```ruby
Plaza.configure do
  base_url 'http://my_domain.com/rest'
  use      Foobar::SomeMiddleware, Goobar::MoreMiddleware
  use      Moobar::MoreMiddleware
end
```

Middleware is applied in the same order that Faraday would apply it; the first middleware listed
wraps the second middleware which wraps the thrid middleware and so forth until the request is made.

#### Multiple Services

If your plaza models need to connect to multiple services with different base urls, they can be
configured as such:

```ruby
Plaza.configure :my_first_service do
  base_url 'http://www.first_example.com/rest'
end

Plaza.configure :my_second_service do
  base_url 'http://www.later_example.com/rest'
end

class Amabob
  include Plaza::RestfulModel
  plaza_config :my_first_service  # <-- This tells the model to use the :my_first_service configuration

  attribute :thing_id, Integer
end
```

### Using Plaza Models

You can:

Create new models: `my_thing = Thing.new(:name => 'Fred')` (not persisted to api)

Create models: `my_thing = Thing.create(:name => 'Bob')`. This results in an POST api call like
`POST http://example.com/rest/things`

Find existing models: `my_thing = Thing.find(10)`. This results in a GET API call like `GET
http://example.com/things/10`

Pass query string to API: `Thing.where(:name = 'bob')`. This results in an api call like `GET
http://example.com/rest/things?name=bob`. Returns an array.

Update model attributes: `my_thing.name = 'Kevin'`

Save new or update existing models: `my_thing.save`. This results in either a PUT or POST to the api
depending on if `my_thing.id` is `nil` or not.

Delete Models: `my_thing.delete`

Get associated objects: `amabobs_array = my_thing.amabobs`. This requires that you define the
   `has_many` relationship in the class definition. (See Thing definition above)

If you need make associations as part of a module, you will need to specify the `has_many` association as follows

    module Foobar
      class Thing
        include Plaza::RestfulModel
        has_many Foobar::Amajig     # Perfered Method, but you may run into issues with load order
        has_many 'Foobar::Amajig'   # Alternative you can specify the class as a string.
      end
    end

Get related models for which you have the foreign key: `my_thing = a_mabob.thing`
Note on this: If you ask a rest model for a attribute and it doesn't have it, but it has the
same attribute with an underscore id, it's smart enough to know thats a foreign key and go off and
fetch the related rest model.

Want to know more, go checkout the code, the guts of it are located at
`lib/plaza/models/restful_model.rb`

## Questions & Answers

**Q**. Why not ActiveResource?

**A**. ActiveResource is dependent on ActiveModel and ActiveSupport, both of which are tied to a 
specific version of rails. We didn't want all the dependency. Building on top of Faraday and Virtus
offered greater flexibility, more awesome, and less dependencies.

## Contributing

1. Fork it ( https://github.com/[my-github-username]/plaza/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Add Specs!
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

## STD (Stuff To Do) before 1.0.0

4. Add Support for messages (see rest_area)

[1]:https://github.com/bguest/rest_area
[2]:https://github.com/solnic/virtus
[3]:https://github.com/lostisland/faraday
[4]:https://github.com/plataformatec/faraday-http-cache