Deregisters a node, service or check

        Parameters:
            node (Object or ObjectID): Node
            check (ObjectID): Check ID
            service (ObjectID): Service ID
            write_token (ObjectID): Token ID
        Returns:
            bool: ``True`` on success

        **Node** expects a body that look like one of the following::

            {
                "Datacenter": "dc1",
                "Node": "foobar",
            }

        ::

            {
                "Datacenter": "dc1",
                "Node": "foobar",
                "CheckID": "service:redis1"
            }

        ::

            {
              "Datacenter": "dc1",
              "Node": "foobar",
              "ServiceID": "redis1",
            }

        The behavior of the endpoint depends on what keys are provided.
        The endpoint requires **Node** to be provided while **Datacenter**
        will be defaulted to match that of the agent. If only **Node** is
        provided, the node and all associated services and checks are deleted.
        If **CheckID** is provided, only that check is removed.
        If **ServiceID** is provided, the service and its associated health
        check (if any) are removed.

        An optional ACL token may be provided to perform the deregister action
        by adding a **WriteRequest** block in the query, like this::

            {
                "WriteRequest": {
                    "Token": "foo"
                }
            }

async def deregister(self, node, *,
                         check=None, service=None, write_token=None):
        """Deregisters a node, service or check

        Parameters:
            node (Object or ObjectID): Node
            check (ObjectID): Check ID
            service (ObjectID): Service ID
            write_token (ObjectID): Token ID
        Returns:
            bool: ``True`` on success

        **Node** expects a body that look like one of the following::

            {
                "Datacenter": "dc1",
                "Node": "foobar",
            }

        ::

            {
                "Datacenter": "dc1",
                "Node": "foobar",
                "CheckID": "service:redis1"
            }

        ::

            {
              "Datacenter": "dc1",
              "Node": "foobar",
              "ServiceID": "redis1",
            }

        The behavior of the endpoint depends on what keys are provided.
        The endpoint requires **Node** to be provided while **Datacenter**
        will be defaulted to match that of the agent. If only **Node** is
        provided, the node and all associated services and checks are deleted.
        If **CheckID** is provided, only that check is removed.
        If **ServiceID** is provided, the service and its associated health
        check (if any) are removed.

        An optional ACL token may be provided to perform the deregister action
        by adding a **WriteRequest** block in the query, like this::

            {
                "WriteRequest": {
                    "Token": "foo"
                }
            }
        """
        entry = {}
        if isinstance(node, str):
            entry["Node"] = node
        else:
            for k in ("Datacenter", "Node", "CheckID",
                      "ServiceID", "WriteRequest"):
                if k in node:
                    entry[k] = node[k]
        service_id = extract_attr(service, keys=["ServiceID", "ID"])
        check_id = extract_attr(check, keys=["CheckID", "ID"])
        if service_id and not check_id:
            entry["ServiceID"] = service_id
        elif service_id and check_id:
            entry["CheckID"] = "%s:%s" % (service_id, check_id)
        elif not service_id and check_id:
            entry["CheckID"] = check_id
        if write_token:
            entry["WriteRequest"] = {
                "Token": extract_attr(write_token, keys=["ID"])
            }
        response = await self._api.put("/v1/catalog/deregister", data=entry)
        return response.status == 200