> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentación de CREATE HANDLER

# CREATE HANDLER

Crea un handler HTTP personalizado definido mediante SQL, sin editar el archivo de configuración del servidor. Los handlers definidos mediante SQL son una alternativa a los [handlers de la interfaz HTTP](/docs/es/concepts/features/interfaces/http).

<div id="syntax">
  ## Sintaxis
</div>

```sql theme={null}
CREATE HANDLER [IF NOT EXISTS] name [ON CLUSTER cluster]
[PROTOCOL protocol_name|ANY]
URL [PREFIX|REGEXP] '/path'
[METHODS (GET, POST)]
[TYPE query]
AS [SELECT|INSERT|...] ...
```

Crea un handler con el `name` especificado. El nombre se utiliza para gestionar handlers mediante consultas SQL, en mensajes de diagnóstico y para ordenarlos.

<div id="clauses">
  ## Cláusulas
</div>

* `PROTOCOL` — opcional. Si se especifica un nombre de protocolo, el controlador solo está activo para el [protocolo componible](/docs/es/concepts/features/configuration/server-config/composable-protocols) indicado. De lo contrario, el controlador está activo en todos los endpoints HTTP: los puertos integrados `http`/`https` y todos los listeners de [protocolo componible](/docs/es/concepts/features/configuration/server-config/composable-protocols) de tipo HTTP. `PROTOCOL ANY` selecciona explícitamente este comportamiento predeterminado; en `ALTER HANDLER`, elimina una restricción de protocolo establecida previamente. Se puede hacer referencia a un protocolo llamado literalmente `any` mediante comillas invertidas: ``PROTOCOL `any` ``.
* `URL` — obligatorio. Puede ser una URL exacta, un `URL PREFIX` o un `URL REGEXP`. Para las URL exactas y los prefijos, se comprueba si hay ambigüedad al crear o alterar el controlador y se genera una excepción si la hay. En el caso de las expresiones regulares, no se puede comprobar la ambigüedad. La URL se compara sin la cadena de consulta `?` ni el identificador de fragmento `#`. Un `URL PREFIX` se compara como una ruta base, en un límite de segmento de ruta — con la misma semántica que la regla `url_prefix` de los [controladores definidos mediante configuración](/docs/es/concepts/features/interfaces/http): `URL PREFIX '/api/v1'` coincide con `/api/v1`, `/api/v1/` y `/api/v1/write`, pero no con `/api/v1beta`. La `/` final del prefijo se ignora, por lo que `'/api/v1/'` y `'/api/v1'` se comportan igual.
* `METHODS` — opcional. La lista de métodos HTTP permitidos. De forma predeterminada, solo se permite `GET`. Los métodos compatibles son `GET`, `POST`, `PUT` y `DELETE`. Los métodos que modifican datos, `POST`, `PUT` y `DELETE`, pueden ejecutar consultas modificadoras; los métodos seguros, como `GET` y `HEAD`, siempre se ejecutan en modo `readonly`. Por lo tanto, un controlador cuya consulta modifica datos (por ejemplo, `INSERT` o DDL) debe permitir al menos un método de modificación; crear un controlador de este tipo únicamente con métodos de solo lectura (por ejemplo, el `GET` predeterminado) genera una excepción. Las consultas cuyos efectos secundarios persisten en modo `readonly` constituyen un caso especial: `BACKUP` y `RESTORE` tienen efectos secundarios duraderos; las sentencias que modifican la sesión, `SET`, `SET ROLE`, `USE`, `BEGIN TRANSACTION`, `COMMIT`, `ROLLBACK` y `SET TRANSACTION SNAPSHOT`, cambian el estado de la sesión o de la transacción, que persiste entre solicitudes cuando se usa `session_id`; y `CREATE TEMPORARY TABLE` / `CREATE TEMPORARY VIEW` crean un objeto que existe en la sesión. Sin embargo, el modo `readonly` de los métodos seguros no bloquea ninguna de ellas. Las mutaciones de una tabla temporal *existente* tampoco quedan bloqueadas por el modo `readonly`, por lo que las consultas que puedan tener una tabla de este tipo como destino se tratan del mismo modo: un `INSERT` cuya tabla de destino no está calificada con una base de datos (un nombre no calificado puede resolverse como una tabla temporal de sesión), un `DROP TEMPORARY TABLE`, un `DROP TABLE` / `TRUNCATE TABLE` de una tabla no calificada con una base de datos y un `ALTER` de una tabla no calificada con una base de datos (`ALTER TEMPORARY TABLE` es la misma sentencia). Un destino calificado con una base de datos nunca puede ser una tabla temporal, por lo que dichas consultas no están sujetas a esta regla. HTTP exige que los métodos seguros no tengan efectos secundarios (un controlador declarado para `GET` también se sirve para `HEAD`, donde se suprime el cuerpo de la respuesta y el efecto sería invisible). Por lo tanto, un controlador que ejecute una consulta de este tipo debe enumerar *únicamente* métodos de modificación; crearlo o modificarlo para incluir un método seguro genera una excepción. Se inspeccionan las sentencias compuestas: para `statement1 PARALLEL WITH statement2 ...` y `EXECUTE AS <user> <statement>`, las reglas anteriores se aplican a las sentencias encapsuladas, ya que son las que se ejecutan (cada una con una copia del contexto del controlador, que conserva el modo `readonly`). Un `EXECUTE AS <user>` sin sentencia hace que toda la sesión se ejecute como otro usuario, por lo que cuenta como una modificación de la sesión por sí mismo. Además, cualquier controlador `EXECUTE AS`, ya sea sin sentencia o encapsulando una sentencia, debe permitir al menos un método de modificación: la suplantación requiere el privilegio `IMPERSONATE`, que el modo `readonly` de los métodos seguros deniega.
* `TYPE` — opcional. Por ahora, el único tipo compatible es `query`.
* `AS` — la consulta SQL que invocará este handler. La consulta puede parametrizarse. Durante la creación o modificación del handler, se analiza la corrección sintáctica de la consulta, pero no su semántica; por ejemplo, las tablas a las que hace referencia pueden no existir en el momento de crear el handler. Las cláusulas `FORMAT` y similares pertenecen a la consulta, no a toda la sentencia `CREATE`/`ALTER`. La consulta puede incluirse entre paréntesis para evitar ambigüedades. Una consulta `INSERT` no debe contener datos en línea después de la cláusula `VALUES` o `FORMAT`: crear o modificar un handler de este tipo genera una excepción, ya que la carga útil en línea no puede conservarse en la definición del handler; los datos deben proporcionarse en el cuerpo HTTP (o calcularse mediante un `INSERT ... SELECT`). Una solicitud a un handler cuya consulta lee el cuerpo —un `INSERT` que toma sus datos del cuerpo o una consulta que utiliza el parámetro `_request_body`— debe declarar su longitud: una solicitud no fragmentada sin un encabezado `Content-Length` recibe la respuesta `411 Length Required`, ya que, de lo contrario, el cuerpo se leería hasta el final del flujo y una conexión interrumpida se aceptaría como una solicitud completa. Todos los métodos de dicho handler también deben incluir un cuerpo (`POST`, `PUT` o `DELETE`): crearlo con un método seguro en la cláusula `METHODS` (por ejemplo, el `GET` predeterminado) genera una excepción, porque un método seguro nunca proporciona un cuerpo de solicitud y la consulta leería silenciosamente uno vacío; un `GET` declarado también se sirve para `HEAD`, por lo que mezclar métodos seguros y métodos con cuerpo mantendría accesibles esas invocaciones. Un `INSERT ... SELECT` no lee el cuerpo (sus datos proceden del `SELECT`), por lo que no está sujeto a estos requisitos, salvo que su `SELECT` lea de la función de tabla `input`, que recibe datos del cuerpo de la solicitud. Un `INSERT` que lee el cuerpo debe ser la propia consulta del handler: `EXECUTE AS` y `PARALLEL WITH` ejecutan las sentencias que contienen sin el cuerpo de la solicitud, por lo que envolver uno en ellas se rechaza al crearlo en lugar de descartar silenciosamente cada carga. Una consulta que lee el cuerpo tampoco debe utilizar el parámetro `_request_body`: hay un único cuerpo de solicitud, y la vinculación de `_request_body` lo consume antes de que la consulta lea sus datos de entrada, por lo que dicho handler se rechaza al crearlo en lugar de perder silenciosamente cada carga; utilice la propia entrada del cuerpo de la consulta o `_request_body`, pero no ambos. Los handlers que no leen el cuerpo no tienen este requisito; el cuerpo de una solicitud a dicho handler se ignora y nunca se añade a la consulta del handler. El texto de consulta almacenado vuelve a analizarse en el servidor con profundidad del analizador y retrocesos ilimitados cada vez que se recarga o invoca el handler, por lo que un handler creado en una sesión con `max_parser_depth` / `max_parser_backtracks` aumentados sigue pudiendo cargarse e invocarse con los límites habituales de sesión.

