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()