AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible uri Module: Make HTTP/REST API Calls from Playbooks (Guide)

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Complete guide to Ansible uri module. Make GET, POST, PUT, DELETE requests, authenticate with APIs, upload files, handle JSON responses, and implement health.

The ansible.builtin.uri module sends HTTP and HTTPS requests from Ansible playbooks. It's the Ansible equivalent of curl — use it for REST API calls, health checks, webhooks, and any HTTP interaction.

Basic HTTP Requests

GET Request

- name: Simple GET
  ansible.builtin.uri:
    url: https://api.example.com/status
  register: response

- name: Show response ansible.builtin.debug: msg: "Status: {{ response.status }}, Body: {{ response.json }}"

POST Request (JSON)

- name: Create resource via API
  ansible.builtin.uri:
    url: https://api.example.com/users
    method: POST
    body:
      name: "John Doe"
      email: "john@example.com"
      role: admin
    body_format: json
    status_code: 201
  register: create_result

PUT Request

- name: Update resource
  ansible.builtin.uri:
    url: "https://api.example.com/users/{{ user_id }}"
    method: PUT
    body:
      name: "Jane Doe"
      role: superadmin
    body_format: json
    status_code: 200

DELETE Request

- name: Delete resource
  ansible.builtin.uri:
    url: "https://api.example.com/users/{{ user_id }}"
    method: DELETE
    status_code: [200, 204]

PATCH Request

- name: Partial update
  ansible.builtin.uri:
    url: "https://api.example.com/users/{{ user_id }}"
    method: PATCH
    body:
      role: admin
    body_format: json

See also: Ansible 2.17.0-rc1: Elevating Automation with ‘Gallows Pole’

Authentication

Bearer Token

- name: API call with bearer token
  ansible.builtin.uri:
    url: https://api.example.com/data
    headers:
      Authorization: "Bearer {{ api_token }}"

Basic Auth

- name: Basic authentication
  ansible.builtin.uri:
    url: https://api.example.com/data
    url_username: "{{ api_user }}"
    url_password: "{{ api_password }}"
    force_basic_auth: true

API Key

- name: API key in header
  ansible.builtin.uri:
    url: https://api.example.com/data
    headers:
      X-API-Key: "{{ api_key }}"

Custom Headers

- name: Request with custom headers
  ansible.builtin.uri:
    url: https://api.example.com/data
    headers:
      Content-Type: application/json
      Accept: application/json
      X-Request-ID: "{{ ansible_date_time.iso8601 }}"
      User-Agent: "Ansible/{{ ansible_version.full }}"

See also: Ansible systemd Module: Manage Services, Timers & Units (Guide)

Handle Responses

Parse JSON Response

- name: Get user list
  ansible.builtin.uri:
    url: https://api.example.com/users
    return_content: true
  register: users_response

- name: Show user count ansible.builtin.debug: msg: "Found {{ users_response.json | length }} users"

- name: Show first user ansible.builtin.debug: msg: "{{ users_response.json[0].name }}"

- name: Filter active users ansible.builtin.debug: msg: "{{ users_response.json | selectattr('active', 'equalto', true) | list }}"

Check Status Code

- name: Expect specific status codes
  ansible.builtin.uri:
    url: https://api.example.com/resource
    status_code: [200, 201, 204]
  register: result
  # Fails if response code is not in the list

- name: Don't fail on error codes ansible.builtin.uri: url: https://api.example.com/maybe-missing status_code: [200, 404] register: result

- name: Handle 404 ansible.builtin.debug: msg: "Resource not found — creating it" when: result.status == 404

Save Response to File

- name: Download file
  ansible.builtin.uri:
    url: https://example.com/archive.tar.gz
    dest: /tmp/archive.tar.gz
    creates: /tmp/archive.tar.gz  # Skip if file exists

Health Checks & Monitoring

Simple Health Check

- name: Check application health
  ansible.builtin.uri:
    url: "http://localhost:{{ app_port }}/health"
    status_code: 200
    timeout: 10

Health Check with Retries

- name: Wait for service to be healthy
  ansible.builtin.uri:
    url: "http://localhost:8080/health"
    status_code: 200
  register: health
  retries: 30
  delay: 5
  until: health.status == 200

Verify SSL Certificate

