Repository: saleor/saleor

Issue:
Filter by ids in query.
When doing any query with filter by ids and provide invalid id query return all objects instead of all matching form ids in the input. 

Working query on [demo](https://pwa.demo.saleor.rocks/graphql/)
```
{
  categories(first:10, filter:{ids: ["Q2F0ZWdvcnk6MTU=", "Q2F0ZWdvcnk6MTI="]}){
    edges{
      node{
        id
      }
    }
  }
}
```
For not working query chage ids to `["Q2F0ZWdvcnk6MTU=", "Q2F0ZWdvcnkxMg=="]`
Secound query retrun all categories. 




Discussion:

Resolving patch:
diff --git a/saleor/graphql/core/fields.py b/saleor/graphql/core/fields.py
--- a/saleor/graphql/core/fields.py
+++ b/saleor/graphql/core/fields.py
@@ -1,3 +1,4 @@
+import json
 from functools import partial
 
 import graphene
@@ -7,6 +8,7 @@
 from graphene.relay import PageInfo
 from graphene_django.converter import convert_django_field
 from graphene_django.fields import DjangoConnectionField
+from graphql.error import GraphQLError
 from graphql_relay.connection.arrayconnection import connection_from_list_slice
 from promise import Promise
 
@@ -186,9 +188,13 @@ def connection_resolver(
         filter_input = args.get(filters_name)
 
         if filter_input and filterset_class:
-            iterable = filterset_class(
+            instance = filterset_class(
                 data=dict(filter_input), queryset=iterable, request=info.context
-            ).qs
+            )
+            # Make sure filter input has valid values
+            if not instance.is_valid():
+                raise GraphQLError(json.dumps(instance.errors.get_json_data()))
+            iterable = instance.qs
 
         if Promise.is_thenable(iterable):
             return Promise.resolve(iterable).then(on_resolve)


Test patch:
diff --git a/tests/api/test_attributes.py b/tests/api/test_attributes.py
--- a/tests/api/test_attributes.py
+++ b/tests/api/test_attributes.py
@@ -98,6 +98,32 @@ def test_attributes_query(user_api_client, product):
     assert len(attributes_data) == attributes.count()
 
 
+NOT_EXISTS_IDS_ATTRIBUTES_QUERY = """
+    query ($filter: AttributeFilterInput!) {
+        attributes(first: 5, filter: $filter) {
+            edges {
+                node {
+                    id
+                    name
+                }
+            }
+        }
+    }
+"""
+
+
+def test_attributes_query_ids_not_exists(user_api_client, category):
+    query = NOT_EXISTS_IDS_ATTRIBUTES_QUERY
+    variables = {"filter": {"ids": ["ygRqjpmXYqaTD9r=", "PBa4ZLBhnXHSz6v="]}}
+    response = user_api_client.post_graphql(query, variables)
+    content = get_graphql_content(response, ignore_errors=True)
+    message_error = '{"ids": [{"message": "Invalid ID specified.", "code": ""}]}'
+
+    assert len(content["errors"]) == 1
+    assert content["errors"][0]["message"] == message_error
+    assert content["data"]["attributes"] is None
+
+
 def test_attributes_query_hidden_attribute(user_api_client, product, color_attribute):
     query = QUERY_ATTRIBUTES
 
diff --git a/tests/api/test_category.py b/tests/api/test_category.py
--- a/tests/api/test_category.py
+++ b/tests/api/test_category.py
@@ -681,6 +681,32 @@ def test_category_level(user_api_client, category):
     assert category_data["parent"]["name"] == category.name
 
 
+NOT_EXISTS_IDS_CATEGORIES_QUERY = """
+    query ($filter: CategoryFilterInput!) {
+        categories(first: 5, filter: $filter) {
+            edges {
+                node {
+                    id
+                    name
+                }
+            }
+        }
+    }
+"""
+
+
+def test_categories_query_ids_not_exists(user_api_client, category):
+    query = NOT_EXISTS_IDS_CATEGORIES_QUERY
+    variables = {"filter": {"ids": ["W3KATGDn3fq3ZH4=", "zH9pYmz7yWD3Hy8="]}}
+    response = user_api_client.post_graphql(query, variables)
+    content = get_graphql_content(response, ignore_errors=True)
+    message_error = '{"ids": [{"message": "Invalid ID specified.", "code": ""}]}'
+
+    assert len(content["errors"]) == 1
+    assert content["errors"][0]["message"] == message_error
+    assert content["data"]["categories"] is None
+
+
 FETCH_CATEGORY_QUERY = """
     query fetchCategory($id: ID!){
         category(id: $id) {
diff --git a/tests/api/test_collection.py b/tests/api/test_collection.py
--- a/tests/api/test_collection.py
+++ b/tests/api/test_collection.py
@@ -598,6 +598,32 @@ def test_remove_products_from_collection(
     assert data["products"]["totalCount"] == no_products_before - len(product_ids)
 
 
+NOT_EXISTS_IDS_COLLECTIONS_QUERY = """
+    query ($filter: CollectionFilterInput!) {
+        collections(first: 5, filter: $filter) {
+            edges {
+                node {
+                    id
+                    name
+                }
+            }
+        }
+    }
+"""
+
+
+def test_collections_query_ids_not_exists(user_api_client, category):
+    query = NOT_EXISTS_IDS_COLLECTIONS_QUERY
+    variables = {"filter": {"ids": ["ncXc5tP7kmV6pxE=", "yMyDVE5S2LWWTqK="]}}
+    response = user_api_client.post_graphql(query, variables)
+    content = get_graphql_content(response, ignore_errors=True)
+    message_error = '{"ids": [{"message": "Invalid ID specified.", "code": ""}]}'
+
+    assert len(content["errors"]) == 1
+    assert content["errors"][0]["message"] == message_error
+    assert content["data"]["collections"] is None
+
+
 FETCH_COLLECTION_QUERY = """
     query fetchCollection($id: ID!){
         collection(id: $id) {
diff --git a/tests/api/test_product.py b/tests/api/test_product.py
--- a/tests/api/test_product.py
+++ b/tests/api/test_product.py
@@ -3444,6 +3444,32 @@ def test_product_type_query_with_sort(
         assert product_types[order]["node"]["name"] == product_type_name
 
 
+NOT_EXISTS_IDS_COLLECTIONS_QUERY = """
+    query ($filter: ProductTypeFilterInput!) {
+        productTypes(first: 5, filter: $filter) {
+            edges {
+                node {
+                    id
+                    name
+                }
+            }
+        }
+    }
+"""
+
+
+def test_product_types_query_ids_not_exists(user_api_client, category):
+    query = NOT_EXISTS_IDS_COLLECTIONS_QUERY
+    variables = {"filter": {"ids": ["fTEJRuFHU6fd2RU=", "2XwnQNNhwCdEjhP="]}}
+    response = user_api_client.post_graphql(query, variables)
+    content = get_graphql_content(response, ignore_errors=True)
+    message_error = '{"ids": [{"message": "Invalid ID specified.", "code": ""}]}'
+
+    assert len(content["errors"]) == 1
+    assert content["errors"][0]["message"] == message_error
+    assert content["data"]["productTypes"] is None
+
+
 MUTATION_BULK_PUBLISH_PRODUCTS = """
         mutation publishManyProducts($ids: [ID]!, $is_published: Boolean!) {
             productBulkPublish(ids: $ids, isPublished: $is_published) {