Skip to content

Commit

Permalink
Update JSONAPI.View and related tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleboe committed Jun 14, 2024
1 parent b2f8b23 commit 4046cdb
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 284 deletions.
146 changes: 4 additions & 142 deletions lib/jsonapi/view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule JSONAPI.View do
end
defmodule DogView do
use JSONAPI.View, namespace: "/pupperz-api"
use JSONAPI.View
end
You can now call `UserView.show(user, conn, conn.params)` and it will render
Expand Down Expand Up @@ -112,19 +112,6 @@ defmodule JSONAPI.View do
If you always want to include a relationship. First make sure its always preloaded
and then use the `[user: {UserView, :include}]` syntax in your `includes` function. This tells
the serializer to *always* include if its loaded.
## Options
* `:host` (binary) - Allows the `host` to be overridden for generated URLs. Defaults to `host` of the supplied `conn`.
* `:scheme` (atom) - Enables configuration of the HTTP scheme for generated URLS. Defaults to `scheme` from the provided `conn`.
* `:namespace` (binary) - Allows the namespace of a given resource. This may be
configured globally or overridden on the View itself. Note that if you have
a globally defined namespace and need to *remove* the namespace for a
resource, set the namespace to a blank String.
The default behaviour for `host` and `scheme` is to derive it from the `conn` provided, while the
default style for presentation in names is to be underscored and not dashed.
"""

alias Plug.Conn
Expand All @@ -143,38 +130,25 @@ defmodule JSONAPI.View do
@callback fields() :: [field()]
@callback get_field(field(), data(), Conn.t()) :: any()
@callback hidden(data()) :: [field()]
@callback links(data(), Conn.t()) :: links() | nil
@callback links(data(), Conn.t(), map() | nil) :: links() | nil
@callback meta(data(), Conn.t()) :: meta() | nil
# @callback namespace() :: String.t()
# @callback pagination_links(data(), Conn.t(), Paginator.page(), Paginator.options()) ::
# Paginator.links()
# @callback path() :: String.t() | nil
@callback relationships() :: [
{atom(), t() | {t(), :include} | {atom(), t()} | {atom(), t(), :include}}
]
@callback type() :: resource_type()
# @callback url_for(data(), Conn.t() | nil) :: String.t()
# @callback url_for_pagination(data(), Conn.t(), Paginator.params()) :: String.t()
# @callback url_for_rel(term(), String.t(), Conn.t() | nil) :: String.t()
@callback visible_fields(data(), Conn.t() | nil) :: list(atom)

@optional_callbacks [get_field: 3]

defmacro __using__(opts \\ []) do
type = Keyword.fetch!(opts, :type)
# {namespace, _opts} = Keyword.pop(opts, :namespace)
# {path, _opts} = Keyword.pop(opts, :path)
# {paginator, _opts} = Keyword.pop(opts, :paginator)
{type, _opts} = Keyword.pop(opts, :type)

quote do
alias JSONAPI.{Serializer, View}

@behaviour View

@resource_type unquote(type)
# @namespace unquote(namespace)
# @path unquote(path)
# @paginator unquote(paginator)

@impl View
def id(nil), do: nil
Expand All @@ -200,7 +174,6 @@ defmodule JSONAPI.View do

Map.put(intermediate_map, field, value)
end)
|> IO.inspect(label: "attributes")
end

@impl View
Expand All @@ -210,32 +183,11 @@ defmodule JSONAPI.View do
def hidden(_data), do: []

@impl View
def links(_data, _conn), do: nil
def links(_data, _conn, _query_page), do: nil

@impl View
def meta(_data, _conn), do: nil

# @impl View
# if @namespace do
# def namespace, do: @namespace
# else
# def namespace, do: Application.get_env(:jsonapi, :namespace, "")
# end

# @impl View
# def pagination_links(data, conn, page, options) do
# paginator = Application.get_env(:jsonapi, :paginator, @paginator)

# if Code.ensure_loaded?(paginator) && function_exported?(paginator, :paginate, 5) do
# paginator.paginate(data, __MODULE__, conn, page, options)
# else
# %{}
# end
# end

# @impl View
# def path, do: @path

@impl View
def relationships, do: []

Expand All @@ -246,18 +198,6 @@ defmodule JSONAPI.View do
def type, do: raise("Need to implement type/0")
end

# @impl View
# def url_for(data, conn),
# do: View.url_for(__MODULE__, data, conn)

# @impl View
# def url_for_pagination(data, conn, pagination_params),
# do: View.url_for_pagination(__MODULE__, data, conn, pagination_params)

# @impl View
# def url_for_rel(data, rel_type, conn),
# do: View.url_for_rel(__MODULE__, data, rel_type, conn)

@impl View
def visible_fields(data, conn),
do: View.visible_fields(__MODULE__, data, conn)
Expand Down Expand Up @@ -296,60 +236,6 @@ defmodule JSONAPI.View do
end
end

# @spec url_for(t(), term(), Conn.t() | nil) :: String.t()
# def url_for(view, data, nil = _conn) when is_nil(data) or is_list(data),
# do: URI.to_string(%URI{path: Enum.join([view.namespace(), path_for(view)], "/")})

# def url_for(view, data, nil = _conn) do
# URI.to_string(%URI{
# path: Enum.join([view.namespace(), path_for(view), view.id(data)], "/")
# })
# end

# def url_for(view, data, %Plug.Conn{} = conn) when is_nil(data) or is_list(data) do
# URI.to_string(%URI{
# scheme: scheme(conn),
# host: host(conn),
# port: port(conn),
# path: Enum.join([view.namespace(), path_for(view)], "/")
# })
# end

# def url_for(view, data, %Plug.Conn{} = conn) do
# URI.to_string(%URI{
# scheme: scheme(conn),
# host: host(conn),
# port: port(conn),
# path: Enum.join([view.namespace(), path_for(view), view.id(data)], "/")
# })
# end

# @spec url_for_rel(t(), data(), resource_type(), Conn.t() | nil) :: String.t()
# def url_for_rel(view, data, rel_type, conn) do
# "#{url_for(view, data, conn)}/relationships/#{rel_type}"
# end

# @spec url_for_rel(t(), data(), Conn.query_params(), Paginator.params()) :: String.t()
# def url_for_pagination(
# view,
# data,
# %{query_params: query_params} = conn,
# nil = _pagination_params
# ) do
# query =
# query_params
# |> Utils.List.to_list_of_query_string_components()
# |> URI.encode_query()

# prepare_url(view, query, data, conn)
# end

# def url_for_pagination(view, data, %{query_params: query_params} = conn, pagination_params) do
# query_params = Map.put(query_params, "page", pagination_params)

# url_for_pagination(view, data, %{conn | query_params: query_params}, nil)
# end

@spec visible_fields(t(), data(), Conn.t() | nil) :: list(atom)
def visible_fields(view, data, conn) do
all_fields =
Expand All @@ -372,33 +258,9 @@ defmodule JSONAPI.View do
|> MapSet.to_list()
end

# defp prepare_url(view, "", data, conn), do: url_for(view, data, conn)

# defp prepare_url(view, query, data, conn) do
# view
# |> url_for(data, conn)
# |> URI.parse()
# |> struct(query: query)
# |> URI.to_string()
# end

defp requested_fields_for_type(view, %Conn{assigns: %{jsonapi_query: %{fields: fields}}}) do
fields[view.type()]
end

defp requested_fields_for_type(_view, _conn), do: nil

# defp host(%Conn{host: host}),
# do: Application.get_env(:jsonapi, :host, host)

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

# defp port(%Conn{port: port}),
# do: Application.get_env(:jsonapi, :port, port)

# defp scheme(%Conn{scheme: scheme}),
# do: Application.get_env(:jsonapi, :scheme, to_string(scheme))

# defp path_for(view), do: view.path() || view.type()
end
138 changes: 2 additions & 136 deletions test/jsonapi/view_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule JSONAPI.ViewTest do
use ExUnit.Case

defmodule PostView do
use JSONAPI.View, type: "posts", namespace: "/api"
use JSONAPI.View, type: "posts"

def fields do
[:title, :body]
Expand All @@ -16,7 +16,7 @@ defmodule JSONAPI.ViewTest do
end

defmodule CommentView do
use JSONAPI.View, type: "comments", namespace: "/api"
use JSONAPI.View, type: "comments"

def fields do
[:body]
Expand Down Expand Up @@ -71,140 +71,6 @@ defmodule JSONAPI.ViewTest do
assert PostView.type() == "posts"
end

describe "namespace/0" do
setup do
Application.put_env(:jsonapi, :namespace, "/cake")

on_exit(fn ->
Application.delete_env(:jsonapi, :namespace)
end)

{:ok, []}
end

test "uses macro configuration first" do
assert PostView.namespace() == "/api"
end

test "uses global namespace if available" do
assert UserView.namespace() == "/cake"
end

test "can be blank" do
assert CarView.namespace() == ""
end
end

describe "url_for/2 when host and scheme not configured" do
test "url_for/2" do
assert PostView.url_for(nil, nil) == "/api/posts"
assert PostView.url_for([], nil) == "/api/posts"
assert PostView.url_for(%{id: 1}, nil) == "/api/posts/1"
assert PostView.url_for([], %Plug.Conn{}) == "http://www.example.com/api/posts"
assert PostView.url_for([], %Plug.Conn{port: 123}) == "http://www.example.com:123/api/posts"
assert PostView.url_for(%{id: 1}, %Plug.Conn{}) == "http://www.example.com/api/posts/1"

assert PostView.url_for_rel([], "comments", %Plug.Conn{}) ==
"http://www.example.com/api/posts/relationships/comments"

assert PostView.url_for_rel(%{id: 1}, "comments", %Plug.Conn{}) ==
"http://www.example.com/api/posts/1/relationships/comments"
end
end

describe "url_for/2 when host configured" do
setup do
Application.put_env(:jsonapi, :host, "www.otherhost.com")

on_exit(fn ->
Application.delete_env(:jsonapi, :host)
end)

{:ok, []}
end

test "uses configured host instead of that on Conn" do
assert PostView.url_for_rel([], "comments", %Plug.Conn{}) ==
"http://www.otherhost.com/api/posts/relationships/comments"

assert PostView.url_for_rel(%{id: 1}, "comments", %Plug.Conn{}) ==
"http://www.otherhost.com/api/posts/1/relationships/comments"

assert PostView.url_for([], %Plug.Conn{}) == "http://www.otherhost.com/api/posts"
assert PostView.url_for(%{id: 1}, %Plug.Conn{}) == "http://www.otherhost.com/api/posts/1"
end
end

describe "url_for/2 when scheme configured" do
setup do
Application.put_env(:jsonapi, :scheme, "ftp")

on_exit(fn ->
Application.delete_env(:jsonapi, :scheme)
end)

{:ok, []}
end

test "uses configured scheme instead of that on Conn" do
assert PostView.url_for([], %Plug.Conn{}) == "ftp://www.example.com/api/posts"
assert PostView.url_for(%{id: 1}, %Plug.Conn{}) == "ftp://www.example.com/api/posts/1"

assert PostView.url_for_rel([], "comments", %Plug.Conn{}) ==
"ftp://www.example.com/api/posts/relationships/comments"

assert PostView.url_for_rel(%{id: 1}, "comments", %Plug.Conn{}) ==
"ftp://www.example.com/api/posts/1/relationships/comments"
end
end

describe "url_for/2 when port configured" do
setup do
Application.put_env(:jsonapi, :port, 42)

on_exit(fn ->
Application.delete_env(:jsonapi, :port)
end)

{:ok, []}
end

test "uses configured port instead of that on Conn" do
assert PostView.url_for([], %Plug.Conn{}) == "http://www.example.com:42/api/posts"
assert PostView.url_for(%{id: 1}, %Plug.Conn{}) == "http://www.example.com:42/api/posts/1"

assert PostView.url_for_rel([], "comments", %Plug.Conn{}) ==
"http://www.example.com:42/api/posts/relationships/comments"

assert PostView.url_for_rel(%{id: 1}, "comments", %Plug.Conn{}) ==
"http://www.example.com:42/api/posts/1/relationships/comments"
end
end

describe "url_for_pagination/3" do
setup do
{:ok, conn: Plug.Conn.fetch_query_params(%Plug.Conn{})}
end

test "with pagination information", %{conn: conn} do
assert PostView.url_for_pagination(nil, conn, %{}) == "http://www.example.com/api/posts"

assert PostView.url_for_pagination(nil, conn, %{number: 1, size: 10}) ==
"http://www.example.com/api/posts?page%5Bnumber%5D=1&page%5Bsize%5D=10"
end

test "with query parameters", %{conn: conn} do
conn_with_query_params =
Kernel.update_in(conn.query_params, &Map.put(&1, "comments", [5, 2]))

assert PostView.url_for_pagination(nil, conn_with_query_params, %{number: 1, size: 10}) ==
"http://www.example.com/api/posts?comments%5B%5D=5&comments%5B%5D=2&page%5Bnumber%5D=1&page%5Bsize%5D=10"

assert PostView.url_for_pagination(nil, conn_with_query_params, %{}) ==
"http://www.example.com/api/posts?comments%5B%5D=5&comments%5B%5D=2"
end
end

test "render/2 is defined when 'Phoenix' is loaded" do
assert {:render, 2} in CommentView.__info__(:functions)
end
Expand Down
Loading

0 comments on commit 4046cdb

Please sign in to comment.