Ir al contenido

Presentamos FileMaker OData Webhooks Manager #

La herramienta open-source, las decisiones de arquitectura y los siete comportamientos de la API no documentados que absolutamente nadie me advirtió #


Hace unas semanas escribí sobre cómo los webhooks OData de FileMaker Server 22.0.4 convierten la plataforma en un ciudadano realmente basado en eventos, apropiadamente moderno. Todavía lo creo. La capacidad es genuinamente un punto de inflexión.

Pero entonces me senté para construir algo real encima. Un gestor de webhooks. Una herramienta que te permita navegar por tus bases de datos FileMaker, crear y editar webhooks visualmente, probarlos sin tocar datos de producción e inspeccionar el estado de cada entrega pendiente.

Lo que encontré en el proceso fue una brecha — entre la característica existe y la característica es realmente utilizable — que es más amplia de lo que deja entrever cualquier documentación oficial.

Este es el artículo de seguimiento. El menos halagador. El que, con suerte, te ahorra un fin de semana.


La Herramienta: FMS-odata-webhooks #

Primero, déjame mostrarte lo que construí, porque es el contexto de todo lo demás.

FMS-odata-webhooks es una aplicación web React que te proporciona una interfaz visual para la API de webhooks OData de FileMaker. Es de código abierto, licenciada MIT y construida para manejar todas las peculiaridades descritas a continuación para que no tengas que descubrirlas tú mismo.

Qué hace #

Navegador de bases de datos — Conéctate a cualquier instancia de FileMaker Server 22.0.4+ con tus credenciales OData. La aplicación lista tus bases de datos disponibles, te permite seleccionar una y expone los metadatos completos de tablas y campos, incluyendo las anotaciones de tipo específicas de FileMaker. Puedes explorar tu esquema antes de escribir una sola línea de código de integración.

Gestor de webhooks — Una interfaz CRUD completa para la gestión de webhooks:

  • Crea webhooks con selección visual de campos desde el esquema en vivo
  • Configura expresiones de filtro OData con validación en tiempo real
  • Establece cabeceras HTTP personalizadas (para la autenticación del receptor, metadatos o enrutamiento)
  • Activa las notificaciones de cambio de esquema por webhook
  • Edita webhooks — que abstrae el patrón de borrar+crear que requiere la API (más sobre esto a continuación)
  • Borra webhooks con confirmación
  • Invoca manualmente cualquier webhook contra IDs de registro específicos para pruebas

Panel de Operaciones Pendientes (próximo) — Cada webhook lleva una cola pendingOperations[] de eventos que esperan ser entregados o que han fallado. El próximo panel expondrá esta cola directamente en la interfaz: tipo de operación (ADD, UPDATE, DELETE, SCHEMA), estado de entrega, códigos de error, mensajes de error y recuento de reintentos. Esta información está en la respuesta de la API pero completamente ausente de la documentación oficial. Exponerla está en la hoja de ruta, porque es oro para la depuración.

Prueba de endpoints — Un conjunto de utilidades de consola del navegador (window.FileMakerTests.*) para la exploración de la API de bajo nivel: verificaciones de conectividad, validación completa de endpoints a través de todos los métodos HTTP, pruebas de integración que crean y limpian webhooks reales.

Stack tecnológico #

