I have a list
- name: List
set_fact:
array1:
- param1: "efg"
param2: "abdc"
param3: "nsdadsd"
param4: "dadas dsadasda"
which looks like:
"array1": [
{
"param1": "efg",
"param2": "abdc",
"param3": "nsdadsd",
"param4": "dadas dsadasda"
}
]
Which I want to to send in a body of the following API call
- name: API call
delegate_to: localhost
uri:
url: https://some_url/abcd/
validate_certs: false
method: POST
body_format: json
headers:
X-some-APIKey: "{{api_token}}"
body:
'{
"{{array1}}"
}'
register: api_output
For this I get an error:
"msg": "Unable to pass options to module, they must be JSON serializable: Object of type 'set' is not JSON serializable"
I found on internet that the problem could be that it's not a string that is passed but a "set" and one of the answers was to convert it to a string, so I tried this
- name: array2
set_fact:
array2: "{{array1 | string }}"
Also tried different variations with quotes, either ' or " for the values and even parameters, but nothing helped.
Update:
Let me add that just for the test I changed the array to be just with one item, and still getting "serializable" error. So I'm thinking maybe it's not the array which is a problem, but syntax for calling this variable from an API?
- name: array
set_fact:
array1:
- abdcdef
SOLUTION: Update no2.
Problem was with two things. First there was Content-Type: "application/json" missing from API call. Second was that this API web service does not accept arrays.
CodePudding user response:
You are creating an invalid json, in your example you're trying to create a structure similar to
{
[
{
"param1": "efg",
"param2": "abdc",
"param3": "nsdadsd",
"param4": "dadas dsadasda"
}
]
}
which is invalid, since {} implies name/value pair, see https://www.json.org/json-en.html
Ansible has a to_json
filter, which helps converting vars to a valid json, so creating a correct fact and then converting it to json sounds like a good idea.
If your api accepts arrays, the following playbook should work:
- hosts: localhost
tasks:
- name: List
set_fact:
list1:
- param1: "efg"
param2: "abdc"
param3: "nsdadsd"
param4: "dadas dsadasda"
- name: API call
delegate_to: localhost
uri:
url: http://localhost:8080
method: POST
body_format: json
body: "{{list1 | to_json }}"
register: api_output
Tested with awesome https://hub.docker.com/r/mendhak/http-https-echo image, which echoes http requests, using podman run -p 8080:8080 --rm -t mendhak/http-https-echo:24
, output contains:
{
"path": "/",
"headers": {
"accept-encoding": "identity",
"content-length": "86",
"host": "localhost:8080",
"user-agent": "ansible-httpget",
"content-type": "application/json",
"connection": "close"
},
"method": "POST",
"body": "[{\"param1\": \"efg\", \"param2\": \"abdc\", \"param3\": \"nsdadsd\", \"param4\": \"dadas dsadasda\"}]",
"fresh": false,
"hostname": "localhost",
"ip": "::ffff:10.0.2.100",
"ips": [],
"protocol": "http",
"query": {},
"subdomains": [],
"xhr": false,
"os": {
"hostname": "40f1fcddf57d"
},
"connection": {},
"json": [
{
"param1": "efg",
"param2": "abdc",
"param3": "nsdadsd",
"param4": "dadas dsadasda"
}
]
}
Update:
With info from comments, it seems that array is not required, then fact setting task should be converted to
- name: List
set_fact:
list1:
param1: "efg"
param2: "abdc"
param3: "nsdadsd"
param4: "dadas dsadasda"
however, to not to confuse futher readers of your code, list should be renamed to dict in both task name and fact name