diff --git a/README.md b/README.md index b071e54..de1a74f 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Websocket server for GraphQL subscriptions. Currently supports: * [aiohttp](https://github.com/graphql-python/graphql-ws#aiohttp) * [Gevent](https://github.com/graphql-python/graphql-ws#gevent) +* Sanic (uses [websockets](https://github.com/aaugustin/websockets/) library) # Installation instructions @@ -40,6 +41,29 @@ app.router.add_get('/subscriptions', subscriptions) web.run_app(app, port=8000) ``` +### Sanic + +Works with any framework that uses the websockets library for +it's websocket implementation. For this example, plug in +your Sanic server. + +```python +from graphql_ws.websockets_lib import WsLibSubscriptionServer + + +app = Sanic(__name__) + +subscription_server = WsLibSubscriptionServer(schema) + +@app.websocket('/subscriptions', subprotocols=['graphql-ws']) +async def subscriptions(request, ws): + await subscription_server.handle(ws) + return ws + + +app.run(host="0.0.0.0", port=8000) +``` + And then, plug into a subscribable schema: ```python diff --git a/examples/websockets_lib/__init__.py b/examples/websockets_lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/websockets_lib/app.py b/examples/websockets_lib/app.py new file mode 100644 index 0000000..0de6988 --- /dev/null +++ b/examples/websockets_lib/app.py @@ -0,0 +1,31 @@ +from graphql_ws.websockets_lib import WsLibSubscriptionServer +from graphql.execution.executors.asyncio import AsyncioExecutor +from sanic import Sanic, response +from sanic_graphql import GraphQLView +from schema import schema +from template import render_graphiql + +app = Sanic(__name__) + + +@app.listener('before_server_start') +def init_graphql(app, loop): + app.add_route(GraphQLView.as_view(schema=schema, + executor=AsyncioExecutor(loop=loop)), + '/graphql') + + +@app.route('/graphiql') +async def graphiql_view(request): + return response.html(render_graphiql()) + +subscription_server = WsLibSubscriptionServer(schema) + + +@app.websocket('/subscriptions', subprotocols=['graphql-ws']) +async def subscriptions(request, ws): + await subscription_server.handle(ws) + return ws + + +app.run(host="0.0.0.0", port=8000) diff --git a/examples/websockets_lib/requirements.txt b/examples/websockets_lib/requirements.txt new file mode 100644 index 0000000..6d3e723 --- /dev/null +++ b/examples/websockets_lib/requirements.txt @@ -0,0 +1,4 @@ +graphql_ws +sanic>=0.7.0 +graphene>=2.0 +sanic-graphql>=1.1.0 diff --git a/examples/websockets_lib/schema.py b/examples/websockets_lib/schema.py new file mode 100644 index 0000000..3c23d00 --- /dev/null +++ b/examples/websockets_lib/schema.py @@ -0,0 +1,34 @@ +import random +import asyncio +import graphene + + +class Query(graphene.ObjectType): + base = graphene.String() + + +class RandomType(graphene.ObjectType): + seconds = graphene.Int() + random_int = graphene.Int() + + +class Subscription(graphene.ObjectType): + count_seconds = graphene.Float(up_to=graphene.Int()) + random_int = graphene.Field(RandomType) + + async def resolve_count_seconds(root, info, up_to=5): + for i in range(up_to): + print("YIELD SECOND", i) + yield i + await asyncio.sleep(1.) + yield up_to + + async def resolve_random_int(root, info): + i = 0 + while True: + yield RandomType(seconds=i, random_int=random.randint(0, 500)) + await asyncio.sleep(1.) + i += 1 + + +schema = graphene.Schema(query=Query, subscription=Subscription) diff --git a/examples/websockets_lib/template.py b/examples/websockets_lib/template.py new file mode 100644 index 0000000..03587bb --- /dev/null +++ b/examples/websockets_lib/template.py @@ -0,0 +1,124 @@ + +from string import Template + + +def render_graphiql(): + return Template(''' + + +
+ +