Skip to content

Commit c61f0f7

Browse files
authored
Add Base64 scalar (#1221)
1 parent 5b2eb11 commit c61f0f7

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

graphene/types/base64.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from binascii import Error as _Error
2+
from base64 import b64decode, b64encode
3+
4+
from graphql.error import GraphQLError
5+
from graphql.language import StringValueNode, print_ast
6+
7+
from .scalars import Scalar
8+
9+
10+
class Base64(Scalar):
11+
"""
12+
The `Base64` scalar type represents a base64-encoded String.
13+
"""
14+
15+
@staticmethod
16+
def serialize(value):
17+
if not isinstance(value, bytes):
18+
if isinstance(value, str):
19+
value = value.encode("utf-8")
20+
else:
21+
value = str(value).encode("utf-8")
22+
return b64encode(value).decode("utf-8")
23+
24+
@classmethod
25+
def parse_literal(cls, node):
26+
if not isinstance(node, StringValueNode):
27+
raise GraphQLError(
28+
f"Base64 cannot represent non-string value: {print_ast(node)}"
29+
)
30+
return cls.parse_value(node.value)
31+
32+
@staticmethod
33+
def parse_value(value):
34+
if not isinstance(value, bytes):
35+
if not isinstance(value, str):
36+
raise GraphQLError(
37+
f"Base64 cannot represent non-string value: {repr(value)}"
38+
)
39+
value = value.encode("utf-8")
40+
try:
41+
return b64decode(value, validate=True).decode("utf-8")
42+
except _Error:
43+
raise GraphQLError(f"Base64 cannot decode value: {repr(value)}")

graphene/types/tests/test_base64.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import base64
2+
3+
from graphql import GraphQLError
4+
5+
from ..objecttype import ObjectType
6+
from ..scalars import String
7+
from ..schema import Schema
8+
from ..base64 import Base64
9+
10+
11+
class Query(ObjectType):
12+
base64 = Base64(_in=Base64(name="input"), _match=String(name="match"))
13+
bytes_as_base64 = Base64()
14+
string_as_base64 = Base64()
15+
number_as_base64 = Base64()
16+
17+
def resolve_base64(self, info, _in=None, _match=None):
18+
if _match:
19+
assert _in == _match
20+
return _in
21+
22+
def resolve_bytes_as_base64(self, info):
23+
return b"Hello world"
24+
25+
def resolve_string_as_base64(self, info):
26+
return "Spam and eggs"
27+
28+
def resolve_number_as_base64(self, info):
29+
return 42
30+
31+
32+
schema = Schema(query=Query)
33+
34+
35+
def test_base64_query():
36+
base64_value = base64.b64encode(b"Random string").decode("utf-8")
37+
result = schema.execute(
38+
"""{{ base64(input: "{}", match: "Random string") }}""".format(base64_value)
39+
)
40+
assert not result.errors
41+
assert result.data == {"base64": base64_value}
42+
43+
44+
def test_base64_query_with_variable():
45+
base64_value = base64.b64encode(b"Another string").decode("utf-8")
46+
47+
# test datetime variable in string representation
48+
result = schema.execute(
49+
"""
50+
query GetBase64($base64: Base64) {
51+
base64(input: $base64, match: "Another string")
52+
}
53+
""",
54+
variables={"base64": base64_value},
55+
)
56+
assert not result.errors
57+
assert result.data == {"base64": base64_value}
58+
59+
60+
def test_base64_query_none():
61+
result = schema.execute("""{ base64 }""")
62+
assert not result.errors
63+
assert result.data == {"base64": None}
64+
65+
66+
def test_base64_query_invalid():
67+
bad_inputs = [
68+
dict(),
69+
123,
70+
"This is not valid base64",
71+
]
72+
73+
for input_ in bad_inputs:
74+
result = schema.execute(
75+
"""{ base64(input: $input) }""", variables={"input": input_},
76+
)
77+
assert isinstance(result.errors, list)
78+
assert len(result.errors) == 1
79+
assert isinstance(result.errors[0], GraphQLError)
80+
assert result.data is None
81+
82+
83+
def test_base64_from_bytes():
84+
base64_value = base64.b64encode(b"Hello world").decode("utf-8")
85+
result = schema.execute("""{ bytesAsBase64 }""")
86+
assert not result.errors
87+
assert result.data == {"bytesAsBase64": base64_value}
88+
89+
90+
def test_base64_from_string():
91+
base64_value = base64.b64encode(b"Spam and eggs").decode("utf-8")
92+
result = schema.execute("""{ stringAsBase64 }""")
93+
assert not result.errors
94+
assert result.data == {"stringAsBase64": base64_value}
95+
96+
97+
def test_base64_from_number():
98+
base64_value = base64.b64encode(b"42").decode("utf-8")
99+
result = schema.execute("""{ numberAsBase64 }""")
100+
assert not result.errors
101+
assert result.data == {"numberAsBase64": base64_value}

0 commit comments

Comments
 (0)