El cliente de API era de la casa y sin pretensiones: un panel interno para disparar peticiones contra nuestro propio backend mientras depuramos. Lo único que pidió el equipo fue un botón, «copiar como cURL», para pegar la petición en una terminal y acabar con el «pues a mí me funciona».
Dos semanas tranquilas. Hasta que Marta copió el comando de una petición que estaba fallando, lo pegó tal cual y el servidor le contestó 200 y un registro perfecto. El fallo había desaparecido justo al intentar reproducirlo. Lo que había desaparecido, en realidad, eran dos apóstrofos: el nombre salía del panel como O'Donnell y llegaba al backend como ODonnell.
Dentro de comillas simples no se escapa nada
El generador hacía lo obvio: envolver el JSON entre comillas simples y pegarlo detrás de --data. Con un apóstrofo dentro, la shell cierra la cadena ahí mismo y el comando ni arranca. Con dos, las comillas vuelven a cuadrar: se ejecuta sin una queja, el JSON sigue siendo válido, el servidor responde 200 y por el camino se han caído los dos caracteres. El fallo ruidoso lo pillas en diez segundos; el silencioso te hace dudar del backend.
Mi primer parche fue poner una contrabarra delante. Se lo conté a la IA del IDE y me devolvió el matiz que me faltaba:
Una contrabarra dentro de comillas simples es una contrabarra. La única salida es cerrar la cadena, meter la comilla entre dobles y volver a abrir: cada ' se escribe '\''.
Con esa regla, la función de citado son tres líneas. Lo que de verdad ahorró la tarde fue lo siguiente: le pedí la lista de cosas que rompen un comando pegado a mano, y salió sin adornos.
- Un apóstrofo suelto rompe fuerte; dos rompen en silencio.
- $(...) y los acentos graves en un campo de texto: si envuelves con comillas dobles, la shell los ejecuta.
- Saltos de línea en el cuerpo: --data los elimina, hay que usar --data-raw o --data-binary.
- Cuerpo vacío, cabecera sin valor y un signo de exclamación, que en bash interactivo muerde por la expansión de historial.
De ahí salieron los test. Pegué el cuerpo real de la petición de Marta, pedí la tabla de entradas y comandos esperados, y el tercer caso ya fallaba.
Por qué esto no se pega en un conversor online
Hay webs que convierten un fetch en cURL de maravilla. No podía usar ninguna: la petición que tenía delante llevaba una cabecera Authorization con un token vivo, el correo de un cliente real en el cuerpo y la URL de un servicio interno. Pegar eso en el formulario de un desconocido es regalarlo. Y mandarle el ejemplo limpio a un modelo remoto tampoco servía, porque el ejemplo limpio es justo el que no reproduce el bug.
En el IDE del navegador no hay que elegir entre una cosa y la otra. El modelo corre en la pestaña, sobre tu GPU: el prompt con el token, el JSON del cliente y el código del generador se quedaron donde estaban. Sin cuenta, sin subida y media tarde con el wifi apagado, que es la mejor prueba de que no sale nada.
Abre Elffuss Code y escribe tu propia función de citado con los casos raros delante: el editor y el modelo corren en el navegador, así que ni el código ni el prompt con el token salen de tu equipo.
Abrir Code →