webhook-listen 1.0.1

A webhook listener which drops the responses with into specified directories.
% Usage

# Configuration

The configuration file is a file containing a JSON object with the `handlers`
key. This key is an object mapping paths to objects describing where to write
incoming objects to:

```json
{
  "handlers": {
    "<url-path 1>": {…},
    "<url-path 2>": {…}
  }
}
```

Each handler must have the `path` string which is where objects should be
written to as well as a `filter` list which contains objects describing how to
handle incoming objects. Each filter has a `kind` string to use if the filter
succeeds.

```json
"<url-path 1>": {
  "path": "<path to write objects to>",
  "filters": […]
}
```

Filters may contain the `have_keys` list of strings as well as the `items`
list of objects. If given, all of the [JSON Pointer][] lookups in the
`have_keys` list must exist, otherwise the filter will not accept the incoming
object. Similarly, the `items` object consisting of mappings from
[JSON Pointer][] to a value within the input object and an expected value for
it. If any value does match the lookup is either missing or does not match the
expected value, the filter will not accept the incoming object.

```json
{
  "kind": "<kind name>",
  "have_keys": […],
  "items": {
    "<json pointer 1>": …,
    "<json pointer 2>": …
  }
}
```

Once a filter matches, the incoming JSON object is written to the handler's
path given by the `path` variable using a filename based on the time the object
is being written out and a random string in case there are objects being
written out at the same time. The contents are a JSON object with two keys,
`kind` as given by the matching filter and `data` containing the complete input
object.

Filters are tried in order and the first one which matches is used. If no
filter matches, a `400 Bad Request` status code is returned.

# Reloading the Configuration

The listener will reread its configuration upon a `PUT` request to the
`/__reload` path. If the configuration is invalid, a `406 Not Acceptable`
status will be returned and the old configuration will still be used.

# Communicating

The tool will listen on the configured address for `POST` requests to the
handlers. Any other method or unconfigured path will be ignored.

# Example

The following configuration file:

```json
{
  "handlers": {
    "filtered": {
      "path": "/path/to/filtered",
      "filters": [
        {
          "kind": "check_keys_and_items",
          "have_keys": ["/required"],
          "items": {
            "/count": 5,
          },
        },
        {
          "kind": "check_keys",
          "have_keys": ["/required"],
        },
        {
          "kind": "check_values",
          "items": {
            "/nested/key": true,
            "/nested/other_key": false,
          },
        },
        { "kind": "catchall" }
      ]
    },
    "no_filters": {
      "path": "/path/for/no_filters",
      "filters": []
    },
  }
}
```

will response to `POST` requests to `/filtered` and `/no_filters`. The
following objects will receive the indicated `kind` into the relevant directory
for the `filtered` endpoint whereas the `no_filters` endpoint will ignore all
input because no filter explicitly matched:

`{ "required": null }` is of kind `check_keys` because it contains all of the
keys required by that filter, but the `/count` lookup from the
`check_keys_and_items` filter fails.

`{ "required": null, "count": 4 }` is of kind `check_keys` because it contains
all of the keys required by that filter, but the `/count` lookup gives a value
of `4` rather than the expected `5`.

`{ "nested": { "key": true, "other_key": false } }` is of kind `check_values`
because it is missing the `required` key used for `check_keys` and
`check_keys_and_items` and matches all of the required items.

`{}` is of kind `catchall` because no other filter matched it and none of the
required keys (none) nor the items failed to match the object.

[JSON Pointer]: https://tools.ietf.org/html/rfc6901