Repository: mirumee/ariadne

Issue:
Create shortcut function for GraphQLMiddleware.make_simple_server
Getting started with Ariadne could be made even simpler by providing shortcut function abstracting the `GraphQLMiddleware` away on first contact, thus saving users possible confusion about what they really are doing.


Discussion:

Resolving patch:
diff --git a/ariadne/__init__.py b/ariadne/__init__.py
--- a/ariadne/__init__.py
+++ b/ariadne/__init__.py
@@ -1,6 +1,6 @@
 from .executable_schema import make_executable_schema
 from .resolvers import add_resolve_functions_to_schema, default_resolver, resolve_to
-from .utils import gql
+from .utils import gql, start_simple_server
 from .wsgi_middleware import GraphQLMiddleware
 
 __all__ = [
@@ -10,4 +10,5 @@
     "make_executable_schema",
     "resolve_to",
     "gql",
+    "start_simple_server",
 ]
diff --git a/ariadne/utils.py b/ariadne/utils.py
--- a/ariadne/utils.py
+++ b/ariadne/utils.py
@@ -1,6 +1,26 @@
+from typing import List, Union
+
 from graphql import parse
 
+from .wsgi_middleware import GraphQLMiddleware
+
 
 def gql(value: str) -> str:
     parse(value)
     return value
+
+
+def start_simple_server(
+    type_defs: Union[str, List[str]],
+    resolvers: Union[dict, List[dict]],
+    host: str = "127.0.0.1",
+    port: int = 8888,
+):
+    try:
+        print("Simple GraphQL server is running on the http://%s:%s" % (host, port))
+        graphql_server = GraphQLMiddleware.make_simple_server(
+            type_defs, resolvers, host, port
+        )
+        graphql_server.serve_forever()
+    except KeyboardInterrupt:
+        pass


Test patch:
diff --git a/tests/test_start_simple_server.py b/tests/test_start_simple_server.py
new file mode 100644
--- /dev/null
+++ b/tests/test_start_simple_server.py
@@ -0,0 +1,78 @@
+import pytest
+
+from ariadne import GraphQLMiddleware, start_simple_server
+
+
+@pytest.fixture
+def simple_server_mock(mocker):
+    return mocker.Mock(serve_forever=mocker.Mock(return_value=True))
+
+
+@pytest.fixture
+def middleware_make_simple_server_mock(mocker):
+    return mocker.patch.object(
+        GraphQLMiddleware, "make_simple_server", new=mocker.Mock()
+    )
+
+
+@pytest.fixture
+def type_defs():
+    return """
+        type Query {
+            hello: String
+        }
+    """
+
+
+@pytest.fixture
+def resolvers():
+    return {}
+
+
+def test_wsgi_simple_server_serve_forever_is_called(
+    mocker, type_defs, resolvers, simple_server_mock
+):
+    mocker.patch("wsgiref.simple_server.make_server", return_value=simple_server_mock)
+    start_simple_server(type_defs, resolvers)
+    simple_server_mock.serve_forever.assert_called_once()
+
+
+def test_keyboard_interrupt_is_handled_gracefully(mocker, type_defs, resolvers):
+    mocker.patch(
+        "wsgiref.simple_server.make_server", side_effect=KeyboardInterrupt("test")
+    )
+    start_simple_server(type_defs, resolvers)
+
+
+def test_type_defs_resolvers_host_and_ip_are_passed_to_graphql_middleware(
+    middleware_make_simple_server_mock
+):
+    start_simple_server("type_defs", "resolvers", "0.0.0.0", 4444)
+    middleware_make_simple_server_mock.assert_called_once_with(
+        "type_defs", "resolvers", "0.0.0.0", 4444
+    )
+
+
+def test_default_host_and_ip_are_passed_to_graphql_middleware_if_not_set(
+    middleware_make_simple_server_mock
+):
+    start_simple_server("type_defs", "resolvers")
+    middleware_make_simple_server_mock.assert_called_once_with(
+        "type_defs", "resolvers", "127.0.0.1", 8888
+    )
+
+
+def test_default_host_and_ip_are_printed_on_server_creation(
+    middleware_make_simple_server_mock, capsys
+):  # pylint: disable=unused-argument
+    start_simple_server("", {})
+    captured = capsys.readouterr()
+    assert "http://127.0.0.1:8888" in captured.out
+
+
+def test_custom_host_and_ip_are_printed_on_server_creation(
+    middleware_make_simple_server_mock, capsys
+):  # pylint: disable=unused-argument
+    start_simple_server("", {}, "0.0.0.0", 4444)
+    captured = capsys.readouterr()
+    assert "http://0.0.0.0:4444" in captured.out