Repository: jeregrine/jsonapi
Pull request #106 (2018-05-01 21:21:07)

Dasherize keys in relationship urls
Hi, thanks for this library, it's really nice to use!

I noticed that the keys that become part of relationship urls weren't getting dashed. So this is a small test and fix. Should be compatible with #102.

Cheers!


Patch:
diff --git a/lib/jsonapi/query_parser.ex b/lib/jsonapi/query_parser.ex
index 9456963..c8fe705 100644
--- a/lib/jsonapi/query_parser.ex
+++ b/lib/jsonapi/query_parser.ex
@@ -4,6 +4,7 @@ defmodule JSONAPI.QueryParser do
   alias JSONAPI.Page
   alias JSONAPI.Exceptions.InvalidQuery
   alias Plug.Conn
+  alias JSONAPI.Utils.Underscore
   import JSONAPI.Utils.IncludeTree
 
   @moduledoc """
@@ -192,7 +193,11 @@ defmodule JSONAPI.QueryParser do
   end
 
   def handle_nested_include(key, valid_include, config) do
-    keys = key |> String.split(".") |> Enum.map(&String.to_existing_atom/1)
+    keys =
+      key
+      |> String.split(".")
+      |> Enum.map(&dash/1)
+      |> Enum.map(&String.to_existing_atom/1)
 
     last = List.last(keys)
     path = Enum.slice(keys, 0, Enum.count(keys) - 1)
@@ -204,6 +209,14 @@ defmodule JSONAPI.QueryParser do
     end
   end
 
+  def dash(data) do
+    if Underscore.underscore?() do
+      Underscore.dash(data)
+    else
+      data
+    end
+  end
+
   def get_valid_fields_for_type(%{view: view}, type) do
     if type == view.type do
       view.fields
diff --git a/lib/jsonapi/serializer.ex b/lib/jsonapi/serializer.ex
index 47b7821..338e827 100644
--- a/lib/jsonapi/serializer.ex
+++ b/lib/jsonapi/serializer.ex
@@ -81,12 +81,13 @@ defmodule JSONAPI.Serializer do
 
     only_rel_view = get_view(rel_view)
     # Build the relationship url
-    rel_url = view.url_for_rel(data, key, conn)
+    rel_key = underscore(key)
+    rel_url = view.url_for_rel(data, rel_key, conn)
     # Build the relationship
     acc =
       put_in(
         acc,
-        [:relationships, underscore(key)],
+        [:relationships, rel_key],
         encode_relation({only_rel_view, rel_data, rel_url, conn})
       )
 
diff --git a/lib/jsonapi/utils/underscore.ex b/lib/jsonapi/utils/underscore.ex
index a3fd2b6..be109cc 100644
--- a/lib/jsonapi/utils/underscore.ex
+++ b/lib/jsonapi/utils/underscore.ex
@@ -5,6 +5,10 @@ defmodule JSONAPI.Utils.Underscore do
 
   def underscore?, do: Application.get_env(:jsonapi, :underscore_to_dash, false)
 
+  def dash(value) when is_binary(value) do
+    String.replace(value, "-", "_")
+  end
+
   def underscore(value) when is_atom(value) do
     value
     |> to_string


Test patch:
diff --git a/test/jsonapi_query_parser_test.exs b/test/jsonapi_query_parser_test.exs
index 3c1edba..d637833 100644
--- a/test/jsonapi_query_parser_test.exs
+++ b/test/jsonapi_query_parser_test.exs
@@ -20,7 +20,7 @@ defmodule JSONAPI.QueryParserTest do
 
     def fields, do: [:id, :username]
     def type, do: "user"
-    def relationships, do: []
+    def relationships, do: [top_posts: MyView]
   end
 
   defmodule CommentView do
@@ -67,6 +67,16 @@ defmodule JSONAPI.QueryParserTest do
     assert parse_include(config, "author").includes == [:author]
     assert parse_include(config, "comments,author").includes == [:comments, :author]
     assert parse_include(config, "comments.user").includes == [comments: :user]
+
+    assert_raise ArgumentError, "argument error", fn ->
+      assert parse_include(config, "author.top-posts")
+    end
+
+    Application.put_env(:jsonapi, :underscore_to_dash, true)
+
+    assert parse_include(config, "author.top-posts").includes == [author: :top_posts]
+
+    Application.delete_env(:jsonapi, :underscore_to_dash)
   end
 
   test "parse_include/2 returns a map with duplicate values for include and includes for compatibility" do
diff --git a/test/serializer_test.exs b/test/serializer_test.exs
index e85e2e6..449a7da 100644
--- a/test/serializer_test.exs
+++ b/test/serializer_test.exs
@@ -386,6 +386,9 @@ defmodule JSONAPISerializerTest do
 
     assert List.first(relationships["best-comments"][:data])[:id] == "5"
 
+    assert relationships["best-comments"][:links][:self] ==
+             "/mytype/1/relationships/best-comments"
+
     Application.delete_env(:jsonapi, :underscore_to_dash)
   end