I have a mutation where I would like to return arbitrarily shaped data, but I'm having a hard time envisioning how to do this via a graphene mutation.
I would like to return data like this:
{
"foo": {
"success": [
{
"id": "abc123",
"goober": {
"success": [
{
"id": "goober-type-1",
"baz": "blahblahblah"
},
{
"id": "goober-type-2",
"baz": "blahblahblah"
}
],
"failed": [],
"cancelled": []
},
"tronic": {
"success": [
{
"id": "tronic-type-1",
"baz": "blahblahblah"
},
{
"id": "tronic-type-2",
"baz": "blahblahblah"
}
],
"failed": [],
"cancelled": []
}
}
],
"failed": [
{
"id": "abc123",
"goober": {
"success": [],
"failed": [
{
"id": "goober-type-3",
"baz": "blahblahblah"
}
],
"cancelled": [
{
"id": "goober-type-4",
"baz": "blahblahblah"
}
]
},
"tronic": {
"success": [],
"failed": [
{
"id": "tronic-type-4",
"baz": "blahblahblah"
}
],
"cancelled": [
{
"id": "tronic-type-3",
"baz": "blahblahblah"
}
]
}
}
]
}
}
My instinct was wanting to define graphene.ObjectType
's in a fashion like this:
class Goober(graphene.ObjectType):
id = graphene.String()
baz = graphene.String()
class Tronic(graphene.ObjectType):
id = graphene.String()
baz = graphene.String()
class Foo(graphene.ObjectType):
id = graphene.String()
goober = graphene.ObjectType(
success = graphene.List(Goober),
failed = graphene.List(Goober),
cancelled = graphene.List(Goober)
)
tronic = graphene.ObjectType(
success = graphene.List(Tronic),
failed = graphene.List(Tronic),
cancelled = graphene.List(Tronic)
)
class Results(graphene.ObjectType):
foo = graphene.ObjectType(
success=graphene.List(Foo),
failed=graphene.List(Foo)
)
But I'm really not getting anywhere with this approach, and feeling like I'm fundamentally misunderstanding something.
I've had success in other areas, returning SQL objects and some custom ones, but not with generating and returning relatively complex, nested data like this. Any advice would be much appreciated.
The truth is that Graphene documentation lacks a lot. Take a look at this rather lengthy but complete example replicating your data:
import json
import graphene
# let's just prepare some data
SUCCESS = [{
"id": "abc123",
"goober": {
"success": [
{
"id": "goober-type-1",
"baz": "blahblahblah"
},
{
"id": "goober-type-2",
"baz": "blahblahblah"
}
],
"failed": [],
"cancelled": []
},
"tronic": {
"success": [
{
"id": "tronic-type-1",
"baz": "blahblahblah"
},
{
"id": "tronic-type-2",
"baz": "blahblahblah"
}
],
"failed": [],
"cancelled": []
}
}]
FAILED = [{
"id": "abc123",
"goober": {
"success": [],
"failed": [
{
"id": "goober-type-3",
"baz": "blahblahblah"
}
],
"cancelled": [
{
"id": "goober-type-4",
"baz": "blahblahblah"
}
]
},
"tronic": {
"success": [],
"failed": [
{
"id": "tronic-type-4",
"baz": "blahblahblah"
}
],
"cancelled": [
{
"id": "tronic-type-3",
"baz": "blahblahblah"
}
]
}
}]
class Goober(graphene.ObjectType):
id = graphene.String()
baz = graphene.String()
class Tronic(graphene.ObjectType):
id = graphene.String()
baz = graphene.String()
class GooberResult(graphene.ObjectType):
success = graphene.List(Goober)
failed = graphene.List(Goober)
cancelled = graphene.List(Goober)
class TronicResult(graphene.ObjectType):
success = graphene.List(Tronic)
failed = graphene.List(Tronic)
cancelled = graphene.List(Tronic)
class FooResult(graphene.ObjectType):
id = graphene.String()
goober = graphene.Field(GooberResult)
tronic = graphene.Field(TronicResult)
class Foo(graphene.Mutation):
success = graphene.List(FooResult)
failed = graphene.List(FooResult)
def mutate(self, info):
# provide some data as a mutation result
success = SUCCESS
failed = FAILED
return Foo(success=success, failed=failed)
class Mutation(graphene.ObjectType):
foo = Foo.Field()
schema = graphene.Schema(mutation=Mutation)
result = schema.execute("""
mutation Foo {
foo {
success {
id
goober {
success {
id
baz
}
}
}
failed {
id
tronic {
cancelled {
id
baz
}
}
}
}
}
""")
print(json.dumps(result.data, indent=2))
When you run this script, you'll get the expected result:
{
"foo": {
"success": [
{
"id": "abc123",
"goober": {
"success": [
{
"id": "goober-type-1",
"baz": "blahblahblah"
},
{
"id": "goober-type-2",
"baz": "blahblahblah"
}
]
}
}
],
"failed": [
{
"id": "abc123",
"tronic": {
"cancelled": [
{
"id": "tronic-type-3",
"baz": "blahblahblah"
}
]
}
}
]
}
}
The place to start in the documentation is probably at the relationship between ObjectType
s and Field
s. Scalars act as Field
s, however your defined ObjectType
s do not, that's why you need to wrap them in graphene.Field
. Then just take a look at Mutation
s to use it all together.