Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add put_path_params_style/2 step #373

Merged
merged 5 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/req.ex
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ defmodule Req do
* `:path_params` - if set, uses a templated request path (via
[`put_path_params`](`Req.Steps.put_path_params/1`) step.)

* `:path_params_style` - configures how `:path_params` are expressed (via
[`put_path_params_style`](`Req.Steps.put_path_params_style/1`) step). Can be one of:

* `:colon` - default, params are expressed as `:name` in the path.

* `:curly` - uses [OpenAPI](https://swagger.io/specification/)-style `{name}` parameters.

*Available since v0.5.1*.

Authentication options:

* `:auth` - sets request authentication (via [`auth`](`Req.Steps.auth/1`) step.)
Expand Down
38 changes: 32 additions & 6 deletions lib/req/steps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ defmodule Req.Steps do
:base_url,
:params,
:path_params,
:path_params_style,
:auth,
:form,
:json,
Expand Down Expand Up @@ -71,6 +72,7 @@ defmodule Req.Steps do
put_base_url: &Req.Steps.put_base_url/1,
auth: &Req.Steps.auth/1,
put_params: &Req.Steps.put_params/1,
put_path_params_style: &Req.Steps.put_path_params_style/1,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you merge this into the put_path_params step instead? It's going to be easier to document too, just another option for that step. Finally, I don't think we need to store it in req.private and instead look at req.options when applying params. I prefer to keep as least things as possible in req.private since it's user accessible. wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suresies, incoming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wojtekmach done!

put_path_params: &Req.Steps.put_path_params/1,
put_range: &Req.Steps.put_range/1,
cache: &Req.Steps.cache/1,
Expand Down Expand Up @@ -398,6 +400,14 @@ defmodule Req.Steps do
@doc """
Uses a templated request path.

By default, params in the URL path are expressed as strings prefixed with `:`. For example,
`:code` in `https://httpbin.org/status/:code`. If you want to use the `{code}` syntax,
set `path_params_style: :curly` (see `put_path_params_style/1`).

Path params are replaced in the request URL path. The path params are specified as a keyword
list of parameter names and values, as in the examples below. The values of the parameters are
converted to strings using the `String.Chars` protocol (`to_string/1`).

## Request Options

* `:path_params` - params to add to the templated path. Defaults to `[]`.
Expand All @@ -424,23 +434,39 @@ defmodule Req.Steps do
end

defp apply_path_params(request, params) do
regex =
case Req.Request.get_private(request, :path_params_style) || raise("missing") do
:colon -> ~r/:([a-zA-Z]{1}[\w_]*)/
:curly -> ~r/\{([a-zA-Z]{1}[\w_]*)\}/
end

update_in(request.url.path, fn
nil ->
nil

path ->
Regex.replace(~r/:([a-zA-Z]{1}[\w_]*)/, path, fn match, key ->
Regex.replace(regex, path, fn match, key ->
case params[String.to_existing_atom(key)] do
nil ->
match

value ->
value |> to_string() |> URI.encode()
nil -> match
value -> value |> to_string() |> URI.encode()
end
end)
end)
end

@doc """
TODO
"""
@doc since: "0.5.1"
@doc step: :request
def put_path_params_style(request) do
Req.Request.put_private(
request,
:path_params_style,
Req.Request.get_option(request, :path_params_style, :colon)
)
end

@doc """
Adds params to request query string.

Expand Down
16 changes: 13 additions & 3 deletions test/req/steps_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,18 @@ defmodule Req.StepsTest do
end

test "put_path_params" do
req = Req.new(url: "http://foo/:id", path_params: [id: "abc|def"]) |> Req.Request.prepare()
assert URI.to_string(req.url) == "http://foo/abc%7Cdef"
req =
Req.new(url: "http://foo/:id{ola}", path_params: [id: "abc|def"]) |> Req.Request.prepare()

assert URI.to_string(req.url) == "http://foo/abc%7Cdef{ola}"
end

test "put_path_params_style" do
req =
Req.new(url: "http://foo/{id}:bar", path_params: [id: "abc|def"], path_params_style: :curly)
|> Req.Request.prepare()

assert URI.to_string(req.url) == "http://foo/abc%7Cdef:bar"
end

test "put_range" do
Expand Down Expand Up @@ -1138,7 +1148,7 @@ defmodule Req.StepsTest do
assert_receive :ping
refute_receive _

assert req.private == %{req_redirect_count: 3}
assert %{req_redirect_count: 3} = req.private
wojtekmach marked this conversation as resolved.
Show resolved Hide resolved
assert Exception.message(e) == "too many redirects (3)"
end

Expand Down
Loading