diff --git a/doc/POABackend.CustomHandler.REST.html b/doc/POABackend.CustomHandler.REST.html index 0a715b3..f588d1d 100644 --- a/doc/POABackend.CustomHandler.REST.html +++ b/doc/POABackend.CustomHandler.REST.html @@ -101,6 +101,7 @@ dynamically MessagePack formats

ping endpoint @@ -108,12 +109,18 @@ dynamically POST /ping

request:

-
Headers: {"content-type", "application/json"}
+
Headers: {"content-type", "application/json" or "application/msgpack"}
 payload:
+  JSON:
+
   {
     id: String() # agent id
     secret: String() # secret string for authentication/authorisation
-  }
+ } + + MessagePack: + + Same format as JSON but packed thru MessagePack library

responses:

@@ -132,7 +139,7 @@ payload: - + @@ -169,14 +176,20 @@ Note: Unnecessary use of -X or --request, POST is already inferred.
POST /data

request:

-
Headers: {"content-type", "application/json"}
+
Headers: {"content-type", "application/json" or "application/msgpack"}
 payload:
+  JSON:
+
   {
     id: String() # agent id
     secret: String() # secret string for authentication/authorisation
     type: String() # data type (for now only ethereum_metrics)
     data: Object() # metric data itself
-  }
+ } + + MessagePack: + + Same format as JSON but packed thru MessagePack library

responses:

401Unauthorized
415Unsupported Media Type (only application/json allowed)415Unsupported Media Type (only application/json and application/msgpack allowed)
422Unprocessable Entity. Required fields missing
@@ -195,7 +208,7 @@ payload: - + @@ -232,12 +245,18 @@ Note: Unnecessary use of -X or --request, POST is already inferred.
POST /bye

request:

-
Headers: {"content-type", "application/json"}
+
Headers: {"content-type", "application/json" or "application/msgpack"}
 payload:
+  JSON:
+
   {
     id: String() # agent id
     secret: String() # secret string for authentication/authorisation
-  }
+ } + + MessagePack: + + Same format as JSON but packed thru MessagePack library

responses:

401Unauthorized
415Unsupported Media Type (only application/json allowed)415Unsupported Media Type (only application/json and application/msgpack allowed)
422Unprocessable Entity. Required fields missing
@@ -256,7 +275,7 @@ payload: - + @@ -348,7 +367,7 @@ restart the timeout countdown

