Add support for customizable webhook payloads #3378

Closed
opened 2025-12-29 18:28:31 +01:00 by adam · 7 comments
Owner

Originally created by @jeremystretch on GitHub (Feb 21, 2020).

Originally assigned to: @jeremystretch on GitHub.

Environment

  • Python version: 3.6.9
  • NetBox version: 2.7.7

Proposed Functionality

Extend the webhook model to support custom payload formats and HTTP methods. The proposal is to add two new fields to the model:

  • http_method - A static choice of valid HTTP methods GET, POST, DELETE, etc. (I'm curious to know if there's an argument for allowing arbitrary custom methods here.)
  • template - Jinja2 template code for forming the request body. All of the existing payload data will be passed as context available within the template. If the template is not defined for a webhook, it will use the current format.

No changes to the manner in which webhooks are currently enqueued should be needed, so there should not be any performance penalty noticeable to the user. Upon extraction of a queued webhook action, the worker process will render the request body using the provided template code stored in the database.

Use Case

Currently, a webhook can only make an HTTP POST request with a particular data structure. While useful, this typically requires some type of middleware to translate the data from NetBox into something actionable by the receiver. (For example, to inject a Slack message in response to the creation of a new site.) Providing the option of crafting an arbitrary request body is likely to mitigate the need for interim middleware for many (but certainly not all) use cases.

Database Changes

Introduce the two fields described above to the extras.Webhook model.

External Dependencies

None

Originally created by @jeremystretch on GitHub (Feb 21, 2020). Originally assigned to: @jeremystretch on GitHub. ### Environment * Python version: 3.6.9 * NetBox version: 2.7.7 ### Proposed Functionality Extend the webhook model to support custom payload formats and HTTP methods. The proposal is to add two new fields to the model: * `http_method` - A static choice of valid HTTP methods `GET`, `POST`, `DELETE`, etc. (I'm curious to know if there's an argument for allowing arbitrary custom methods here.) * `template` - Jinja2 template code for forming the request body. All of the existing payload data will be passed as context available within the template. If the template is not defined for a webhook, it will use the current format. No changes to the manner in which webhooks are currently enqueued should be needed, so there should not be any performance penalty noticeable to the user. Upon extraction of a queued webhook action, the worker process will render the request body using the provided template code stored in the database. ### Use Case Currently, a webhook can only make an HTTP POST request with a [particular data structure](https://netbox.readthedocs.io/en/stable/additional-features/webhooks/#requests). While useful, this typically requires some type of middleware to translate the data from NetBox into something actionable by the receiver. (For example, to inject a Slack message in response to the creation of a new site.) Providing the option of crafting an arbitrary request body is likely to mitigate the need for interim middleware for many (but certainly not all) use cases. ### Database Changes Introduce the two fields described above to the `extras.Webhook` model. ### External Dependencies None
adam added the status: acceptedtype: feature labels 2025-12-29 18:28:31 +01:00
adam closed this issue 2025-12-29 18:28:31 +01:00
Author
Owner

@sdktr commented on GitHub (Feb 21, 2020):

Would this enable people to trigger a Netbox Script (via the API) upon a webhook trigger? If this could work some guidance might be useful to direct people in the right direction as to whether this behavior is supported, or that a possible future internal ‘middleware’ trigger is planned for this.

@sdktr commented on GitHub (Feb 21, 2020): Would this enable people to trigger a Netbox Script (via the API) upon a webhook trigger? If this could work some guidance might be useful to direct people in the right direction as to whether this behavior is supported, or that a possible future internal ‘middleware’ trigger is planned for this.
Author
Owner

@sdktr commented on GitHub (Feb 21, 2020):

Also: should the Jinja template be able to render headers as well? So people could for example manipulate the path or calculate their own security checksums etc.

Method: GET path: http://externalcache/netbox/device/{{ webhookcontext.devicename }}

@sdktr commented on GitHub (Feb 21, 2020): Also: should the Jinja template be able to render headers as well? So people could for example manipulate the path or calculate their own security checksums etc. `Method: GET path: http://externalcache/netbox/device/{{ webhookcontext.devicename }}`
Author
Owner

@jeremystretch commented on GitHub (Feb 21, 2020):

@sdktr Webhooks are intended for interacting with external systems. I would strongly advise against creating any feedback loops within NetBox, as that could be very dangerous.

@jeremystretch commented on GitHub (Feb 21, 2020): @sdktr Webhooks are intended for interacting with external systems. I would **strongly** advise against creating any feedback loops within NetBox, as that could be very dangerous.
Author
Owner

@jeremystretch commented on GitHub (Feb 21, 2020):

@sdktr NetBox already allows the user to define arbitrary HTTP headers to be sent with the request. I'm not sure there's a solid use case for providing contextual data for headers.

@jeremystretch commented on GitHub (Feb 21, 2020): @sdktr NetBox already allows the user to define arbitrary HTTP headers to be sent with the request. I'm not sure there's a solid use case for providing contextual data for headers.
Author
Owner

@sdktr commented on GitHub (Feb 21, 2020):

@sdktr NetBox already allows the user to define arbitrary HTTP headers to be sent with the request. I'm not sure there's a solid use case for providing contextual data for headers.

The contextual path would serve us well, we’d trigger an external-to-netbox cache refresh doing something like:

Path: http://netbox-frontend-cache/device/{{ deviceid }} Cache-Control: max-age=0

It would skip a custom middleware tooling exactly as this issue set out to achieve.

@sdktr commented on GitHub (Feb 21, 2020): > @sdktr NetBox already allows the user to define arbitrary HTTP headers to be sent with the request. I'm not sure there's a solid use case for providing contextual data for headers. The contextual path would serve us well, we’d trigger an external-to-netbox cache refresh doing something like: `Path: http://netbox-frontend-cache/device/{{ deviceid }} Cache-Control: max-age=0` It would skip a custom middleware tooling exactly as this issue set out to achieve.
Author
Owner

@jeremystretch commented on GitHub (Feb 24, 2020):

The headers are currently defined and stored as JSON data. IMO we should avoid intermingling JSON with Jinja2 code. (Edit: I should clarify that I mean it would be a bad idea to attempt storing Jinja2 template code in a JSON field. The other way around is fine.)

curly_braces

It might be cleaner to change these to a simple Header: value format, just as they appear in an actual HTTP request:

X-My-Custom-Header: some-value-goes-here
X-Templatized-Header: name={{ data['name' }}; commit=true

We could use a migration to change any existing header definitions from JSON to plaintext. I don't know how disruptive that would be.

@jeremystretch commented on GitHub (Feb 24, 2020): The headers are currently defined and stored as JSON data. IMO we should avoid intermingling JSON with Jinja2 code. (Edit: I should clarify that I mean it would be a bad idea to attempt storing Jinja2 template code in a JSON field. The other way around is fine.) ![curly_braces](https://user-images.githubusercontent.com/13487278/75192388-1faa9900-5722-11ea-9a32-a5f7addc7526.jpeg) It might be cleaner to change these to a simple `Header: value` format, just as they appear in an actual HTTP request: ``` X-My-Custom-Header: some-value-goes-here X-Templatized-Header: name={{ data['name' }}; commit=true ``` We could use a migration to change any existing header definitions from JSON to plaintext. I don't know how disruptive that would be.
Author
Owner

@jeremystretch commented on GitHub (Feb 24, 2020):

We should probably add a choice field for the HTTP method (GET, POST, etc.) while we're at it.

@jeremystretch commented on GitHub (Feb 24, 2020): We should probably add a choice field for the HTTP method (`GET`, `POST`, etc.) while we're at it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#3378