Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions lib/jsonapi_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ defmodule JSONAPIPlug do
doc: "Controls wether the attribute is deserialized in requests.",
type: :boolean,
default: true
],
required: [
doc: "Attribute is required.",
type: :boolean,
default: false
],
type: [
doc: "Attribute type",
type: {:in, [:string, :number]},
default: :string
]
]

Expand All @@ -225,12 +235,8 @@ defmodule JSONAPIPlug do
doc:
"Resource attributes. This will be used to (de)serialize requests/responses:\n\n" <>
NimbleOptions.docs(@attribute_schema, nest_level: 1),
type:
{:or,
[
{:list, :atom},
{:keyword_list, [*: [type: [keyword_list: [keys: @attribute_schema]]]]}
]},
type: :keyword_list,
keys: [*: [type: :keyword_list, keys: @attribute_schema]],
default: []
],
id_attribute: [
Expand Down
63 changes: 46 additions & 17 deletions lib/jsonapi_plug/document.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ defmodule JSONAPIPlug.Document do
https://jsonapi.org/format/#document-structure
"""

alias JSONAPIPlug.{
Document.ErrorObject,
Document.JSONAPIObject,
Document.LinkObject,
Document.ResourceObject,
Exceptions.InvalidDocument,
Resource
}
alias JSONAPIPlug.Document.{ErrorObject, JSONAPIObject, LinkObject, ResourceObject}
alias JSONAPIPlug.Exceptions.InvalidDocument
alias JSONAPIPlug.Resource

@type value :: String.t() | integer() | float() | [value()] | %{String.t() => value()} | nil

Expand Down Expand Up @@ -99,7 +94,12 @@ defmodule JSONAPIPlug.Document do
defp deserialize_data(%{"data" => _data, "errors" => _errors}) do
raise InvalidDocument,
message: "Document cannot contain both 'data' and 'errors' members",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document cannot contain both 'data' and 'errors' members",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp deserialize_data(%{"data" => resources}) when is_list(resources),
Expand All @@ -124,14 +124,24 @@ defmodule JSONAPIPlug.Document do
when is_list(included) do
raise InvalidDocument,
message: "Document 'included' cannot be present if 'data' isn't also present",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document 'included' cannot be present if 'data' isn't also present",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp deserialize_included(%{"included" => included})
when not is_nil(included) do
raise InvalidDocument,
message: "Document 'included' must be a list",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document 'included' must be a list",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp deserialize_included(_data), do: nil
Expand All @@ -152,7 +162,12 @@ defmodule JSONAPIPlug.Document do
defp deserialize_meta(%{"meta" => meta}) when not is_nil(meta) do
raise InvalidDocument,
message: "Document 'meta' must be an object",
reference: "https://jsonapi.org/format/#document-meta"
errors: [
%ErrorObject{
title: "Document 'meta' must be an object",
detail: "https://jsonapi.org/format/#document-meta"
}
]
end

defp deserialize_meta(_data), do: nil
Expand Down Expand Up @@ -183,11 +198,15 @@ defmodule JSONAPIPlug.Document do

defp serialize_data(nil), do: nil

defp serialize_errors(errors)
when not is_nil(errors) and not is_list(errors) do
defp serialize_errors(errors) when not is_nil(errors) and not is_list(errors) do
raise InvalidDocument,
message: "Document 'errors' must be a list",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document 'errors' must be a list",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp serialize_errors(errors) when is_list(errors),
Expand All @@ -199,7 +218,12 @@ defmodule JSONAPIPlug.Document do
when not is_nil(included) and not is_list(included) do
raise InvalidDocument,
message: "Document 'included' must be a list resource objects",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document 'included' must be a list resource objects",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp serialize_included(included) when is_list(included),
Expand All @@ -210,7 +234,12 @@ defmodule JSONAPIPlug.Document do
defp serialize_meta(meta) when not is_nil(meta) and not is_map(meta) do
raise InvalidDocument,
message: "Document 'meta' must be a map",
reference: "https://jsonapi.org/format/#document-top-level"
errors: [
%ErrorObject{
title: "Document 'meta' must be a map",
detail: "https://jsonapi.org/format/#document-top-level"
}
]
end

defp serialize_meta(meta), do: meta
Expand Down
22 changes: 18 additions & 4 deletions lib/jsonapi_plug/document/jsonapi_object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ defmodule JSONAPIPlug.Document.JSONAPIObject do
JSON:API Document JSON:API Object
"""

alias JSONAPIPlug.{Document, Exceptions.InvalidDocument}
alias JSONAPIPlug.Document
alias JSONAPIPlug.Document.ErrorObject
alias JSONAPIPlug.Exceptions.InvalidDocument

@type version :: :"1.0" | :"1.1"

Expand All @@ -19,8 +21,14 @@ defmodule JSONAPIPlug.Document.JSONAPIObject do

defp deserialize_meta(%{"meta" => _meta}) do
raise InvalidDocument,
message: "JSON:API object 'meta' must be an object",
reference: "https://jsonapi.org/format/#document-jsonapi-object"
message: "JSON:API Object 'meta' must be an object",
errors: [
%ErrorObject{
title: "JSON:API object 'meta' must be an object",
detail: "https://jsonapi.org/format/#document-jsonapi-object",
source: %{pointer: "/jsonapi/meta"}
}
]
end

defp deserialize_meta(_data), do: nil
Expand All @@ -30,7 +38,13 @@ defmodule JSONAPIPlug.Document.JSONAPIObject do
defp deserialize_version(%{"version" => version}) do
raise InvalidDocument,
message: "JSON:API Object has invalid version (#{version})",
reference: "https://jsonapi.org/format/#document-jsonapi-object"
errors: [
%ErrorObject{
title: "JSON:API Object has invalid version (#{version})",
detail: "https://jsonapi.org/format/#document-jsonapi-object",
source: %{pointer: "/jsonapi/version"}
}
]
end

defp deserialize_version(_data), do: nil
Expand Down
19 changes: 11 additions & 8 deletions lib/jsonapi_plug/document/relationship_object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ defmodule JSONAPIPlug.Document.RelationshipObject do
https://jsonapi.org/format/#document-resource-object-relationships
"""

alias JSONAPIPlug.{
Document,
Document.LinkObject,
Document.ResourceIdentifierObject,
Exceptions.InvalidDocument
}
alias JSONAPIPlug.Document
alias JSONAPIPlug.Document.{ErrorObject, LinkObject, ResourceIdentifierObject}
alias JSONAPIPlug.Exceptions.InvalidDocument

@type links :: %{atom() => LinkObject.t()}

Expand Down Expand Up @@ -54,8 +51,14 @@ defmodule JSONAPIPlug.Document.RelationshipObject do

defp deserialize_meta(%{"meta" => _meta}) do
raise InvalidDocument,
message: "Relationship object 'meta' must be an object",
reference: "https://jsonapi.org/format/#document-resource-object-relationships"
message: "Relationship Object 'meta' must be an object",
errors: [
%ErrorObject{
title: "Relationship Object 'meta' must be an object",
detail: "https://jsonapi.org/format/#document-resource-object-relationships",
source: %{pointer: "/meta"}
}
]
end

defp deserialize_meta(_data), do: nil
Expand Down
20 changes: 16 additions & 4 deletions lib/jsonapi_plug/document/resource_identifier_object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ defmodule JSONAPIPlug.Document.ResourceIdentifierObject do
https://jsonapi.org/format/#document-resource-object-linkage
"""

alias JSONAPIPlug.{Document, Document.ResourceObject, Exceptions.InvalidDocument}
alias JSONAPIPlug.Document
alias JSONAPIPlug.Document.{ErrorObject, ResourceObject}
alias JSONAPIPlug.Exceptions.InvalidDocument

@type t :: %__MODULE__{
id: ResourceObject.id() | nil,
Expand Down Expand Up @@ -36,7 +38,12 @@ defmodule JSONAPIPlug.Document.ResourceIdentifierObject do
defp deserialize_meta(%{"meta" => _meta}) do
raise InvalidDocument,
message: "Resource Identifier object 'meta' must be an object",
reference: "https://jsonapi.org/format/#document-resource-identifier-objects"
errors: [
%ErrorObject{
title: "Resource Identifier object 'meta' must be an object",
detail: "https://jsonapi.org/format/#document-resource-identifier-objects"
}
]
end

defp deserialize_meta(_payload), do: nil
Expand All @@ -45,7 +52,12 @@ defmodule JSONAPIPlug.Document.ResourceIdentifierObject do

defp deserialize_type(type) do
raise InvalidDocument,
message: "Resource Identifier object type (#{type}) is invalid",
reference: "https://jsonapi.org/format/#document-resource-objects"
message: "Resource Identifier object type '#{type}' is invalid",
errors: [
%ErrorObject{
title: "Resource Identifier object type '#{type}' is invalid",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end
end
61 changes: 47 additions & 14 deletions lib/jsonapi_plug/document/resource_object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@ defmodule JSONAPIPlug.Document.ResourceObject do
https://jsonapi.org/format/#resource_object-resource-objects
"""

alias JSONAPIPlug.{
Document,
Document.LinkObject,
Document.RelationshipObject,
Exceptions.InvalidDocument
}
alias JSONAPIPlug.Document
alias JSONAPIPlug.Document.{ErrorObject, LinkObject, RelationshipObject}
alias JSONAPIPlug.Exceptions.InvalidDocument

@type id :: String.t()
@type type :: String.t()
@type attributes :: %{String.t() => Document.value()}

@type t :: %__MODULE__{
id: id() | nil,
lid: id() | nil,
type: type(),
attributes: %{String.t() => Document.value()},
attributes: attributes() | nil,
links: Document.links() | nil,
meta: Document.meta() | nil,
relationships: %{String.t() => [RelationshipObject.t()]}
Expand Down Expand Up @@ -56,19 +54,34 @@ defmodule JSONAPIPlug.Document.ResourceObject do
defp deserialize_type(%{"type" => type}) do
raise InvalidDocument,
message: "Resource object type '#{type}' is invalid",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object type (#{type}) is invalid",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_attributes(%{"attributes" => %{"id" => _id}}) do
raise InvalidDocument,
message: "Resource object cannot have an attribute named 'id'",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object cannot have an attribute named 'id'",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_attributes(%{"attributes" => %{"type" => _type}}) do
raise InvalidDocument,
message: "Resource object cannot have an attribute named 'type'",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object cannot have an attribute named 'type'",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_attributes(%{"attributes" => attributes})
Expand All @@ -88,13 +101,23 @@ defmodule JSONAPIPlug.Document.ResourceObject do
defp deserialize_relationships(%{"relationships" => %{"id" => _id}}) do
raise InvalidDocument,
message: "Resource object cannot have a relationship named 'id'",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object cannot have a relationship named 'id'",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_relationships(%{"relationships" => %{"type" => _type}}) do
raise InvalidDocument,
message: "Resource object cannot have a relationship named 'type'",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object cannot have a relationship named 'type'",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_relationships(%{"relationships" => relationships})
Expand All @@ -113,7 +136,12 @@ defmodule JSONAPIPlug.Document.ResourceObject do
}) do
raise InvalidDocument,
message: "Resource object 'relationships' attribute must be an object",
reference: "https://jsonapi.org/format/#document-resource-object-relationships"
errors: [
%ErrorObject{
title: "Resource object 'relationships' attribute must be an object",
detail: "https://jsonapi.org/format/#document-resource-object-relationships"
}
]
end

defp deserialize_relationships(_data), do: %{}
Expand All @@ -123,7 +151,12 @@ defmodule JSONAPIPlug.Document.ResourceObject do
defp deserialize_meta(%{"meta" => _meta}) do
raise InvalidDocument,
message: "Resource object 'meta' must be an object",
reference: "https://jsonapi.org/format/#document-resource-objects"
errors: [
%ErrorObject{
title: "Resource object 'meta' must be an object",
detail: "https://jsonapi.org/format/#document-resource-objects"
}
]
end

defp deserialize_meta(_data), do: nil
Expand Down
Loading