<commit_before># What is `SimpleJSONAPIClient`?

`SimpleJSONAPIClient` is a framework for building Ruby clients for JSONAPI-compliant services.  

# How do I use `SimpleJSONAPIClient`?

## Setup

First create models inheriting from `SimpleJSONAPIClient::Base`, and specifying a few details.

* `COLLECTION_URL` - the path to fetch the resource collection
* `INDIVIDUAL_URL` - the path to fetch an individual resource
* `TYPE` - the JSONAPI resource type to use when creating a new resource
* `attributes` - the names of attributes which can be found on the resource
* relationships - `has_one` and `has_many` define relationships, and take these arguments:
  * relationship name (e.g., the `:goats` in `has_many :goats`)
  * `class_name` to use when instantiating related objects

They should look like this:

```ruby
class Post < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/posts'
  INDIVIDUAL_URL = '/posts/%{id}'
  TYPE = 'posts'

  attributes :title, :text

  has_one :author, class_name: 'Author'
  has_many :comments, class_name: 'Comment'
end

class Author < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/authors'
  INDIVIDUAL_URL = '/authors/%{id}'
  TYPE = 'authors'

  attributes :name

  has_many :posts, class_name: 'Post'
  has_many :comments, class_name: 'Comment'
end

class Comment < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/comments'
  INDIVIDUAL_URL = '/comments/%{id}'
  TYPE = 'comments'

  attributes :text

  has_one :post, class_name: 'Post'
  has_one :author, class_name: 'Author'
end
```

If you have behavior you'd like to share across models, you may want to first create an abstract class inheriting from `SimpleJSONAPIClient::Base` and then have all your models inherit from that.

