File size: 2,791 Bytes
2e92879
 
 
 
a8d7371
2e92879
b2ff4b5
 
 
2e92879
 
 
 
 
 
a8d7371
0b53aa4
 
 
a8d7371
0b53aa4
 
abcde98
a8d7371
abcde98
 
0b53aa4
 
 
 
a8d7371
8f1b0f2
a8d7371
 
 
 
 
 
 
0b53aa4
2e92879
 
b2ff4b5
2e92879
0b53aa4
b2ff4b5
2e92879
 
 
 
 
8f1b0f2
a8d7371
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2e92879
0b53aa4
2e92879
b2ff4b5
 
 
 
 
 
 
 
 
abcde98
 
 
b2ff4b5
 
 
 
 
 
76486d3
0b53aa4
2e92879
 
0b53aa4
 
 
 
b2ff4b5
0b53aa4
 
 
2e92879
 
 
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
94
95
96
97
98
99
100
101
102
103
104
105
106
defmodule Srh.Http.BaseRouter do
  use Plug.Router
  alias Srh.Http.RequestValidator
  alias Srh.Http.CommandHandler
  alias Srh.Http.ResultEncoder

  plug(:match)
  plug(Plug.Parsers, parsers: [:json], pass: ["application/json"], json_decoder: Jason)
  plug(:dispatch)

  get "/" do
    handle_response({:ok, "Welcome to Serverless Redis HTTP!"}, conn)
  end

  post "/" do
    do_command_request(conn, &CommandHandler.handle_command(&1, &2))
  end

  post "/pipeline" do
    do_command_request(conn, &CommandHandler.handle_command_array(&1, &2))
  end

  post "/multi-exec" do
    do_command_request(conn, &CommandHandler.handle_command_transaction_array(&1, &2))
  end

  match _ do
    send_resp(conn, 404, "Endpoint not found")
  end

  defp do_command_request(conn, success_lambda) do
    encoding_enabled = handle_extract_encoding?(conn)

    conn
    |> handle_extract_auth(&success_lambda.(conn, &1))
    |> handle_encoding_step(encoding_enabled)
    |> handle_response(conn)
  end

  defp handle_extract_auth(conn, success_lambda) do
    case conn
         |> get_req_header("authorization")
         |> RequestValidator.validate_bearer_header() do
      {:ok, token} ->
        success_lambda.(token)

      {:error, _} ->
        {:malformed_data, "Missing/Invalid authorization header"}
    end
  end

  defp handle_extract_encoding?(conn) do
    case conn
         |> get_req_header("upstash-encoding")
         |> RequestValidator.validate_encoding_header() do
      {:ok, _encoding_enabled} -> true
      {:error, _} -> false # it's not required to be present
    end
  end

  defp handle_encoding_step(response, encoding_enabled) do
    case encoding_enabled do
      true ->
        # We need to use the encoder to
        ResultEncoder.encode_response(response)
      false -> response
    end
  end

  defp handle_response(response, conn) do
    %{code: code, message: message, json: json} =
      case response do
        {:ok, data} ->
          %{code: 200, message: Jason.encode!(data), json: true}

        {:not_found, message} ->
          %{code: 404, message: message, json: false}

        {:malformed_data, message} ->
          %{code: 400, message: message, json: false}

        {:redis_error, data} ->
          %{code: 400, message: Jason.encode!(data), json: true}

        {:not_authorized, message} ->
          %{code: 401, message: message, json: false}

        {:server_error, _} ->
          %{code: 500, message: "An error occurred internally", json: false}

        _ ->
          %{code: 500, message: "An error occurred internally", json: false}
      end

    case json do
      true ->
        conn
        |> put_resp_header("content-type", "application/json")

      false ->
        conn
    end
    |> send_resp(code, message)
  end
end