Skip to content

# `nautobot.apps.graphql`

GraphQL API for Nautobot.

## `nautobot.apps.graphql.BigInteger`

Bases: `Scalar`

An integer which, unlike GraphQL's native Int type, doesn't reject values outside (-2^31, 2^31-1).

Currently only used for ASNField, which goes up to 2^32-1 (i.e., unsigned 32-bit int); it's possible that this approach may fail for values in excess of 2^53-1 (the largest integer value supported in JavaScript).

Source code in `nautobot/core/graphql/__init__.py`

    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    class BigInteger(Scalar):
        """An integer which, unlike GraphQL's native Int type, doesn't reject values outside (-2^31, 2^31-1).

        Currently only used for ASNField, which goes up to 2^32-1 (i.e., unsigned 32-bit int); it's possible
        that this approach may fail for values in excess of 2^53-1 (the largest integer value supported in JavaScript).
        """

        serialize = int
        parse_value = int

        @staticmethod
        def parse_literal(node):
            if isinstance(node, ast.IntValue):
                return int(node.value)
            return None

## `nautobot.apps.graphql.ContentTypeType`

Bases: `OptimizedNautobotObjectType`

Graphene-Django object type for ContentType records.

Needed because ContentType is a built-in model, not one that we own and can auto-generate types for.

Source code in `nautobot/core/graphql/types.py`

    19
    20
    21
    22
    23
    24
    25
    26
    27
    class ContentTypeType(OptimizedNautobotObjectType):
        """
        Graphene-Django object type for ContentType records.

        Needed because ContentType is a built-in model, not one that we own and can auto-generate types for.
        """

        class Meta:
            model = ContentType

## `nautobot.apps.graphql.construct_resolver(model_name, resolver_type)`

Constructs a resolve_[cable_peer|connected_endpoint]_ function for a given model type.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`model_name` | `str` | Name of the model to construct a resolver function for (e.g. CircuitTermination). | required
`resolver_type` | `str` | One of ['connected_endpoint', 'cable_peer'] | required

Source code in `nautobot/core/graphql/utils.py`

     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    def construct_resolver(model_name, resolver_type):
        """Constructs a resolve_[cable_peer|connected_endpoint]_<endpoint> function for a given model type.

        Args:
            model_name (str): Name of the model to construct a resolver function for (e.g. CircuitTermination).
            resolver_type (str): One of ['connected_endpoint', 'cable_peer']
        """
        if resolver_type == "cable_peer":

            def resolve_cable_peer(self, args):
                peer = self.get_cable_peer()
                if type(peer).__name__ == model_name:
                    return peer
                return None

            return resolve_cable_peer

        if resolver_type == "connected_endpoint":

            def resolve_connected_endpoint(self, args):
                peer = self.connected_endpoint
                if type(peer).__name__ == model_name:
                    return peer
                return None

            return resolve_connected_endpoint

        raise ValueError(f"resolver_type must be 'cable_peer' or 'connected_endpoint', not '{resolver_type}'")

## `nautobot.apps.graphql.execute_query(query, variables=None, request=None, user=None)`

Execute a query from the ORM.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`query` | `str` | String with GraphQL query. | required
`variables` | `dict` | If the query has variables they need to be passed in as a dictionary. | `None`
`request` | `django.test.client.RequestFactory` | Used to authenticate. | `None`
`user` | `django.contrib.auth.models.User` | Used to authenticate. | `None`

Returns:

Type | Description
--- | ---
`GraphQLDocument` | Result for query

Source code in `nautobot/core/graphql/__init__.py`

    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    def execute_query(query, variables=None, request=None, user=None):
        """Execute a query from the ORM.

        Args:
            query (str): String with GraphQL query.
            variables (dict, optional): If the query has variables they need to be passed in as a dictionary.
            request (django.test.client.RequestFactory, optional): Used to authenticate.
            user (django.contrib.auth.models.User, optional): Used to authenticate.

        Returns:
            (GraphQLDocument): Result for query
        """
        if not request and not user:
            raise ValueError("Either request or username should be provided")
        if not request:
            request = RequestFactory().post("/graphql/")
            request.user = user
        backend = get_default_backend()
        schema = graphene_settings.SCHEMA
        document = backend.document_from_string(schema, query)
        if variables:
            return document.execute(context_value=request, variable_values=variables)
        else:
            return document.execute(context_value=request)

## `nautobot.apps.graphql.execute_saved_query(saved_query_name, **kwargs)`

Execute saved query from the ORM.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`saved_query_name` | `str` | Name of a saved GraphQL query. | required

Other Parameters:

Name | Type | Description
--- | --- | ---
`variables` | `Optional[dict]` | If the query has variables they need to be passed in as a dictionary.
`request` | `Optional[django.test.client.RequestFactory]` | Used to authenticate.
`user` | `Optional[django.contrib.auth.models.User]` | Used to authenticate.

