Skip to content

Golden Config API Package

nautobot_golden_config.api

REST API module for nautobot_golden_config app.

serializers

REST API serializer capabilities for graphql app.

ComplianceFeatureSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ComplianceFeature object.

Source code in nautobot_golden_config/api/serializers.py
class ComplianceFeatureSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ComplianceFeature object."""

    class Meta:
        """Set Meta Data for ComplianceFeature, will serialize all fields."""

        model = models.ComplianceFeature
        fields = "__all__"
Meta

Set Meta Data for ComplianceFeature, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ComplianceFeature, will serialize all fields."""

    model = models.ComplianceFeature
    fields = "__all__"

ComplianceRuleSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ComplianceRule object.

Source code in nautobot_golden_config/api/serializers.py
class ComplianceRuleSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ComplianceRule object."""

    class Meta:
        """Set Meta Data for ComplianceRule, will serialize all fields."""

        model = models.ComplianceRule
        fields = "__all__"
Meta

Set Meta Data for ComplianceRule, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ComplianceRule, will serialize all fields."""

    model = models.ComplianceRule
    fields = "__all__"

ConfigComplianceSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ConfigCompliance object.

Source code in nautobot_golden_config/api/serializers.py
class ConfigComplianceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ConfigCompliance object."""

    class Meta:
        """Set Meta Data for ConfigCompliance, will serialize fields."""

        model = models.ConfigCompliance
        fields = "__all__"
Meta

Set Meta Data for ConfigCompliance, will serialize fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ConfigCompliance, will serialize fields."""

    model = models.ConfigCompliance
    fields = "__all__"

ConfigPlanSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ConfigPlan object.

Source code in nautobot_golden_config/api/serializers.py
class ConfigPlanSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ConfigPlan object."""

    class Meta:
        """Set Meta Data for ConfigPlan, will serialize all fields."""

        model = models.ConfigPlan
        fields = "__all__"
        read_only_fields = ["device", "plan_type", "feature", "config_set"]
Meta

Set Meta Data for ConfigPlan, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ConfigPlan, will serialize all fields."""

    model = models.ConfigPlan
    fields = "__all__"
    read_only_fields = ["device", "plan_type", "feature", "config_set"]

ConfigRemoveSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ConfigRemove object.

Source code in nautobot_golden_config/api/serializers.py
class ConfigRemoveSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ConfigRemove object."""

    class Meta:
        """Set Meta Data for ConfigRemove, will serialize all fields."""

        model = models.ConfigRemove
        fields = "__all__"
Meta

Set Meta Data for ConfigRemove, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ConfigRemove, will serialize all fields."""

    model = models.ConfigRemove
    fields = "__all__"

ConfigReplaceSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for ConfigReplace object.

Source code in nautobot_golden_config/api/serializers.py
class ConfigReplaceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for ConfigReplace object."""

    class Meta:
        """Set Meta Data for ConfigReplace, will serialize all fields."""

        model = models.ConfigReplace
        fields = "__all__"
Meta

Set Meta Data for ConfigReplace, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for ConfigReplace, will serialize all fields."""

    model = models.ConfigReplace
    fields = "__all__"

ConfigToPushSerializer

Bases: DeviceSerializer

Serializer for ConfigToPush view.

Source code in nautobot_golden_config/api/serializers.py
class ConfigToPushSerializer(DeviceSerializer):  # pylint: disable=nb-sub-class-name
    """Serializer for ConfigToPush view."""

    config = serializers.SerializerMethodField()

    class Meta(DeviceSerializer.Meta):
        """Extend the Device serializer with the configuration after postprocessing."""

        fields = "__all__"
        model = Device

    def get_config(self, obj):
        """Provide the intended configuration ready after postprocessing to the config field."""
        request = self.context.get("request")
        config_details = models.GoldenConfig.objects.get(device=obj)
        return get_config_postprocessing(config_details, request)
Meta

Bases: Meta

Extend the Device serializer with the configuration after postprocessing.

Source code in nautobot_golden_config/api/serializers.py
class Meta(DeviceSerializer.Meta):
    """Extend the Device serializer with the configuration after postprocessing."""

    fields = "__all__"
    model = Device
get_config(obj)

Provide the intended configuration ready after postprocessing to the config field.

Source code in nautobot_golden_config/api/serializers.py
def get_config(self, obj):
    """Provide the intended configuration ready after postprocessing to the config field."""
    request = self.context.get("request")
    config_details = models.GoldenConfig.objects.get(device=obj)
    return get_config_postprocessing(config_details, request)

GenerateIntendedConfigSerializer

Bases: Serializer

