16

I have an Ansible task that makes a URI request to a website to get a JSON response. I want Ansible to do something if the nested JSON variable is defined, and something else if it isn't.

- name: Get JSON from the Interwebs
  uri: url="http://whatever.com/jsonresponse" return_content=yes
  register: json_response

- name: Write nested JSON variable to disk
  copy: content={{json_response.json.nested1.nested2}} dest="/tmp/foo.txt"

Note that using ignore_errors only works for the task's command failing, not for checking undefined values in nested data structures within a Jinja template. So if json_response.json.nested1.nested2 isn't defined, this task will still fail despite ignore_errors=yes being set.

How do I get this playbook to store some default value in /tmp/foo.txt if the request fails, or if the request doesn't have the right nested value defined?

Neil
  • 2,425
  • 8
  • 36
  • 45

3 Answers3

20

You need to use a jinja2 filter (http://docs.ansible.com/ansible/playbooks_filters.html). In this case, the name of the filter is from_json. In the following example I'll take an action when the key is found and other action when the could not be found:

 ---                                                                                                            

 - hosts: somehost                                                                                               
   sudo: yes                                                                                                    

   tasks:                                                                                                       

   - name: Get JSON from the Interwebs                                                                          
     uri: url="https://raw.githubusercontent.com/ljharb/node-json-file/master/package.json" return_content=yes  
     register: json_response                                                                                    

   - debug: msg="Error - undefined tag"                                                                         
     when: json_response["non_existent_tag"] is not defined                                                     

   - debug: msg="Success - tag defined =>{{  (json_response.content|from_json)['scripts']['test'] }}<="  
     when:  (json_response.content|from_json)['scripts']['test']  is defined    

Now replace the debug for the appropriate to take the desired action.

Hope it helps,

alfredocambera
  • 446
  • 2
  • 12
3

I stumbled here after looking for a way on how to extract a field from json from the github api. I ended up with the following solution.

uri: url="https://api.github.com/repos/.../.../releases/latest" return_contents=yes

register: github_json

and use it somewhere else like this:

"{{ github_json.json.$key }}"
  • 1
    I am not sure this actually helps the OP: you don't really explain where $key comes from, and the question is basically asking what happens when there is no `$key` field in the response - i.e. something jinja's `default` filter might be useful for. – iwaseatenbyagrue Apr 10 '17 at 16:42
  • 1
    This wasn't a direct response to the OP since the question is more than a year and half old but I was hoping it could be helpful for people that wanted to get JSON values from an API using only Ansible which is how I stumbled on this page. – Samy Coenen Apr 11 '17 at 18:36
2

As per documentation at https://docs.ansible.com/ansible/latest/modules/uri_module.html

Whether or not to return the body of the response as a "content" key in the dictionary result. Independently of this option, if the reported Content-type is "application/json", then the JSON is always loaded into a key called json in the dictionary results.

---
- name: Example of JSON body parsing with uri module
  connection: local
  gather_facts: true
  hosts: localhost
  tasks:

    - name: Example of JSON body parsing with uri module
      uri: 
        url: https://jsonplaceholder.typicode.com/users
        method: GET
        return_content: yes
        status_code: 200
        body_format: json
      register: data
      # failed_when: <optional condition based on JSON returned content>

    - name: Print returned json dictionary
      debug:
        var: data.json

    - name: Print certain element
      debug:
        var: data.json[0].address.city
Boeboe
  • 247
  • 2
  • 3