diff --git a/docs/introspection.rst b/docs/introspection.rst index dea55bd86..2097c30a1 100644 --- a/docs/introspection.rst +++ b/docs/introspection.rst @@ -29,6 +29,20 @@ you're ready to use Relay with Graphene GraphQL implementation. The schema file is sorted to create a reproducible canonical representation. +GraphQL SDL Representation +-------------------------- + +The schema can also be exported as a GraphQL SDL file by changing the file +extension : + +.. code:: bash + + ./manage.py graphql_schema --schema tutorial.quickstart.schema --out schema.graphql + +When exporting the schema as a ``.graphql`` file the ``--indent`` option is +ignored. + + Advanced Usage -------------- diff --git a/graphene_django/management/commands/graphql_schema.py b/graphene_django/management/commands/graphql_schema.py index 1e8baf65b..751a38552 100644 --- a/graphene_django/management/commands/graphql_schema.py +++ b/graphene_django/management/commands/graphql_schema.py @@ -1,3 +1,4 @@ +import os import importlib import json import functools @@ -5,6 +6,7 @@ from django.core.management.base import BaseCommand, CommandError from django.utils import autoreload +from graphql import print_schema from graphene_django.settings import graphene_settings @@ -44,24 +46,40 @@ def add_arguments(self, parser): class Command(CommandArguments): - help = "Dump Graphene schema JSON to file" + help = "Dump Graphene schema as a JSON or GraphQL file" can_import_settings = True - def save_file(self, out, schema_dict, indent): + def save_json_file(self, out, schema_dict, indent): with open(out, "w") as outfile: json.dump(schema_dict, outfile, indent=indent, sort_keys=True) + def save_graphql_file(self, out, schema): + with open(out, "w") as outfile: + outfile.write(print_schema(schema)) + def get_schema(self, schema, out, indent): schema_dict = {"data": schema.introspect()} if out == "-": self.stdout.write(json.dumps(schema_dict, indent=indent, sort_keys=True)) else: - self.save_file(out, schema_dict, indent) + # Determine format + _, file_extension = os.path.splitext(out) + + if file_extension == ".graphql": + self.save_graphql_file(out, schema) + elif file_extension == ".json": + self.save_json_file(out, schema_dict, indent) + else: + raise CommandError( + 'Unrecognised file format "{}"'.format(file_extension) + ) style = getattr(self, "style", None) success = getattr(style, "SUCCESS", lambda x: x) - self.stdout.write(success("Successfully dumped GraphQL schema to %s" % out)) + self.stdout.write( + success("Successfully dumped GraphQL schema to {}".format(out)) + ) def handle(self, *args, **options): options_schema = options.get("schema") diff --git a/graphene_django/tests/test_command.py b/graphene_django/tests/test_command.py index dbabafa33..8b0a8e6a0 100644 --- a/graphene_django/tests/test_command.py +++ b/graphene_django/tests/test_command.py @@ -1,17 +1,21 @@ +from textwrap import dedent + from django.core import management -from mock import patch, mock_open +from mock import mock_open, patch from six import StringIO +from graphene import ObjectType, Schema, String + -@patch("graphene_django.management.commands.graphql_schema.Command.save_file") -def test_generate_file_on_call_graphql_schema(savefile_mock, settings): +@patch("graphene_django.management.commands.graphql_schema.Command.save_json_file") +def test_generate_json_file_on_call_graphql_schema(savefile_mock, settings): out = StringIO() management.call_command("graphql_schema", schema="", stdout=out) assert "Successfully dumped GraphQL schema to schema.json" in out.getvalue() @patch("json.dump") -def test_files_are_canonical(dump_mock): +def test_json_files_are_canonical(dump_mock): open_mock = mock_open() with patch("graphene_django.management.commands.graphql_schema.open", open_mock): management.call_command("graphql_schema", schema="") @@ -25,3 +29,34 @@ def test_files_are_canonical(dump_mock): assert ( dump_mock.call_args[1]["indent"] > 0 ), "output should be pretty-printed by default" + + +def test_generate_graphql_file_on_call_graphql_schema(): + class Query(ObjectType): + hi = String() + + mock_schema = Schema(query=Query) + + open_mock = mock_open() + with patch("graphene_django.management.commands.graphql_schema.open", open_mock): + management.call_command( + "graphql_schema", schema=mock_schema, out="schema.graphql" + ) + + open_mock.assert_called_once() + + handle = open_mock() + assert handle.write.called_once() + + schema_output = handle.write.call_args[0][0] + assert schema_output == dedent( + """\ + schema { + query: Query + } + + type Query { + hi: String + } + """ + )