URI and API Automation¶
What You'll Learn¶
- Calling an HTTP API declaratively with
ansible.builtin.uri - Why
uribeatsshell: curlfor anything beyond a throwaway check
Minimal Example¶
- name: Check that the app is healthy
ansible.builtin.uri:
url: "http://localhost:8080/health"
status_code: 200
Practical Example — POST With a JSON Body and Auth¶
- name: Register this host with the service registry
ansible.builtin.uri:
url: "https://registry.internal/api/v1/hosts"
method: POST
headers:
Authorization: "Bearer {{ registry_token }}"
body_format: json
body:
hostname: "{{ inventory_hostname }}"
role: web
status_code: [200, 201]
register: registration
no_log: true
body_format: jsonserializesbody:to JSON and sets the rightContent-Typeautomatically.status_code:accepts a list — anything else fails the task outright, no manual exit-code parsing needed.no_log: truebecause the request includes a bearer token — see Security.
Why Not shell: curl ...¶
# Loses structure: raw exit code, unparsed stdout, no built-in status check
- ansible.builtin.shell: curl -X POST https://registry.internal/api/v1/hosts -d '{"hostname":"{{ inventory_hostname }}"}'
uri gives you a structured, register-able result (registration.json, registration.status) instead of a string you'd have to parse yourself, checks the status code declaratively via status_code:, and avoids building a shell command string out of variables — which is a real injection risk the moment any value is even slightly untrusted.
Common Mistakes¶
- Forgetting
status_code:and treating a non-2xx response as success because the task didn't fail —urionly fails on a status not in the list you gave it (default: 200-299). - Not setting
no_log: trueon requests carrying credentials or tokens. - Reaching for
shell: curlout of habit whenurialready covers the case — see Command vs. Shell.
Interview Questions¶
- What does
uri'sstatus_code:parameter actually control? - Why is
uripreferred overshell: curlfor API automation in a reviewed playbook?
Next¶
Continue to Playbook Engineering.