<div id="priority">
  ## Prioridad
</div>

Los handlers definidos en la configuración del servidor tienen prioridad sobre los definidos en SQL. Los handlers definidos en SQL se comparan en orden lexicográfico según sus nombres.

<div id="parameters">
  ## Parámetros
</div>

Los parámetros de consulta para consultas parametrizadas se proporcionan, al igual que en los handlers definidos mediante configuración, a partir de:

* parámetros de URL HTTP en la cadena de consulta, mediante la convención `param_<name>` (por ejemplo, `?param_id=42` vincula `{id:Type}`);
* grupos de captura con nombre en una `URL REGEXP` (por ejemplo, `URL REGEXP '/users/(?P<id>\d+)'` vincula `{id:Type}`);
* campos de formulario del cuerpo de la solicitud, para un handler cuya consulta declara parámetros: un cuerpo `application/x-www-form-urlencoded` (por ejemplo, `curl -d 'param_id=42'`) y los campos de un cuerpo `multipart/form-data` vinculan parámetros `{name:Type}` de la misma forma que los parámetros de URL en los métodos con cuerpo `POST`, `PUT` y `DELETE`. Un parámetro presente tanto en la URL como en el cuerpo toma su valor de la URL. Un cuerpo analizado como formulario es consumido por la capa de handlers: no se pasa a la consulta como datos de `INSERT`. Un handler cuyo único uso del cuerpo es `_request_body` recibe el cuerpo sin procesar en lugar de analizarlo como formulario; un handler que declara `_request_body` junto con otros parámetros recibe ambos: se conserva una copia del cuerpo sin procesar en `_request_body` (sujeta a `http_max_request_param_data_size`) antes de analizar el cuerpo como formulario.