React 18 + Vite, Tailwind CSS, componentes shadcn/ui. Sin backend, sin base de datos. Todo el estado vive en FileMaker Server. En desarrollo, Vite hace proxy de /fmi/* a tu servidor y gestiona CORS. En producción, necesitas nginx para hacer lo mismo — que es uno de los comportamientos no documentados tratados a continuación.

El código está en github.com/fsans/FMS-odata-webhooks. Fork it, úsalo, abre issues.


Comenzar en cinco minutos #

git clone https://github.com/fsans/FMS-odata-webhooks.git
cd FMS-odata-webhooks
npm install
npm run dev

Abre http://localhost:5173. Antes de conectar, visita https://your-filemaker-server/fmi/odata/v4 en tu navegador y acepta la advertencia de certificado SSL — esto desbloquea el proxy en modo desarrollo. Introduce el host de tu servidor y las credenciales OData, haz clic en Connect.

Eso es todo. Estás navegando por tu esquema FileMaker y gestionando webhooks.


Las siete cosas que nadie me dijo #

Ahora por la parte que más tiempo costó. Estos no son casos límite. Son comportamientos fundamentales de la API de webhooks OData de FileMaker que encontrarás en cualquier proyecto de integración serio. Ninguno de ellos está documentado en la guía OData de Claris.

1. “Solo POST” es un mito — el contrato real es mixto GET/POST #

La información pública sobre esta API es escasa — casi nula. Una publicación mínima en Claris Community del personal técnico de Claris, y brevemente mi propio README, decían lo mismo: todas las operaciones de webhook son solo POST.

Falso.

Según la guía oficial OData de Claris y confirmado a través de pruebas sistemáticas, el contrato HTTP real es:

EndpointMétodoNotes
Webhook.GetAllGETRetorna la lista completa
Webhook.Get(<id>)GET<id> en la ruta URL
Webhook.AddPOSTConfig en el cuerpo JSON
Webhook.Delete(<id>)POST<id> en la ruta URL
Webhook.Invoke(<id>)POST<id> en la ruta URL, rowIDs en el cuerpo

Los endpoints de lectura son GET. Los endpoints de acción son POST. Y el <id> es un argumento de función OData en la ruta URL — no un campo webhookID en el cuerpo JSON. Si te equivocas, obtienes respuestas HTTP 400 sin ningún mensaje de error útil. La aplicación gestiona esto correctamente; lo documento aquí porque lo encontrarás el momento que intentes llamar a la API directamente.

  • ❌ PUT y PATCH no existen en ningún endpoint de webhook.
  • ❌ El estilo REST DELETE /Webhook/<id> tampoco existe. Usa POST /Webhook.Delete(<id>).

2. La trampa del campo id — y por qué puede congelar tu webhook permanentemente #

Esta tiene un borde afilado.

La cadena en minúsculas id es tratada como una palabra reservada internamente por el motor OData de FileMaker. Se asigna al ID de registro interno de FileMaker. Si tienes un campo en tu tabla también llamado id, obtienes una colisión de nombres — y la colisión no falla simplemente con gracia.

Aquí hay un error real de mi entorno de pruebas, capturado directamente de la cola pendingOperations:

{
  "operation": "UPDATE",
  "rowIDs": [19972],
  "status": "NOT_SENT",
  "lastErrorCode": -1002,
  "lastErrorMessage": "Error: syntax error in URL at: 'id'",
  "sendAttempts": 36
}

FileMaker sigue reintentando. En mi entorno de pruebas sendAttempts subió pasando decenas de miles sin resolución y la cola nunca se despejó por sí sola — el webhook está efectivamente congelado hasta que lo borres.

La solución:

  • Mejor: cambia el nombre del campo. ID (mayúsculas) no colisiona. Tampoco record_id, row_id, contact_id, o cualquier cosa que no sea la cadena exacta en minúsculas id.
  • Solución rápida: ponla entre comillas en $select — usa "id" en lugar de id.
$select=first_name,last_name,"id"   ✅
$select=first_name,last_name,id     ❌ (error de sintaxis en URL)

La aplicación valida las selecciones de campos y te avisa si un campo llamado id se incluye sin comillas.

3. No PATCH, no PUT — cada edición es una eliminación #

¿Quieres ajustar el filtro de un webhook? ¿Ajustar qué campos incluye? ¿Cambiar la URL de callback?

No puedes. No hay Webhook.Update. No hay PATCH. No hay ninguna edición suave de ningún tipo.

La única manera de modificar un webhook es borrarlo y crear uno nuevo. El nuevo webhook obtiene un ID entero secuencial fresco. Cada sistema externo que almacenó el ID antiguo — la lógica de enrutamiento de tu receptor, tu tablero de monitoreo, tu documentación — ahora hace referencia a un webhook muerto.

Este es el contrato subyacente. La aplicación lo abstrae: el diálogo Edita realiza borrar+crear de manera transparente y te muestra el nuevo ID. Pero necesitas saber que esto está pasando, porque el cambio de ID tiene consecuencias reales aguas abajo en producción.

Un consejo práctico: almacena los IDs de webhook en la configuración de tu receptor como variables de entorno, no codificados. De esta manera, un ciclo de borrar+crear es una actualización de configuración, no un despliegue de código.

4. La cola pendingOperations: tu mejor herramienta de depuración, completamente no documentada #

Cada webhook retornado por Webhook.GetAll lleva una matriz pendingOperations[]. Cada entrada describe un evento que está en la cola para ser entregado o que ha fallado:

{
  "operation": "UPDATE",
  "rowIDs": [19967],
  "status": "NOT_SENT",
  "lastErrorCode": 0,
  "lastErrorMessage": "",
  "sendAttempts": 0
}

Las operaciones pueden ser ADD, UPDATE, DELETE o SCHEMA. El campo status, lastErrorCode, lastErrorMessage y sendAttempts te dicen exactamente qué intentó FileMaker, cuándo falló y cuántas veces ha reintentado.

Esta es la superficie de depuración más útil de toda la API. También no está en ningún lugar en la documentación pública. La descubres leyendo una respuesta de API cruda.

Cuando el Panel de Operaciones Pendientes salga, la aplicación lo mostrará en línea para cada webhook. Hasta entonces, puedes inspeccionar la cola leyendo la respuesta cruda Webhook.GetAll — si un webhook está fallando silenciosamente, este es donde primero miras.

5. El esquema de carga útil del receptor no está documentado — tienes que hacer ingeniería inversa #

¿Qué realmente POST FileMaker a tu URL de webhook cuando cambia un registro?

No hay ningún esquema documentado. Lo sabes configurando un endpoint de receptor, registrando lo que llega y haciendo ingeniería inversa de la estructura.

Según mis pruebas, una carga útil de cambio de contenido se ve así:

{
  "@odata.context": "fmi/odata/v4/Contacts/$metadata#contact(\"uuid\",\"mod_id\",\"row_id\")",
  "value": [
    {
      "@odata.editLink": "fmi/odata/v4/Contacts/contact(3276,...)",
      "@odata.id": "fmi/odata/v4/Contacts/contact(3276,...)",
      "mod_id": 0,
      "row_id": 19071,
      "uuid": "211EE2A8-D2C4-4F14-AA4A-A4B05E60C8FE"
    }
  ]
}

Una notificación de cambio de esquema se ve completamente diferente:

{
  "@odata.context": "fmi/odata/v4/Contacts/$metadata#FileMaker_Tables(...)",
  "value": [
    {
      "BaseTableName": "contact",
      "ModCount": 32,
      "TableId": 1065106,
      "TableName": "contact"
    }
  ]
}

Dos observaciones importantes:

  • El mod_id es 0 en webhooks invocados manualmente (Webhook.Invoke). No cambiaron datos realmente, así que no hay ningún ID de modificación a reportar. Tu receptor necesita manejar este caso.
  • La carga útil solo contiene los campos listados en $select. Si quieres el contenido del registro, debes incluir esos campos en $select en el momento de la creación del webhook, o usar los rowIDs de la carga útil para obtener el registro completo a través de un OData GET separado.

Las cargas útiles de muestra verificadas están documentadas en DISCOVERINGS.md en el repositorio.

6. Certificados autofirmados, CORS y el proxy nginx que no habías presupuestado #

FileMaker Server habla HTTPS usando un certificado autofirmado por defecto, y no emite cabeceras CORS. Esta combinación significa que una aplicación basada en navegador no puede hablarle directamente en producción — el navegador rechazará la solicitud antes de que mismo salga de la máquina.

La arquitectura que funciona:

Browser → nginx (tu servidor web)
           ├── /fmwebhooks/*  → sirve la app React (dist/)
           └── /fmi/*         → proxy_pass a FileMaker Server
                                 (proxy_ssl_verify off)

nginx termina TLS para tu dominio público, y hace proxy de /fmi/* a FileMaker Server con proxy_ssl_verify off para aceptar el certificado autofirmado de FMS. El frontend usa URLs relativas (/fmi/odata/v4/...) a lo largo, así que el mismo código cliente funciona en desarrollo (proxy Vite) y producción (proxy nginx) sin modificación.

El repositorio incluye una configuración de sitio nginx lista para usar en docs/servers_enabled/fmwebhooks.conf y un fragmento de proxy inverso independiente en nginx-reverse-proxy.conf.

Esta es una decisión de arquitectura que tendrás que tomar. Los documentos nunca te advierten.

7. La buena sorpresa: los webhooks sobreviven a los reinicios del servidor #

Aquí está el único que fue bien.

FileMaker Server persiste las configuraciones de webhook internamente. Si reinicias FMS — mantenimiento planificado, reinicio inesperado, ciclo de actualización — tus webhooks vuelven. Webhook.GetAll los retorna exactamente como configurados.

Esto no está documentado en ningún lugar. Lo confirmé a través de pruebas deliberadas. Para los despliegues de producción, significa que no necesitas volver a registrar webhooks después de cada evento del servidor. Las configuraciones son duraderas.

El sesgo, por una vez, está a tu favor.


Una lectura honesta sobre el estado actual #

Esto parece una característica que envió completa en capacidades e incompleta en documentación.

El motor funciona. El contrato OData es internamente consistente una vez que haces ingeniería inversa. La superficie 22.0.4 — expresiones de filtro, notifySchemaChanges, Invoke manual, la cola pendingOperations — está genuinamente bien diseñada. Alguien en Claris pensó cuidadosamente en estas características.

Pero la experiencia del desarrollador alrededor es: lee la especificación, construye una sandbox, mira lo que retorna, escribe tus propios documentos. Prueba, error y una pestaña de red saludable.

Convertí esa experiencia en una herramienta de código abierto para que no tengas que repetirla.


Lo que me gustaría ver en 22.0.5 o 23.0 #

Una lista de deseos corta para Claris, en orden de prioridad:

  • Un esquema de carga útil del receptor documentado. Simplemente publica lo que FMS envía para cada tipo de operación. Una página. Ahorraría varias horas a cada desarrollador que toque esta API.
  • Un Webhook.Update(<id>) nativo de manera que las ediciones no rompan las referencias de ID externas.
  • IDs de webhooks estables a través de las ediciones, o como mínimo un campo de clave estable proporcionado por el usuario.
  • Firma HMAC de los webhooks salientes de manera que los receptores puedan verificar la procedencia.
  • Una política de reintento documentada y una historia maxFailedAttempts visible de punta a punta.
  • Enumeración de scripts vía $metadata — hoy no hay ninguna manera documentada de listar los scripts que una cuenta OData puede llamar.
  • Semántica lastErrorCode significativa — el entero opaco actual necesita una clave publicada.

Ninguno de esto es trabajo de arquitectura fundamental. Es pulido de experiencia del desarrollador que convierte una capacidad poderosa en algo que la gente despliega sin leer doscientos hilos de foro primero.


El TL;DR #

Las siete cosas a recordar:

  • Los endpoints de lectura son GET, los endpoints de acción son POST. El <id> va en la ruta URL.
  • Nunca pongas id sin comillas en $select — congela el webhook.
  • Cada edición es un borrar + crear; los IDs cambian.
  • La cola pendingOperations es tu depurador.
  • El esquema de carga útil del receptor no está documentado — registra primero, analiza después.
  • La producción necesita un proxy inverso nginx para /fmi/*.
  • Los webhooks sobreviven a los reinicios del servidor.

Gestor de webhooks de código abierto: github.com/fsans/FMS-odata-webhooks. Dale una estrella si te ahorra un fin de semana.

Si has encontrado tu propio comportamiento OData de FileMaker no documentado, déjalo en los comentarios. La lista colectiva de errores es, cada vez más, la documentación.


Esta es la Parte 2 de una serie sobre webhooks OData de FileMaker Server. La Parte 1 trata el anuncio de la característica y lo que significa para la posición de FileMaker en arquitecturas modernas.


Lectura adicional: