Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 147 additions & 2 deletions docs/integrations/graphql-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ curl -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
http://netbox/graphql/ \
--data '{"query": "query {circuit_list(filters:{status: STATUS_ACTIVE}) {cid provider {name}}}"}'
--data '{"query": "query {circuit_list(filters:{status: STATUS_ACTIVE}) {results {cid provider {name}}}}"}'
```

The response will include the requested data formatted as JSON:
Expand All @@ -36,6 +36,30 @@ The response will include the requested data formatted as JSON:
}
}
```
If using the GraphQL API v2 the format will be:

```json
{
"data": {
"circuit_list": {
"results": [
{
"cid": "1002840283",
"provider": {
"name": "CenturyLink"
}
},
{
"cid": "1002840457",
"provider": {
"name": "CenturyLink"
}
}
]
}
}
}
```

!!! note
It's recommended to pass the return data through a JSON parser such as `jq` for better readability.
Expand All @@ -47,12 +71,15 @@ NetBox provides both a singular and plural query field for each object type:

For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of filters) to fetch all devices.

!!! note "Changed in NetBox v4.5"
If using the GraphQL API v2, List queries now return paginated results. The actual objects are contained within the `results` field of the response, along with `total_count` and `page_info` fields for pagination metadata. Prior to v4.5, list queries returned objects directly as an array.

For more detail on constructing GraphQL queries, see the [GraphQL queries documentation](https://graphql.org/learn/queries/). For filtering and lookup syntax, please refer to the [Strawberry Django documentation](https://strawberry.rocks/docs/django/guide/filters).

## Filtering

!!! note "Changed in NetBox v4.3"
The filtering syntax fo the GraphQL API has changed substantially in NetBox v4.3.
The filtering syntax for the GraphQL API has changed substantially in NetBox v4.3.

Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only active sites:

Expand All @@ -67,6 +94,21 @@ query {
}
}
```
If using the GraphQL API v2 the format will be:

```
query {
site_list(
filters: {
status: STATUS_ACTIVE
}
) {
results {
name
}
}
}
```

Filters can be combined with logical operators, such as `OR` and `NOT`. For example, the following will return every site that is planned _or_ assigned to a tenant named Foo:

Expand All @@ -88,6 +130,28 @@ query {
}
}
```
If using the GraphQL API v2 the format will be:

```
query {
site_list(
filters: {
status: STATUS_PLANNED,
OR: {
tenant: {
name: {
exact: "Foo"
}
}
}
}
) {
results {
name
}
}
}
```

Filtering can also be applied to related objects. For example, the following query will return only enabled interfaces for each device:

Expand All @@ -102,6 +166,21 @@ query {
}
}
```
If using the GraphQL API v2 the format will be:

```
query {
device_list {
results {
id
name
interfaces(filters: {enabled: {exact: true}}) {
name
}
}
}
}
```

## Multiple Return Types

Expand All @@ -128,6 +207,31 @@ Certain queries can return multiple types of objects, for example cable terminat
}
}
```
If using the GraphQL API v2 the format will be:

```
{
cable_list {
results {
id
a_terminations {
... on CircuitTerminationType {
id
class_type
}
... on ConsolePortType {
id
class_type
}
... on ConsoleServerPortType {
id
class_type
}
}
}
}
}
```

The field "class_type" is an easy way to distinguish what type of object it is when viewing the returned data, or when filtering. It contains the class name, for example "CircuitTermination" or "ConsoleServerPort".

