JSON API Client Library For Elixir
Clone or download
Latest commit 00f692b Sep 11, 2018
Permalink
Failed to load latest commit information.
.github 2.1.0 Mar 15, 2018
config mix format Jan 12, 2018
lib [3.0.4] Aug 30, 2018
scripts 1.1.0 Oct 25, 2017
test 3.0.2 May 29, 2018
.credo.exs mix format Jan 12, 2018
.dialyzer_ignore.exs [3.0.4] Dialyzer fixes Aug 31, 2018
.dockerignore 2.0.0 Jan 3, 2018
.formatter.exs Configure mix format Jan 12, 2018
.gitignore 0.2.0 Oct 10, 2017
.tool-versions [3.0.4] Aug 30, 2018
CHANGELOG.md Httpoison update Sep 11, 2018
Dockerfile 2.0.0 Jan 3, 2018
LICENSE.txt update urls Oct 10, 2017
README.md 3.0.1 May 10, 2018
mix.exs Allow ~> 0.13 to keep it compatible with some other dependencies Sep 11, 2018
mix.lock Httpoison update Sep 11, 2018

README.md

JsonApiClient

Hex.pm Build Docs

A JSON API Client for elixir.

NOTICE: This library is new and in active development. There could be backwards incompatible changes as the design shakes out. YMMV, PRs welcome.

Installation

This package can be installed by adding json_api_client to your list of dependencies in mix.exs:

def deps do
  [
    {:json_api_client, "~> 3.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/json_api_client.

Usage

import JsonApiClient.Request

base_url = "http://example.com/"

# Fetch a resource by URL
{:ok, response} = fetch Request.new(base_url <> "/articles/123")

# build the request by composing helper functions
{:ok, response} = Request.new(base_url <> "/articles")
|> id("123")
|> fetch

# Fetch a list of resources
{:ok, response} = Request.new(base_url <> "/articles")
|> fields(articles: "title,topic", authors: "first-name,last-name,twitter")
|> include(:author)
|> sort(:id)
|> page(size: 10, number: 1)
|> filter(published: true)
|> params(custom1: 1, custom2: 2)
|> fetch

# Delete a resource
{:ok, response} = Request.new(base_url <> "/articles")
|> id("123")
|> delete

# Create a resource
new_article = %Resource{
  type: "articles",
  attributes: %{
    title: "JSON API paints my bikeshed!",
  }
}
{:ok, %{status: 201, doc: %{data: article}}} = Request.new(base_url <> "/articles")
|> resource(new_article)
|> create

# Update a resource
{:ok, %{status: 200, doc: %{data: updated_article}}} = Request.new(base_url <> "/articles")
|> resource(%Resource{article | attributes: %{title: "New Title}})
|> update

Non-compliant servers

For the most part this library assumes that the server you're talking to implements the JSON:API spec correctly and treats deviations from that spec as exceptional (causing JsonApiClient.execute/1 to return an {:error, _} tuple for example). One exception to this rule is the case where a server sends back an invalid body (HTML or some non-json string) along with a 4** or 5** status code. In those cases the body will simply be ignored. See the docs for JsonApiClient.execute/1 for more details.

Helpers for common URI structures

The JSON:API specification doesn't provide any guidance on URI structure, but there is a common convention for REST apis to expose an endpoints with the following structure

# fetch a list of resources of a given type
GET /:type_name

# Create a resource of a given type
POST /:type_name

# Fetch/Update/Delete a resource by id
GET /:type_name/:id
PATCH /:type_name/:id
DELETE /:type_name/:id

When making requests to API endpoints that follow these conventions you can avoid having to build the full path yourself by adding JsonApiClient.Resource to the request.

# GET base_url <> "/articles/123"
{:ok, response} = Request.new(base_url)
|> resource(%Resource{id: "123", type: "articles"})
|> fetch

# GET base_url <> "/articles"
{:ok, response} = Request.new(base_url)
|> resource(%Resource{type: "articles"})
|> fetch

You can also build paths to nested resources by passing a Resource to path/2

# GET base_url <> "/articles/123/comments/456"
{:ok, response} = Request.new(base_url)
|> path(%Resource{id: "123", type: "articles"})
|> resource(%Resource{id: "456", type: "comments"})
|> fetch

If the API your making requests which follows a different URI pattern you can pass a string to path/2 and it will be appended to the base url.

Configuration

user agent suffix

Every request made carries a special User-Agent header that looks like: json_api_client/1.0.0/user_agent_suffix. Each client is expected to set its user_agent_suffix via:

config :json_api_client, user_agent_suffix: "yourSufix"

timeout

This library allows its users to specify a timeout for all its service calls by using a timeout setting. By default, the timeout is set to 500msecs.

config :json_api_client, timeout: 200

middlewares

JsonApiClient is implemented using a middleware architecture. You can configure the middleware stack by setting middlewares to a list of {Module, opts} tuples where Module is a module that implements the JsonApiClient.Middleware behavior and opts is the options that will be passed as the last argument to the modules call function.

config :json_api_client,
  middlewares: [
    {JsonApiClient.Middleware.DocumentParser, nil}
    {JsonApiClient.Middleware.HTTPClient, nil},
  ]

If you don't configure a value for middlewares you'll get a stack equivalent to the one configured in the preceding example.

included middlewre

The following middleware ships with JsonApiClient:

  • JsonApiClient.Middleware.Fuse
  • JsonApiClient.Middleware.StatsTracker

Please refer to the module documentation for each middleware for information