Serializer for GenerateIntendedConfigView.

Source code in nautobot_golden_config/api/serializers.py
class GenerateIntendedConfigSerializer(serializers.Serializer):  # pylint: disable=abstract-method
    """Serializer for GenerateIntendedConfigView."""

    intended_config = serializers.CharField()
    intended_config_lines = serializers.ListField(child=serializers.CharField())

GoldenConfigSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for GoldenConfig object.

Source code in nautobot_golden_config/api/serializers.py
class GoldenConfigSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for GoldenConfig object."""

    class Meta:
        """Set Meta Data for GoldenConfig, will serialize all fields."""

        model = models.GoldenConfig
        fields = "__all__"
Meta

Set Meta Data for GoldenConfig, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for GoldenConfig, will serialize all fields."""

    model = models.GoldenConfig
    fields = "__all__"

GoldenConfigSettingSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for GoldenConfigSetting object.

Source code in nautobot_golden_config/api/serializers.py
class GoldenConfigSettingSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for GoldenConfigSetting object."""

    class Meta:
        """Set Meta Data for GoldenConfigSetting, will serialize all fields."""

        model = models.GoldenConfigSetting
        fields = "__all__"
Meta

Set Meta Data for GoldenConfigSetting, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for GoldenConfigSetting, will serialize all fields."""

    model = models.GoldenConfigSetting
    fields = "__all__"

GraphQLSerializer

Bases: Serializer

Serializer for a GraphQL object.

Source code in nautobot_golden_config/api/serializers.py
class GraphQLSerializer(serializers.Serializer):  # pylint: disable=abstract-method
    """Serializer for a GraphQL object."""

    data = serializers.JSONField()

RemediationSettingSerializer

Bases: NautobotModelSerializer, TaggedModelSerializerMixin

Serializer for RemediationSetting object.

Source code in nautobot_golden_config/api/serializers.py
class RemediationSettingSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
    """Serializer for RemediationSetting object."""

    class Meta:
        """Set Meta Data for RemediationSetting, will serialize all fields."""

        model = models.RemediationSetting
        fields = "__all__"
Meta

Set Meta Data for RemediationSetting, will serialize all fields.

Source code in nautobot_golden_config/api/serializers.py
class Meta:
    """Set Meta Data for RemediationSetting, will serialize all fields."""

    model = models.RemediationSetting
    fields = "__all__"

urls

API for Custom Jobs .

views

View for Golden Config APIs.

ComplianceFeatureViewSet

Bases: NautobotModelViewSet

API viewset for interacting with ComplianceFeature objects.

Source code in nautobot_golden_config/api/views.py
class ComplianceFeatureViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ComplianceFeature objects."""

    queryset = models.ComplianceFeature.objects.all()
    serializer_class = serializers.ComplianceFeatureSerializer
    filterset_class = filters.ComplianceFeatureFilterSet

ComplianceRuleViewSet

Bases: NautobotModelViewSet

API viewset for interacting with ComplianceRule objects.

Source code in nautobot_golden_config/api/views.py
class ComplianceRuleViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ComplianceRule objects."""

    queryset = models.ComplianceRule.objects.all()
    serializer_class = serializers.ComplianceRuleSerializer
    filterset_class = filters.ComplianceRuleFilterSet

ConfigComplianceViewSet

Bases: NautobotModelViewSet

API viewset for interacting with ConfigCompliance objects.

Source code in nautobot_golden_config/api/views.py
class ConfigComplianceViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ConfigCompliance objects."""

    queryset = models.ConfigCompliance.objects.all()
    serializer_class = serializers.ConfigComplianceSerializer
    filterset_class = filters.ConfigComplianceFilterSet

ConfigPlanViewSet

Bases: NautobotAPIVersionMixin, NotesViewSetMixin, ModelViewSetMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin, BulkUpdateModelMixin, BulkDestroyModelMixin, GenericViewSet

API viewset for interacting with ConfigPlan objects. Does not support POST to create objects.

Source code in nautobot_golden_config/api/views.py
class ConfigPlanViewSet(
    NautobotAPIVersionMixin,
    NotesViewSetMixin,
    ModelViewSetMixin,
    RetrieveModelMixin,
    UpdateModelMixin,
    DestroyModelMixin,
    ListModelMixin,
    BulkUpdateModelMixin,
    BulkDestroyModelMixin,
    GenericViewSet,
):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ConfigPlan objects. Does not support POST to create objects."""

    queryset = models.ConfigPlan.objects.all()
    serializer_class = serializers.ConfigPlanSerializer
    filterset_class = filters.ConfigPlanFilterSet

    def get_serializer_context(self):
        """Gather all custom fields for the model. Copied from nautobot.extras.api.views.CustomFieldModelViewSet."""
        content_type = ContentType.objects.get_for_model(self.queryset.model)
        custom_fields = content_type.custom_fields.all()

        context = super().get_serializer_context()
        context.update(
            {
                "custom_fields": custom_fields,
            }
        )
        return context