Next, create a [`Faraday`](https://github.com/lostisland/faraday) connection to handle the domain, authorization strategy, and anything else you need (making sure to include [JSON parsing middleware](https://github.com/lostisland/faraday_middleware/wiki/Parsing-responses)):

```ruby
def connection(token)
  default_headers = {
    'Accept' => 'application/vnd.api+json',
    'Content-Type' => 'application/vnd.api+json',
    'Authorization' => "token=#{token}"
  }

  @connection ||= Faraday.new(url: 'https://example.com', headers: default_headers) do |connection|
    connection.request :json
    connection.response :json, :content_type => /\bjson$/ # use middleware to parse JSON when response Content-Type is json
    connection.adapter :net_http
  end
end
```

Now you can start making requests!

## Fetching

```ruby
Post.fetch_all(connection: connection)
=> #<Enumerator: #<Enumerator::Generator:0x00562894acd420>:each>
```

What's going on?  `SimpleJSONAPIClient` tries to be as lazy as possible while still being convenient.  So if you actually want to fetch everything, you'll be able to call `Array` methods and it will fetch the resource, paginating through all the results.  If it's an endpoint with thousands of pages, you can use `Enumerator` methods like `#each` and it'll paginate through the results, fetching the next page when it runs out of objects.

Let's call `#to_a` to see a bit more detail.

```ruby
posts = Post.fetch_all(connection: connection).to_a
=> [#<JSONAPIAppClient::Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/1/comments>>,
 #<JSONAPIAppClient::Post id=2 title="The System is Down" text="The Cheat" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/2/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/2/comments>>]
```

Attributes are loaded immediately, but relationships are lazily instantiated.  So if we dig a little bit further:

```ruby
posts.first.author
=> #<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author>
```

Nope, still lazy!  However, once we start fetching details about the author, `SimpleJSONAPI` knows a request has to be made, and fills in the details:

```ruby
posts.first.author.id
=> "3"

posts.first.author
=> #<JSONAPIAppClient::Author id=3 name="Filbert" posts=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Post url=http://jsonapi_app:3000/authors/3/posts> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/authors/3/comments>>
```

We can read more easily by calling `#as_json`:

```ruby
posts.first.author.as_json
=> {
  :data => {
    :type => "authors",
    :attributes => { :name => "Filbert" },
    :relationships => {
      :posts => {
        :data => [{ :type => "posts", :id => "1" }]
      },
      :comments => { :data => [] }
    }
  }
}
```

You can also explicitly fetch a single item:

```ruby
post = JSONAPIAppClient::Post.fetch(connection: connection, url_opts: { id: 1 })
=> #<JSONAPIAppClient::Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/1/comments>>
```

`url_opts`, in all cases where you see them, are passed to the template Strings for `INDIVIDUAL_URL` and `COLLECTION_URL` in the model.

## Updating

If you want to update a record, you can do it from the model itself:

```ruby
post = JSONAPIAppClient::Post.fetch(url_opts: { id: 1 }, connection: connection)
=> #<JSONAPIAppClient::Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/1/comments>>
[2] pry(main)> post.update(attributes: { text: 'foo' })
=> #<JSONAPIAppClient::Post id=1 title="A Very Proper Post Title" text="foo" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/1/comments>>
```

If you have the ID of the record handy, you update straight from the model class without fetching the record first:

```ruby
JSONAPIAppClient::Post.update(id: 1, url_opts: { id: 1 }, connection: connection, attributes: { text: 'foo' })
=> #<JSONAPIAppClient::Post id=1 title="A Very Proper Post Title" text="foo" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=JSONAPIAppClient::Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=JSONAPIAppClient::Comment url=http://jsonapi_app:3000/posts/1/comments>><commit_msg>Remove JSONAPIAppClient references from README<commit_after># What is `SimpleJSONAPIClient`?

`SimpleJSONAPIClient` is a framework for building Ruby clients for JSONAPI-compliant services.  

# How do I use `SimpleJSONAPIClient`?

## Setup

First create models inheriting from `SimpleJSONAPIClient::Base`, and specifying a few details.

* `COLLECTION_URL` - the path to fetch the resource collection
* `INDIVIDUAL_URL` - the path to fetch an individual resource
* `TYPE` - the JSONAPI resource type to use when creating a new resource
* `attributes` - the names of attributes which can be found on the resource
* relationships - `has_one` and `has_many` define relationships, and take these arguments:
  * relationship name (e.g., the `:goats` in `has_many :goats`)
  * `class_name` to use when instantiating related objects

They should look like this:

```ruby
class Post < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/posts'
  INDIVIDUAL_URL = '/posts/%{id}'
  TYPE = 'posts'

  attributes :title, :text

  has_one :author, class_name: 'Author'
  has_many :comments, class_name: 'Comment'
end

class Author < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/authors'
  INDIVIDUAL_URL = '/authors/%{id}'
  TYPE = 'authors'

  attributes :name

  has_many :posts, class_name: 'Post'
  has_many :comments, class_name: 'Comment'
end

class Comment < SimpleJSONAPIClient::Base
  COLLECTION_URL = '/comments'
  INDIVIDUAL_URL = '/comments/%{id}'
  TYPE = 'comments'

  attributes :text

  has_one :post, class_name: 'Post'
  has_one :author, class_name: 'Author'
end
```

If you have behavior you'd like to share across models, you may want to first create an abstract class inheriting from `SimpleJSONAPIClient::Base` and then have all your models inherit from that.

Next, create a [`Faraday`](https://github.com/lostisland/faraday) connection to handle the domain, authorization strategy, and anything else you need (making sure to include [JSON parsing middleware](https://github.com/lostisland/faraday_middleware/wiki/Parsing-responses)):

```ruby
def connection(token)
  default_headers = {
    'Accept' => 'application/vnd.api+json',
    'Content-Type' => 'application/vnd.api+json',
    'Authorization' => "token=#{token}"
  }

  @connection ||= Faraday.new(url: 'https://example.com', headers: default_headers) do |connection|
    connection.request :json
    connection.response :json, :content_type => /\bjson$/ # use middleware to parse JSON when response Content-Type is json
    connection.adapter :net_http
  end
end
```

Now you can start making requests!

## Fetching

```ruby
Post.fetch_all(connection: connection)
=> #<Enumerator: #<Enumerator::Generator:0x00562894acd420>:each>
```

What's going on?  `SimpleJSONAPIClient` tries to be as lazy as possible while still being convenient.  So if you actually want to fetch everything, you'll be able to call `Array` methods and it will fetch the resource, paginating through all the results.  If it's an endpoint with thousands of pages, you can use `Enumerator` methods like `#each` and it'll paginate through the results, fetching the next page when it runs out of objects.

Let's call `#to_a` to see a bit more detail.

```ruby
posts = Post.fetch_all(connection: connection).to_a
=> [#<Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/1/comments>>,
 #<Post id=2 title="The System is Down" text="The Cheat" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/2/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/2/comments>>]
```

Attributes are loaded immediately, but relationships are lazily instantiated.  So if we dig a little bit further:

```ruby
posts.first.author
=> #<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author>
```

Nope, still lazy!  However, once we start fetching details about the author, `SimpleJSONAPI` knows a request has to be made, and fills in the details:

```ruby
posts.first.author.id
=> "3"

posts.first.author
=> #<Author id=3 name="Filbert" posts=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Post url=http://jsonapi_app:3000/authors/3/posts> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/authors/3/comments>>
```

We can read more easily by calling `#as_json`:

```ruby
posts.first.author.as_json
=> {
  :data => {
    :type => "authors",
    :attributes => { :name => "Filbert" },
    :relationships => {
      :posts => {
        :data => [{ :type => "posts", :id => "1" }]
      },
      :comments => { :data => [] }
    }
  }
}
```

You can also explicitly fetch a single item:

```ruby
post = Post.fetch(connection: connection, url_opts: { id: 1 })
=> #<Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/1/comments>>
```

`url_opts`, in all cases where you see them, are passed to the template Strings for `INDIVIDUAL_URL` and `COLLECTION_URL` in the model.

## Updating

If you want to update a record, you can do it from the model itself:

```ruby
post = Post.fetch(url_opts: { id: 1 }, connection: connection)
=> #<Post id=1 title="A Very Proper Post Title" text="I am absolutely incensed about something." author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/1/comments>>
[2] pry(main)> post.update(attributes: { text: 'foo' })
=> #<Post id=1 title="A Very Proper Post Title" text="foo" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/1/comments>>
```

If you have the ID of the record handy, you update straight from the model class without fetching the record first:

```ruby
Post.update(id: 1, url_opts: { id: 1 }, connection: connection, attributes: { text: 'foo' })
=> #<Post id=1 title="A Very Proper Post Title" text="foo" author=#<SimpleJSONAPIClient::Base::SingularLinkRelationship model_class=Author url=http://jsonapi_app:3000/posts/1/author> comments=#<SimpleJSONAPIClient::Base::ArrayLinkRelationship model_class=Comment url=http://jsonapi_app:3000/posts/1/comments>>
{'fraction_non_alphanumeric': 0.12441916915181359, 'fraction_numerical': 0.014009293293570983, 'mean_word_length': 5.902824317855433, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 103, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '1705874', 'n_tokens_mistral': 4576, 'n_tokens_neox': 4403, 'n_words': 1267}