Handling HTTP requests in Elixir is becoming increasingly easier with powerful libraries like Req. One useful feature when working with HTTP requests is tracking redirects. Let's look at a practical way of doing that in Elixir.

In this post, we will walk through a simple solution for tracking redirects using Req, an Elixir HTTP client. We will focus on how to create a function that logs the final URL after any redirections have occurred.

Introduction to Req

Req is a lightweight and highly composable HTTP client for Elixir. It simplifies the process of making HTTP requests while providing flexible options to handle request and response transformations. By building on top of Req's ability to manipulate the request lifecycle, we can implement a feature to track and capture any redirects that occur during the request.

Tracking redirects

Let's say you want to track the final destination of a request that undergoes multiple redirections. Below is the implementation of how to achieve that:

defmodule MyApplication.Tracking do
  def track_redirected(request, opts \\ []) do
    request
    |> Req.Request.register_options([:track_redirected])
    |> Req.Request.merge_options(opts)
    |> Req.Request.prepend_response_steps(track_redirected: &track_redirected_uri/1)
  end

  defp track_redirected_uri({request, response}) do
    {request, put_in(response.private[:final_url], request.url)}
  end
end

Breaking down the code

We start by defining a module, MyApplication.Tracking, which will contain our tracking functionality.

The track_redirected/2 function the main function that handles the redirection tracking. It takes a request and an optional list of options:

  • register_options/1: This registers a new option, :track_redirected, with the request.
  • merge_options/2: Any additional options provided during the function call will be merged here.
  • prepend_response_steps/2: This inserts a step into the request pipeline that processes each response to track the redirected URL.

The track_redirected_uri/1 function captures the final URL after any redirects by updating the private[:final_url] field in the response. This ensures we can easily access the final destination URL after the request is completed.

Putting it to use

With our module in place, we can now make an HTTP request and track its final destination:

resp = Req.new()
|> track_redirected()
|> Req.get!(url: "https://example.com")

URI.to_string(resp.private.final_url) |> IO.inspect()

Here's what's happening in the code:

  • We create a new request using Req.new().
  • We invoke the track_redirected/2 function we defined to track the redirected URL.
  • The request is then sent using Req.get!/1 to the URL https://example.com.
  • Finally, we inspect the final_url from the resp.private field, which contains the final destination after all redirects.

Practical use cases

Tracking redirects is particularly useful in scenarios like:

  • Monitoring URL changes: If you're working with services that frequently update or redirect URLs, it's useful to ensure you're always landing on the correct destination.

  • Debugging: When debugging issues in production or tracking down why a request is being redirected unexpectedly, this method helps uncover the full redirection chain.

  • SEO and web scraping: For web scraping or SEO auditing purposes, understanding the final destination of a URL can provide insights into link behaviors and redirection policies.

Conclusion

Tracking redirects in Elixir with the Req library is simple and efficient. By building a custom function to capture the final URL after redirection, we can ensure that our applications stay resilient and better handle dynamic URL changes.

With this technique in your toolbox, handling HTTP requests and debugging redirections in Elixir will become much easier.

source