Skip to content

Commit

Permalink
replace underscores with dashes in relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchellhenke committed Oct 10, 2017
1 parent 31c4ae6 commit 0c50bc6
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 43 deletions.
13 changes: 11 additions & 2 deletions lib/jsonapi/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule JSONAPI.Serializer do
"""

import JSONAPI.Ecto, only: [assoc_loaded?: 1]
alias JSONAPI.Utils.Underscore

@doc """
Takes a view, data and a optional plug connection and returns a fully JSONAPI Serialized document.
Expand Down Expand Up @@ -41,7 +42,7 @@ defmodule JSONAPI.Serializer do
doc = %{
id: view.id(data),
type: view.type(),
attributes: view.attributes(data, conn),
attributes: underscore(view.attributes(data, conn)),
relationships: %{},
links: %{
self: view.url_for(data, conn)
Expand Down Expand Up @@ -75,7 +76,7 @@ defmodule JSONAPI.Serializer do
# Build the relationship url
rel_url = view.url_for_rel(data, key, conn)
# Build the relationship
acc = put_in(acc, [:relationships, key], encode_relation(only_rel_view, rel_data, rel_url, conn))
acc = put_in(acc, [:relationships, underscore(key)], encode_relation(only_rel_view, rel_data, rel_url, conn))

valid_include_view = include_view(valid_includes, key)

Expand Down Expand Up @@ -163,4 +164,12 @@ defmodule JSONAPI.Serializer do

def get_view({view, :include}), do: view
def get_view(view), do: view

def underscore(data) do
if Underscore.underscore?() do
Underscore.underscore(data)
else
data
end
end
end
31 changes: 31 additions & 0 deletions lib/jsonapi/utils/underscore.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule JSONAPI.Utils.Underscore do
@moduledoc """
Helpers for replacing underscores with dashes.
"""

def underscore?, do: Application.get_env(:jsonapi, :underscore_to_dash, false)

def underscore(value) when is_atom(value) do
value
|> to_string
|> underscore
end

def underscore(value) when is_binary(value) do
String.replace(value, "_", "-")
end

def underscore(value) when is_map(value) do
value
|> Enum.map(&underscore/1)
|> Enum.into(%{})
end

def underscore({key, value}) do
if is_map(value) do
{underscore(key), underscore(value)}
else
{underscore(key), value}
end
end
end
24 changes: 1 addition & 23 deletions lib/jsonapi/view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,8 @@ defmodule JSONAPI.View do
def type, do: raise "Need to implement type/0"
end

#TODO Figure out the nesting of fields
def attributes(data, conn) do
data = visible_fields(data)

if underscore?() do
underscore(data)
else
data
end
visible_fields(data)
end

def meta(_data, _conn), do: nil
Expand Down Expand Up @@ -152,21 +145,6 @@ defmodule JSONAPI.View do

defp visible_fields(data), do: Map.take(data, fields() -- hidden())

defp underscore?, do: Application.get_env(:jsonapi, :underscore_to_dash, false)

defp underscore(data) do
data
|> Enum.map(fn {key, value} -> {underscore_key(key), value} end)
|> Enum.into(%{})
end

defp underscore_key(key) do
key
|> to_string
|> String.replace("_", "-")
|> String.to_atom
end

defp host(conn), do: Application.get_env(:jsonapi, :host, conn.host)

defp scheme(conn), do: Application.get_env(:jsonapi, :scheme, to_string(conn.scheme))
Expand Down
7 changes: 0 additions & 7 deletions test/jsonapi/view_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,4 @@ defmodule JSONAPI.ViewTest do
expected_map = %{age: 100, first_name: "Jason", last_name: "S"}
assert expected_map == UserView.attributes(%{age: 100, first_name: "Jason", last_name: "S", password: "securepw"}, nil)
end

test "attributes/2 with `:underscore_to_dash` option" do
Application.put_env(:jsonapi, :underscore_to_dash, true)
expected_map = %{age: 100, "first-name": "Jason", "last-name": "S"}
assert expected_map == UserView.attributes(%{age: 100, first_name: "Jason", last_name: "S"}, nil)
Application.put_env(:jsonapi, :underscore_to_dash, false)
end
end
51 changes: 40 additions & 11 deletions test/serializer_test.exs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
defmodule JSONAPISerializerTest do
use ExUnit.Case
use ExUnit.Case, async: false
alias JSONAPI.Serializer

defmodule PostView do
use JSONAPI.View

def fields, do: [:text, :body]
def fields, do: [:text, :body, :full_description]
def meta(data, _conn), do: %{meta_text: "meta_#{data[:text]}"}
def type, do: "mytype"
def relationships do
[author: {JSONAPISerializerTest.UserView, :include},
comments: {JSONAPISerializerTest.CommentView, :include}]
best_comments: {JSONAPISerializerTest.CommentView, :include}
]
end
end

defmodule UserView do
use JSONAPI.View

def fields, do: [:username]
def fields, do: [:username, :first_name, :last_name]
def type, do: "user"
def relationships, do: []
end
Expand Down Expand Up @@ -46,7 +47,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: [
best_comments: [
%{ id: 5, text: "greatest comment ever", user: %{id: 4, username: "jack"}},
%{ id: 6, text: "not so great", user: %{id: 2, username: "jason"}}
]
Expand Down Expand Up @@ -75,7 +76,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: [
best_comments: [
%{ id: 5, text: "greatest comment ever", user: %{id: 4, username: "jack"}},
%{ id: 6, text: "not so great", user: %{id: 2, username: "jason"}}
]
Expand Down Expand Up @@ -105,7 +106,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: []
best_comments: []
}

encoded = Serializer.serialize(PostView, data, nil)
Expand All @@ -130,7 +131,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: nil
best_comments: nil
}

encoded = Serializer.serialize(PostView, data, nil)
Expand All @@ -155,7 +156,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: []
best_comments: []
}

