Skip to content

GraphQL filter functionality missing in v4.3.0-beta1 #19225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tyler-8 opened this issue Apr 17, 2025 · 3 comments
Closed

GraphQL filter functionality missing in v4.3.0-beta1 #19225

tyler-8 opened this issue Apr 17, 2025 · 3 comments
Assignees
Labels
beta Concerns a bug/feature in a beta release status: accepted This issue has been accepted for implementation type: bug A confirmed report of unexpected behavior in the application

Comments

@tyler-8
Copy link
Contributor

tyler-8 commented Apr 17, 2025

Deployment Type

Self-hosted

NetBox Version

v4.3.0-beta1

Python Version

3.12

Steps to Reproduce

  1. Attempt to write a GraphQL query to filter circuit_list by 1 or more sites. Or filter an ip_address_list by the device or VM they belong to.

Expected Behavior

Filters exist to filter circuits by the site one of their terminations belongs to, filters exist to filter IP addresses based on the device or virtual machine they're attached to.

Example query for circuits based on site entries that works pre-4.2:

query siteCircuits($sites: [String!]) {
  circuit_list(filters: {site: $sites}) {
    id
    cid
    provider {
      name
    }
    termination_z {
      termination {
        ... on SiteType {
          id
          name
        }
      }
    }
  }
}

The $sites variable is:

{
  "sites": [
    "dm-albany",
    "dm-rochester"
  ]
}

Observed Behavior

No filters exist to do this on IPAddress or Circuit filter options in GraphQL in 4.3-beta1.

For circuits, the closest I can get is 'reversing' the query and querying circuit terminations instead.

query MyQuery {
  circuit_termination_list(
    filters: {termination_type: {app_label: {exact: "dcim"}, model: {exact: "site"}}, termination_id: "7"}
  ) {
    termination {
      ... on SiteType {
        id
        name
      }
    }
    term_side
    circuit {
      cid
      commit_rate
      install_date
      id
      provider {
        id
        name
      }
      provider_account {
        account
        id
        name
      }
    }
  }
}

However: this requires the NetBox ID of the site to be known (instead of being able to use the slug today), and the only way to filter on multiple related-object IDs is to do a verbose "OR" operator instead of being able to do termination_id: {in_list: [1, 2, 3, 4]} (for circuit terminations, not circuits).

In the case of IP Addresses you can't even do a filter such as assigned_object_id: {in_list: [1, 2, 3, 4]} (for IP Addresses) using multiple interface IDs from a single device.

As has always been the case since GraphQL was introduced, you could write a more "indirect" query starting with the device_list, and adding interfaces for the device, and each interface's IP Addresses nested within, but this is a significant change from previous behavior and also limits the flexibility & functionality of the GraphQL API.

There maybe be other GraphQL objects that are impacted, these are just the two most immediate cases that I've uncovered. Not being able to filter by multiple IDs (even using standard GraphQL syntax of "some_object_id: {in_list: [1, 2, 3, 4]}") is a big hindrance, but being able to filter by indirect relationships is very valuable and is how the NetBox GraphQL API has worked for quite a while now.

@tyler-8 tyler-8 added status: needs triage This issue is awaiting triage by a maintainer type: bug A confirmed report of unexpected behavior in the application labels Apr 17, 2025
@tyler-8 tyler-8 changed the title GraphQL filter functionality missing GraphQL filter functionality missing in v4.3.0-beta1 Apr 17, 2025
@jeremystretch jeremystretch added the beta Concerns a bug/feature in a beta release label Apr 17, 2025
@arthanson arthanson added status: under review Further discussion is needed to determine this issue's scope and/or implementation and removed status: needs triage This issue is awaiting triage by a maintainer labels Apr 17, 2025
@jeremystretch
Copy link
Member

Prior to NetBox v4.3, the GraphQL filters were automatically generated from the FilterSet classes which exist primarily for the UI and REST API. Due to changes in Strawberry (see #7598 for context), this is no longer the case: Beginning with NetBox v4.3, separate GraphQL filters are now defined for each model.

This divergence is significant because many filters that are defined on the original filter sets out of necessity are not actually needed on their GraphQL counterparts due to the nested nature of GraphQL filtering. For instance, filtering a device by manufacturer requires a dedicated manufacturer filter on DeviceFilterSet to span the relationship from the Device model to DeviceType, and from DeviceType to manufacturer.

GET /api/dcim/devices/?manufacturer=cisco

This filter is not required on a GraphQL filter set because it's possible to nest a manufacturer filter inside a device type filter when querying devices:

device_list (filters: {
  device_type: {
    manufacturer: {
        name: {exact: "Cisco"}
    }
  }
})

Focusing on the example of circuits specifically, I believe it would be an anti-pattern to introduce a site filter directly on the GraphQL circuit filter because there is no direct relationship from a circuit to a site. I think what's missing here is the ability to filter circuits by their terminations, and to filter those terminations by associated objects (e.g. site). Ultimately what we want to achieve is the following pattern:

circuit_list (filters:{
  terminations:{
    site:{
      name:{exact: "DM-Akron"}
    }
  }
})

There maybe be other GraphQL objects that are impacted, these are just the two most immediate cases that I've uncovered.

Further work is needed to discover any additional patterns which need to be implemented.

@jeremystretch
Copy link
Member

I've started a draft PR adding a terminations filter for circuits as proposed above. Still need to look into IP addresses and other models.

@tyler-8
Copy link
Contributor Author

tyler-8 commented Apr 18, 2025

I agree that the overall direction and filtering syntax/structure can be better than the old way.

I'm noticing there's no ability to do an inList filter like:

circuit_list (filters:{
  terminations:{
    site:{
      name:{inList: ["DM-Akron", "DM-Scranton"]}
    }
  }
})

or even something simpler like:

device_list (filters: {
    id: {inList: [1, 2, 3, 4]}
  }
) {
  id
  name
}

strawberry-django seems to support this out of the box in FilterLookup and BaseFilterLookup but it looks like neither of these classes are used in NetBox except one usage of FilterLookup (I could be mistaken or they're referenced/rebuilt in another way).

While you can chain OR filters together, it's far more verbose and much harder to use graphql variables to dynamically search for multiple values on the same field

{
  circuit_list(filters: {provider: {id: 2, OR: {id: 5}}}) {
    cid
    description
  }
}

vs

query SpecialProviderCircuits($providerIDs: [ID!]) {
  circuit_list(filters: {provider: {id: {inList: $providerIDs}}) {
    cid
    description
  }
}
# variables passed in as {"providerIDs": [2,5]}

It probably doesn't make sense to support inList on every single field, but I would think IDs, names/slugs, and any enum-like field would make a lot of sense to support inList filters. This would retain a capability that both the REST API and GraphQL APIs have had up until now, even if the syntax to do it has changed.

bctiemann added a commit that referenced this issue Apr 22, 2025
@jeremystretch jeremystretch added status: accepted This issue has been accepted for implementation and removed status: under review Further discussion is needed to determine this issue's scope and/or implementation labels Apr 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta Concerns a bug/feature in a beta release status: accepted This issue has been accepted for implementation type: bug A confirmed report of unexpected behavior in the application
Projects
None yet
Development

No branches or pull requests

3 participants