Alembic v4.0.0 Alembic.Link View Source

A link object represents a URL and metadata about it.

Link to this section Summary

Types

  • a String.t containing the link’s URL.
  • a t
t()

An link object which can contain the following members:

  • href - the link’s URL.
  • meta - contains non-standard meta-information about the link

Functions

Converts JSON to a link

Extracts Alembic.Pagination.Page.t number from url "page[number]" and size from url "page[size]"

Link to this section Types

  • a String.t containing the link’s URL.
  • a t
Link to this type t() View Source
t() :: %Alembic.Link{href: String.t() | nil, meta: Alembic.Meta.t() | nil}

An link object which can contain the following members:

  • href - the link’s URL.
  • meta - contains non-standard meta-information about the link.

Link to this section Functions

Link to this function from_json(string, error_template) View Source
from_json(String.t(), Alembic.Error.t()) :: {:ok, String.t()}
from_json(Alembic.json_object(), Alembic.Error.t()) ::
  {:ok, t()} | Alembic.FromJson.error()
from_json(nil | true | false | list() | float() | integer(), Alembic.Error.t()) ::
  Alembic.FromJson.error()

Converts JSON to a link.

A link can be a String.t, so strings will just pass through. A link can also be a t, in which case the JSON object is checked for href.

Strings

A string will pass through as simple URLs are allowed.

iex> url = "http://example.com"
iex> {:ok, url} == Alembic.Link.from_json(
...>   url,
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
true

Objects

URLs can be annotated using “link objects” with an "href" and "meta"

iex> Alembic.Link.from_json(
...>   %{
...>     "href" => "http://example.com",
...>     "meta" => %{
...>       "last_updated_on" => "2015-12-21"
...>     }
...>   },
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{
  :ok,
  %Alembic.Link{
    href: "http://example.com",
    meta: %{
      "last_updated_on" => "2015-12-21"
    }
  }
}

However, the JSON API spec only says a “link object” 'can contain' href and meta, not that it MUST, so no members are actually required in a “link object”

iex> Alembic.Link.from_json(
...>   %{},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{:ok, %Alembic.Link{}}

The wording does mean that the “link” if not a String must be a JSON object (i.e. an Elixir map)

iex> Alembic.Link.from_json(
...>   ["http://example.com"],
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/links/0` type is not link object",
        meta: %{
          "type" => "link object"
        },
        source: %Alembic.Source{
          pointer: "/links/0"
        },
        status: "422",
        title: "Type is wrong"
      }
    ]
  }
}

While href is optional, if present, must be a String.t

iex> Alembic.Link.from_json(
...>   %{"href" => []},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/links/0/href` type is not string",
        meta: %{
          "type" => "string"
        },
        source: %Alembic.Source{
          pointer: "/links/0/href"
        },
        status: "422",
        title: "Type is wrong"
      }
    ]
  }
}

Likewise, meta, if present, must be a JSON object (i.e. an Elixir map)

iex> Alembic.Link.from_json(
...>   %{"meta" => "© 2015"},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/links/0/meta` type is not meta object",
        meta: %{
          "type" => "meta object"
        },
        source: %Alembic.Source{
          pointer: "/links/0/meta"
        },
        status: "422",
        title: "Type is wrong"
      }
    ]
  }
}

If there are errors in both href and meta, they will accumulate so all errors can be corrected in a second request

iex> Alembic.Link.from_json(
...>   %{
...>     "href" => [],
...>     "meta" => "© 2015"
...>   },
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/links/0"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/links/0/href` type is not string",
        meta: %{
          "type" => "string"
        },
        source: %Alembic.Source{
          pointer: "/links/0/href"
        },
        status: "422",
        title: "Type is wrong"
      },
      %Alembic.Error{
        detail: "`/links/0/meta` type is not meta object",
        meta: %{
          "type" => "meta object"
        },
        source: %Alembic.Source{
          pointer: "/links/0/meta"
        },
        status: "422",
        title: "Type is wrong"
      }
    ]
  }
}

Extracts Alembic.Pagination.Page.t number from url "page[number]" and size from url "page[size]".

iex> Alembic.Link.to_page("https://example.com/api/v1/users?page%5Bnumber%5D=2&page%5Bsize%5D=10")
%Alembic.Pagination.Page{number: 2, size: 10}

If a url does not have both "page[number]" and "page[size]" then nil is returned

iex> Alembic.Link.to_page("https://example.com/api/v1/users?page%5Bnumber%5D=2")
nil
iex> Alembic.Link.to_page("https://example.com/api/v1/users?page%5Bsize%5D=10")
nil
iex> Alembic.Link.to_page("https://example.com/api/v1/users?q=")
nil

If a url does not have a query then nil is returned

iex> Alembic.Link.to_page("https://example.com/api/v1/users")
nil