Returns:

Type | Description
--- | ---
`GraphQLDocument` | Result for query

Source code in `nautobot/core/graphql/__init__.py`

    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    def execute_saved_query(saved_query_name, **kwargs):
        """Execute saved query from the ORM.

        Args:
            saved_query_name (str): Name of a saved GraphQL query.

        Keyword Args:
            variables (Optional[dict]): If the query has variables they need to be passed in as a dictionary.
            request (Optional[django.test.client.RequestFactory]): Used to authenticate.
            user (Optional[django.contrib.auth.models.User]): Used to authenticate.

        Returns:
            (GraphQLDocument): Result for query
        """
        query = GraphQLQuery.objects.get(name=saved_query_name)
        return execute_query(query=query.query, **kwargs)

## `nautobot.apps.graphql.get_filtering_args_from_filterset(filterset_class)`

Generate a list of filter arguments from a filterset.

The FilterSet class will be instantiated before extracting the list of arguments to account for dynamic filters, inserted when the class is instantiated. (required for Custom Fields filters).

Filter fields that are inheriting from BooleanFilter and NumberFilter will be converted to their appropriate type, everything else will be of type String. if the filter field is a subclass of MultipleChoiceFilter, the argument will be converted as a list

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`filterset_class` | `FilterSet` | FilterSet class used to extract the argument | required

Returns:

Type | Description
--- | ---
`dict[graphene.Argument]` | Filter Arguments organized in a dictionary

Source code in `nautobot/core/graphql/utils.py`

    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    def get_filtering_args_from_filterset(filterset_class):
        """Generate a list of filter arguments from a filterset.

        The FilterSet class will be instantiated before extracting the list of arguments to
        account for dynamic filters, inserted when the class is instantiated. (required for Custom Fields filters).

        Filter fields that are inheriting from BooleanFilter and NumberFilter will be converted
        to their appropriate type, everything else will be of type String.
        if the filter field is a subclass of MultipleChoiceFilter, the argument will be converted as a list

        Args:
            filterset_class (FilterSet): FilterSet class used to extract the argument

        Returns:
            (dict[graphene.Argument]): Filter Arguments organized in a dictionary
        """

        args = {}
        instance = filterset_class()

        for filter_name, filter_field in instance.filters.items():
            # For general safety, but especially for the case of custom fields
            # (https://github.com/nautobot/nautobot/issues/464)
            # We don't have a way to map a GraphQL-sanitized filter name (such as "cf_my_custom_field") back to the
            # actual filter name (such as "cf_my-custom-field"), so if the sanitized filter name doesn't match the original
            # filter name, we just have to omit it for now. Better that than advertise a filter that doesn't actually work!
            if str_to_var_name(filter_name) != filter_name:
                logger.warning(
                    'Filter "%s" on %s is not GraphQL safe, and will be omitted', filter_name, filterset_class.__name__
                )
                continue

            field_type = graphene.String
            filter_field_class = type(filter_field)

            if issubclass(filter_field_class, MultiValueBigNumberFilter):
                field_type = graphene.List(BigInteger)
            elif issubclass(filter_field_class, (MultiValueFloatFilter, MultiValueDecimalFilter)):
                field_type = graphene.List(graphene.Float)
            elif issubclass(filter_field_class, MultiValueNumberFilter):
                field_type = graphene.List(graphene.Int)
            else:
                if issubclass(filter_field_class, BooleanFilter):
                    field_type = graphene.Boolean
                elif issubclass(filter_field_class, NumberFilter):
                    field_type = graphene.Int
                else:
                    field_type = graphene.String

                if issubclass(filter_field_class, MultipleChoiceFilter):
                    field_type = graphene.List(field_type)

            args[filter_name] = graphene.Argument(
                field_type,
                description=filter_field.label,
                required=False,
            )

        # Hack to swap `type` fields to `_type` since they will conflict with
        # `graphene.types.fields.Field.type` in Graphene 2.x.
        # 2.0 TODO(jathan): Once we upgrade to Graphene 3.x we can remove this, but we
        # will still need to do an API migration to deprecate it. This argument was
        # validated to be safe to keep even in Graphene 3.
        if "type" in args:
            args["_type"] = args.pop("type")

        return args

## `nautobot.apps.graphql.str_to_var_name(verbose_name)`

Convert a string to a variable compatible name.

Examples:

IP Addresses > ip_addresses

Source code in `nautobot/core/graphql/utils.py`

    18
    19
    20
    21
    22
    23
    24
    def str_to_var_name(verbose_name):
        """Convert a string to a variable compatible name.

        Examples:
            IP Addresses > ip_addresses
        """
        return slugify_dashes_to_underscores(verbose_name)