Skip to content
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

Closes #2007: Implement GraphQL API #6678

Merged
merged 21 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
8 changes: 8 additions & 0 deletions base_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ django-debug-toolbar
# https://github.com/carltongibson/django-filter
django-filter

# Django debug toolbar extension with support for GraphiQL
# https://github.com/flavors/django-graphiql-debug-toolbar/
django-graphiql-debug-toolbar

# Modified Preorder Tree Traversal (recursive nesting of objects)
# https://github.com/django-mptt/django-mptt
django-mptt
Expand Down Expand Up @@ -54,6 +58,10 @@ djangorestframework
# https://github.com/axnsan12/drf-yasg
drf-yasg[validation]

# Django wrapper for Graphene (GraphQL support)
# https://github.com/graphql-python/graphene-django
graphene_django

# WSGI HTTP server
# https://gunicorn.org/
gunicorn
Expand Down
8 changes: 8 additions & 0 deletions docs/configuration/optional-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ EXEMPT_VIEW_PERMISSIONS = ['*']

---

## GRAPHQL_ENABLED

Default: True

Setting this to False will disable the GraphQL API.

---

## HTTP_PROXIES

Default: None
Expand Down
70 changes: 70 additions & 0 deletions docs/graphql-api/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# GraphQL API Overview

NetBox provides a read-only [GraphQL](https://graphql.org/) API to complement its REST API. This API is powered by the [Graphene](https://graphene-python.org/) library and [Graphene-Django](https://docs.graphene-python.org/projects/django/en/latest/).

## Queries

GraphQL enables the client to specify an arbitrary nested list of fields to include in the response. All queries are made to the root `/graphql` API endpoint. For example, to return the circuit ID and provider name of each circuit with an active status, you can issue a request such as the following:

```
curl -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
http://netbox/graphql/ \
--data '{"query": "query {circuits(status:\"active\" {cid provider {name}}}"}'
```

The response will include the requested data formatted as JSON:

```json
{
"data": {
"circuits": [
{
"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.

NetBox provides both a singular and plural query field for each object type:

* `$OBJECT`: Returns a single object. Must specify the object's unique ID as `(id: 123)`.
* `$OBJECT_list`: Returns a list of objects, optionally filtered by given parameters.

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 fitlers) to fetch all devices.

For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/).

## Filtering

The GraphQL API employs the same filtering logic as the UI and REST API. Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only sites within the North Carolina region with a status of active:

```
{"query": "query {sites(region:\"north-carolina\", status:\"active\") {name}}"}
```

## Authentication

NetBox's GraphQL API uses the same API authentication tokens as its REST API. Authentication tokens are included with requests by attaching an `Authorization` HTTP header in the following form:

```
Authorization: Token $TOKEN
```

## Disabling the GraphQL API

If not needed, the GraphQL API can be disabled by setting the [`GRAPHQL_ENABLED`](../configuration/optional-settings.md#graphql_enabled) configuration parameter to False and restarting NetBox.
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ nav:
- Overview: 'rest-api/overview.md'
- Filtering: 'rest-api/filtering.md'
- Authentication: 'rest-api/authentication.md'
- GraphQL API:
- Overview: 'graphql-api/overview.md'
- Development:
- Introduction: 'development/index.md'
- Getting Started: 'development/getting-started.md'
Expand Down
Empty file.
21 changes: 21 additions & 0 deletions netbox/circuits/graphql/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import graphene

from netbox.graphql.fields import ObjectField, ObjectListField
from .types import *


class CircuitsQuery(graphene.ObjectType):
circuit = ObjectField(CircuitType)
circuit_list = ObjectListField(CircuitType)

circuit_termination = ObjectField(CircuitTerminationType)
circuit_termination_list = ObjectListField(CircuitTerminationType)

circuit_type = ObjectField(CircuitTypeType)
circuit_type_list = ObjectListField(CircuitTypeType)

provider = ObjectField(ProviderType)
provider_list = ObjectListField(ProviderType)

provider_network = ObjectField(ProviderNetworkType)
provider_network_list = ObjectListField(ProviderNetworkType)
50 changes: 50 additions & 0 deletions netbox/circuits/graphql/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from circuits import filtersets, models
from netbox.graphql.types import BaseObjectType, ObjectType, TaggedObjectType

__all__ = (
'CircuitTerminationType',
'CircuitType',
'CircuitTypeType',
'ProviderType',
'ProviderNetworkType',
)


class CircuitTerminationType(BaseObjectType):

class Meta:
model = models.CircuitTermination
fields = '__all__'
filterset_class = filtersets.CircuitTerminationFilterSet


class CircuitType(TaggedObjectType):

class Meta:
model = models.Circuit
fields = '__all__'
filterset_class = filtersets.CircuitFilterSet


class CircuitTypeType(ObjectType):

class Meta:
model = models.CircuitType
fields = '__all__'
filterset_class = filtersets.CircuitTypeFilterSet


class ProviderType(TaggedObjectType):

class Meta:
model = models.Provider
fields = '__all__'
filterset_class = filtersets.ProviderFilterSet


class ProviderNetworkType(TaggedObjectType):

class Meta:
model = models.ProviderNetwork
fields = '__all__'
filterset_class = filtersets.ProviderNetworkFilterSet
Empty file added netbox/dcim/graphql/__init__.py
Empty file.
105 changes: 105 additions & 0 deletions netbox/dcim/graphql/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import graphene

from netbox.graphql.fields import ObjectField, ObjectListField
from .types import *


class DCIMQuery(graphene.ObjectType):
cable = ObjectField(CableType)
cable_list = ObjectListField(CableType)

console_port = ObjectField(ConsolePortType)
console_port_list = ObjectListField(ConsolePortType)

console_port_template = ObjectField(ConsolePortTemplateType)
console_port_template_list = ObjectListField(ConsolePortTemplateType)

console_server_port = ObjectField(ConsoleServerPortType)
console_server_port_list = ObjectListField(ConsoleServerPortType)

console_server_port_template = ObjectField(ConsoleServerPortTemplateType)
console_server_port_template_list = ObjectListField(ConsoleServerPortTemplateType)

device = ObjectField(DeviceType)
device_list = ObjectListField(DeviceType)

device_bay = ObjectField(DeviceBayType)
device_bay_list = ObjectListField(DeviceBayType)

device_bay_template = ObjectField(DeviceBayTemplateType)
device_bay_template_list = ObjectListField(DeviceBayTemplateType)

device_role = ObjectField(DeviceRoleType)
device_role_list = ObjectListField(DeviceRoleType)

device_type = ObjectField(DeviceTypeType)
device_type_list = ObjectListField(DeviceTypeType)

front_port = ObjectField(FrontPortType)
front_port_list = ObjectListField(FrontPortType)

front_port_template = ObjectField(FrontPortTemplateType)
front_port_template_list = ObjectListField(FrontPortTemplateType)

interface = ObjectField(InterfaceType)
interface_list = ObjectListField(InterfaceType)

interface_template = ObjectField(InterfaceTemplateType)
interface_template_list = ObjectListField(InterfaceTemplateType)

inventory_item = ObjectField(InventoryItemType)
inventory_item_list = ObjectListField(InventoryItemType)

location = ObjectField(LocationType)
location_list = ObjectListField(LocationType)

manufacturer = ObjectField(ManufacturerType)
manufacturer_list = ObjectListField(ManufacturerType)

platform = ObjectField(PlatformType)
platform_list = ObjectListField(PlatformType)

power_feed = ObjectField(PowerFeedType)
power_feed_list = ObjectListField(PowerFeedType)

power_outlet = ObjectField(PowerOutletType)
power_outlet_list = ObjectListField(PowerOutletType)

power_outlet_template = ObjectField(PowerOutletTemplateType)
power_outlet_template_list = ObjectListField(PowerOutletTemplateType)

power_panel = ObjectField(PowerPanelType)
power_panel_list = ObjectListField(PowerPanelType)

power_port = ObjectField(PowerPortType)
power_port_list = ObjectListField(PowerPortType)

power_port_template = ObjectField(PowerPortTemplateType)
power_port_template_list = ObjectListField(PowerPortTemplateType)

rack = ObjectField(RackType)
rack_list = ObjectListField(RackType)

rack_reservation = ObjectField(RackReservationType)
rack_reservation_list = ObjectListField(RackReservationType)

rack_role = ObjectField(RackRoleType)
rack_role_list = ObjectListField(RackRoleType)

rear_port = ObjectField(RearPortType)
rear_port_list = ObjectListField(RearPortType)

rear_port_template = ObjectField(RearPortTemplateType)
rear_port_template_list = ObjectListField(RearPortTemplateType)

region = ObjectField(RegionType)
region_list = ObjectListField(RegionType)

site = ObjectField(SiteType)
site_list = ObjectListField(SiteType)

site_group = ObjectField(SiteGroupType)
site_group_list = ObjectListField(SiteGroupType)

virtual_chassis = ObjectField(VirtualChassisType)
virtual_chassis_list = ObjectListField(VirtualChassisType)
Loading