[![Actions Status](https://github.com/lizmat/JSON-Webhook/actions/workflows/linux.yml/badge.svg)](https://github.com/lizmat/JSON-Webhook/actions) [![Actions Status](https://github.com/lizmat/JSON-Webhook/actions/workflows/macos.yml/badge.svg)](https://github.com/lizmat/JSON-Webhook/actions) [![Actions Status](https://github.com/lizmat/JSON-Webhook/actions/workflows/windows.yml/badge.svg)](https://github.com/lizmat/JSON-Webhook/actions)

NAME
====

JSON::Webhook - provide webhook logic for processing JSON payloads

SYNOPSIS
========

```raku
use JSON::Webhook;

JSON::Webhook.new :$host, :$port, :$application;
```

DESCRIPTION
===========

The `JSON::Webhook` distribution provides a `JSON::Webhook` role that provides the logic for running a webservice that accepts JSON payloads (typically from services such as Github / Codeberg) and collects them using the logic provided by [JSON::Collector](https://raku.land/zef:lizmat/JSON::Collector).

Customization can either be done by providing extra named arguments to the `new` and/or `application` methods, or by consuming the `JSON::Webhook` role into a class that provides customized `collector` and `processor` methods.

```raku
use JSON::Webhook;

# Custom class that inserts the value of the "channels" named
# argument from the request into the data structure to be saved
class JSON::Webhook::Channels does JSON::Webhook {
    method processor() {
        -> \data, \request {
            my %data = data;
            %data<channels> := eager .split(",")
              with request.query-hash<channels>;
            %data
        }
    }
}
```

METHODS
=======

new
---

```raku
say "starting server";
JSON::Webhook.new :$host, :$port, :$application, ...
say "server stopped";
```

The `new` method provides the simplest way to set up an endpoint for a JSON push service. It creates a `JSON::Webhook` object with the given arguments.

If a `JSON::Webhook` is sunk, it calls the `serve` method which starts listening on the indicated host IP and port and activates a control-C handler to stop the server in an orderly manner.

It takes the following named arguments:

### :host

The name of the endpoint to set up a listening server on. Defaults to calling the `host` method, which by default returns the value of the dynamic variable `$*WEBHOOK-HOST`, the environment variable `WEBHOOK_HOST` or `"localhost"`.

### :port

The port number on which the server will be listening on. Defaults to calling the `port` method, which by default returns the value of the dynamic variable `$*WEBHOOK-PORT`, the environment variable `WEBHOOK_PORT` or `9999`.

### :application

The `Cro::HTTP::Router::RouteSet` compatible object that will be used to run the server with. If not specified, will call the `application` class method with the rest of the named arguments to set up the application.

### additional named argments

Any additional named arguments are passed on as appropriate.

application
-----------

The `application` instance method returns whatever was (implicitely) specified with `:application` named argument to the `new` method.

```raku
my $application = JSON::Webhook.application :$collector, :$processor, ...
JSON::Webhook.new(:$host, :$port, :$application);
```

The `application` class method returns a `Cro::HTTP::Router::RouteSet` compatible object that can be used as the "application" in setting up a `JSON::Webhook` object.

It takes the following named arguments:

### :collector

The object with `JSON::Collector` semantics that will be used to store any incoming JSON payloads. If not specified, it will call the `collector` method, which by default creates a `JSON::Collector` object with any additional named arguments passed.

### :processor

A `Callable` that will be called with the data structure representing the JSON payload that was received, and the [`Cro::HTTP::Request`](https://cro.raku.org/docs/reference/cro-http-request) object. It should return the data structure that should be stored by the collector. If not specified, it will call the `processor` method, which by default returns a `Callable` that will just return the data structure of the JSON payload verbatim.

serve
-----

```raku
my $webhook = JSON::Webhook.new(:$host, :$port, :$application);
say "starting";
$webhook.serve;
say "stopped";
```

The `serve` method takes an instantiated `JSON::Webhook` object, starts listening on the given `host` and `port`, and starts serving requests with the given <application>. Also installs a control-C handler for an orderly shutdown when control-C is pressed.

stop
----

```raku
my $webhook = JSON::Webhook.new(:$host, :$port, :$application);
say "starting";
start {
    $webhook.serve;
    say "stopped";
}
...
$webhook.stop;  # stopped
```

The `stop` method will stop the server from accepting requests, and thus continue execution **after** the call to `serve`.

OVERRIDABLE METHODS
===================

These methods can be overriden by a consumer of the `JSON::Webhook` class to customize behaviour.

host
----

Expected to return a value that can be used as a `:host` argument to `Cro::HTTP::Server.new`. By default returns the value of the dynamic variable `$*WEBHOOK-HOST`, the environment variable `WEBHOOK_HOST` or `"localhost"`.

port
----

Expected to return a value that can be used as a `:port` argument to `Cro::HTTP::Server.new`. By default returns the value of the dynamic variable `$*WEBHOOK-PORT`, the environment variable `WEBHOOK_PORT` or `9999`.

collector
---------

Expected to return an object with `JSON::Collector` semantics. By default creates a `JSON::Collector` object with any additional named arguments passed.

processor
---------

Expected to return a `Callable` that will take the data structure parsed from a JSON payload, and the [`Cro::HTTP::Request`](https://cro.raku.org/docs/reference/cro-http-request) object, and return a possibly adapted data structure to be stored by the collector. By default, this is a simple `Callable` that returns the data structure unchanged.

AUTHOR
======

Elizabeth Mattijsen <liz@raku.rocks>

COPYRIGHT AND LICENSE
=====================

Copyright 2026 Elizabeth Mattijsen

Source can be located at: https://codeberg.org/lizmat/JSON-Collector . Comments and Pull Requests are welcome.

If you like this module, or what I'm doing more generally, committing to a [small sponsorship](https://github.com/sponsors/lizmat/) would mean a great deal to me!

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

