---
name: dav_delete_resource
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def dav_delete_resource(base_url: str, username: str, password: str, resource_path: str, *, etag: str = '', timeout_s: float = 20.0, verify_tls: bool = True) -> dict"
description: "Borra (HTTP DELETE) un recurso DAV individual (un VCARD o un VCALENDAR) con HTTP Basic auth. Construye el header Authorization: Basic base64(user:pass) a mano con stdlib. El resource_path puede ser un href absoluto (como los que devuelven dav_list_resources / dav_get_collection) o una URL completa. Opcionalmente envia If-Match: <etag> para un borrado condicional que evita pisar una edicion concurrente. DESTRUCTIVO e IRREVERSIBLE: usar con confirmacion explicita, nunca a ciegas. verify_tls=True por defecto. Maneja errores sin lanzar. Solo stdlib (urllib, base64, ssl). Probado contra Xandikos."
tags: [dav, carddav, caldav, delete, remove, http, infra]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [base64, ssl, urllib.error, urllib.request]
params:
  - name: base_url
    desc: "URL base del servidor DAV. Se ignora si resource_path ya es una URL absoluta."
  - name: username
    desc: "usuario para HTTP Basic auth (p.ej. 'enmanuel')."
  - name: password
    desc: "contrasena para HTTP Basic auth. Resolver desde pass con pass_get_secret, nunca hardcodear."
  - name: resource_path
    desc: "href absoluto (p.ej. '/enmanuel/contacts/addressbook/x.vcf') o URL completa del recurso a borrar. Acepta directamente los hrefs que devuelven dav_list_resources / dav_get_collection."
  - name: etag
    desc: "etag del recurso para borrado condicional via If-Match. Si se da, el servidor solo borra cuando el etag actual coincide (412 si cambio). Vacio = borrado incondicional."
  - name: timeout_s
    desc: "timeout de la peticion HTTP en segundos. Default 20.0."
  - name: verify_tls
    desc: "si True (default) verifica el certificado TLS. No desactivar salvo entorno de prueba."
output: "dict. En exito: {status:'ok', http_status:int, url:str} (DELETE devuelve normalmente 204 No Content o 200). En error (sin lanzar): {status:'error', error:str, http_status:int|None}. Un 404 (ya no existe) llega como error con http_status=404, tratable como idempotente."
tested: true
tests:
  - "test_construye_request_delete_con_auth"
  - "test_resource_path_relativo_se_resuelve_con_base_url"
  - "test_resource_path_absoluto_se_respeta"
  - "test_if_match_se_envia_cuando_hay_etag"
  - "test_sin_etag_no_envia_if_match"
  - "test_204_devuelve_ok"
  - "test_404_devuelve_status_error"
test_file_path: "python/functions/infra/dav_delete_resource_test.py"
file_path: "python/functions/infra/dav_delete_resource.py"
---

## Ejemplo

```python
import sys
sys.path.insert(0, "python/functions")
from infra.pass_get_secret import pass_get_secret
from infra.carddav_put_vcard import carddav_put_vcard
from infra.dav_delete_resource import dav_delete_resource

base = "https://dav-eedeb681c4ab89ab8e444ac9.organic-machine.com"
coll = "/enmanuel/contacts/addressbook/"
pw = pass_get_secret("dav/xandikos-enmanuel")["value"]  # NO logear

# Sube un vCard de prueba y luego lo borra (limpieza de un test):
vcard = "BEGIN:VCARD\r\nVERSION:3.0\r\nFN:Tmp\r\nUID:zz-tmp\r\nEND:VCARD\r\n"
carddav_put_vcard(base, "enmanuel", pw, coll, "zz-tmp", vcard)
res = dav_delete_resource(base, "enmanuel", pw, coll + "zz-tmp.vcf")
print(res["status"], res["http_status"])  # ok 204
```

## Cuando usarla

Cuando necesitas RETIRAR un recurso de una coleccion CardDAV/CalDAV: limpiar el
vCard de prueba que subiste para validar un sync, borrar un contacto obsoleto,
o eliminar un evento cancelado. Completa el CRUD del grupo `dav` (put / get /
list / get-collection / **delete**). Para limpieza segura tras un test usa el
href que devuelve `carddav_put_vcard` (campo `url`) o el `href` de
`dav_get_collection`.

## Gotchas

- DESTRUCTIVO e IRREVERSIBLE en el servidor. No llamarla en un bucle de sync sin
  confirmacion explicita (`confirm=True` / `--yes` en el caller). Pensada para
  acciones puntuales controladas, no para reconciliacion automatica.
- Un 404 (el recurso ya no existe) llega como `{status:'error', http_status:404}`.
  Para un borrado idempotente, el caller puede tratar 404 como exito ("ya estaba
  borrado").
- Pasa `etag` para borrado condicional (If-Match): si el recurso cambio desde que
  lo leiste, el servidor responde 412 Precondition Failed y NO borra — evita
  pisar una edicion concurrente del movil.
- Borrado remoto real sobre TLS; password de `pass`, no se logea.
- `verify_tls=False` solo en pruebas; abre MITM.
