diff options
author | Hentioe <me@bluerain.io> | 2020-10-26 09:17:59 +0800 |
---|---|---|
committer | Hentioe <me@bluerain.io> | 2020-10-26 09:17:59 +0800 |
commit | bce6e6041157c26e3282efab1e79db65decbc324 (patch) | |
tree | 1f752b8a669060af6647ef28ee53b299ce67a45a /lib | |
parent | Fix returns type (diff) |
Independent endpoint construction
Diffstat (limited to 'lib')
-rw-r--r-- | lib/azure_ex/ast.ex | 68 | ||||
-rw-r--r-- | lib/azure_ex/endpoint.ex | 20 | ||||
-rw-r--r-- | lib/azure_ex/request.ex | 27 |
3 files changed, 92 insertions, 23 deletions
diff --git a/lib/azure_ex/ast.ex b/lib/azure_ex/ast.ex new file mode 100644 index 0000000..9ff7b0b --- /dev/null +++ b/lib/azure_ex/ast.ex @@ -0,0 +1,68 @@ +defmodule AzureEx.AST do + @moduledoc false + + @path_var_re ~r/\{([^\}]+)\}/ + + defmacro defendpoint(name, raw_uri) do + # 扫描原始 URI 中的路径变量 + r = Regex.scan(@path_var_re, raw_uri) + # 处理并得到路径变量名称列表 + path_vars = + r + |> Enum.map(&List.last/1) + |> Enum.map(&Macro.underscore/1) + + # 路径变量列表对应的参数 AST + path_var_args_ast = + path_vars + |> Enum.map(fn var_name -> {String.to_atom(var_name), [], Elixir} end) + + # 函数签名 AST + fun_sign_ast = { + String.to_atom(Macro.underscore(name)), + [], + path_var_args_ast ++ [{:params, [], Elixir}] + } + + # 使用变量分割 URI + raw_segments = Regex.split(@path_var_re, raw_uri) + + unless length(raw_segments) == length(path_vars) + 1 do + raise """ + Error parsing raw URI, wrong number of path variables.\n + URI: #{raw_uri} + Vars: #{inspect(path_vars)} + """ + end + + # <<>> 宏的参数 AST + splicing_args_ast = + raw_segments + |> Enum.with_index() + |> Enum.reduce([], fn {seg, i}, acc -> + acc = acc ++ [seg] + + if var = Enum.at(path_vars, i) do + var_ast = + {:"::", [], + [ + {{:., [], [Kernel, :to_string]}, [], [{String.to_atom(var), [], Elixir}]}, + {:binary, [], Elixir} + ]} + + acc ++ [var_ast] + else + acc + end + end) + + # 函数体 AST(拼接字符串) + fun_body_ast = {:<<>>, [], splicing_args_ast} + + quote do + def unquote(fun_sign_ast) do + unquote(fun_body_ast) <> "?" <> URI.encode_query(unquote({:params, [], Elixir})) + end + end + end +end diff --git a/lib/azure_ex/endpoint.ex b/lib/azure_ex/endpoint.ex new file mode 100644 index 0000000..c880645 --- /dev/null +++ b/lib/azure_ex/endpoint.ex @@ -0,0 +1,20 @@ +defmodule AzureEx.Endpoint do + @moduledoc false + + require AzureEx.AST + import AzureEx.AST + + defendpoint( + "ListAllVirtualMachines", + "https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Compute/virtualMachines" + ) + + @doc """ + iex> AzureEx.Endpoint.get_network_interface("sub-1", "resgp-1", "net-1", api_version: "2020-1-1") + "https://management.azure.com/subscriptions/sub-1/resourceGroups/resgp-1/providers/Microsoft.Network/networkInterfaces/net-1?api_version=2020-1-1" + """ + defendpoint( + "GetNetworkInterface", + "https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkInterfaces/{networkInterfaceName}" + ) +end diff --git a/lib/azure_ex/request.ex b/lib/azure_ex/request.ex index bc6d92b..675ed84 100644 --- a/lib/azure_ex/request.ex +++ b/lib/azure_ex/request.ex @@ -5,23 +5,15 @@ defmodule AzureEx.Request do alias AzureEx.Config - @api_version "2020-06-01" - - def endpoint(api), - do: - "https://management.azure.com/subscriptions/#{Config.subscription_id()}/providers/Microsoft.Compute/#{ - api - }?api-version=#{@api_version}" - - @type params :: %{query_params: keyword | map, body: keyword | map} + @type params :: %{body: keyword | map} @type result :: any @type error :: any @type httpoison_result :: {:ok, HTTPoison.Response.t()} | {:error, HTTPoison.Error.t()} @spec call(binary, atom, params) :: {:ok, result} | {:error, error} - def call(api, method, params \\ %{query_params: %{}, body: %{}}) do - method |> send(endpoint(api), params) |> handle_response() + def call(endpoint, method, params \\ %{body: %{}}) do + method |> send(endpoint, params) |> handle_response() end @spec handle_response({:ok, HTTPoison.Response.t()}) :: {:ok, result} | {:error, error} @@ -30,18 +22,7 @@ defmodule AzureEx.Request do end @spec send(:get, String.t(), params) :: httpoison_result - def send(:get, endpoint, %{query_params: query_params}) do - endpoint = endpoint <> to_query(query_params) - + def send(:get, endpoint, %{}) do HTTPoison.get(endpoint, [Authorization: "Bearer #{Config.access_token()}"], Config.timeouts()) end - - def to_query(params, opts \\ []) when is_list(params) or is_map(params) do - prefix_question = Keyword.get(opts, :prefix_question, false) - - # TODO: 待实现 - str = "" - - if prefix_question, do: "?" <> str, else: str - end end |