Repository: strawberry-graphql/strawberry

Issue:
Raise error when using Scalars (or non strawberry types) with Union
If we do something any of the following:

```python
X = strawberry.Union("X", (int, str))

@strawberry.type
class A:
    field: Union[int, str]


@strawberry.type
class A:
    field: Union[NonStrawberryTypeA, NonStrawberryTypeB]
```

we should get an error informing that:

1. you can't use unions with scalars (not supported by GraphQL)
2. you can only use union with strawberry types


Discussion:

Resolving patch:
diff --git a/strawberry/exceptions.py b/strawberry/exceptions.py
--- a/strawberry/exceptions.py
+++ b/strawberry/exceptions.py
@@ -72,6 +72,12 @@ def __init__(
         super().__init__(message)
 
 
+class InvalidUnionType(Exception):
+    """The union is constructed with an invalid type"""
+
+    pass
+
+
 class MissingTypesForGenericError(Exception):
     """Raised when a generic types was used without passing any type."""
 
diff --git a/strawberry/union.py b/strawberry/union.py
--- a/strawberry/union.py
+++ b/strawberry/union.py
@@ -1,4 +1,7 @@
-from typing import NoReturn, Optional, Tuple, Type
+from typing import NoReturn, Optional, Tuple, Type, TypeVar
+
+from .exceptions import InvalidUnionType
+from .scalars import SCALAR_TYPES
 
 
 class StrawberryUnion:
@@ -37,8 +40,6 @@ def union(
 
     Example usages:
 
-    >>> strawberry.union("Some Thing", (int, str))
-
     >>> @strawberry.type
     ... class A: ...
     >>> @strawberry.type
@@ -46,6 +47,21 @@ def union(
     >>> strawberry.union("Name", (A, Optional[B]))
     """
 
+    # Validate types
+    if len(types) == 0:
+        raise TypeError("No types passed to `union`")
+
+    for _type in types:
+        if _type in SCALAR_TYPES:
+            raise InvalidUnionType(
+                f"Scalar type `{_type.__name__}` cannot be used in a GraphQL Union"
+            )
+
+        if not isinstance(_type, TypeVar) and not hasattr(_type, "_type_definition"):
+            raise InvalidUnionType(
+                f"Union type `{_type.__name__}` is not a Strawberry type"
+            )
+
     union_definition = StrawberryUnion(name=name, types=types, description=description)
 
     return union_definition


Test patch:
diff --git a/tests/types/test_generic.py b/tests/types/test_generic.py
--- a/tests/types/test_generic.py
+++ b/tests/types/test_generic.py
@@ -259,11 +259,15 @@ class Edge(Generic[T]):
 
     # let's make a copy of this generic type
 
-    Copy = copy_type_with(Edge, str)
+    @strawberry.type
+    class Node:
+        name: str
+
+    Copy = copy_type_with(Edge, Node)
 
     definition = Copy._type_definition
 
-    assert definition.name == "StrEdge"
+    assert definition.name == "NodeEdge"
     assert definition.is_generic is False
     assert definition.type_params == {}
 
@@ -273,8 +277,8 @@ class Edge(Generic[T]):
 
     union_definition = definition.fields[0].type
     assert isinstance(union_definition, StrawberryUnion)
-    assert union_definition.name == "ErrorStr"
-    assert union_definition.types == (Error, str)
+    assert union_definition.name == "ErrorNode"
+    assert union_definition.types == (Error, Node)
 
     assert definition.fields[0].is_optional is False
 
diff --git a/tests/types/test_union.py b/tests/types/test_union.py
--- a/tests/types/test_union.py
+++ b/tests/types/test_union.py
@@ -1,8 +1,10 @@
+from dataclasses import dataclass
 from typing import Generic, List, Optional, TypeVar, Union
 
 import pytest
 
 import strawberry
+from strawberry.exceptions import InvalidUnionType
 from strawberry.union import StrawberryUnion
 
 
@@ -138,3 +140,26 @@ class B:
 
     with pytest.raises(ValueError, match=r"Cannot use union type directly"):
         Result()
+
+
+def test_error_with_empty_type_list():
+    with pytest.raises(TypeError, match="No types passed to `union`"):
+        strawberry.union("Result", [])
+
+
+def test_error_with_scalar_types():
+    with pytest.raises(
+        InvalidUnionType, match="Scalar type `int` cannot be used in a GraphQL Union"
+    ):
+        strawberry.union("Result", (int,))
+
+
+def test_error_with_non_strawberry_type():
+    @dataclass
+    class A:
+        a: int
+
+    with pytest.raises(
+        InvalidUnionType, match="Union type `A` is not a Strawberry type"
+    ):
+        strawberry.union("Result", (A,))