How to return json in python graphene resolver without backslashes before quotation marks
Your initial result of
{
"data": {
"questionnaire": "{\"s1\": \"Section 1\", \"s2\": \"Section 2\", \"s3\": \"Section 3\", \"s4\": \"Section 4\"}"
}
}
is the intended behavior. After all, questionnaire
resolves to a JSONString. Since it is a string it must be double quoted, thus its inner quotations must be escaped. This is according to JSON's standards.
To use that string you, would have to run some sort of JSON parser on the data.questionnaire
object. In javascript, for instance, it would be something like:
var data;
// Fetching logic to get the data object from your GraphQL server
var sections = JSON.parse(data.questionaire);
// Now you can access its objects
console.log(sections.s1) // Should print "Section 1" on the dev console
However, the method described above is not ideal if the keys of sections
are not predetermined (sections.s5
may be defined in one case but undefined in another). Instead, you might rather have an array that you can iterate over. To do this, you would have to define a "model" that has explicit key-value pairs. Doing this way is format suited for GraphQL, too. For instance:
import graphene
# Our new model
class Section(graphene.ObjectType):
key = graphene.String() # dictionary key
header = graphene.String() # dictionary value
# Your previous schema with modifications
class Query(graphene.ObjectType):
# questionnaire = graphene.types.json.JSONString(description='JSON result test')
# Return a list of section objects
questionnaire = graphene.List(Section)
def resolve_questionnaire(self, info: graphql.ResolveInfo):
sections = {
's1': "Section 1",
's2': "Section 2",
's3': "Section 3",
's4': "Section 4"
}
sections_as_obj_list = [] # Used to return a list of Section types
# Create a new Section object for each item and append it to list
for key, value in sections.items(): # Use sections.iteritems() in Python2
section = Section(key, value) # Creates a section object where key=key and header=value
sections_as_obj_list.append(section)
# return sections
return sections_as_obj_list
Now, if we run the query:
query {
questionnaire {
key
header
}
}
It returns a JSON array that can be iterated through.
{
"data" {
"questionnaire": [
{
"key": "s1",
"header": "Section 1"
},
{
"key": "s2",
"header": "Section 2"
},
{
"key": "s3",
"header": "Section 3"
},
{
"key": "s4",
"header": "Section 4"
},
]
}
}
You can just subclass the JSON type and replace the serialize method:
class Any(JSON):
@staticmethod
def serialize(dt):
return dt
Then instead of
questionnaire = Field(JSON)
write
questionnaire = Field(Any)
Yes, this does break the strictly-typed spirit of GraphQL, but if that's what you want to do, there's how to do it. Note that this is an output-only hack — it won't allow you to accept arbitrary structures as arguments.
Graphene now has a GenericScalar
type for this.
from graphene.types import generic
...
errors = generic.GenericScalar()