Skip to content

Commit

Permalink
refactor: modernization
Browse files Browse the repository at this point in the history
  • Loading branch information
doomspork committed Jun 25, 2024
1 parent 48db78a commit a9af9cf
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 105 deletions.
4 changes: 2 additions & 2 deletions lib/jsonapi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule JSONAPI do
A module for working with the JSON API specification in Elixir
"""

@mime_type "application/vnd.api+json"

@doc """
Returns the configured JSON encoding library for JSONAPI.
To customize the JSON library, including the following
Expand All @@ -26,8 +28,6 @@ defmodule JSONAPI do
end
end

@mime_type "application/vnd.api+json"

@doc """
This returns the MIME type for JSONAPIs
"""
Expand Down
12 changes: 6 additions & 6 deletions lib/jsonapi/error_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ defmodule JSONAPI.ErrorView do

@spec missing_relationship_data_param_error_attrs(binary()) :: error_attrs()
def missing_relationship_data_param_error_attrs(relationship_name) do
"Missing data member in relationship"
|> build_error(
build_error(
"Missing data member in relationship",
400,
"Check out https://jsonapi.org/format/#crud-creating and https://jsonapi.org/format/#crud-updating-resource-relationships for more info.",
"/data/relationships/#{relationship_name}/data"
Expand All @@ -119,8 +119,8 @@ defmodule JSONAPI.ErrorView do

@spec missing_relationship_data_id_param_error_attrs(binary()) :: error_attrs()
def missing_relationship_data_id_param_error_attrs(relationship_name) do
"Missing id in relationship data parameter"
|> build_error(
build_error(
"Missing id in relationship data parameter",
400,
@relationship_resource_linkage_message,
"/data/relationships/#{relationship_name}/data/id"
Expand All @@ -129,8 +129,8 @@ defmodule JSONAPI.ErrorView do

@spec missing_relationship_data_type_param_error_attrs(binary()) :: error_attrs()
def missing_relationship_data_type_param_error_attrs(relationship_name) do
"Missing type in relationship data parameter"
|> build_error(
build_error(
"Missing type in relationship data parameter",
400,
@relationship_resource_linkage_message,
"/data/relationships/#{relationship_name}/data/type"
Expand Down
56 changes: 30 additions & 26 deletions lib/jsonapi/plugs/query_parser.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
defmodule JSONAPI.QueryParser do
@behaviour Plug
alias JSONAPI.{Config, Deprecation}
alias JSONAPI.Exceptions.InvalidQuery
alias Plug.Conn
import JSONAPI.Utils.IncludeTree
import JSONAPI.Utils.String, only: [underscore: 1]

@moduledoc """
Implements a fully JSONAPI V1 spec for parsing a complex query string via the
`query_params` field from a `Plug.Conn` struct and returning Elixir datastructures.
Expand Down Expand Up @@ -82,6 +75,14 @@ defmodule JSONAPI.QueryParser do
For more details please see `JSONAPI.UnderscoreParameters`.
"""
@behaviour Plug

import JSONAPI.Utils.IncludeTree
import JSONAPI.Utils.String, only: [underscore: 1]

alias JSONAPI.Exceptions.InvalidQuery
alias JSONAPI.{Config, Deprecation}
alias Plug.Conn

@impl Plug
def init(opts) do
Expand Down Expand Up @@ -119,7 +120,7 @@ defmodule JSONAPI.QueryParser do

Enum.reduce(filter, config, fn {key, val}, acc ->
check_filter_validity!(opts_filter, key, config)
%{acc | filter: Keyword.put(acc.filter, String.to_atom(key), val)}
%{acc | filter: Keyword.put(acc.filter, String.to_existing_atom(key), val)}
end)
end

Expand Down Expand Up @@ -183,7 +184,7 @@ defmodule JSONAPI.QueryParser do
raise InvalidQuery, resource: config.view.type(), param: field, param_type: :sort
end

build_sort(direction, String.to_atom(field))
build_sort(direction, String.to_existing_atom(field))
end)
|> List.flatten()

Expand All @@ -210,26 +211,29 @@ defmodule JSONAPI.QueryParser do
|> Enum.filter(&(&1 !== ""))
|> Enum.map(&underscore/1)

Enum.reduce(includes, [], fn inc, acc ->
check_include_validity!(inc, config)
Enum.reduce(includes, [], &include_reducer(config, valid_includes, &1, &2))
end

defp include_reducer(config, valid_includes, inc, acc) do
check_include_validity!(inc, config)

if inc =~ ~r/\w+\.\w+/ do
acc ++ handle_nested_include(inc, valid_includes, config)
else
inc =
try do
String.to_existing_atom(inc)
rescue
ArgumentError -> raise_invalid_include_query(inc, config.view.type())
end

if Enum.any?(valid_includes, fn {key, _val} -> key == inc end) do
acc ++ [inc]
else
raise_invalid_include_query(inc, config.view.type())
if inc =~ ~r/\w+\.\w+/ do
acc ++ handle_nested_include(inc, valid_includes, config)
else
inc =
try do
String.to_existing_atom(inc)
rescue
ArgumentError -> raise_invalid_include_query(inc, config.view.type())
end

# credo:disable-for-next-line
if Enum.any?(valid_includes, fn {key, _val} -> key == inc end) do
Enum.reverse([inc | acc])
else
raise_invalid_include_query(inc, config.view.type())
end
end)
end
end

defp check_include_validity!(key, %Config{opts: opts, view: view}) do
Expand Down
18 changes: 9 additions & 9 deletions lib/jsonapi/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ defmodule JSONAPI.Serializer do
@moduledoc """
Serialize a map of data into a properly formatted JSON API response object
"""
require Logger

alias JSONAPI.{Config, Utils, View}
alias Plug.Conn

require Logger

@type document :: map()

@doc """
Expand Down Expand Up @@ -51,7 +50,7 @@ defmodule JSONAPI.Serializer do
def encode_data(view, data, conn, query_includes, options) when is_list(data) do
Enum.map_reduce(data, [], fn d, acc ->
{to_include, encoded_data} = encode_data(view, d, conn, query_includes, options)
{to_include, acc ++ [encoded_data]}
{to_include, Enum.reverse([encoded_data | acc])}
end)
end

Expand Down Expand Up @@ -114,8 +113,9 @@ defmodule JSONAPI.Serializer do
rel_query_includes =
if is_list(query_includes) do
query_includes
# credo:disable-for-next-line
|> Enum.reduce([], fn
{^relationship_name, value}, acc -> acc ++ [value]
{^relationship_name, value}, acc -> Enum.reverse([value | acc])
_, acc -> acc
end)
|> List.flatten()
Expand All @@ -126,7 +126,7 @@ defmodule JSONAPI.Serializer do
{rel_included, encoded_rel} =
encode_data(rel_view, rel_data, conn, rel_query_includes, options)

{rel_included ++ [encoded_rel], acc}
{Enum.reverse([encoded_rel | rel_included]), acc}
else
{nil, acc}
end
Expand Down Expand Up @@ -208,15 +208,15 @@ defmodule JSONAPI.Serializer do
end

defp merge_base_links(%{links: links} = doc, data, view, conn) do
view_links = Map.merge(view.links(data, conn), links)
view_links = data |> view.links(conn) |> Map.merge(links)
Map.merge(doc, %{links: view_links})
end

defp merge_links(doc, data, view, conn, page, false, options) when is_list(data) do
links =
Map.merge(view.pagination_links(data, conn, page, options), %{
self: view.url_for_pagination(data, conn, page)
})
data
|> view.pagination_links(conn, page, options)
|> Map.merge(%{self: view.url_for_pagination(data, conn, page)})

doc
|> Map.merge(%{links: links})
Expand Down
4 changes: 2 additions & 2 deletions lib/jsonapi/utils/data_to_params.ex
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ defmodule JSONAPI.Utils.DataToParams do

defp update_list_relationship(existing, id) do
case existing do
val when is_list(val) -> {val, val ++ [id]}
val when is_binary(val) -> {val, [val] ++ [id]}
val when is_list(val) -> {val, Enum.reverse([id | val])}
val when is_binary(val) -> {val, [val, id]}
_ -> {nil, id}
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/jsonapi/utils/string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ defmodule JSONAPI.Utils.String do

# If there are multiple words, perform the camelizing
[h | t] ->
[String.downcase(h) | camelize_list(t)]
|> Enum.join()
Enum.join([String.downcase(h) | camelize_list(t)])
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonapi/view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ defmodule JSONAPI.View do
do: Application.get_env(:jsonapi, :host, host)

defp port(%Conn{port: 0} = conn),
do: port(%{conn | port: URI.default_port(scheme(conn))})
do: port(%{conn | port: conn |> scheme() |> URI.default_port()})

defp port(%Conn{port: port}),
do: Application.get_env(:jsonapi, :port, port)
Expand Down
4 changes: 2 additions & 2 deletions test/jsonapi/plugs/content_type_negotiation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ defmodule JSONAPI.ContentTypeNegotiationTest do
use ExUnit.Case
use Plug.Test

alias JSONAPI.ContentTypeNegotiation

import JSONAPI, only: [mime_type: 0]

alias JSONAPI.ContentTypeNegotiation

test "passes request through" do
conn =
:post
Expand Down
22 changes: 14 additions & 8 deletions test/jsonapi/plugs/deserializer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ defmodule JSONAPI.DeserializerTest do
use ExUnit.Case
use Plug.Test

@ct JSONAPI.mime_type()

defmodule ExamplePlug do
use Plug.Builder
plug(Plug.Parsers, parsers: [:json], json_decoder: Jason)
Expand All @@ -13,11 +15,10 @@ defmodule JSONAPI.DeserializerTest do
end
end

@ct JSONAPI.mime_type()

test "Ignores bodyless requests" do
conn =
Plug.Test.conn("GET", "/")
"GET"
|> Plug.Test.conn("/")
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand All @@ -29,7 +30,8 @@ defmodule JSONAPI.DeserializerTest do
req_body = Jason.encode!(%{"some-nonsense" => "yup"})

conn =
Plug.Test.conn("POST", "/", req_body)
"POST"
|> Plug.Test.conn("/", req_body)
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand All @@ -47,7 +49,8 @@ defmodule JSONAPI.DeserializerTest do
})

conn =
Plug.Test.conn("POST", "/", req_body)
"POST"
|> Plug.Test.conn("/", req_body)
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand Down Expand Up @@ -85,7 +88,8 @@ defmodule JSONAPI.DeserializerTest do
})

conn =
Plug.Test.conn("POST", "/", req_body)
"POST"
|> Plug.Test.conn("/", req_body)
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand Down Expand Up @@ -135,7 +139,8 @@ defmodule JSONAPI.DeserializerTest do
})

conn =
Plug.Test.conn("POST", "/", req_body)
"POST"
|> Plug.Test.conn("/", req_body)
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand Down Expand Up @@ -192,7 +197,8 @@ defmodule JSONAPI.DeserializerTest do
})

conn =
Plug.Test.conn("POST", "/", req_body)
"POST"
|> Plug.Test.conn("/", req_body)
|> put_req_header("content-type", @ct)
|> put_req_header("accept", @ct)

Expand Down
3 changes: 2 additions & 1 deletion test/jsonapi/plugs/query_parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ defmodule JSONAPI.QueryParserTest do
use Plug.Test

import JSONAPI.QueryParser
alias JSONAPI.Exceptions.InvalidQuery

alias JSONAPI.Config
alias JSONAPI.Exceptions.InvalidQuery

defmodule MyView do
use JSONAPI.View
Expand Down
Loading

0 comments on commit a9af9cf

Please sign in to comment.