get_serializer_context()

Gather all custom fields for the model. Copied from nautobot.extras.api.views.CustomFieldModelViewSet.

Source code in nautobot_golden_config/api/views.py
def get_serializer_context(self):
    """Gather all custom fields for the model. Copied from nautobot.extras.api.views.CustomFieldModelViewSet."""
    content_type = ContentType.objects.get_for_model(self.queryset.model)
    custom_fields = content_type.custom_fields.all()

    context = super().get_serializer_context()
    context.update(
        {
            "custom_fields": custom_fields,
        }
    )
    return context

ConfigPushPermissions

Bases: BasePermission

Permissions class to validate access to Devices and GoldenConfig view.

Source code in nautobot_golden_config/api/views.py
class ConfigPushPermissions(BasePermission):
    """Permissions class to validate access to Devices and GoldenConfig view."""

    def has_permission(self, request, view):
        """Method to validated permissions to API view."""
        return request.user.has_perm("nautobot_golden_config.view_goldenconfig")

    def has_object_permission(self, request, view, obj):
        """Validate user access to the object, taking into account constraints."""
        return request.user.has_perm("dcim.view_device", obj=obj)
has_object_permission(request, view, obj)

Validate user access to the object, taking into account constraints.

Source code in nautobot_golden_config/api/views.py
def has_object_permission(self, request, view, obj):
    """Validate user access to the object, taking into account constraints."""
    return request.user.has_perm("dcim.view_device", obj=obj)
has_permission(request, view)

Method to validated permissions to API view.

Source code in nautobot_golden_config/api/views.py
def has_permission(self, request, view):
    """Method to validated permissions to API view."""
    return request.user.has_perm("nautobot_golden_config.view_goldenconfig")

ConfigRemoveViewSet

Bases: NautobotModelViewSet

API viewset for interacting with ConfigRemove objects.

Source code in nautobot_golden_config/api/views.py
class ConfigRemoveViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ConfigRemove objects."""

    queryset = models.ConfigRemove.objects.all()
    serializer_class = serializers.ConfigRemoveSerializer
    filterset_class = filters.ConfigRemoveFilterSet

ConfigReplaceViewSet

Bases: NautobotModelViewSet

API viewset for interacting with ConfigReplace objects.

Source code in nautobot_golden_config/api/views.py
class ConfigReplaceViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with ConfigReplace objects."""

    queryset = models.ConfigReplace.objects.all()
    serializer_class = serializers.ConfigReplaceSerializer
    filterset_class = filters.ConfigReplaceFilterSet

ConfigToPushViewSet

Bases: RetrieveModelMixin, GenericViewSet

Detail REST API view showing configuration after postprocessing.

Source code in nautobot_golden_config/api/views.py
class ConfigToPushViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """Detail REST API view showing configuration after postprocessing."""

    permission_classes = [IsAuthenticated & ConfigPushPermissions]
    queryset = Device.objects.all()
    serializer_class = serializers.ConfigToPushSerializer

GenerateIntendedConfigException

Bases: APIException

Exception for when the intended config cannot be generated.

Source code in nautobot_golden_config/api/views.py
class GenerateIntendedConfigException(APIException):
    """Exception for when the intended config cannot be generated."""

    status_code = 400
    default_detail = "Unable to generate the intended config for this device."
    default_code = "error"

GenerateIntendedConfigView

Bases: NautobotAPIVersionMixin, GenericAPIView

API view for generating the intended config for a Device.

