Skip to content

Add webhooks and webhook events (logs) to GraphQL

What does this MR do and why?

This MR adds ProjectHook, GroupHook and WebhookEvent to GraphQL to take advantage of keyset pagination. Users can now query for webhook information and webhook events within the last 7 days on project and groups (group hooks are EE-only). These new queries set us up to be able to rewrite the webhooks recent events UI, path /-/hooks/:id/edit, to also use keyset pagination and filter by timestamp range.

Notable implementation decisions:

  • For now, only single projectHook and groupHook fields were implemented on ProjectType and GroupType respectively. In the future, projectHooks and groupHooks fields to return a connection or array may be implemented without affecting the corresponding fields using single resolvers.
  • webHookEvents are limited to being resolved for no more than one webhook per query to prevent N+1 queries. web_hooks_logs_daily is a daily partitioned db table without an index for web_hook_id, so there's no great existing way to preload webhook events. Because there no real need to load webhook events for multiple webhooks at once, implementing extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 seemed the best approach
  • WebHookLogsFinder already implemented filtering by response status, but there's no DB index on it, so the status filter wasn't exposed as an argument in WebHooks::EventsResolver. It shouldn't be a breaking change to add it as an optional filter in the future once an index is added or we determine how to safely use it.
  • The WebHookLog model in Rails are exposed as WebhookEvents in GraphQL because we already use the term "events" in the UI to refer to these records, and the type Events already exists for the Event model.
  • Naming in general around webhooks in the UI and in the rails backend is bit inconsistent. For consistency in these new resources, I tried to stick as close to the original model name as possible within the WebHooks namespace.
  • Added a new input type, Types::TimestampRangeInputType to take advantage of RangeInputType similar to Types::TimeframeInputType but using Types::TimeType instead of Types::DateType. This allows web hook events to be filtered down to the second.
  • GraphQL types for SystemHook and ServiceHook were not added in this MR

References

How to set up and validate locally

  1. Create a webhook on a group and project. Tip: https://webhook.site may be helpful to generate a working webhook URL.
  2. Generate webhook events on the hooks using the "test" button or performing actions in GitLab according to the triggers checked on the webhooks. Make the hook execute more than 20 times or lower max_page_count to see pagination working
  3. Open the GraphQL explorer and query for projectHook/groupHook and webhookEvents/webhookEvent on a project or group resource. Tip: Global IDs can be found in the rails console using GitlabSchema.id_from_object(group_or_project_hook_object) and timestamps must be in in ISO 8601 format (e.g. "2025-09-24T00:00:00Z")
  4. Verify the output matches the webhook and webhook log attributes, max webhook event size is respected, and no N+1 queries occur.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #504101

Edited by Sam Word

Merge request reports

Loading