- name: Check SSL certificate
  ansible.builtin.uri:
    url: https://www.example.com
    validate_certs: true
    status_code: 200
  register: ssl_check

- name: Show certificate info ansible.builtin.debug: msg: "SSL OK, response time: {{ ssl_check.elapsed }}s"

See also: Ansible wait_for Module: Wait for Conditions, Ports & Files (Guide)

Real-World Patterns

Webhook Notifications

- name: Send Slack notification
  ansible.builtin.uri:
    url: "{{ slack_webhook_url }}"
    method: POST
    body:
      text: "Deployment complete: {{ app_version }} on {{ inventory_hostname }}"
      channel: "#deployments"
    body_format: json
  delegate_to: localhost
  run_once: true

- name: Send PagerDuty event ansible.builtin.uri: url: https://events.pagerduty.com/v2/enqueue method: POST body: routing_key: "{{ pagerduty_key }}" event_action: trigger payload: summary: "Deployment failed on {{ inventory_hostname }}" severity: critical source: ansible body_format: json delegate_to: localhost

Create-or-Update Pattern

- name: Check if resource exists
  ansible.builtin.uri:
    url: "https://api.example.com/items/{{ item_name }}"
    status_code: [200, 404]
  register: check

- name: Create resource (if not found) ansible.builtin.uri: url: https://api.example.com/items method: POST body: name: "{{ item_name }}" config: "{{ item_config }}" body_format: json status_code: 201 when: check.status == 404

- name: Update resource (if exists) ansible.builtin.uri: url: "https://api.example.com/items/{{ item_name }}" method: PUT body: config: "{{ item_config }}" body_format: json when: check.status == 200

Pagination

- name: Fetch all pages of results
  ansible.builtin.uri:
    url: "https://api.example.com/items?page={{ item }}&per_page=100"
    return_content: true
  register: page_results
  loop: "{{ range(1, total_pages + 1) | list }}"

- name: Combine all results ansible.builtin.set_fact: all_items: "{{ page_results.results | map(attribute='json') | flatten }}"

Upload File

- name: Upload file via multipart form
  ansible.builtin.uri:
    url: https://api.example.com/upload
    method: POST
    src: /tmp/report.pdf
    headers:
      Content-Type: application/pdf
    status_code: [200, 201]

Parameters Reference

| Parameter | Description | Default | |-----------|-------------|---------| | url | Target URL (required) | — | | method | HTTP method | GET | | body | Request body | — | | body_format | json, form-urlencoded, raw | raw | | headers | Custom headers (dict) | — | | status_code | Expected status code(s) | 200 | | return_content | Include body in response | false | | timeout | Request timeout (seconds) | 30 | | validate_certs | Verify SSL certificates | true | | dest | Save response body to file | — | | creates | Skip if file exists | — | | follow_redirects | none, safe, all | safe |

FAQ

What is the Ansible equivalent of curl?

The ansible.builtin.uri module is the Ansible equivalent of curl. It supports GET, POST, PUT, DELETE, PATCH, custom headers, authentication, file uploads, and response parsing — all natively in YAML.

How do I make a POST request with JSON body?

Use method: POST, body_format: json, and pass the body as a YAML dictionary: body: {key: value}. Ansible automatically serializes it to JSON and sets the Content-Type header.

How do I handle API errors without failing the playbook?

Add the error status codes to status_code: status_code: [200, 404]. Then check result.status in subsequent tasks to handle each case differently.

How do I wait for an API to be ready?

Use the uri module with retries and until: retries: 30, delay: 5, until: result.status == 200. This polls the endpoint every 5 seconds for up to 150 seconds.

Can I use Ansible uri module with self-signed certificates?

Yes, set validate_certs: false to skip SSL verification. For production, use ca_path to specify a custom CA certificate instead of disabling validation entirely.

Conclusion

GET/POST/PUT/DELETE — Full HTTP method support • body_format: json — Auto-serialize YAML to JSON • status_code: — Define expected response codes • retries + until — Health check polling • return_content: true — Access response.json for parsed JSON • Always use delegate_to: localhost for API calls from the controller

Related Articles

Ansible wait_for Module: Wait for ConditionsAnsible register: Save Task OutputAnsible delegate_to: Run Tasks on Different Hosts

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home