Current section

39 Versions

Jump to

Compare versions

9 files changed
+102 additions
-6 deletions
  @@ -2,7 +2,7 @@
2 2 ExHal
3 3 =====
4 4
5 - [![Build Status](https://travis-ci.org/pezra/exhal.svg?branch=master)](https://travis-ci.org/pezra/exhal)
5 + [![Build Status](https://travis-ci.org/pezra/exhal.svg?branch=master)](https://travis-ci.org/pezra/exhal)
6 6 [![Hex.pm](https://img.shields.io/hexpm/v/exhal.svg)](https://hex.pm/packages/exhal)
7 7
8 8 An easy to use [HAL](http://stateless.co/hal_specification.html) API client for elixir.
  @@ -109,6 +109,17 @@ iex> Stream.map(collection, fn follow_results ->
109 109 ["http://example.com/beginning", "http://example.com/middle", "http://example.com/end"]
110 110 ```
111 111
112 + ### Serialization
113 +
114 + Collections and Document can render themselves to a json-like
115 + structure that can then be serialized using your favorite json encoder
116 + (e.g. Poison):
117 +
118 + ExHal.Collection.to_json_hash([ex_hal_doc]) |> Poison.encode!
119 +
120 + or
121 +
122 + ExHal.Document.to_json_hash(ex_hal_doc) |> Poison.encode!
112 123
113 124
114 125 Installation
  @@ -28,4 +28,4 @@
28 28 [{<<"app">>,<<"uri_template">>},
29 29 {<<"optional">>,false},
30 30 {<<"requirement">>,<<"~>1.0">>}]}]}.
31 - {<<"version">>,<<"3.0.0">>}.
31 + {<<"version">>,<<"3.1.0">>}.
  @@ -3,6 +3,8 @@ defmodule ExHal.Collection do
3 3 Utility functions for dealing with RFC 6473 collections
4 4 """
5 5
6 + alias ExHal.Document
7 +
6 8 @doc """
7 9 Returns a stream that iterate over the collection represented by `a_doc`.
8 10 """
  @@ -19,4 +21,10 @@ defmodule ExHal.Collection do
19 21 fn _ -> nil end
20 22 )
21 23 end
24 +
25 + @doc """
26 + """
27 + def to_json_hash(enum) do
28 + %{ "_embedded" => %{"item" => Enum.map(enum, &(Document.to_json_hash(&1)))} }
29 + end
22 30 end
  @@ -6,7 +6,7 @@ defmodule ExHal.Document do
6 6 alias ExHal.Link
7 7 alias ExHal.NsReg
8 8
9 - defstruct properties: %{}, links: %{}, client:
9 + defstruct properties: %{}, links: %{}, client:
10 10
11 11 @doc """
12 12 Returns a new `%ExHal.Document` representing the HAL document provided.
  @@ -17,8 +17,8 @@ defmodule ExHal.Document do
17 17 end
18 18
19 19 @doc """
20 - Returns new ExHal.Document
21 - """
20 + Returns new ExHal.Document
21 + """
22 22 def from_parsed_hal(client, parsed_hal) do
23 23 %__MODULE__{client: client,
24 24 properties: properties_in(parsed_hal),
  @@ -32,10 +32,44 @@ defmodule ExHal.Document do
32 32 Map.has_key?(doc.links, rel)
33 33 end
34 34
35 + @doc """
36 + Returns a map that matches the shape of the intended JSON output.
37 + """
38 + def to_json_hash(doc) do
39 + doc.properties
40 + |> Map.merge(links_sections_to_json_hash(doc))
41 + end
42 +
43 + defp links_sections_to_json_hash(doc) do
44 + {embedded, references} = doc.links
45 + |> Map.to_list
46 + |> Enum.flat_map(fn ({_,v}) -> v end)
47 + |> Enum.partition(&(Link.embedded?(&1)))
48 +
49 + %{"_embedded" => render_links(embedded),
50 + "_links" => render_links(references)}
51 + end
52 +
53 + defp render_links(enum) do
54 + enum
55 + |> Enum.group_by(&(&1.rel))
56 + |> Map.to_list
57 + |> Enum.map(fn ({rel, links}) -> {rel, Enum.map(links, &Link.to_json_hash(&1))} end)
58 + |> Enum.map(fn ({rel, fragments}) -> {rel, unbox_single_fragments(fragments)} end)
59 + |> Map.new
60 + end
61 +
35 62 defp properties_in(parsed_json) do
36 63 Map.drop(parsed_json, ["_links", "_embedded"])
37 64 end
38 65
66 + defp unbox_single_fragments(fragments) do
67 + case fragments do
68 + [fragment] -> fragment
69 + _ -> fragments
70 + end
71 + end
72 +
39 73 defp links_in(client, parsed_json) do
40 74 namespaces = NsReg.from_parsed_json(parsed_json)
41 75 raw_links = simple_links_in(parsed_json) ++ embedded_links_in(client, parsed_json)
  @@ -91,6 +91,21 @@ defmodule ExHal.Link do
91 91 |> Enum.map(fn rel -> %{link | rel: rel} end)
92 92 end
93 93
94 + def embedded?(link) do
95 + !!link.target
96 + end
97 +
98 + def to_json_hash(link) do
99 + if embedded?(link) do
100 + Document.to_json_hash(link.target)
101 + else
102 + hash = %{"href" => link.href}
103 + if !!link.templated, do: hash = Map.merge(hash, %{"templated" => true})
104 + if !!link.name, do: hash = Map.merge(hash, %{"name" => link.name})
105 + hash
106 + end
107 + end
108 +
94 109 defp with_url(link, tmpl_vars, fun) do
95 110 case target_url(link, tmpl_vars) do
96 111 {:ok, url} -> fun.(url)
Loading more files…