Skip to main content
blog title image

3 minute read - Test Automation RestAssured UniRest Tips

Ordering Headers In HTTP Requests

Jul 6, 2020

TLDR; RestAssured does not support ordering headers in HTTP Requests. But UniRest does.

An Edge Case

I recently encountered an edge case with RestAssured.

I needed to send some HTTP requests to a server behind a cache, but the cache was refusing my requests.

By looking at the XHR requests being made from the browser the only difference of note I could see was the ordering of the headers.

I put my requests through a Proxy to test this, and sure enough

With this ordering, it worked.

Host: ...
Cookie: ...
Accept: */*
User-Agent: ...
Connection: close
Accept-Encoding: gzip, deflate

But with this ordering it did not.

Cookie: ...
Accept: */*
User-Agent: ...
Host: ...
Connection: close
Accept-Encoding: gzip, deflate

RestAssured

Rest Assured has the option to set headers when constructing the request.

Using a Headers object.

Header host = new Header("Host", "...");
Header accept = new Header("Accept-Language", "en-US,en;q=0.9");
Header useragent = new Header("User-Agent", PRETEND_TO_BE_BROWSER);
Headers headers = new Headers(host, useragent, accept);

Response response = RestAssured.given().
        cookies(cookies).
        headers(headers).
        when().
        get(url).andReturn();

And directly in the request.

Response response = RestAssured.given().
        cookies(cookies).
        headers(headers).
        header("Host", "...").
        header("Accept-Language", "en-US,en;q=0.9").
        header("User-Agent", PRETEND_TO_BE_BROWSER).
        when().
        get(initialCall).andReturn();

But, no matter how I ordered this, the header ordering did not change.

To debug and double check this, I used both RestAssured logging and output through a proxy. I explain how to log to console, file and proxy in this post.

UniRest

I’ve had UniRest on my list of libraries to try, for quite a while, but I never had an excuse until now.

UniRest is a fairly simple drop in replacement for RestAssured… assuming that you wrapped RestAssured in an abstraction and were not using it for the Given/When/Then assertion checking.

I, did have RestAssured wrapped in an abstraction so I implemented the basic interface with a UniRest implementation. Here is an example of the ‘get’ method that makes a call with ordered headers.

public HttpResponse<String> get(String url) {
    final GetRequest request = Unirest.get(url).
            header("Host", "...").
            header("Accept-Language", "en-US,en;q=0.9").
            header("User-Agent", PRETEND_TO_BE_BROWSER);

    for(Map.Entry<String,String> cookie : cookies.entrySet()){
        request.cookie(cookie.getKey(), cookie.getValue());
    }

    return request.asString();
}

You can see some obvious differences.

I had to set Cookies individually because there wasn’t a Map constructor that I could see, but other than that, the code is much the same.

And when I passed this through a proxy to double check the output, the headers were in the order I specified in the request.

UniRest proxy usage

UniRest is slightly less forgiving than RestAssured when it comes to configuration.

Once UniRest is configured, it doesn’t like you reconfiguring it without resetting the configuration.

    if(!Unirest.config().isRunning()) {
        Unirest.config().
            proxy("localhost", 8080).
            verifySsl(false).
            enableCookieManagement(false);
    }

So I simply wrapped the config call in an if to check if it was already configured or not.

The above code, configures UniRest to

  • use a proxy proxy("localhost", 8080).
  • switch off SSL verification verifySsl(false).
  • switch off cookie management enableCookieManagement(false); which I needed to to do avoid responses interfering with my requests by amending and adding new Cookies.

Summary

This is an edge case. I’ve never needed to get this low level with HTTP Header request configuration before.

If UniRest had not worked then I would have dropped down to an HTTP library directly.

Using Proxies was essential during the debugging to see the actual messages, and allow manipulation of the messages and replaying them until I could identify the root of the problem and get the message down to its minimum acceptable configuration.

If you are interested in learning how to Automate and Test APIs, then you might find my book “Automating and Testing a REST API” useful.