Skip to main content
blog title image

4 minute read - Java For Testers RestAssured API Testing WebDriver

Using RestAssured to download a file

Jan 25, 2019

TLDR; Downloading a file with RestAssured is as simple as taking the body of a request as a byte array and writing it to a file.

When automating I often have to download files. One very common FAQ for WebDriver is “How do I download a file with WebDriver?”.

How to download a file with WebDriver

Answer: Don’t, use an HTTP Library instead.

You can, by configuring the browser session to not prompt for location dialogs, and then click download button. But usually that is more pain that it is worth so, if I have to download a file, I’ll use an HTTP library.

RestAssured is an HTTP library

RestAssured is marketed as an API testing library. And I do use it to test APIs, as I documented in my book “Automating and Testing a REST API”. I also use it as a general purpose HTTP library, and that is really how I am describing it here.

Basic code to download a file

I’ve extracted the following code from an actual set of Tactical Automated Execution code that I wrote recently.

private void writeImageIfNotExists(
                final PostDetails postDetails, 
                final File outputImagePath,
                final String image_url,
                final String fileNameMain,
                final String fileNamePostExtDetails) throws IOException {
                
    File outputImageFile = new File(outputImagePath.getPath(), 
                            fileNameMain + fileNamePostExtDetails);
                            
    if (!outputImageFile.exists()) {
    
        Map<String, String> cookies = new HashMap();
        cookies.put("session_id", Secret.SESSION_ID);

        byte[] image = RestAssured.given().
                        cookies(cookies).
                        when().get(image_url).
                        asByteArray();
                        
        // output image to file
        OutputStream outStream = new FileOutputStream(outputImageFile);
        outStream.write(image);
        outStream.close();
    }
}

The above is pretty hacky (but it is tactical, which means I wrote it for a specific purpose and may be short lived).

It basically creates a File object from a path, and file name Strings.

If the file doesn’t already exist then.

I create a HashMap of cookies. Then I add one cookie, a session_id because I’m bypassing the login process to rip out data from the system. If I was download a file during GUI Automating then I might rip the cookie from the WebDriver session and inject the details into my RestAssured session. In the above example I copy and pasted the session id from the browser because it was tactically supporting me doing some work.

Then I make a call using RestAssured

byte[] image = RestAssured.given().
                cookies(cookies).
                when().get(image_url).
                asByteArray();

This makes a GET request and returns the body as a byte array.

Which I can then write to the output file.

OutputStream outStream = new FileOutputStream(outputImageFile);
outStream.write(image);
outStream.close();

This is the basic code to download a file but isn’t necessarily the best example.

A Better Example of How to Download a File

I have created a slightly longer example and added it to my LibraryExamples project on Github

You can read the code to see full details, or watch the explanatory video.

Summary though (see sample code below the summary):

  • I pass in a map of cookies and headers to allow me to authenticate easily
  • rather than return the body asByteArray I return the response,
    • this allows me to check if the url actually exists first with a 200 status, this makes the whole process more reliable long term
  • I can still convert the body to a byte array when I know it exists
    • response.getBody().asByteArray()
  • If I wanted a very flexible solution, I wouldn’t assume an extension and I would use the Contenty-Type header to assign an extension, but in this example I just output the header to the console so you can see how to get it
    • response.getHeader("Content-Type")
  • The output file writing is a little more robust in that it catches any exceptions and reports the error.
  • If I was automating strategically I would use code more like the following, and gradually refactor it into a library to ever more generically support my strategic automating approach. e.g.
    • paramaterise whether to delete file or not
    • add extension based on content type
    • return a boolean if it downloaded correctly
    • support finding out if an exception happened if it did not download correctly
    • etc.
private void downloadUrlAsFile(
                final Map<String,String> cookies,
                final Map<String,String> headers,
                final String urlToDownload,
                final File outputPath,
                final String filename) throws IOException {

    File outputFile = new File(outputPath.getPath(), filename);


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

    // check if the URL actually exists
    if(response.getStatusCode() == 200){

        if (outputFile.exists()) {
            outputFile.delete();
        }

        System.out.println("Downloaded an " + response.getHeader("Content-Type"));

        byte[] fileContents = response.getBody().asByteArray();

        // output contents to file
        OutputStream outStream=null;

        try {
            outStream = new FileOutputStream(outputFile);
            outStream.write(fileContents);
        }catch(Exception e){
            System.out.println("Error writing file " + outputFile.getAbsolutePath());
        }finally {
            if(outStream!=null){
                outStream.close();
            }
        }
    }
}

Step By Step Video Explaining the Code