Source code in nautobot_golden_config/api/views.py
class GenerateIntendedConfigView(NautobotAPIVersionMixin, GenericAPIView):
    """API view for generating the intended config for a Device."""

    name = "Generate Intended Config for Device"
    permission_classes = [IsAuthenticated]
    serializer_class = serializers.GenerateIntendedConfigSerializer

    def _get_object(self, request, model, query_param):
        """Get the requested model instance, restricted to requesting user."""
        pk = request.query_params.get(query_param)
        if not pk:
            raise GenerateIntendedConfigException(f"Parameter {query_param} is required")
        try:
            return model.objects.restrict(request.user, "view").get(pk=pk)
        except model.DoesNotExist as exc:
            raise GenerateIntendedConfigException(f"{model.__name__} with id '{pk}' not found") from exc

    def _get_jinja_template_path(self, settings, device, git_repository):
        """Get the Jinja template path for the device in the provided git repository."""
        try:
            rendered_path = render_jinja2(template_code=settings.jinja_path_template, context={"obj": device})
        except (TemplateSyntaxError, TemplateError) as exc:
            raise GenerateIntendedConfigException("Error rendering Jinja path template") from exc
        filesystem_path = Path(git_repository.filesystem_path) / rendered_path
        if not filesystem_path.is_file():
            msg = f"Jinja template {filesystem_path} not found in git repository {git_repository}"
            raise GenerateIntendedConfigException(msg)
        return filesystem_path

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="device_id",
                required=True,
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.QUERY,
            ),
            OpenApiParameter(
                name="git_repository_id",
                required=True,
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.QUERY,
            ),
        ]
    )
    def get(self, request, *args, **kwargs):
        """Generate intended configuration for a Device with an arbitrary GitRepository."""
        device = self._get_object(request, Device, "device_id")
        git_repository = self._get_object(request, GitRepository, "git_repository_id")
        settings = models.GoldenConfigSetting.objects.get_for_device(device)
        if not settings:
            raise GenerateIntendedConfigException("No Golden Config settings found for this device")
        if not settings.sot_agg_query:
            raise GenerateIntendedConfigException("Golden Config settings sot_agg_query not set")

        try:
            ensure_git_repository(git_repository)
        except Exception as exc:
            raise GenerateIntendedConfigException("Error trying to sync git repository") from exc

        filesystem_path = self._get_jinja_template_path(settings, device, git_repository)

        status_code, context = graph_ql_query(request, device, settings.sot_agg_query.query)
        if status_code == status.HTTP_200_OK:
            try:
                intended_config = self._render_config_nornir_serial(
                    device=device,
                    jinja_template=filesystem_path.name,
                    jinja_root_path=filesystem_path.parent,
                    graphql_data=context,
                )
            except Exception as exc:
                raise GenerateIntendedConfigException("Error rendering Jinja template") from exc
            return Response(
                data={
                    "intended_config": intended_config,
                    "intended_config_lines": intended_config.split("\n"),
                },
                status=status.HTTP_200_OK,
            )

        raise GenerateIntendedConfigException("Unable to generate the intended config for this device")

    def _render_config_nornir_serial(self, device, jinja_template, jinja_root_path, graphql_data):
        """Render the Jinja template for the device using Nornir serial runner.

        This is a small stub of the logic in nornir_plays.config_intended.config_intended.
        """
        jinja_env = get_django_env()
        with InitNornir(
            runner={"plugin": "serial"},
            logging={"enabled": False},
            inventory={
                "plugin": "nautobot-inventory",
                "options": {
                    "credentials_class": NORNIR_SETTINGS.get("credentials"),
                    "params": NORNIR_SETTINGS.get("inventory_params"),
                    "queryset": Device.objects.filter(pk=device.pk),
                    "defaults": {"now": make_aware(datetime.datetime.now())},
                },
            },
        ) as nornir_obj:
            results = nornir_obj.run(
                task=_nornir_task_inject_graphql_data,
                name="REST API GENERATE CONFIG",
                graphql_data=graphql_data,
                obj=device,  # Used by the nornir tasks for logging to the logger below
                logger=logging.getLogger(
                    dispatcher.__module__
                ),  # The nornir tasks are built for logging to a JobResult, pass a standard logger here
                jinja_template=jinja_template,
                jinja_root_path=jinja_root_path,
                output_file_location="/dev/null",  # The nornir task outputs the templated config to a file, but this API doesn't need it
                jinja_filters=jinja_env.filters,
                jinja_env=jinja_env,
                **dispatch_params(
                    "generate_config", device.platform.network_driver, logging.getLogger(dispatch_params.__module__)
                ),
            )
            return results[device.name][1][1][0].result["config"]
get(request, *args, **kwargs)

Generate intended configuration for a Device with an arbitrary GitRepository.

