Spaces:
Sleeping
Sleeping
Merge pull request #15 from hiett/14-error-overhaul
Browse files
lib/srh/http/base_router.ex
CHANGED
@@ -5,6 +5,7 @@ defmodule Srh.Http.BaseRouter do
|
|
5 |
alias Srh.Http.ResultEncoder
|
6 |
|
7 |
plug(:match)
|
|
|
8 |
plug(Plug.Parsers, parsers: [:json], pass: ["application/json"], json_decoder: Jason)
|
9 |
plug(:dispatch)
|
10 |
|
@@ -25,7 +26,7 @@ defmodule Srh.Http.BaseRouter do
|
|
25 |
end
|
26 |
|
27 |
match _ do
|
28 |
-
|
29 |
end
|
30 |
|
31 |
defp do_command_request(conn, success_lambda) do
|
@@ -71,41 +72,42 @@ defmodule Srh.Http.BaseRouter do
|
|
71 |
end
|
72 |
|
73 |
defp handle_response(response, conn) do
|
74 |
-
|
|
|
|
|
|
|
|
|
75 |
case response do
|
76 |
{:ok, data} ->
|
77 |
-
|
78 |
|
79 |
{:not_found, message} ->
|
80 |
-
|
81 |
|
82 |
{:malformed_data, message} ->
|
83 |
-
|
84 |
|
85 |
{:redis_error, data} ->
|
86 |
-
|
87 |
|
88 |
{:not_authorized, message} ->
|
89 |
-
|
90 |
|
91 |
{:connection_error, message} ->
|
92 |
-
|
93 |
-
|
94 |
-
{:server_error, _} ->
|
95 |
-
%{code: 500, message: "An error occurred internally", json: false}
|
96 |
|
97 |
_ ->
|
98 |
-
|
99 |
end
|
100 |
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|> put_resp_header("content-type", "application/json")
|
105 |
-
|
106 |
-
false ->
|
107 |
-
conn
|
108 |
-
end
|
109 |
-
|> send_resp(code, message)
|
110 |
end
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
end
|
|
|
5 |
alias Srh.Http.ResultEncoder
|
6 |
|
7 |
plug(:match)
|
8 |
+
plug(Srh.Http.ContentTypeCheckPlug)
|
9 |
plug(Plug.Parsers, parsers: [:json], pass: ["application/json"], json_decoder: Jason)
|
10 |
plug(:dispatch)
|
11 |
|
|
|
26 |
end
|
27 |
|
28 |
match _ do
|
29 |
+
handle_response({:not_found, "SRH: Endpoint not found. SRH might not support this feature yet."}, conn)
|
30 |
end
|
31 |
|
32 |
defp do_command_request(conn, success_lambda) do
|
|
|
72 |
end
|
73 |
|
74 |
defp handle_response(response, conn) do
|
75 |
+
# Errors are strings, and data just means the content is directly encoded with Jason.encode!
|
76 |
+
# {404, {:error, "Message"}}
|
77 |
+
# {200, {:data, ""}}
|
78 |
+
|
79 |
+
{code, resp_data} =
|
80 |
case response do
|
81 |
{:ok, data} ->
|
82 |
+
{200, {:data, data}}
|
83 |
|
84 |
{:not_found, message} ->
|
85 |
+
{404, {:error, message}}
|
86 |
|
87 |
{:malformed_data, message} ->
|
88 |
+
{400, {:error, message}}
|
89 |
|
90 |
{:redis_error, data} ->
|
91 |
+
{400, {:data, data}}
|
92 |
|
93 |
{:not_authorized, message} ->
|
94 |
+
{401, {:error, message}}
|
95 |
|
96 |
{:connection_error, message} ->
|
97 |
+
{500, {:error, message}}
|
|
|
|
|
|
|
98 |
|
99 |
_ ->
|
100 |
+
{500, {:error, "SRH: An error occurred internally"}}
|
101 |
end
|
102 |
|
103 |
+
conn
|
104 |
+
|> put_resp_header("content-type", "application/json")
|
105 |
+
|> send_resp(code, create_response_body(resp_data))
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
end
|
107 |
+
|
108 |
+
# :data just directly encodes
|
109 |
+
defp create_response_body({:data, data}), do: Jason.encode!(data)
|
110 |
+
|
111 |
+
# :error wraps the message in an error object
|
112 |
+
defp create_response_body({:error, error}), do: Jason.encode!(%{error: error})
|
113 |
end
|
lib/srh/http/content_type_check_plug.ex
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule Srh.Http.ContentTypeCheckPlug do
|
2 |
+
import Plug.Conn
|
3 |
+
|
4 |
+
def init(opts), do: opts
|
5 |
+
|
6 |
+
def call(conn, _opts) do
|
7 |
+
# Only parse for POST, PUT, PATCH, and DELETE requests, which is what Plug.Parsers does
|
8 |
+
case conn.method do
|
9 |
+
"POST" ->
|
10 |
+
check_content_type(conn)
|
11 |
+
|
12 |
+
"PUT" ->
|
13 |
+
check_content_type(conn)
|
14 |
+
|
15 |
+
"PATCH" ->
|
16 |
+
check_content_type(conn)
|
17 |
+
|
18 |
+
"DELETE" ->
|
19 |
+
check_content_type(conn)
|
20 |
+
|
21 |
+
# All other methods can proceed
|
22 |
+
_ ->
|
23 |
+
conn
|
24 |
+
end
|
25 |
+
end
|
26 |
+
|
27 |
+
defp check_content_type(conn) do
|
28 |
+
case get_req_header(conn, "content-type") do
|
29 |
+
["application/json"] ->
|
30 |
+
# Proceed, this is the valid content type for SRH
|
31 |
+
conn
|
32 |
+
|
33 |
+
# Either missing, or a type that we don't support
|
34 |
+
_ ->
|
35 |
+
# Return a custom error, ensuring the same format as the other errors
|
36 |
+
conn
|
37 |
+
|> put_resp_content_type("application/json")
|
38 |
+
|> send_resp(400, Jason.encode!(%{error: "Invalid content type. Expected application/json."}))
|
39 |
+
|> halt()
|
40 |
+
end
|
41 |
+
end
|
42 |
+
end
|