Creating a webhook

Hi again,

I am currently creating a webhook to receive whatsapp messages. I wish to test the webhook by creating a new line with the content of the message in the UI. I read it is possible that consumers can execute commands. How do I establish my code to execute a command whenever a message is received via the webhook?

  1. Application
	'Test Webhook': collection ['Index'] {
		'Index': text // @default: auto-increment || "001"
		'Content': text
		'Webhook tester': command @hidden {
			'Content': text
		} as $ => update ^ .'Test Webhook' = create (
			'Index' = "1"
			'Content' = $ .'Content'
		)
	}
  1. Implementation
	'Webhook': collection = (
		'Test Webhook' = $ .'Test Webhook'* as $'webhook' (
			'Content': text = $'webhook'.'Content'
			'Webhook tester': command as $ => execute $^ $'webhook'.'Webhook tester' (
				'Content': text = $ .'Content'
			)
		)
	)
  1. Interface
	'Webhook': collection ['Key'] {
		'Key': text
		'Content': text
		'Webhook tester': command {
			'Content': text
		}
	}
  1. Processor
consumer ( )

add-hook 'network'::'webserver' "/echo"
do (
	'status' = 200
	'headers' = create [ "content-type" ] "application/json"
	'content' = $'request' => serialize as JSON => call 'unicode'::'as binary' with ( )
)

Ok, so it looks like you need something like this:

  1. Find the correct webhook entry based on a key.
  2. Invoke the command.
  3. Send a reply to the other party.

You can reuse/adapt some ideas from this code:

add-hook 'network'::'webserver' "/callback"
do {
	let $'key' = "key" // <-- get this from request data, e.g. from a header, query parameter or posted data

	switch $ .'Webhook'[ $'key' ] (
		| value as $ => {
			execute $ command 'Webhook tester' with (
				'Content' = "content" // <-- also get this from request data
			)
			(
				'status' = 200
				'headers' = no-op
				'content' = "OK" => call 'unicode'::'as binary' with ( )
			)
		}
		| error => (
			'status' = 500
			'headers' = no-op
			'content' = "Webhook key not found" => call 'unicode'::'as binary' with ( )
		)
	)
}

Using the switch statement, you will be able do determine whether the provided key exists or not.

Please let me know if this helps.

1 Like

Thank you!

I am figuring out how to put the data received through the webhook in variables. execute $ command 'Webhook tester' with ( 'Content' = $'request'.'content' => serialize as JSON does not give any syntax error, however let $'Data' = $'request'.'content' => serialize as JSON does.

add-hook 'network'::'webserver' "/callback"
do {
	let $'Data' = $'request'.'content' => serialize as JSON

	execute $ command 'Webhook tester' with (
		'Content' = $'request'.'content' => serialize as JSON
	)
	(
		'status' = 200
		'headers' = create [ "content-type" ] "application/json"
		'content' = $'request' => serialize as JSON => call 'unicode'::'as binary' with ( )
	)

The request content is defined as an optional field of the binary type:

define 'network request' as @API {
	'method': 'network method'
	'parameters': optional 'key value list'
	'headers': optional 'key value list'
	'content': optional binary
}

To read this field, it should be guarded to provide a fallback in case it is missing, like this:

let $'request content' = $'request'.'content' get || throw "Missing network content"

That results in a binary type value in $'request content'. If you then want to convert to a text type value, for example to parse it as JSON later, you can do:

let $'request text' = $'request content' => call 'unicode'::'import' with ( $'encoding' = "UTF-8" ) || throw "Invalid content"

You can add further steps to parse JSON using ... => parse as JSON and convert it to a typed data structure using ... => decorate as ....

1 Like

It should be noted that you can chain several operations with the => operator to avoid creating temporary variables, if you’re only interested in the end result. The binary to text conversion, JSON parsing and decoration as a typed data structure are often combined in a single statement:

let $'data' = ^ $'request'.'content' get => call 'unicode'::'import' with ( $'encoding' = "UTF-8" ) => parse as JSON => decorate as {
	// <-- here you specify the schema of your data structure
} || throw "unable to parse request data"
1 Like