Source code in nautobot_golden_config/api/views.py
@extend_schema(
    parameters=[
        OpenApiParameter(
            name="device_id",
            required=True,
            type=OpenApiTypes.UUID,
            location=OpenApiParameter.QUERY,
        ),
        OpenApiParameter(
            name="git_repository_id",
            required=True,
            type=OpenApiTypes.UUID,
            location=OpenApiParameter.QUERY,
        ),
    ]
)
def get(self, request, *args, **kwargs):
    """Generate intended configuration for a Device with an arbitrary GitRepository."""
    device = self._get_object(request, Device, "device_id")
    git_repository = self._get_object(request, GitRepository, "git_repository_id")
    settings = models.GoldenConfigSetting.objects.get_for_device(device)
    if not settings:
        raise GenerateIntendedConfigException("No Golden Config settings found for this device")
    if not settings.sot_agg_query:
        raise GenerateIntendedConfigException("Golden Config settings sot_agg_query not set")

    try:
        ensure_git_repository(git_repository)
    except Exception as exc:
        raise GenerateIntendedConfigException("Error trying to sync git repository") from exc

    filesystem_path = self._get_jinja_template_path(settings, device, git_repository)

    status_code, context = graph_ql_query(request, device, settings.sot_agg_query.query)
    if status_code == status.HTTP_200_OK:
        try:
            intended_config = self._render_config_nornir_serial(
                device=device,
                jinja_template=filesystem_path.name,
                jinja_root_path=filesystem_path.parent,
                graphql_data=context,
            )
        except Exception as exc:
            raise GenerateIntendedConfigException("Error rendering Jinja template") from exc
        return Response(
            data={
                "intended_config": intended_config,
                "intended_config_lines": intended_config.split("\n"),
            },
            status=status.HTTP_200_OK,
        )

    raise GenerateIntendedConfigException("Unable to generate the intended config for this device")

GoldenConfigRootView

Bases: APIRootView

Golden Config API root view.

Source code in nautobot_golden_config/api/views.py
class GoldenConfigRootView(APIRootView):
    """Golden Config API root view."""

    def get_view_name(self):
        """Golden Config API root view boilerplate."""
        return "Golden Config"
get_view_name()

Golden Config API root view boilerplate.

Source code in nautobot_golden_config/api/views.py
def get_view_name(self):
    """Golden Config API root view boilerplate."""
    return "Golden Config"

GoldenConfigSettingViewSet

Bases: NautobotModelViewSet

API viewset for interacting with GoldenConfigSetting objects.

Source code in nautobot_golden_config/api/views.py
class GoldenConfigSettingViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with GoldenConfigSetting objects."""

    queryset = models.GoldenConfigSetting.objects.all()
    serializer_class = serializers.GoldenConfigSettingSerializer
    filterset_class = filters.GoldenConfigSettingFilterSet

GoldenConfigViewSet

Bases: NautobotModelViewSet

API viewset for interacting with GoldenConfig objects.

Source code in nautobot_golden_config/api/views.py
class GoldenConfigViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with GoldenConfig objects."""

    queryset = models.GoldenConfig.objects.all()
    serializer_class = serializers.GoldenConfigSerializer
    filterset_class = filters.GoldenConfigFilterSet

RemediationSettingViewSet

Bases: NautobotModelViewSet

API viewset for interacting with RemediationSetting objects.

Source code in nautobot_golden_config/api/views.py
class RemediationSettingViewSet(NautobotModelViewSet):  # pylint:disable=too-many-ancestors
    """API viewset for interacting with RemediationSetting objects."""

    queryset = models.RemediationSetting.objects.all()
    serializer_class = serializers.RemediationSettingSerializer
    filterset_class = filters.RemediationSettingFilterSet

SOTAggDeviceDetailView

Bases: APIView

Detail REST API view showing graphql, with a potential "transformer" of data on a specific device.

Source code in nautobot_golden_config/api/views.py
class SOTAggDeviceDetailView(APIView):
    """Detail REST API view showing graphql, with a potential "transformer" of data on a specific device."""

    permission_classes = [AllowAny]

    def get(self, request, *args, **kwargs):
        """Get method serialize for a dictionary to json response."""
        device = Device.objects.get(pk=kwargs["pk"])
        settings = get_device_to_settings_map(queryset=Device.objects.filter(pk=device.pk))[device.id]
        status_code, data = graph_ql_query(request, device, settings.sot_agg_query.query)
        data = json.loads(json.dumps(data))
        return Response(serializers.GraphQLSerializer(data=data).initial_data, status=status_code)
get(request, *args, **kwargs)

Get method serialize for a dictionary to json response.

Source code in nautobot_golden_config/api/views.py
def get(self, request, *args, **kwargs):
    """Get method serialize for a dictionary to json response."""
    device = Device.objects.get(pk=kwargs["pk"])
    settings = get_device_to_settings_map(queryset=Device.objects.filter(pk=device.pk))[device.id]
    status_code, data = graph_ql_query(request, device, settings.sot_agg_query.query)
    data = json.loads(json.dumps(data))
    return Response(serializers.GraphQLSerializer(data=data).initial_data, status=status_code)