Alembic v1.0.0 Alembic.Resource
The individual JSON object of elements of the list of the data
member of the
JSON API document are
resources as are the members of the included
member.
Summary
Functions
Converts a JSON object into a JSON API Resource, t
Types
t :: %Alembic.Resource{attributes: Alembic.json_object | nil, id: String.t | nil, links: Alembic.Links.t | nil, meta: Alembic.Meta.t | nil, relationships: Alembic.Relationships.t | nil, type: String.t}
Resource objects” appear in a JSON API document to represent resources.
A resource object MUST contain at least the following top-level members:
id
type
Exception: The id
member is not required when the resource object originates at the client and represents a new
resource to be created on the server. (%{action: :create, source: :client}
)
In addition, a resource object **MAY(( contain any of these top-level members:
attributes
- an attributes object representing some of the resource’s data.links
- anAlembic.Link.links
containing links related to the resource.meta
- contains non-standard meta-information about a resource that can not be represented as an attribute or relationship.relationships
- a relationships object describing relationships between the resource and other JSON API resources.
Functions
Specs
from_json(Alembic.json_object, %Alembic.Error{code: term, detail: term, id: term, links: term, meta: Alembic.Meta.t, source: term, status: term, title: term}) ::
{:ok, t} |
Alembic.FromJson.error
from_json(nil | true | false | list | float | integer | String.t, Alembic.Error.t) :: Alembic.FromJson.error
Converts a JSON object into a JSON API Resource, t
.
Invalid
A non-resource will be matched, but return an error.
iex> Alembic.Resource.from_json(
...> "1",
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data` type is not resource",
meta: %{
"type" => "resource"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Action
The Alembic.Error.t
meta
"action"
key influences whether "id"
is required: "id"
is optional
for "action"
:create
sent from "sender"
:client
; otherwise, it "id"
is required.
Creating
Only "type"
is required when creating a resource from a client because the "id"
will be assigned by the server.
iex> Alembic.Resource.from_json(
...> %{ "type" => "thing" },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{:ok, %Alembic.Resource{type: "thing"}}
Only "type"
will be marked as missing when creating a resource from a client
iex> Alembic.Resource.from_json(
...> %{},
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
But, normally you’d include some "attributes"
too
iex> Alembic.Resource.from_json(
...> %{
...> "attributes" => %{
...> "name" => "Thing 1"
...> },
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:ok,
%Alembic.Resource{
attributes: %{
"name" => "Thing 1"
},
type: "thing"
}
}
"attributes"
are quite free-form, but must still be an Alembic.json_object
iex> Alembic.Resource.from_json(
...> %{
...> "attributes" => [
...> "name"
...> ],
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/attributes` type is not json object",
meta: %{
"type" => "json object"
},
source: %Alembic.Source{
pointer: "/data/attributes"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Deleting
Only "id"
and "type"
is required when when deleting a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "id" => "1", "type" => "thing"},
...> %Alembic.Error{
...> meta: %{
...> "action" => :delete,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{:ok, %Alembic.Resource{id: "1", type: "thing"}}
With "id"
, "type"
will be marked as missing when deleting a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "id" => "1" },
...> %Alembic.Error{
...> meta: %{
...> "action" => :delete,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
With "type"
, "id"
will be marked as missing when deleting a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "type" => "thing" },
...> %Alembic.Error{
...> meta: %{
...> "action" => :delete,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/id` is missing",
meta: %{
"child" => "id"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
Both "id"
and "type"
will be marked as missing when deleting a resource from a client
iex> Alembic.Resource.from_json(
...> %{},
...> %Alembic.Error{
...> meta: %{
...> "action" => :delete,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/id` is missing",
meta: %{
"child" => "id"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
},
%Alembic.Error{
detail: "`/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
Updating
Only "id"
and "type"
is required when when updating a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "id" => "1", "type" => "thing"},
...> %Alembic.Error{
...> meta: %{
...> "action" => :update,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{:ok, %Alembic.Resource{id: "1", type: "thing"}}
With "id"
, "type"
will be marked as missing when upating a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "id" => "1" },
...> %Alembic.Error{
...> meta: %{
...> "action" => :update,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
With "type"
, "id"
will be marked as missing when updating a resource from a client
iex> Alembic.Resource.from_json(
...> %{ "type" => "thing" },
...> %Alembic.Error{
...> meta: %{
...> "action" => :update,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/id` is missing",
meta: %{"child" => "id"},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
Both "id"
and "type"
will be marked as missing when updating a resource from a client
iex> Alembic.Resource.from_json(
...> %{},
...> %Alembic.Error{
...> meta: %{
...> "action" => :update,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/id` is missing",
meta: %{"child" => "id"},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
},
%Alembic.Error{
detail: "`/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data"
},
status: "422",
title: "Child missing"
}
]
}
}
Optional members
"links"
, "meta"
and "relationships"
are optional, but if they are present, they MUST be valid or their
errors will make the overall t
invalid.
"links"
A valid "links"
maps link names to either a JSON object with "href"
and/or "meta"
member or a String.t
URL.
iex> Alembic.Resource.from_json(
...> %{
...> "links" => %{
...> "string" => "http://example.com",
...> "link_object" => %{
...> "href" => "http://example.com",
...> "meta" => %{
...> "last_updated_on" => "2015-12-21"
...> }
...> }
...> },
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:ok,
%Alembic.Resource{
links: %{
"link_object" => %Alembic.Link{
href: "http://example.com",
meta: %{
"last_updated_on" => "2015-12-21"
}
},
"string" => "http://example.com"
},
type: "thing"
}
}
Even though "links"
is optional, if it has errors, those errors will make the entire resource invalid
iex> Alembic.Resource.from_json(
...> %{
...> "links" => ["http://example.com"],
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/links` type is not links object",
meta: %{
"type" => "links object"
},
source: %Alembic.Source{
pointer: "/data/links"
},
status: "422",
title: "Type is wrong"
}
]
}
}
"meta"
A valid "meta"
is any JSON object
iex> Alembic.Resource.from_json(
...> %{
...> "meta" => %{"copyright" => "© 2015"},
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:ok,
%Alembic.Resource{
meta: %{
"copyright" => "© 2015"
},
type: "thing"
}
}
If "meta"
isn’t a JSON object, then that error will make the whole resource invalid
iex> Alembic.Resource.from_json(
...> %{
...> "meta" => "© 2015",
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/meta` type is not meta object",
meta: %{
"type" => "meta object"
},
source: %Alembic.Source{
pointer: "/data/meta"
},
status: "422",
title: "Type is wrong"
}
]
}
}
Relationships
"relationships"
allow linking to other resource in the documents "included"
using resource identifiers
iex> Alembic.Resource.from_json(
...> %{
...> "relationships" => %{
...> "shirt" => %{
...> "data" => %{
...> "id" => "1",
...> "type" => "shirt"
...> }
...> }
...> },
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:ok,
%Alembic.Resource{
relationships: %{
"shirt" => %Alembic.Relationship{
data: %Alembic.ResourceIdentifier{
id: "1",
type: "shirt"
}
}
},
type: "thing"
}
}
If any relationship has an error, then it will make the entire resource invalid
iex> Alembic.Resource.from_json(
...> %{
...> "relationships" => %{
...> "shirt" => %{
...> "data" => %{}
...> }
...> },
...> "type" => "thing"
...> },
...> %Alembic.Error{
...> meta: %{
...> "action" => :create,
...> "sender" => :client
...> },
...> source: %Alembic.Source{
...> pointer: "/data"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/data/relationships/shirt/data/type` is missing",
meta: %{
"child" => "type"
},
source: %Alembic.Source{
pointer: "/data/relationships/shirt/data"
},
status: "422",
title: "Child missing"
},
%Alembic.Error{
detail: "`/data/relationships/shirt/data/id` is missing",
meta: %{
"child" => "id"
},
source: %Alembic.Source{
pointer: "/data/relationships/shirt/data"
},
status: "422",
title: "Child missing"
}
]
}
}