We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
If you have an URL, you sometimes need to be able to remove items from the query string given one or more specific prefixes. A common use-case is for example to remove all the analytics parameters from a URL (which usually start with the prefix utm_
).
In Elixir, you can use the URI module to parse the URL and modify the query parameters. Here's a function that takes a URL, a list of prefixes, and removes all query parameters that start with any of the specified prefixes:
defmodule UrlCleaner do
def remove_params_with_prefix(url, prefixes) do
uri = URI.parse(url)
params =
parse_query_params(uri.query)
|> Enum.reject(fn {key, _value} ->
Enum.any?(prefixes, &starts_with_case_insensitive?(key, &1))
end)
uri
|> encode_query_params(params)
|> URI.to_string()
end
defp parse_query_params(nil), do: []
defp parse_query_params(""), do: []
defp parse_query_params(params), do: params |> URI.decode_query()
defp encode_query_params(uri, []), do: uri |> Map.put(:query, nil)
defp encode_query_params(uri, params), do: uri |> Map.put(:query, URI.encode_query(params))
defp starts_with_case_insensitive?(key, prefix) do
String.starts_with?(String.downcase(key), String.downcase(prefix))
end
end
The main function in this module, remove_params_with_prefix/2
, takes a URL and a list of prefixes as input. It returns the URL with query parameters that match any of the specified prefixes removed. This operation is case-insensitive, ensuring a robust solution for cleaning up query strings.
Here is how it works:
-
Parsing the URL: the function starts by parsing the given URL into a
%URI{}
struct using Elixir's built-inURI.parse/1
. This makes it easier to manipulate different parts of the URL, such as the query string.uri = URI.parse(url)
-
Extracting and Filtering Parameters: the query string (
uri.query
) is processed into a map of key-value pairs using the helper functionparse_query_params/1
.- If the query string is
nil
or empty, it returns an empty list. - Otherwise, it decodes the query string into a key-value map.
Once the parameters are parsed,
Enum.reject/2
is used to filter out any parameters where the key starts with one of the specified prefixes. Thestarts_with_case_insensitive?/2
helper ensures the comparison is case-insensitive.params = parse_query_params(uri.query) |> Enum.reject(fn {key, _value} -> Enum.any?(prefixes, &starts_with_case_insensitive?(key, &1)) end)
- If the query string is
-
Rebuilding the URL: after filtering, the query parameters are re-encoded into the URL using another helper function,
encode_query_params/2
.- If no parameters remain, the query string is removed by setting it to
nil
. - Otherwise, the parameters are encoded back into a query string using
URI.encode_query/1
.
uri |> encode_query_params(params) |> URI.to_string()
- If no parameters remain, the query string is removed by setting it to
Letβs look at the helper functions in detail:
-
parse_query_params/1
: converts the query string into a map of key-value pairs. It handles cases where the query isnil
or empty gracefully by returning an empty list.defp parse_query_params(nil), do: [] defp parse_query_params(""), do: [] defp parse_query_params(params), do: params |> URI.decode_query()
-
encode_query_params/2
: rebuilds the query string after filtering. If the filtered parameters are empty, the query is set tonil
. Otherwise, it encodes the remaining parameters into a query string.defp encode_query_params(uri, []), do: uri |> Map.put(:query, nil) defp encode_query_params(uri, params), do: uri |> Map.put(:query, URI.encode_query(params))
-
starts_with_case_insensitive?/2
: compares the beginning of a string (key
) with a prefix in a case-insensitive manner usingString.downcase/1
.defp starts_with_case_insensitive?(key, prefix) do String.starts_with?(String.downcase(key), String.downcase(prefix)) end
Here's how this function can be used:
url = "https://example.com?utm_source=google&ref=homepage&id=123"
prefixes = ["utm_", "ref"]
cleaned_url = UrlCleaner.remove_params_with_prefix(url, prefixes)
IO.puts(cleaned_url)
# Output: "https://example.com?id=123"
Feel free to adapt this module to handle additional use cases, such as preserving specific parameters or adding logging for the removed keys.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.