Los encabezados HTTP estándar de ClickHouse (como `X-ClickHouse-Database`, `X-ClickHouse-User` y `X-ClickHouse-Key`) se respetan como de costumbre al invocar un handler.

Las funciones [`currentHandler`](/docs/es/reference/functions/regular-functions/other-functions#currentHandler) y [`currentRequestURL`](/docs/es/reference/functions/regular-functions/other-functions#currentRequestURL) se pueden utilizar para personalizar el comportamiento de la consulta según el handler invocado y la URL de la solicitud.

<div id="access-control">
  ## Control de acceso
</div>

`CREATE HANDLER`, `DROP HANDLER` y `ALTER HANDLER` requieren los privilegios `CREATE HANDLER`, `DROP HANDLER` y `ALTER HANDLER`, respectivamente.

La lectura de la tabla [`system.handlers`](/docs/es/reference/system-tables/handlers) requiere el privilegio `SHOW HANDLERS`. Los secretos que puedan estar incluidos en la consulta de un handler se ocultan allí, a menos que el usuario también tenga permiso para ver secretos (consulte [`system.handlers`](/docs/es/reference/system-tables/handlers)).

La invocación de un handler no requiere ningún privilegio independiente, pero los privilegios se comprueban como de costumbre durante la invocación de la consulta y la autenticación funciona de la forma habitual. Para encapsular el acceso a determinadas consultas, cree una [`VIEW` con `SQL SECURITY DEFINER`](/docs/es/reference/statements/create/view#sql_security) y defina un handler que seleccione de esa vista.

<div id="storage">
  ## Almacenamiento
</div>

Los handler se guardan en un almacenamiento local o de Keeper, de forma similar a las [colecciones con nombre](/docs/es/concepts/features/configuration/server-config/named-collections), configurado en la sección `query_rules_storage` del archivo de configuración:

```xml theme={null}
<query_rules_storage>
    <type>local</type> <!-- or zookeeper -->
    <path>/var/lib/clickhouse/handlers/</path>
</query_rules_storage>
```

Con el almacenamiento Keeper, los handlers se sincronizan automáticamente en todas las réplicas, por lo que una cláusula `ON CLUSTER` explícita es redundante y haría que cada réplica intentara crear el mismo handler. Habilite la configuración `ignore_on_cluster_for_replicated_handler_queries` para que `CREATE`, `ALTER` y `DROP HANDLER` ignoren `ON CLUSTER` cuando el almacenamiento sea replicado, al igual que `ignore_on_cluster_for_replicated_named_collections_queries`.

<div id="alter-handler">
  ## ALTER HANDLER
</div>

```sql theme={null}
ALTER HANDLER name
[PROTOCOL protocol_name|ANY]
[URL [PREFIX|REGEXP] '/path']
[METHODS (GET, POST)]
[TYPE query]
[AS SELECT ...]
```

Reemplaza el handler por uno nuevo. La consulta `ALTER` solo puede incluir un subconjunto de cláusulas; por ejemplo, puede utilizarse únicamente para cambiar la URL o la consulta. Las cláusulas no especificadas conservan sus valores anteriores. `PROTOCOL ANY` elimina una restricción de protocolo existente, lo que vuelve a activar el handler en todos los endpoints HTTP.

<div id="drop-handler">
  ## DROP HANDLER
</div>

```sql theme={null}
DROP HANDLER [IF EXISTS] name
```

Elimina el handler con el nombre especificado.

<div id="introspection">
  ## Introspección
</div>

La tabla [`system.handlers`](/docs/es/reference/system-tables/handlers) enumera todos los handlers definidos en SQL. La tabla [`system.query_log`](/docs/es/reference/system-tables/query_log) registra, para cada consulta, el nombre del handler y la ruta de la solicitud HTTP (sin la cadena de consulta) en las columnas `http_handler_name` y `http_request_url`.

<div id="example">
  ## Ejemplo
</div>

```sql theme={null}
CREATE HANDLER my_handler URL '/my_handler' AS SELECT version();
```

```bash theme={null}
$ curl 'http://localhost:8123/my_handler'
```

Un handler parametrizado con una URL con formato Regexp:

```sql theme={null}
CREATE HANDLER get_user URL REGEXP '/users/(?P<id>\d+)' AS SELECT * FROM users WHERE id = {id:UInt64};
```

```bash theme={null}
$ curl 'http://localhost:8123/users/42'
```

<div id="related-statements">
  ## Sentencias relacionadas
</div>

`CREATE HANDLER` forma parte de la familia de sentencias `CREATE` y se relaciona con `ALTER` y `DROP`.
