README.md

# Griffin

### Model

- JSON-like data modeling which seamlessly hooks into GraphQL
- CRUD validation support (integrate from Vex/Ecto?)
- Persistance agonstic with adapters

#### Lifecycle of CRUD operation...
- [ ] GQL to Keylist request
- --
- [x] Validate
- [ ] Pre Middleware
- [ ] Peristence
- [ ] Post Middleware
- [ ] Response to Keylist response
- --
- [ ] Convert response to JSON

````elixir
defmodule WizardModel do
  import Griffin.Model
  
  @fields [
    name: [:string, :required],
    school: [:map, of: [
      name: [:string],
      geo: [:map, of: [
        lat: [:int, :required],
        lng: [:int, :required]
      ]]
    ]] 
  ]

  def resolve(ctx) do
    ctx
      |> validate(@fields)
      |> denormalize_spells
      |> persist
      |> join_spells
      |> send_weclome_email
      |> to_response    
  end
end
````

### View
- Isomorphic: On the server it outputs a string; On the client it hooks into VirtualDOM/Morphdom
- `state()` is an Agent that references a single immutable map
- Component lifecycle hooks?
- Components + Routes > Views + Controllers?

````elixir
defmodule ArtistView
  use Griffin.View

  defp before_mount
    # jQuery thing here
  end

  defp styles
    %{
      container: %{
        width: "100%"
      },
      header: %{
        text_transform: "uppercase"
      }
    }
  end

  def render
    div(:container,
      h1(:header, "Artist name:"),
      p(:name, state().artist.name),
      button(%{ onclick: HomeController.follow_artist },
        "Follow #{state().artist.name"))
  end
end
````

### Controller

```elixir
defmodule HomeController
  use Griffin.Controller

  def follow_artist
    %{ name: name } = mutate """{
      follow_artist(id: #{state().artist._id}) {
        name
      }
    }
    """
    set_state %{ state() | name: name }
  end

  def home
    %{ artists: artists } = query """{
      artists(limit: 10) {
        id
        name
      }
    }
    """
    set_state %{ state() | artists: artists }
    render HomeView
  end
end
```

### Apps

- Individual Plug apps
- Provides a place for routing/glue
- Separated by page reloads... (or not b/c enforced stateless?)
- A root "project" combines apps to be passed into Cowboy

```elixir
defmodule HomeApp do
  use Griffin.App
  use ArtistModel
  use ArtistView

  get "/", HomeController.home
end

defmodule MyProject do
  use Griffin.Project

  mount HomeApp
end
```

```
$ iex -S mix
iex> c "path/to/file.ex"
[MyApp]
iex> {:ok, _} = Plug.Adapters.Cowboy.http MyProject, []
{:ok, #PID<...>}
```