-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathapi_adapter.ex
More file actions
93 lines (79 loc) · 3.11 KB
/
api_adapter.ex
File metadata and controls
93 lines (79 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
if Code.ensure_loaded?(Electric.Shapes.Api) do
defmodule Phoenix.Sync.Electric.ApiAdapter do
@moduledoc false
defstruct [:api, :shape]
alias Phoenix.Sync.PredefinedShape
alias Electric.Shapes
def new(%Shapes.Api{} = api, %PredefinedShape{} = predefined_shape) do
with {:ok, configured_api} <-
Shapes.Api.predefined_shape(api, PredefinedShape.to_api_params(predefined_shape)) do
{:ok, %__MODULE__{api: configured_api, shape: predefined_shape}}
end
end
defimpl Phoenix.Sync.Adapter.PlugApi do
alias Phoenix.Sync.Electric.ApiAdapter
def predefined_shape(_api, %PredefinedShape{} = _shape) do
raise ArgumentError,
message: "#{inspect(__MODULE__)} does not support nested predefined shapes"
end
def call(%ApiAdapter{api: api, shape: shape}, %{method: "GET"} = conn, params) do
if transform_fun = PredefinedShape.transform_fun(shape) do
case Shapes.Api.validate(api, params) do
{:ok, request} ->
response = Shapes.Api.serve_shape_log(request)
response = Map.update!(response, :body, &apply_transform(&1, transform_fun))
conn
|> content_type()
|> Plug.Conn.assign(:request, request)
|> Plug.Conn.assign(:response, response)
|> Shapes.Api.Response.send(response)
{:error, response} ->
conn
|> content_type()
|> Shapes.Api.Response.send(response)
|> Plug.Conn.halt()
end
else
Phoenix.Sync.Adapter.PlugApi.call(api, conn, params)
end
end
def call(%ApiAdapter{api: api}, conn, params) do
Phoenix.Sync.Adapter.PlugApi.call(api, conn, params)
end
# only works if method is GET...
def response(%ApiAdapter{api: api, shape: shape}, %{method: "GET"} = conn, params) do
if transform_fun = PredefinedShape.transform_fun(shape) do
case Shapes.Api.validate(api, params) do
{:ok, request} ->
response = Shapes.Api.serve_shape_log(request)
response = Map.update!(response, :body, &apply_transform(&1, transform_fun))
{request, response}
{:error, response} ->
{nil, response}
end
else
Phoenix.Sync.Adapter.PlugApi.response(api, conn, params)
|> then(fn {request, response} ->
{request, Phoenix.Sync.Electric.consume_response_stream(response)}
end)
end
end
def send_response(%ApiAdapter{}, conn, {request, response}) do
conn
|> content_type()
|> Plug.Conn.assign(:request, request)
|> Plug.Conn.assign(:response, response)
|> Shapes.Api.Response.send(response)
end
defp content_type(conn) do
Plug.Conn.put_resp_content_type(conn, "application/json")
end
defp apply_transform(stream, transform_fun) do
stream
|> Enum.to_list()
|> IO.iodata_to_binary()
|> Phoenix.Sync.Electric.map_response_body(transform_fun)
end
end
end
end