Converting Output from Rest Assured to Curl Requests

Featured image for sharing metadata for article

I work with Rest Assured a fair bit for automated testing against RESTful API services.

These test suites usually log Rest Assured's request/response output, which allows us to see the full request/response of the tests. Not only is it good for debugging, but I find it super useful as this then gives us evidence of the service's contract for the future.

In the cases that these tests do fail, I can then take the given request, and retry it to see if I can spot any fresh errors in logs.

However, this process of taking the output of Rest Assured and making it work with curl is a manual process, so can be a bit painful.

I discovered there is the curl-logger project but that unfortunately requires you to be already using the project to provide logging, and this isn't always possible.

As it's bugged me for long enough, I've written a script that converts a log output such as:

Request method:	POST
Request URI:	https://url?q=config
Proxy:			<none>
Request params:	<none>
Query params:	q=config
Form params:	<none>
Path params:	<none>
Headers:		Accept=application/jwt
				Content-Type=application/json; charset=UTF-8
Cookies:		auth=eyJ...=null
Multiparts:		<none>
Body:
{
    "key": [
        1,
        2,
        3
    ],
    "another": null
}

To the below curl representation:

curl -X POST 'https://url?q=config' -H 'Accept:application/jwt' -H 'Content-Type:application/json; charset=UTF-8' --cookie 'auth=eyJ...=null' -d '{"key": [1,2,3],"another": null}'

This should make it easier to work with these log outputs, and make interacting with the service easier.

The Script

This isn't necessarily the best code I've written, but it does the job!

require 'json'

def parse(lines)
  request = {}
  multiline = nil

  lines.each do |line|
    # we're no longer in a multi-line parameter list if the line starts with i.e.
    # `Body`, as multilines are preceded by whitespace
    multiline = nil if line.match?(/^[A-Z]/)

    # ignore unset options
    next if line.match?(/<none>/)

    if line.start_with? 'Request URI'
      request['uri'] = line.sub(/^Request URI:\s+/, '')
    elsif line.start_with? 'Request method'
      request['method'] = line.sub(/^Request method:\s+/, '')
    elsif line.start_with? 'Proxy'
      request['proxy'] = line.sub(/^Proxy:\s+/, '')
    elsif line.start_with? 'Query params'
      # these are ignored, as the URI provides them, but are matched just to hide
      # the warnings
      multiline = 'query'
      request[multiline] = []
      request[multiline] << line.sub(/^Query params:\s+/, '')
    elsif line.start_with? 'Form params'
      multiline = 'form'
      request[multiline] = []
      request[multiline] << line.sub(/^Form params:\s+/, '')
    elsif line.start_with? 'Cookies'
      multiline = 'cookies'
      request[multiline] = []
      request[multiline] << line.sub(/^Cookies:\s+/, '')
    elsif line.start_with? 'Headers'
      multiline = 'headers'
      request[multiline] = []
      request[multiline] << line.sub(/^Headers:\s+/, '')
    elsif line.start_with? 'Body'
      multiline = 'body'
      request[multiline] = []
      request[multiline] << line.sub(/^Body:\s+/, '')
    elsif multiline
      request[multiline] << line.sub(/^\s+/, '')
    else
      $stderr.puts "Not supported: #{line}"
    end
  end

  request
end

def to_curl(request)
  curl = %w(curl)
  curl << "-X #{request['method']}"
  curl << "'#{request['uri']}'"

  if request['headers']
    request['headers'].each do |header|
      curl << "-H '#{header.sub(/=/, ':')}'"
    end
  end

  if request['cookies']
    request['cookies'].each do |cookie|
      curl << "--cookie '#{cookie}'"
    end
  end

  if request['form']
    request['form'].each do |form|
      curl << "-d '#{form}'"
    end
  end

  if request['proxy']
    curl << "--proxy '#{request['proxy']}'"
  end

  if request['body']
    body = request['body'].join ''
    curl << "-d '#{body}'"
  end

  curl.join(' ').gsub(/\n/, '')
end

request = parse(File.readlines(ARGV[0]))
puts to_curl(request)

You can interact with it by running:

ruby rest-assured-to-curl.rb log.txt

Where log.txt is the output from Rest Assured, starting with Reqest method.

Caveats

This has been tested with Rest Assured v3.3.0, v4.0.0 and v4.3.0, using the below Rest Assured code:

given()
  .cookie("auth=eyJ...")
  .header("Accept", "application/jwt")
  .contentType(ContentType.JSON)
  .queryParam("q", "config")
  .body("{\"key\": [1,2,3], \"another\": null}")
  .log().all()
  .post("https://url");

NOTE: If you are using Rest Assured's auth functionality, this will not display unless you use preemptive().

NOTE: This does not currently support multipart requests.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #rest-assured #command-line.

Also on: Lobste.rs logo

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.