Alembic v4.0.0 Alembic.Source View Source
The source
of an error.
Link to this section Summary
Types
A single error field key in the Ecto.Changeset.t
:errors
Keyword.t
A pointer path is composed of the parent
pointer and the final child
name
Options for Alembic.Source.pointer_path_from_ecto_changeset_error_field_options
Functions
Descends pointer
to child
of current pointer
Converts JSON object to t
Converts an ecto_changeset_error_field
to an Alembic.Source.pointer_path
that can be used to generate both the
Alembic.Source.t
:pointer
and Alembic.Error.t
:detail
Link to this section Types
A single error field key in the Ecto.Changeset.t
:errors
Keyword.t
pointer_path() :: {parent :: Api.json_pointer(), child :: String.t()}
A pointer path is composed of the parent
pointer and the final child
name.
Options for Alembic.Source.pointer_path_from_ecto_changeset_error_field_options
t() :: %Alembic.Source{parameter: String.t(), pointer: nil} | %Alembic.Source{parameter: nil, pointer: Api.json_pointer()}
An object containing references to the source of the error, optionally including any of the following members:
pointer
- JSON Pointer (RFC6901) to the associated entity in the request document (e.g."/data"
for a primary data object, or"/data/attributes/title"
for a specific attribute).parameter
- URL query parameter caused the error.
Link to this section Functions
Descends pointer
to child
of current pointer
iex> Alembic.Source.descend(
...> %Alembic.Source{
...> pointer: "/data"
...> },
...> 1
...> )
%Alembic.Source{
pointer: "/data/1"
}
from_json(%{optional(String.t()) => String.t()}, Alembic.Error.t()) :: Alembic.FromJson.error()
Converts JSON object to t
.
Valid Input
A parameter can be the source of an error
iex> Alembic.Source.from_json(
...> %{
...> "parameter" => "q",
...> },
...> %Alembic.Error{
...> source: %Alembic.Source{
...> pointer: "/errors/0/source"
...> }
...> }
...> )
{
:ok,
%Alembic.Source{
parameter: "q"
}
}
A member of a JSON object can be the source of an error, in which case a pointer to the location in the object will be given
iex> Alembic.Source.from_json(
...> %{
...> "pointer" => "/data"
...> },
...> %Alembic.Error{
...> source: %Alembic.Source{
...> pointer: "/errors/0/source"
...> }
...> }
...> )
{
:ok,
%Alembic.Source{
pointer: "/data"
}
}
Invalid Input
It is assumed that only "parameter"
or "pointer"
can be set in a single error source (although that’s not
explicit in the JSON API specification), so setting both is an error
iex> Alembic.Source.from_json(
...> %{
...> "parameter" => "q",
...> "pointer" => "/data"
...> },
...> %Alembic.Error{
...> source: %Alembic.Source{
...> pointer: "/errors/0/source"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "The following members conflict with each other (only one can be present):\nparameter\npointer",
meta: %{
"children" => [
"parameter",
"pointer"
]
},
source: %Alembic.Source{
pointer: "/errors/0/source"
},
status: "422",
title: "Children conflicting"
}
]
}
}
A parameter MUST be a string
iex> Alembic.Source.from_json(
...> %{
...> "parameter" => true,
...> },
...> %Alembic.Error{
...> source: %Alembic.Source{
...> pointer: "/errors/0/source"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/errors/0/source/parameter` type is not string",
meta: %{
"type" => "string"
},
source: %Alembic.Source{
pointer: "/errors/0/source/parameter"
},
status: "422",
title: "Type is wrong"
}
]
}
}
A pointer MUST be a string
iex> Alembic.Source.from_json(
...> %{
...> "pointer" => ["data"],
...> },
...> %Alembic.Error{
...> source: %Alembic.Source{
...> pointer: "/errors/0/source"
...> }
...> }
...> )
{
:error,
%Alembic.Document{
errors: [
%Alembic.Error{
detail: "`/errors/0/source/pointer` type is not string",
meta: %{
"type" => "string"
},
source: %Alembic.Source{
pointer: "/errors/0/source/pointer"
},
status: "422",
title: "Type is wrong"
}
]
}
}
pointer_path_from_ecto_changeset_error_field( ecto_changeset_error_field(), pointer_path_from_ecto_changeset_error_field_options() ) :: {:ok, pointer_path()} | :error
Converts an ecto_changeset_error_field
to an Alembic.Source.pointer_path
that can be used to generate both the
Alembic.Source.t
:pointer
and Alembic.Error.t
:detail
If ecto_changeset_error_field
is in the association_set
, then the pointer_path
will be under
/data/relationships
and the child
String.t
will be formatted with format_key
, so that the expected underscore
and hypenation rules are followed.
iex> format_key = fn key ->
...> key |> Atom.to_string() |> String.replace("_", "-")
...> end
iex> Alembic.Source.pointer_path_from_ecto_changeset_error_field(
...> :favorite_posts,
...> %{
...> association_set: MapSet.new([:designated_editor, :favorite_posts]),
...> association_by_foreign_key: %{designated_editor_id: :designated_editor},
...> attribute_set: MapSet.new([:first_name, :last_name]),
...> format_key: format_key
...> }
...> )
{:ok, {"/data/relationships", "favorite-posts"}}
If ecto_changeset_error_field
is a key in association_by_foreign_key
, then the associated association is used for
child
and the parent is /data/relationships
the same as if the ecto_cahgneset_error_field
were directly an
associaton name.
iex> format_key = fn key ->
...> key |> Atom.to_string() |> String.replace("_", "-")
...> end
iex> Alembic.Source.pointer_path_from_ecto_changeset_error_field(
...> :designated_editor_id,
...> %{
...> association_set: MapSet.new([:designated_editor, :favorite_posts]),
...> association_by_foreign_key: %{designated_editor_id: :designated_editor},
...> attribute_set: MapSet.new([:first_name, :last_name]),
...> format_key: format_key
...> }
...> )
{:ok, {"/data/relationships", "designated-editor"}}
If ecto_changeset_error_field
is in the attribute_set
, then the pointer_path
will be under /data/attributes
and the child
String.t
will be formated with format_key
, so that the expected underscore and hypenation rules
are followed.
iex> format_key = fn key ->
...> key |> Atom.to_string() |> String.replace("_", "-")
...> end
iex> Alembic.Source.pointer_path_from_ecto_changeset_error_field(
...> :first_name,
...> %{
...> association_set: MapSet.new([:designated_editor, :favorite_posts]),
...> association_by_foreign_key: %{designated_editor_id: :designated_editor},
...> attribute_set: MapSet.new([:first_name, :last_name]),
...> format_key: format_key
...> }
...> )
{:ok, {"/data/attributes", "first-name"}}
If ecto_changeset_error_field
is not in association_set
, attribute_set
or a foreign key in
association_by_foreign_key
, then :error
is returned. Callers should treat this as indicating the error has no
source pointer and the Alembic.Error.t
:source
should be left nil
.
iex> format_key = fn key ->
...> key |> Atom.to_string() |> String.replace("_", "-")
...> end
iex> Alembic.Source.pointer_path_from_ecto_changeset_error_field(
...> :name,
...> %{
...> association_set: MapSet.new([:designated_editor, :favorite_posts]),
...> association_by_foreign_key: %{designated_editor_id: :designated_editor},
...> attribute_set: MapSet.new([:first_name, :last_name]),
...> format_key: format_key
...> }
...> )
:error