diff --git a/djblets/webapi/errors.py b/djblets/webapi/errors.py
index 6bb17d237faff18be034edf06c5981f89033fdcd..98b27a3567c15cc5c91fea1167785d380764bda2 100644
--- a/djblets/webapi/errors.py
+++ b/djblets/webapi/errors.py
@@ -149,3 +149,9 @@ RATE_LIMIT_EXCEEDED = WebAPIError(
     'API rate limit has been exceeded.',
     http_status=429,  # 429 Too Many Requests
 )
+
+GRAPHQL_VALIDATION_ERROR = WebAPIError(
+    115,
+    'GraphQL validation error',
+    http_status=400  # 400 Bad Request
+)
diff --git a/djblets/webapi/resources/mixins/queries.py b/djblets/webapi/resources/mixins/queries.py
index bd0aac4eb65ab63a907f36f150c3cacba8463825..bee9009d40654285d254d6a7120d4d1032e79207 100644
--- a/djblets/webapi/resources/mixins/queries.py
+++ b/djblets/webapi/resources/mixins/queries.py
@@ -55,3 +55,53 @@ class APIQueryUtilsMixin(object):
                     pass
 
         return q
+
+    def build_graphql_queries_for_int_field(self, query_params, field_name,
+                                            query_param_name=None):
+        """Build queries based on graphql input parameters for an int field.
+
+        GraphQL resolvers can use this to allow callers to filter results
+        through range matches. Callers can search for exact matches, or
+        can make use of the following operations:
+
+        * ``<`` (:samp:`query_params: {{name}_lt={value}}`)
+        * ``<=`` (:samp:`query_params: {{name}_lte={value}}`)
+        * ``>`` (:samp:`query_params: {{name}_gt={value}}`)
+        * ``>=`` (:samp:`query_params: {{name}_gte={value}}`)
+
+        Args:
+            query_params (dict):
+                The dictionary of GraphQL input query parameters.
+
+            field_name (unicode):
+                The field name in the database to query against.
+
+            query_param_name (unicode):
+                The query argument passed in the query parameters.
+                Defaults to the ``field_name``.
+
+        Returns:
+            django.db.models.Q:
+            A query expression that can be used in database queries.
+        """
+        if not query_param_name:
+            query_param_name = field_name
+
+        q = Q()
+
+        if query_param_name in query_params:
+            q = q & Q(**{field_name: query_params[query_param_name]})
+
+        for op in ('gt', 'gte', 'lt', 'lte'):
+            param = '%s_%s' % (query_param_name, op)
+
+            if param in query_params:
+                query_field = '%s__%s' % (field_name, op)
+
+                try:
+                    q = q & Q(**{query_field: int(query_params[param])})
+                except ValueError:
+                    # Not a valid query, so ignore it.
+                    pass
+
+        return q
diff --git a/djblets/webapi/tests/test_apiqueryutilsmixin.py b/djblets/webapi/tests/test_apiqueryutilsmixin.py
index 0abc57e32c530094c9e39b4b5f7a9843230af98f..5f7b8312c63d48f0af0d95c4eb03c4803d6785b7 100644
--- a/djblets/webapi/tests/test_apiqueryutilsmixin.py
+++ b/djblets/webapi/tests/test_apiqueryutilsmixin.py
@@ -50,6 +50,52 @@ class APIQueryUtilsMixinTests(TestCase):
 
         self.assertQEqual(q, Q(myfield__gte=10))
 
+    def test_build_graphql_queries_for_int_field_with_lt(self):
+        """Testing APIQueryUtilsMixin.build_graphql_queries_for_int_field with
+        _lt="""
+        query_params = {'myfield_lt': 10}
+        q = self.query_utils.build_graphql_queries_for_int_field(query_params,
+                                                                 'myfield')
+
+        self.assertQEqual(q, Q(myfield__lt=10))
+
+    def test_build_graphql_queries_for_int_field_with_lte(self):
+        """Testing APIQueryUtilsMixin.build_graphql_queries_for_int_field with
+        _lte="""
+        query_params = {'myfield_lte': 10}
+        q = self.query_utils.build_graphql_queries_for_int_field(query_params,
+                                                                 'myfield')
+
+        self.assertQEqual(q, Q(myfield__lte=10))
+
+    def test_build_graphql_queries_for_int_field_with_gt(self):
+        """Testing APIQueryUtilsMixin.build_graphql_queries_for_int_field with
+        _gt="""
+        query_params = {'myfield_gt': 10}
+        q = self.query_utils.build_graphql_queries_for_int_field(query_params,
+                                                                 'myfield')
+
+        self.assertQEqual(q, Q(myfield__gt=10))
+
+    def test_build_graphql_queries_for_int_field_with_gte(self):
+        """Testing APIQueryUtilsMixin.build_graphql_queries_for_int_field with
+        _gte="""
+        query_params = {'myfield_gte': 10}
+        q = self.query_utils.build_graphql_queries_for_int_field(query_params,
+                                                                 'myfield')
+
+        self.assertQEqual(q, Q(myfield__gte=10))
+
+    def test_build_graphql_queries_for_int_field_with_query_param_name(self):
+        """Testing APIQueryUtilsMixin.build_graphql_queries_for_int_field with
+        query_param_name="""
+        query_params = {'foo_gte': 10}
+        q = self.query_utils.build_graphql_queries_for_int_field(query_params,
+                                                                 'myfield',
+                                                                 'foo')
+
+        self.assertQEqual(q, Q(myfield__gte=10))
+
     def assertQEqual(self, q1, q2):
         self.assertEqual(q1.connector, q2.connector)
         self.assertEqual(q1.children, q2.children)