Expand All @@ -142,6 +246,47 @@ query {
}
}
```
### Pagination in GraphQL API V2

All list queries return paginated results using the `OffsetPaginated` type, which includes:

- `results`: The list of objects matching the query
- `total_count`: The total number of objects matching the filters (without pagination)
- `page_info`: Pagination metadata including `offset` and `limit`

By default, queries return up to 100 results. You can control pagination by specifying the `pagination` parameter with `offset` and `limit` values:

```
query {
device_list(pagination: { offset: 0, limit: 20 }) {
total_count
page_info {
offset
limit
}
results {
id
name
}
}
}
```

If you don't need pagination metadata, you can simply query the `results`:

```
query {
device_list {
results {
id
name
}
}
}
```

!!! note
When not specifying the `pagination` parameter, avoid querying `page_info.limit` as it may return an undefined value. Either provide explicit pagination parameters or only query the `results` and `total_count` fields.

## Authentication

Expand Down
41 changes: 40 additions & 1 deletion netbox/circuits/graphql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import strawberry
import strawberry_django
from strawberry_django.pagination import OffsetPaginated

from .types import *


@strawberry.type(name="Query")
class CircuitsQuery:
class CircuitsQueryOld:
circuit: CircuitType = strawberry_django.field()
circuit_list: List[CircuitType] = strawberry_django.field()

Expand Down Expand Up @@ -40,3 +41,41 @@ class CircuitsQuery:

virtual_circuit_type: VirtualCircuitTypeType = strawberry_django.field()
virtual_circuit_type_list: List[VirtualCircuitTypeType] = strawberry_django.field()


@strawberry.type(name="Query")
class CircuitsQuery:
circuit: CircuitType = strawberry_django.field()
circuit_list: OffsetPaginated[CircuitType] = strawberry_django.offset_paginated()

circuit_termination: CircuitTerminationType = strawberry_django.field()
circuit_termination_list: OffsetPaginated[CircuitTerminationType] = strawberry_django.offset_paginated()

circuit_type: CircuitTypeType = strawberry_django.field()
circuit_type_list: OffsetPaginated[CircuitTypeType] = strawberry_django.offset_paginated()

circuit_group: CircuitGroupType = strawberry_django.field()
circuit_group_list: OffsetPaginated[CircuitGroupType] = strawberry_django.offset_paginated()

circuit_group_assignment: CircuitGroupAssignmentType = strawberry_django.field()
circuit_group_assignment_list: OffsetPaginated[CircuitGroupAssignmentType] = strawberry_django.offset_paginated()

provider: ProviderType = strawberry_django.field()
provider_list: OffsetPaginated[ProviderType] = strawberry_django.offset_paginated()

provider_account: ProviderAccountType = strawberry_django.field()
provider_account_list: OffsetPaginated[ProviderAccountType] = strawberry_django.offset_paginated()

provider_network: ProviderNetworkType = strawberry_django.field()
provider_network_list: OffsetPaginated[ProviderNetworkType] = strawberry_django.offset_paginated()

virtual_circuit: VirtualCircuitType = strawberry_django.field()
virtual_circuit_list: OffsetPaginated[VirtualCircuitType] = strawberry_django.offset_paginated()

virtual_circuit_termination: VirtualCircuitTerminationType = strawberry_django.field()
virtual_circuit_termination_list: OffsetPaginated[VirtualCircuitTerminationType] = (
strawberry_django.offset_paginated()
)

virtual_circuit_type: VirtualCircuitTypeType = strawberry_django.field()
virtual_circuit_type_list: OffsetPaginated[VirtualCircuitTypeType] = strawberry_django.offset_paginated()
12 changes: 11 additions & 1 deletion netbox/core/graphql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@

import strawberry
import strawberry_django
from strawberry_django.pagination import OffsetPaginated

from .types import *


@strawberry.type(name="Query")
class CoreQuery:
class CoreQueryOld:
data_file: DataFileType = strawberry_django.field()
data_file_list: List[DataFileType] = strawberry_django.field()

data_source: DataSourceType = strawberry_django.field()
data_source_list: List[DataSourceType] = strawberry_django.field()


@strawberry.type(name="Query")
class CoreQuery:
data_file: DataFileType = strawberry_django.field()
data_file_list: OffsetPaginated[DataFileType] = strawberry_django.offset_paginated()

data_source: DataSourceType = strawberry_django.field()
data_source_list: OffsetPaginated[DataSourceType] = strawberry_django.offset_paginated()
Loading