encoded = Serializer.serialize(PostView, data, nil)
Expand All @@ -170,7 +171,7 @@ defmodule JSONAPISerializerTest do
text: "Hello",
body: "Hello world",
author: %{ id: 2, username: "jason"},
comments: [
best_comments: [
%{id: 5, text: "greatest comment ever", user: %{id: 4, username: "jack"}},
%{id: 6, text: "not so great", user: %{id: 2, username: "jason"}}
]
Expand All @@ -179,7 +180,7 @@ defmodule JSONAPISerializerTest do
conn = %Plug.Conn{
assigns: %{
jsonapi_query: %{
includes: [comments: :user]
includes: [best_comments: :user]
}
}
}
Expand All @@ -189,4 +190,32 @@ defmodule JSONAPISerializerTest do
assert encoded.data.relationships.author.links.self == "http://www.example.com/mytype/1/relationships/author"
assert Enum.count(encoded.included) == 4
end

test "serialize properly uses underscore_to_dash on both attributes and relationships" do
data = %{
id: 1,
text: "Hello",
body: "Hello world",
full_description: "This_is_my_description",
author: %{ id: 2, username: "jbonds", first_name: "jerry", last_name: "bonds"},
best_comments: [
%{id: 5, text: "greatest comment ever", user: %{id: 4, username: "jack", last_name: "bronds"}},
]
}

Application.put_env(:jsonapi, :underscore_to_dash, true)

encoded = Serializer.serialize(PostView, data, nil)

attributes = encoded[:data][:attributes]
relationships = encoded[:data][:relationships]
included = encoded[:included]

assert attributes["full-description"] == data[:full_description]
assert Enum.find(included, fn(i) -> i[:type] == "user" && i[:id] == "2" end)[:attributes]["last-name"] == "bonds"
assert Enum.find(included, fn(i) -> i[:type] == "user" && i[:id] == "4" end)[:attributes]["last-name"] == "bronds"
assert List.first(relationships["best-comments"][:data])[:id] == "5"

Application.delete_env(:jsonapi, :underscore_to_dash)
end
end

0 comments on commit 0c50bc6

Please sign in to comment.