README.md

finch
=====

### don't use this because it's going to change to use the plug spec

this is a little thing that sits in between phoenix and ecto that makes building CRUDy REST APIs really simple.
It does not offer many features. It aims to be really small and easy to understand. 


Things it will do: 
  *  basic CRUD operations for ecto models
  *  separation of your model and API resource layer
  *  filtering, ordering, paging of models at index endpoints
  *  model validation with extensible validation middleware
  *  basic auth with apikeys
  *  sideloading resource relationships

Things it won't do: 
  *  writable resource nesting (maybe for the future)
  *  XML/Protobufs/SOAP/whatever. Only json.
  *  cookie auth. use an api key. you could write a middleware layer that does this though. 
  *  integration with anything other than ecto or phoenix
  *  make you a sandwich



## usage

```elixir


defmodule MyCoolApp.Models.Foo do
  use Finch.Model

  schema "foos" do
    field :title, :string
    field :text, :string
  end

end

defmodule MyCoolApp.Resources.Foo do
  use Finch.Resource
  
  def repo, do: MyCoolApp.Repo
  def model, do: MyCoolApp.Models.Foo

end


defmodule MyCoolApp.Router do
  use Phoenix.Router

  scope path: "/api" do
    scope path: "/v1" do
      resources "/foo", MyCoolApp.Resources.Foo
    end
  end
end


```

The code above will grant you the following powers...


| method  | route | result |
| ------------- | ------------| ------------- |
| GET  | /api/v1/foo  | list all the foos |
| POST  | /api/v1/foo  | make a foo |
| GET  | /api/v1/foo/#{id}  | get a foo with id |
| PUT  | /api/v1/foo/#{id}  | update a foo with id |
| DELETE  | /api/v1/foo/#{id}  | delete a foo with id |



## filtering, paging, and ordering


### paging
By default, a ```GET``` request to an index endpoint will page the models. The default page size is 40, but you can implement ```page_size/0``` to override that. Adding the ```?page=some_number``` url parameter will fetch the page you specify. index endpoints return a meta object that gives you information relevant to paging. 


### filtering
You can filter on fields as well, which just does a case insensitive like query. you
can change how the filtering happens by overriding ```apply_filters/2``` in your 
resource.

Adding ```?filter=field_name:value``` will select the models where ```field_name```
is like ```value```

### ordering
You can order the index endpoint. Add ```?order=field_name``` to get 
models sorted by ```field_name```. To reverse the order, add a - (minus sign)
in front of the ```field_name```


Paging, filtering, ordering all can be combined in a request. All of them
can be overridden for custom behavior. 


## middleware
you can add middleware that runs before and after the request to your resources. 

### Validators
using the same router and Foo model as above, you could so something like this

```elixir

defmodule MyCoolApp.FooValidator do
  use Finch.Middleware.ModelValidator

  def validate_field(_, :title, val) do
    if val == "can you" do
      throw {:bad_request, %{:errors => %{:title => "can you not"}}}
    end
    {:title, val}
  end

  def validate_field(verb, name, val), do: super(verb, name, val)

end


defmodule MyCoolApp.Resources.Foo do

  def repo, do: MyCoolApp.Repo
  def model, do: MyCoolApp.Models.Foo

  use Finch.Resource, [
    before: [MyCoolApp.FooValidator]
  ]
end


```

POSTing the following json 
```json
{
  "title" : 1,
  "text": "some text"
}

```

to the ```/api/v1/foo``` endpoint would result in a 400 BadRequest with the following message

```json
{
  "errors" : {
    "title": "This needs to be a string"
  }
}
```

##### custom validation

you can also implement custom validation on fields. the ```validate_field/3``` function 
gets run for each field. in this case posting the following 

```json
{
  "title" : "can you",
  "text": "some text"
}

```
to ```/api/v1/foo``` would result in a 400 BadRequest with the following message
```json
{
  "errors" : {
    "title": "can you not"
  }
}
```