mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
[Generic Webhook Option for Alerts ](https://github.com/hyperdxio/hyperdx/issues/2#issue-1893833428 ) ### DETAILS: This PR enables the creation and use of generic webhooks alongside the existing slack webhooks. This allows users to configure arbitrary webhook consumers/destinations with custom payloads. For now the lack of signage/security features means more complex webhooks that perform actions on alert will most likely be gated off due to their internal requirements, but this should unlock a variety of message-focused consumers alongside the existing slack implementation. Query parameter usage was built into the migration and logic, and can be enabled in a later version when security options make those more complex use cases (like caching) worthwhile. For the time being many consumers allow/mirror QP functionality in the body of the request, and otherwise building into the url manually achieves the same purpose. This implementation assumes and is limited to POST requests only, which is the ideal sender behavior and has exceptionally large coverage, but optionality for GETs and PUTs can be added in later versions if they are desired. Message templating is still quite limited while the more robust templating system is in development, and users should refer to their specific consumer documentation for implementation. As a minor addition, with the added complexity beyond just single slack webhooks, optional descriptions were also added to the webhook model and displayed on the settings page. ### V1+ NEXT STEPS: - security/signature functionality - user facing webhook edit functionality - functionality to send webhook tests during creation - alignment with current in-progress alert templating - user facing queryParam functionality (and/or url building for ease of use) ### VISUALS: **TEAM SETTINGS UPDATE:**  **GENERIC WEBHOOK CREATION:**  **ALERT CREATION UPDATE:** 
76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
import { ObjectId } from 'mongodb';
|
|
import mongoose, { Schema } from 'mongoose';
|
|
|
|
export enum WebhookService {
|
|
Slack = 'slack',
|
|
Generic = 'generic',
|
|
}
|
|
|
|
interface MongooseMap extends Map<string, string> {
|
|
// https://mongoosejs.com/docs/api/map.html#MongooseMap.prototype.toJSON()
|
|
// Converts this map to a native JavaScript Map for JSON.stringify(). Set the flattenMaps option to convert this map to a POJO instead.
|
|
// doc.myMap.toJSON() instanceof Map; // true
|
|
// doc.myMap.toJSON({ flattenMaps: true }) instanceof Map; // false
|
|
toJSON: (options?: {
|
|
flattenMaps?: boolean;
|
|
}) => { [key: string]: any } | Map<string, any>;
|
|
}
|
|
|
|
export interface IWebhook {
|
|
_id: ObjectId;
|
|
createdAt: Date;
|
|
name: string;
|
|
service: WebhookService;
|
|
team: ObjectId;
|
|
updatedAt: Date;
|
|
url?: string;
|
|
description?: string;
|
|
// reminder to serialize/convert the Mongoose model instance to a plain javascript object when using
|
|
// to strip the additional properties that are related to the Mongoose internal representation -> webhook.headers.toJSON()
|
|
queryParams?: MongooseMap;
|
|
headers?: MongooseMap;
|
|
body?: MongooseMap;
|
|
}
|
|
|
|
const WebhookSchema = new Schema<IWebhook>(
|
|
{
|
|
team: { type: Schema.Types.ObjectId, ref: 'Team' },
|
|
service: {
|
|
type: String,
|
|
enum: Object.values(WebhookService),
|
|
required: true,
|
|
},
|
|
name: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
url: {
|
|
type: String,
|
|
required: false,
|
|
},
|
|
description: {
|
|
type: String,
|
|
required: false,
|
|
},
|
|
queryParams: {
|
|
type: Map,
|
|
of: String,
|
|
required: false,
|
|
},
|
|
headers: {
|
|
type: Map,
|
|
of: String,
|
|
required: false,
|
|
},
|
|
body: {
|
|
type: Map,
|
|
of: String,
|
|
required: false,
|
|
},
|
|
},
|
|
{ timestamps: true },
|
|
);
|
|
|
|
WebhookSchema.index({ team: 1, service: 1, name: 1 }, { unique: true });
|
|
|
|
export default mongoose.model<IWebhook>('Webhook', WebhookSchema);
|