Skip to content

Commit 51938a0

Browse files
committed
more docs
1 parent 32d1e50 commit 51938a0

File tree

3 files changed

+145
-3
lines changed

3 files changed

+145
-3
lines changed

README.md

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,149 @@ Keep reading to learn how to customize your Hooks server with different plugins
139139

140140
### Advanced
141141

142-
TODO
142+
This section will go into a more advanced and detailed example of how to setup a Hooks server with custom plugins, authentication, and more. This section also assumes you already have the `hooks-ruby` gem installed via a bundler Gemfile as shown in the [Installation](#installation-) section above.
143+
144+
Before we get into the details, here is a high-level overview of the steps involved:
145+
146+
1. **Define your configuration**: Create a `hooks.yml` file to define your global configuration, including the directories for your plugins and endpoints.
147+
2. **Create your endpoint configurations**: Define your webhook endpoints in the `config/endpoints` directory, specifying the path and the handler plugin to use.
148+
3. **Implement your handler plugins**: Create custom handler plugins in the `plugins/handlers` directory to process incoming webhook requests.
149+
4. **Implement authentication plugins (optional)**: If you want to secure your webhook endpoints, create custom authentication plugins in the `plugins/auth` directory. Note that you might just be able to get away with using the built-in authentication plugins ([`hmac`](lib/hooks/plugins/auth/hmac.rb), or [`shared_secret`](lib/hooks/plugins/auth/shared_secret.rb)) for most use cases.
150+
151+
This example will assume the following directory structure:
152+
153+
```text
154+
├── config/
155+
│ ├── hooks.yml # global hooks config
156+
│ ├── puma.rb # puma config
157+
│ └── endpoints/
158+
│ ├── hello.yml
159+
│ └── goodbye.yml
160+
└── plugins/
161+
├── handlers/ # custom handler plugins
162+
│ ├── hello_handler.rb
163+
│ └── goodbye_handler.rb
164+
└── auth/
165+
└── goodbye_auth.rb # custom auth plugin (optional)
166+
```
167+
168+
Let's go through each step in detail.
169+
170+
#### 1. Define your global Hooks configuration
171+
172+
First, create a `hooks.yml` file in the `config` directory. This file will define your global configuration for the Hooks server, including the directories for your plugins and endpoints. Here is an example of a minimal configuration file:
173+
174+
```yaml
175+
# file: config/hooks.yml
176+
handler_plugin_dir: ./plugins/handlers
177+
auth_plugin_dir: ./plugins/auth
178+
179+
# Available endpoints
180+
# Each endpoint configuration file should be placed in the endpoints directory
181+
endpoints_dir: ./config/endpoints
182+
183+
log_level: debug
184+
185+
# Path configuration
186+
root_path: /webhooks # Base path for all webhook endpoints (e.g. /webhooks/hello)
187+
health_path: /health
188+
version_path: /version
189+
190+
# Runtime behavior
191+
environment: development # or production
192+
```
193+
194+
#### 2. Create your endpoint configurations
195+
196+
Endpoint configurations are defined in the `config/endpoints` directory. Each endpoint configuration file should specify the path for the webhook endpoint and the handler plugin to use. Here is an example of two endpoint configuration files:
197+
198+
> Note: You can also define auth plugins for each endpoint if you want to secure them. For this example, the `/hello` endpoint will not have authentication, while the `/goodbye` endpoint will use a custom authentication plugin.
199+
200+
```yaml
201+
# file: config/endpoints/hello.yml
202+
path: /hello # becomes /webhooks/hello based on the root_path in hooks.yml
203+
handler: HelloHandler # This is a custom handler plugin you would define in the plugins/handlers
204+
```
205+
206+
```yaml
207+
# file: config/endpoints/goodbye.yml
208+
path: /goodbye # becomes /webhooks/goodbye based on the root_path in hooks.yml
209+
handler: GoodbyeHandler # This is another custom handler plugin you would define in the plugins/handlers
210+
211+
auth:
212+
type: Goodbye # This is a custom authentication plugin you would define in the plugins/auth
213+
secret_env_key: GOODBYE_API_KEY # the name of the environment variable containing the secret
214+
header: Authorization
215+
```
216+
217+
#### 3. Implement your handler plugins
218+
219+
Create custom handler plugins in the `plugins/handlers` directory to process incoming webhook requests. Here is an example of a simple handler plugin for the `/hello` endpoint:
220+
221+
```ruby
222+
# file: plugins/handlers/hello_handler.rb
223+
class HelloHandler < Hooks::Plugins::Handlers::Base
224+
def call(payload:, headers:, config:)
225+
# Process the incoming webhook - optionally use the payload and headers
226+
# to perform some action or validation
227+
# For this example, we will just return a success message
228+
{
229+
message: "webhook processed successfully",
230+
handler: "HelloHandler",
231+
timestamp: Time.now.iso8601
232+
}
233+
end
234+
end
235+
```
236+
237+
And another handler plugin for the `/goodbye` endpoint:
238+
239+
```ruby
240+
# file: plugins/handlers/goodbye_handler.rb
241+
class GoodbyeHandler < Hooks::Plugins::Handlers::Base
242+
def call(payload:, headers:, config:)
243+
# Ditto for the goodbye endpoint
244+
{
245+
message: "goodbye webhook processed successfully",
246+
handler: "GoodbyeHandler",
247+
timestamp: Time.now.iso8601
248+
}
249+
end
250+
end
251+
```
252+
253+
#### 4. Implement authentication plugins (optional)
254+
255+
If you want to secure your webhook endpoints, you can create custom authentication plugins in the `plugins/auth` directory. Here is an example of a simple authentication plugin for the `/goodbye` endpoint:
256+
257+
```ruby
258+
# file: plugins/auth/goodbye.rb
259+
# this is a custom authentication plugin for the Goodbye endpoint
260+
# it is extremely simple and just checks if the Authorization header matches a secret for example purposes
261+
module Hooks
262+
module Plugins
263+
module Auth
264+
class Goodbye < Base
265+
def self.valid?(payload:, headers:, config:)
266+
# get the secret from environment variable as configured with secret_env_key
267+
secret = fetch_secret(config, secret_env_key_name: :secret_env_key)
268+
269+
# check if the Authorization header matches the secret
270+
auth_header = headers[config[:header]]
271+
return false unless auth_header
272+
273+
# compare the Authorization header with the secret
274+
Rack::Utils.secure_compare(auth_header, "Bearer #{secret}")
275+
end
276+
end
277+
end
278+
end
279+
end
280+
```
281+
282+
#### Summary
283+
284+
What these steps have done is set up a Hooks server that listens for incoming webhook requests at `/webhooks/hello` and `/webhooks/goodbye`. The `/hello` endpoint will respond with a success message without any authentication, while the `/goodbye` endpoint will require a valid `Authorization` header that matches the secret defined in the environment variable `GOODBYE_API_KEY`. Before the `/goodbye` endpoint enters the defined handler, it will first check the authentication plugin to ensure the request is valid.
143285

144286
### Authentication
145287

spec/acceptance/config/endpoints/with_custom_auth.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ path: /with_custom_auth_plugin
22
handler: TestHandler
33

44
auth:
5-
type: example_auth_plugin
5+
type: example
66
secret_env_key: SHARED_SECRET # the name of the environment variable containing the shared secret
77
header: Authorization

spec/acceptance/plugins/auth/example_auth_plugin.rb renamed to spec/acceptance/plugins/auth/example.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
module Hooks
88
module Plugins
99
module Auth
10-
class ExampleAuthPlugin < Base
10+
class Example < Base
1111
def self.valid?(payload:, headers:, config:)
1212
# Get the secret from environment variable as configured with secret_env_key
1313
secret = fetch_secret(config, secret_env_key_name: :secret_env_key)

0 commit comments

Comments
 (0)