Ways to provide body payload in Ansible’s URI module [2. Update]

Ansible Logo

Talin to a REST API requires to provide some information, usually in the form of JSON payload. Ansible offers various ways to do that in the URI module in playbooks.

In modern applications REST APIs are often the main API to integrate the given APP with the existing infrastructure. REST often requires posting JSON structures as payload.

Ansible offers the URI module to talk to REST APIs, and there are multiple ways add JSON payload to a playbook task that are shown below.

For example, given that the following arbitrary JSON payload needs to be provided to a REST API via POST:

{
  "mainlevel": {
    "subkey": "finalvalue"
  }
}

The first and for me preferred way to provide JSON payloads is to write down the structure in plain YAML (if possible) and afterwards tell the module to format it as JSON:

HEADER_Content-Type: application/json
status_code: 202
body: 
  mainlevel:
    subkey: finalvalue
body_format: json

Among various reasons this works well because variables can be easily used.

Another way is to define a variable and then use jinja to format it:

vars:
  mainlevel:
    "subkey": finalvalue
...
    body: ' {{mainlevel|to_json}}'

Caution: not the empty space here in the body line. It avoids type detection which tries to check if a string begins with { or [.

Sometimes the payload is the content of a file generated somewhere else. In these cases the best way is to use the lookup plugin to read the file:

body: "{{ lookup('file','myvalues.json') }}"

Of course the lookup plugin can access data from other places as well – for example from a database or a config store, which is a nice way of integrating existing infrastructure with each other via Ansible.

A quicker, shorter way is to use folded style:

body: >
  {"mainlevel":{"subkey":"finalvalue"}}

Note that folded style pastes things as they are – but ignores single new lines. So it might be difficult to add variables here.

Therefore, a little bit better suited is the literal style, indicated by the pipe:

body: |
{
  "mainlevel": {
    "subkey": "finalvalue"
  }
}

This is probably the easiest way to deal with in many debugging situations where you need to be able to quickly change thins in your code.

Last, and honestly something I would try to avoid is the plain one-liner:

body: "{\"mainlevel\":{\"subkey\":\"finalvalue\"}}

Note, all quotation marks need to be escaped which makes it hard to read, hard to maintain and easy to introduce errors.

As shown Ansible is powerful and simple. Thus there are always multiple different ways to reach the goal you are aiming for – and it depends on the requirements what solution is the best one.

For more details I can only recommend Understanding multi line strings in YAML and Ansible (Part I & Part II) from adminswerk.de.

Update:
Added how to add body payload from existing files.

2. Update:
Added details about literal style.

Advertisement

15 thoughts on “Ways to provide body payload in Ansible’s URI module [2. Update]”

  1. Thank you!!! Out of all Google searched I did, yours nailed down my issue. I neglected the leading space in my template string. The URI module doesn’t provide any type of useful feedback when this happens, and we were pulling our hair out troubleshooting a playbook. Great article!

    1. That’s a very good question: use the lookup plugin: body: "{{ lookup('file','issue.json') }}"
      I’ll add that to the blog post.

    2. Hm, then I must admit that I have no easy solution at hand. How about you fill a bug report at Github against the lookup plugin to also cover zip files? Or how about to write your own lookup plugin?

  2. how about the cookies jar can we have some similar to this command?
    curl -v -k -b “${COOKIE_STORE_PATH}” -c “${COOKIE_STORE_PATH}” “${BASE_URL}login?action=lt

  3. I have this working but need to introduce a new key/value pair in the body that is breaking this.

    YAML (not working)
    accounts: “domain\\username”

    JSON in CURL (working)
    “accounts”:”domain\\username”,

    I am getting errors because this needs to arrive in the submission with double-backslash. I assume this is because the receiving API I send this to needs it escaped. I have tried everything I can think of including: triple backslash, quad backslash, single quotes inside AND outside the double quotes. I cannot find a combination that works and I don’t see an option in Ansible URI module to ask it to show me exactly what it is sending against the API. I just keep getting an error from the receiving API indicating that it was not received in the proper format. Any ideas?

    1. To Debug: Run your playbook with -vvv you should see wat uri sends
      ansible-playbook test_uri.yml -vvv
      ….
      “invocation”: {
      “module_args”: {
      “body”:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: