--- id: "0110" title: "Gap registry: helper HTTP cliente C++ (curl/popen) reutilizable" status: pendiente type: feature domain: - cpp-stack - registry-quality scope: registry priority: media depends: [] blocks: - "0111" related: - "0106" created: 2026-05-18 updated: 2026-05-18 tags: [http, cpp, registry-gap, curl, helper] --- # 0110 — Helper HTTP cliente C++ en el registry ## Problema Hoy no existe funcion HTTP cliente reutilizable en `cpp/functions/`. Cada app C++ que necesita golpear un endpoint reinventa la capa: | App | Fichero | Tecnica | LOC aprox | |---|---|---|---| | `apps/services_monitor/` | `http_client.cpp` | cURL popen/WinHTTP segun plataforma | ~150 | | `apps/dag_engine_ui/` | inline en `main.cpp` | curl CLI via popen + parse | ~80 | | `apps/data_factory/` | inline | popen curl | ~60 | | `cpp/functions/core/llm_anthropic.cpp` | propio | cURL popen — solo Anthropic | — | | `apps/process_explorer/` (issue 0111) | `http_client.cpp` local | pendiente — clonara services_monitor | ~150 esperados | El patron ya supera el umbral `>2x` que dispara la regla de promocion (CLAUDE.md "Si patron se repite >2x → propose nueva funcion via fn-constructor"). Cada app duplica: - Detection de plataforma (Linux: `popen("curl -s ...")`, Win: `WinHTTPOpen`/popen) - Manejo de basicAuth / Bearer tokens - Timeouts - Captura de body + status code - Manejo de errores transitorios (DNS, conexion rechazada) ## Decision Anadir al registry dos funciones C++ en dominio `core` (o `infra`): ### `http_request_cpp_core` (impure) ```cpp namespace fn_http { struct Request { std::string method; // "GET", "POST", "PUT", "DELETE" std::string url; std::vector> headers; std::string body; // raw bytes (JSON, etc.) int timeout_ms = 5000; std::string bearer_token; // shortcut: anade Authorization: Bearer std::string basic_user; // shortcut: anade Authorization: Basic base64(user:pass) std::string basic_pass; }; struct Response { int status = 0; // 0 = error de transporte std::string body; std::vector> headers; std::string error; // vacio si OK int64_t duration_ms = 0; }; Response request(const Request& req); } ``` Implementacion: cURL via popen (portable WSL+Win+Linux, igual que `llm_anthropic`). Si en el futuro queremos rendimiento real, swap a libcurl linkado estaticamente o WinHTTP via `#ifdef _WIN32` — interfaz Request/Response no cambia. ### `http_get_json_cpp_core` (impure, pure wrapper) Helper que envuelve `http_request` + parse JSON (via `nlohmann::json` o similar ya disponible en el repo) para los casos comunes: ```cpp namespace fn_http { // Devuelve parsed JSON o lanza si status != 2xx nlohmann::json get_json(const std::string& url, const std::string& bearer_token = "", int timeout_ms = 5000); } ``` ## Plan de migracion Tras crear las funciones, abrir issue separado por cada consumer para migrar: 1. `apps/services_monitor/http_client.cpp` -> usar `fn_http::request` 2. `apps/dag_engine_ui/main.cpp` (inline) 3. `apps/data_factory/` (inline) 4. `cpp/functions/core/llm_anthropic.cpp` — refactor para usar `fn_http::request` por debajo (mantiene API publica) 5. `apps/process_explorer/` (issue 0111) — nace ya usando el helper ## Criterios de aceptacion - [ ] `cpp/functions/core/http_request.{cpp,h,md}` registrado en `registry.db` - [ ] `cpp/functions/core/http_get_json.{cpp,h,md}` idem - [ ] Tests visuales o de integracion contra `httpbin.org` (200/404/timeout/auth) - [ ] Frontmatter completo (`params`/`output`/`tags`/`example`) - [ ] `.md` cumple contrato self-doc (`## Ejemplo`, `## Cuando usarla`, `## Gotchas`) - [ ] Al menos 1 consumer migrado para validar API (recomendado `services_monitor`) - [ ] `fn doctor uses-functions` limpio ## Gotchas conocidos - cURL popen en Windows necesita `curl.exe` en PATH — todos los WSL/Win lo tienen, pero documentar en `## Gotchas`. - Bodies binarios: popen complica el escape; primera version solo string bodies. - TLS verify: por defecto on; permitir `req.insecure = true` solo para testing. - Timeouts: cURL `--max-time` cubre handshake+transfer; documentar diferencia con read-timeout puro. ## Por que no usar libcurl linkado - `popen("curl ...")` no requiere anadir libcurl al toolchain MinGW cross-compile (que ya costo configurar). `llm_anthropic` lleva meses funcionando asi. - Cuando aparezca un caso real de latencia (>10 req/s sostenido), abrimos issue separado para swap a libcurl. ## Out of scope (no en este issue) - WebSocket / SSE — cliente WS C++ es otro gap; abrir issue propio cuando aplique. - Cliente gRPC. - Streaming responses (SSE chunk-by-chunk) — usar caso de `dag_engine_ui` para decidir cuando.