ping_monitor(agent_id) - + View Source diff --git a/lib/poa_backend/custom_handler/rest.ex b/lib/poa_backend/custom_handler/rest.ex index 5ac3c0c..2ca0dc2 100644 --- a/lib/poa_backend/custom_handler/rest.ex +++ b/lib/poa_backend/custom_handler/rest.ex @@ -23,6 +23,8 @@ defmodule POABackend.CustomHandler.REST do This Pluting also defines the endpoints needed to use the POA Protocol. + __All the endpoints accept pure JSON or [MessagePack](https://msgpack.org/) formats__ + ## _ping_ endpoint ``` @@ -32,12 +34,18 @@ defmodule POABackend.CustomHandler.REST do request: ``` - Headers: {"content-type", "application/json"} + Headers: {"content-type", "application/json" or "application/msgpack"} payload: + JSON: + { id: String() # agent id secret: String() # secret string for authentication/authorisation } + + MessagePack: + + Same format as JSON but packed thru MessagePack library ``` responses: @@ -46,7 +54,7 @@ defmodule POABackend.CustomHandler.REST do | :--- | :---------- | | 200 | Success _{"result":"success"}_ | | 401 | Unauthorized | - | 415 | Unsupported Media Type (only _application/json_ allowed) | + | 415 | Unsupported Media Type (only _application/json_ and __application/msgpack__ allowed) | | 422 | Unprocessable Entity. Required fields missing| Example: @@ -86,14 +94,20 @@ defmodule POABackend.CustomHandler.REST do request: ``` - Headers: {"content-type", "application/json"} + Headers: {"content-type", "application/json" or "application/msgpack"} payload: + JSON: + { id: String() # agent id secret: String() # secret string for authentication/authorisation type: String() # data type (for now only ethereum_metrics) data: Object() # metric data itself } + + MessagePack: + + Same format as JSON but packed thru MessagePack library ``` responses: @@ -102,7 +116,7 @@ defmodule POABackend.CustomHandler.REST do | :--- | :---------- | | 200 | Success _{"result":"success"}_ | | 401 | Unauthorized | - | 415 | Unsupported Media Type (only _application/json_ allowed) | + | 415 | Unsupported Media Type (only _application/json_ and __application/msgpack__ allowed) | | 422 | Unprocessable Entity. Required fields missing| Example: @@ -142,12 +156,18 @@ defmodule POABackend.CustomHandler.REST do request: ``` - Headers: {"content-type", "application/json"} + Headers: {"content-type", "application/json" or "application/msgpack"} payload: + JSON: + { id: String() # agent id secret: String() # secret string for authentication/authorisation } + + MessagePack: + + Same format as JSON but packed thru MessagePack library ``` responses: @@ -156,7 +176,7 @@ defmodule POABackend.CustomHandler.REST do | :--- | :---------- | | 200 | Success _{"result":"success"}_ | | 401 | Unauthorized | - | 415 | Unsupported Media Type (only _application/json_ allowed) | + | 415 | Unsupported Media Type (only _application/json_ and __application/msgpack__ allowed) | | 422 | Unprocessable Entity. Required fields missing| Example: @@ -197,8 +217,8 @@ defmodule POABackend.CustomHandler.REST do alias POABackend.Protocol.DataType alias POABackend.Protocol.Message - plug REST.Plugs.Accept, "application/json" - plug Plug.Parsers, parsers: [:json], json_decoder: Poison + plug REST.Plugs.Accept, ["application/json", "application/msgpack"] + plug Plug.Parsers, parsers: [Msgpax.PlugParser, :json], pass: ["application/msgpack", "application/json"], json_decoder: Poison plug REST.Plugs.RequiredFields, ~w(id secret) plug REST.Plugs.Authorization plug :match diff --git a/lib/poa_backend/custom_handler/rest/plugs/accept.ex b/lib/poa_backend/custom_handler/rest/plugs/accept.ex index ff972f7..4bbddbc 100644 --- a/lib/poa_backend/custom_handler/rest/plugs/accept.ex +++ b/lib/poa_backend/custom_handler/rest/plugs/accept.ex @@ -10,10 +10,12 @@ defmodule POABackend.CustomHandler.REST.Plugs.Accept do def call(conn, accept) do import Plug.Conn - case List.keyfind(conn.req_headers, "content-type", 0) do - {"content-type", ^accept} -> - conn - _ -> + with {"content-type", content_type} <- List.keyfind(conn.req_headers, "content-type", 0), + true <- Enum.member?(accept, content_type) + do + conn + else + _error -> conn |> send_resp(415, "") |> halt diff --git a/mix.exs b/mix.exs index fd70861..044323c 100644 --- a/mix.exs +++ b/mix.exs @@ -34,6 +34,7 @@ defmodule POABackend.MixProject do {:worker_pool, "~> 3.1"}, {:ex_aws_dynamo, "~> 2.0"}, {:hackney, "~> 1.12"}, + {:msgpax, "~> 2.1"}, # Tests {:credo, "~> 0.9", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 6908067..2434819 100644 --- a/mix.lock +++ b/mix.lock @@ -21,6 +21,7 @@ "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, + "msgpax": {:hex, :msgpax, "2.1.1", "833bc9ce6d3e073cf966fec94d3f976ca7100685b4f0efb6e30ef512f2e8a4d7", [], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "plug": {:hex, :plug, "1.6.0", "90d338a44c8cd762c32d3ea324f6728445c6145b51895403854b77f1536f1617", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, diff --git a/test/custom_handler/rest_test.exs b/test/custom_handler/rest_test.exs index 5f60513..8ba8db2 100644 --- a/test/custom_handler/rest_test.exs +++ b/test/custom_handler/rest_test.exs @@ -9,7 +9,11 @@ defmodule CustomHandler.RESTTest do # /ping Endpoint Tests # ---------------------------------------- - test "testing the REST /ping endpoint" do + test "testing the REST /ping endpoint [JSON]" do + {200, %{"result" => "success"}} = ping("agentID") + end + + test "testing the REST /ping endpoint [MSGPACK]" do {200, %{"result" => "success"}} = ping("agentID") end @@ -79,7 +83,7 @@ defmodule CustomHandler.RESTTest do %{active: ^active_monitors} = Supervisor.count_children(Monitor.Supervisor) - {200, %{"result" => "success"}} = ping(agent_id) + {200, %{"result" => "success"}} = ping_msgpack(agent_id) %{active: ^active_monitors} = Supervisor.count_children(Monitor.Supervisor) @@ -90,7 +94,7 @@ defmodule CustomHandler.RESTTest do # /data Endpoint Tests # ---------------------------------------- - test "testing the REST /data endpoint" do + test "testing the REST /data endpoint [JSON]" do url = @base_url <> "/data" {:ok, data} = Poison.encode(%{id: "agentID", secret: "mysecret", type: "ethereum_metrics", data: %{hello: :world}}) headers = [{"Content-Type", "application/json"}] @@ -98,6 +102,14 @@ defmodule CustomHandler.RESTTest do {200, %{"result" => "success"}} = post(url, data, headers) end + test "testing the REST /data endpoint [MSGPACK]" do + url = @base_url <> "/data" + {:ok, data} = Msgpax.pack(%{id: "agentID", secret: "mysecret", type: "ethereum_metrics", data: %{hello: :world}}) + headers = [{"Content-Type", "application/msgpack"}] + + {200, %{"result" => "success"}} = post(url, data, headers) + end + test "testing the REST /data endpoint without content-type" do url = @base_url <> "/data" {:ok, data} = Poison.encode(%{id: "agentID", secret: "mysecret", type: "ethereum_metrics", data: %{hello: :world}}) @@ -141,7 +153,7 @@ defmodule CustomHandler.RESTTest do # /bye Endpoint Tests # ---------------------------------------- - test "testing the REST /bye endpoint" do + test "testing the REST /bye endpoint [JSON]" do url = @base_url <> "/bye" {:ok, data} = Poison.encode(%{id: "agentID", secret: "mysecret", data: %{hello: "world"}}) headers = [{"Content-Type", "application/json"}] @@ -149,6 +161,14 @@ defmodule CustomHandler.RESTTest do {200, %{"result" => "success"}} = post(url, data, headers) end + test "testing the REST /bye endpoint [MSGPACK]" do + url = @base_url <> "/bye" + {:ok, data} = Msgpax.pack(%{id: "agentID", secret: "mysecret", data: %{hello: "world"}}) + headers = [{"Content-Type", "application/msgpack"}] + + {200, %{"result" => "success"}} = post(url, data, headers) + end + test "testing the REST /bye endpoint without content-type" do url = @base_url <> "/bye" {:ok, data} = Poison.encode(%{id: "agentID", secret: "mysecret", data: %{hello: "world"}}) @@ -213,11 +233,27 @@ defmodule CustomHandler.RESTTest do end defp ping(agent_id) do + gen_ping(agent_id, "application/json") + end + + defp ping_msgpack(agent_id) do + gen_ping(agent_id, "application/msgpack") + end + + defp gen_ping(agent_id, mime_type) do url = @base_url <> "/ping" - {:ok, data} = Poison.encode(%{id: agent_id, secret: "mysecret", data: %{hello: "world"}}) - headers = [{"Content-Type", "application/json"}] + {:ok, data} = encode_ping(mime_type, agent_id) + headers = [{"Content-Type", mime_type}] post(url, data, headers) end + defp encode_ping("application/json", agent_id) do + Poison.encode(%{id: agent_id, secret: "mysecret", data: %{hello: "world"}}) + end + + defp encode_ping("application/msgpack", agent_id) do + Msgpax.pack(%{id: agent_id, secret: "mysecret", data: %{hello: "world"}}) + end + end \ No newline at end of file
401Unauthorized
415Unsupported Media Type (only application/json allowed)415Unsupported Media Type (only application/json and application/msgpack allowed)
422Unprocessable Entity. Required fields missing