Skip to content

Commit ba87665

Browse files
committed
chore: add issue templates
1 parent 4b70b67 commit ba87665

File tree

4 files changed

+331
-0
lines changed

4 files changed

+331
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
name: Bug Report
3+
about: Report an issue with the Plugin
4+
title: '[BUG] '
5+
labels: 'bug'
6+
assignees: ''
7+
8+
---
9+
10+
<!--
11+
Before submitting a bug report, please:
12+
- Make sure you're using the latest version of the plugin
13+
- Search existing issues to avoid creating duplicates
14+
- Include as much detail as possible
15+
- Write in English only
16+
17+
Please also keep in mind that this is a free plugin without commercial support. Issues may take several days to respond to and bugs may take weeks to fix. Contributions are welcome!
18+
-->
19+
20+
**Bug Description**
21+
<!-- A clear and concise description of the bug -->
22+
23+
**Steps To Reproduce**
24+
25+
1.
26+
2.
27+
3.
28+
4.
29+
30+
**Expected Behavior**
31+
<!-- A clear and concise description of what you expected to happen -->
32+
33+
**Actual Behavior**
34+
<!-- What actually happened instead -->
35+
36+
**Screenshots / Logs**
37+
<!-- If applicable, add screenshots and logs to help explain the problem -->
38+
39+
**Environment:**
40+
- Dify version:
41+
- Cloud or Self-Hosted:
42+
- Plugin version:
43+
44+
**Request/Response Details**
45+
<!-- If applicable, include request/response information (remove sensitive data) -->
46+
```curl command or request details:```
47+
```response:```
48+
49+
**Additional Context**
50+
<!-- Add any other context about the problem here -->
51+
```

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Discord Community Support
4+
url: https://discord.gg/FngNHpbcY7
5+
about: Get help from our active discord community. The plugin author is very active there too!
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: Feature Request
3+
about: Suggest an idea for the Webhook Plugin
4+
title: '[FEATURE] '
5+
labels: 'enhancement'
6+
assignees: ''
7+
8+
---
9+
10+
<!--
11+
Before submitting a feature request, please:
12+
- Make sure you're using the latest version of the plugin
13+
- Search existing issues to avoid creating duplicates
14+
- Write in English only
15+
-->
16+
17+
**Problem Statement**
18+
<!-- A clear and concise description of what problem this feature would solve -->
19+
20+
**Proposed Solution**
21+
<!-- A clear and concise description of what you want to happen -->
22+
23+
**Alternative Solutions**
24+
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
25+
26+
**Additional Context**
27+
<!-- Add any other context, screenshots, or examples about the feature request here -->
28+
29+
**Integration Details**
30+
<!-- If the feature is related to a specific third-party integration, provide details about that service -->
31+
- Third-party service (if applicable):
32+
- Link to relevant API documentation:
33+
34+
**Impact**
35+
<!-- How would this feature benefit users of the Webhook Plugin? -->

docs/MIDDLEWARE_GUIDE.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# Custom Middleware Development Guide
2+
3+
This guide explains how to extend the Webhook Dify Plugin with your own custom middlewares for request processing, validation, and transformation.
4+
5+
## Introduction
6+
7+
Middlewares in the Webhook Dify Plugin allow you to:
8+
- Validate requests from third-party services
9+
- Transform incoming data before it reaches Dify
10+
- Customize responses sent back to the caller
11+
- Implement custom authentication schemes
12+
- Handle special payload formats from external services
13+
14+
## Middleware Architecture
15+
16+
The plugin uses a middleware system that processes requests before they reach the main application logic. Each middleware can:
17+
18+
1. Inspect and modify the request
19+
2. Return an early response (short-circuit the request)
20+
3. Pass the request to the next handler
21+
22+
## Creating a Custom Middleware
23+
24+
### Step 1: Create Your Middleware Class
25+
26+
Create a new Python file in the `middlewares/` directory with your middleware class:
27+
28+
```python
29+
import json
30+
import logging
31+
from werkzeug import Request, Response
32+
from typing import Optional
33+
34+
logger = logging.getLogger(__name__)
35+
36+
class MyCustomMiddleware:
37+
"""
38+
Description of what your middleware does.
39+
"""
40+
41+
def __init__(self, signature_verification_key=None):
42+
"""
43+
Initialize the middleware with configuration parameters.
44+
45+
Args:
46+
signature_verification_key: Configuration parameter passed from settings
47+
"""
48+
self.signature_verification_key = signature_verification_key
49+
logger.info("MyCustomMiddleware initialized with verification key")
50+
51+
def invoke(self, r: Request) -> Optional[Response]:
52+
"""
53+
Process an incoming request.
54+
55+
Args:
56+
r (Request): The incoming request to process
57+
58+
Returns:
59+
Response: A response to send back immediately, or None to continue processing
60+
"""
61+
logger.debug("Processing request in MyCustomMiddleware")
62+
63+
# Example: Validate a custom signature or authentication token
64+
if not self._validate_request(r):
65+
return Response(
66+
json.dumps({"error": "Invalid request"}),
67+
status=401,
68+
content_type="application/json"
69+
)
70+
71+
# Example: Transform the request data
72+
self._transform_request(r)
73+
74+
# Return None to continue processing, or return a Response to short-circuit
75+
return None
76+
77+
def _validate_request(self, r: Request) -> bool:
78+
"""
79+
Custom validation logic.
80+
81+
Args:
82+
r (Request): The request to validate
83+
84+
Returns:
85+
bool: True if valid, False otherwise
86+
"""
87+
# Implement your validation logic
88+
# For example, verify signatures with self.signature_verification_key
89+
return True
90+
91+
def _transform_request(self, r: Request) -> None:
92+
"""
93+
Transform the request data if needed.
94+
95+
Args:
96+
r (Request): The request to transform
97+
"""
98+
# Implement your transformation logic
99+
# You can use r.default_middleware_json to pass data to the handler
100+
pass
101+
```
102+
103+
### Step 2: Register Your Middleware in the Helper Function
104+
105+
Update `endpoints/helpers.py` to include your new middleware:
106+
107+
```python
108+
from middlewares.my_custom_middleware import MyCustomMiddleware
109+
110+
def apply_middleware(r: Request, settings: Mapping) -> Optional[Response]:
111+
# Existing middleware code...
112+
113+
try:
114+
middleware_type = settings.get("middleware")
115+
signature_verification_key = settings.get("signature_verification_key")
116+
117+
# Add your middleware case
118+
if middleware_type == "discord":
119+
middleware = DiscordMiddleware(signature_verification_key)
120+
response = middleware.invoke(r)
121+
if response:
122+
return response
123+
elif middleware_type == "my_custom": # Add this case
124+
middleware = MyCustomMiddleware(signature_verification_key)
125+
response = middleware.invoke(r)
126+
if response:
127+
return response
128+
except (json.JSONDecodeError, KeyError, TypeError) as e:
129+
print(f"Middleware Error: {str(e)}")
130+
return Response(json.dumps({"error": f"Middleware error: {str(e)}"}),
131+
status=500, content_type="application/json")
132+
133+
# Default middleware...
134+
try:
135+
default_middleware = DefaultMiddleware()
136+
default_middleware.invoke(r, settings)
137+
except (json.JSONDecodeError, KeyError, TypeError) as e:
138+
print(f"Default Middleware Error: {str(e)}")
139+
return Response(json.dumps({"error": f"Default Middleware error: {str(e)}"}),
140+
status=500, content_type="application/json")
141+
142+
return None
143+
```
144+
145+
### Step 3: Update the UI Schema
146+
147+
For your middleware to appear in the plugin UI, you need to add your new middleware option to the `webhook.yaml` file. Locate the `middleware` field in the settings section and add your new option to the options array:
148+
149+
```yaml
150+
- name: middleware
151+
type: select
152+
required: true
153+
label:
154+
en_US: Custom Middleware
155+
zh_Hans: 自定义中间件
156+
pt_BR: Middleware Personalizado
157+
options:
158+
- value: discord
159+
label:
160+
en_US: Discord
161+
zh_Hans: Discord
162+
pt_BR: Discord
163+
- value: my_custom # Add this new option
164+
label:
165+
en_US: My Custom Middleware
166+
zh_Hans: 我的自定义中间件
167+
pt_BR: Meu Middleware Personalizado
168+
- value: none
169+
label:
170+
en_US: None
171+
zh_Hans:
172+
pt_BR: Nenhum
173+
default: none
174+
placeholder:
175+
en_US: Custom middlewares can add logic like signature validation
176+
zh_Hans: 自定义中间件可以添加诸如签名验证的逻辑
177+
pt_BR: Middlewares personalizados podem adicionar lógica como validação de assinatura
178+
```
179+
180+
You only need to add a new entry to the `options` array with:
181+
1. A unique `value` that matches the middleware identifier you used in the `helpers.py` file
182+
2. Localized `label` entries for each supported language
183+
184+
Your middleware can use the existing `signature_verification_key` field for custom authentication purposes. If your middleware needs more settings, please consider creating a separate plugin for your specific use case, as this plugin aims to be a general webhook solution.
185+
186+
## Best Practices for Middleware Development
187+
188+
### 1. Error Handling
189+
190+
Always implement proper error handling and avoid crashing the application:
191+
192+
```python
193+
try:
194+
# Your logic here
195+
except Exception as e:
196+
logger.error("Error in middleware: %s", str(e))
197+
return Response(
198+
json.dumps({"error": f"Middleware error: {str(e)}"}),
199+
status=500,
200+
content_type="application/json"
201+
)
202+
```
203+
204+
### 2. Request Modification
205+
206+
To transform the request for downstream handlers, you can use the `default_middleware_json` attribute on the request object:
207+
208+
```python
209+
def _transform_request(self, r: Request) -> None:
210+
try:
211+
# Parse the original request body
212+
data = json.loads(r.data.decode('utf-8'))
213+
214+
# Store transformed data for downstream handlers
215+
r.default_middleware_json = {
216+
'transformed_data': data,
217+
'custom_field': 'custom value'
218+
}
219+
220+
logger.debug("Request transformed successfully")
221+
except Exception as e:
222+
logger.error("Error transforming request: %s", str(e))
223+
```
224+
225+
### 3. Communication with Handlers
226+
227+
The current middleware architecture allows middlewares to:
228+
- Return a Response to short-circuit (to respond directly to the client)
229+
- Set `r.default_middleware_json` to pass data to handlers
230+
- Transform the request object for downstream processing
231+
232+
## Testing Your Middleware
233+
234+
For manual testing during development:
235+
236+
1. Make test requests to your endpoint with appropriate test data
237+
2. Check the logs for debugging information
238+
3. Verify proper responses are returned for both success and error cases
239+
240+
For automated testing, you would need to add tests to the plugin's test suite.

0 commit comments

Comments
 (0)