Files
egutierrez eb8dbf66a1 feat(infra): auto-commit con 88 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-11 00:16:46 +02:00

4.8 KiB

Capability group: hoppscotch

Operar una instancia self-hosted de Hoppscotch (consola de APIs, alternativa open-source a Postman) desde el registry, vía su API GraphQL. El agente crea/edita requests, colecciones y environments por la API; el humano los ve en vivo en su GUI (subscriptions = hot-reload real). Las requests viven en la base de datos del self-host (Postgres), compartida entre el agente y la GUI.

Este es el flujo canónico. El antiguo modo "archivo .json local" (funciones parse_* / run_* / add_hoppscotch_request) fue eliminado: escribía un .json en disco que NO subía al workspace, así que el humano no lo veía en la GUI. No lo reintroduzcas.

Stack self-host

Vive en projects/web_scraping/hoppscotch/selfhost/ (docker compose: AIO + Postgres + mailpit).

Servicio URL Para qué
App (cliente) http://localhost:3009 la GUI donde el humano usa las colecciones (instalable como PWA)
Admin dashboard http://localhost:3100 gestión (usuarios, config)
Backend GraphQL http://localhost:3170/graphql la API que usan las funciones
Mailpit http://localhost:8025 captura el magic link del login (SMTP de pruebas, sin correo real)

Levantar: cd selfhost && docker compose up -d. Team de trabajo: "registry". Cuenta: admin@example.com.

Funciones

ID Firma corta Qué hace
hoppscotch_login_py_infra (email, *, backend_url, mailpit_url) -> {access_token,...} login por magic link headless (lee el link de mailpit) → JWT
hoppscotch_create_request_py_infra (collection_id, method, url, *, title, headers, body, body_type, team_id, access_token) -> dict crea una request en una colección de la team
hoppscotch_update_request_py_infra (request_id, method, url, *, title, headers, body, body_type, access_token) -> dict actualiza una request
hoppscotch_delete_request_py_infra (request_id, *, access_token) -> dict borra una request
hoppscotch_list_requests_py_infra (collection_id, *, access_token) -> {requests:[...]} lista las requests de una colección
hoppscotch_set_environment_py_infra (team_id, name, variables, *, access_token) -> dict crea/actualiza (idempotente) el environment de la team; resuelve secretos pass:
build_hoppscotch_collection_py_infra (calls, *, name, request_names) -> dict helper interno de create/update: serializa call specs al formato HoppRESTRequest. NO para escribir .json a mano
pass_get_secret_py_infra (path, *, line) -> {value} lee un secreto de pass (lo consume set_environment para no hardcodear keys)

access_token se pasa como cookie, no header Authorization. Caduca a 24h → re-login con hoppscotch_login.

Ejemplo canónico (end-to-end)

import sys, os
sys.path.insert(0, os.path.join(os.path.expanduser("~/fn_registry"), "python", "functions"))
from infra.hoppscotch_login import hoppscotch_login
from infra.hoppscotch_create_request import hoppscotch_create_request
from infra.hoppscotch_set_environment import hoppscotch_set_environment

TEAM = "cmq8kn0v500030xls1nvminjy"          # team "registry"
COLL = "cmq8knppc00040xlskt4ist27"          # colección registry_api (de hoppscotch_list/DB)

tok = hoppscotch_login("admin@example.com")["access_token"]

# 1. Variables del workspace (secreto resuelto desde pass, no hardcodeado)
hoppscotch_set_environment(TEAM, "registry", [
    {"key": "baseURL", "value": "https://registry.organic-machine.com", "secret": False},
    {"key": "api_key", "value": "pass:apis/registry", "secret": True},   # pass: -> pass_get_secret
], access_token=tok)

# 2. Crear una request → aparece EN VIVO en la GUI del humano (subscriptions)
hoppscotch_create_request(
    COLL, "GET", "<<baseURL>>/api/status",
    title="status", headers={"Accept": "application/json"},
    team_id=TEAM, access_token=tok,
)

Fronteras (qué NO cubre)

  • No es modo archivo: no escribe colecciones .json locales como fuente. Las requests viven en el Postgres del self-host. (Los .json en collections/ son solo respaldo/semilla importable.)
  • No automatiza la GUI: opera por la API; la GUI la mira el humano.
  • No gestiona usuarios/teams del dashboard: eso es el admin dashboard (:3100).
  • No ejecuta los scripts pre/post-request JS de Hoppscotch.

Gotchas

  • access_token como cookie (cookies={"access_token": tok}), no Authorization. 24h de vida.
  • createRequestInCollection de esta instancia exige team_id en el input (no solo el collectionID).
  • Variables <<var>> se resuelven con el environment de la team (subscriptions las propagan a la GUI).
  • Secretos: usa value="pass:<ruta>" en set_environment → se resuelve de pass, nunca se hardcodea ni se logea en crudo.
  • El secreto viaja en claro al backend local por GraphQL — es local (127.0.0.1), aceptable.