def _process_response(
        self,
        data,
        mandatory_include_fields=None,
        include_attributes=None,
        exclude_attributes=None,
    ):
        """
        Process controller response data such as removing attributes based on the values of
        exclude_attributes and include_attributes query param filters and similar.

        :param data: Response data.
        :type: data: ``list`` or ``dict``
        """
        mandatory_include_fields = mandatory_include_fields or []
        include_attributes = include_attributes or []
        exclude_attributes = exclude_attributes or []

        # NOTE: include_attributes and exclude_attributes are mutually exclusive
        if include_attributes and exclude_attributes:
            msg = (
                "exclude_attributes and include_attributes arguments are mutually exclusive. "
                "You need to provide either one or another, but not both."
            )
            raise ValueError(msg)

        #  Common case - filters are not provided
        if not include_attributes and not exclude_attributes:
            return data

        # Skip processing of error responses
        if isinstance(data, dict) and data.get("faultstring", None):
            return data

        # We only care about the first part of the field name since deep filtering happens inside
        # MongoDB. Deep filtering here would also be quite expensive and waste of CPU cycles.
        cleaned_include_attributes = [
            attribute.split(".")[0] for attribute in include_attributes
        ]

        # Add in mandatory fields which always need to be present in the response (primary keys)
        cleaned_include_attributes += mandatory_include_fields
        cleaned_exclude_attributes = [
            attribute.split(".")[0] for attribute in exclude_attributes
        ]

        # NOTE: Since those parameters are mutually exclusive we could perform more efficient
        # filtering when just exclude_attributes is provided. Instead of creating a new dict, we
        # could just manipulate (delete) from the existing one.
        def process_item(item):
            result = {}
            for name, value in six.iteritems(item):
                if include_attributes and name not in cleaned_include_attributes:
                    continue

                if exclude_attributes and name in cleaned_exclude_attributes:
                    continue

                result[name] = value

            return result

        result = None
        if isinstance(data, (list, tuple)):
            # get_all response
            result = []
            for item in data:
                item = process_item(item)
                result.append(item)
        elif isinstance(data, dict):
            # get_one response
            result = process_item(data)
        else:
            raise ValueError("Unsupported type: %s" % (type(data)))

        return result

        Process controller response data such as removing attributes based on the values of
        exclude_attributes and include_attributes query param filters and similar.

        :param data: Response data.
        :type: data: ``list`` or ``dict``
        
st2common/st2common/router.py