GraphQL Integration
This guide will go over using GraphQL over RSocket, both client and server side. This document assumes you know how to set up an RSocket server with a routing handler.
To use the graphql integration, install using pip install rsocket[graphql]
The implementation uses graphql-core on the server side, and gql for the client side.
Schema
The following examples use the given GraphQL schema:
type Query {
greeting: Greeting
}
type Subscription {
greetings: Greeting
}
type Greeting {
message: String
}
Server
We will construct a simple server which will respond to requests to the schema given in the previous section. First we will define the resolve methods:
import asyncio
async def greeting(*args):
return {
'message': "Hello world"
}
def greetings(*args):
async def results():
for i in range(10):
yield {'greetings': {'message': f"Hello world {i}"}}
await asyncio.sleep(1)
return results()
Load the schema from the file, and connect the methods to it:
from graphql import build_schema
with open('rsocket.graphqls') as fd:
schema = build_schema(fd.read())
schema.query_type.fields['greeting'].resolve = greeting
schema.subscription_type.fields['greetings'].subscribe = greetings
Finally, expose this schema via RSocket:
import asyncio
import logging
import sys
from rsocket.graphql.server_helper import graphql_handler
from rsocket.routing.routing_request_handler import RoutingRequestHandler
from rsocket.rsocket_server import RSocketServer
from rsocket.transports.tcp import TransportTCP
def handler_factory():
return RoutingRequestHandler(graphql_handler(schema, 'graphql'))
async def run_server(server_port):
logging.info('Starting server at localhost:%s', server_port)
def session(*connection):
RSocketServer(TransportTCP(*connection), handler_factory=handler_factory)
server = await asyncio.start_server(session, 'localhost', server_port)
async with server:
await server.serve_forever()
if __name__ == '__main__':
port = sys.argv[1] if len(sys.argv) > 1 else 9191
logging.basicConfig(level=logging.DEBUG)
asyncio.run(run_server(port))
Assuming you already know how to set up an RSocket server over TCP, the above code should look familiar.
The connection between RSocket and GraphQL is done using the graphql_handler
(Line 12) method which accepts 2 arguments:
- The GraphQL schema object.
- The RSocket route under which the schema will be available, both queries, and subscriptions.
Client
The following example client can be used with the server defined in the previous section.
import asyncio
import logging
import sys
from gql import Client
from rsocket.extensions.mimetypes import WellKnownMimeTypes
from rsocket.graphql.rsocket_transport import RSocketTransport
from rsocket.helpers import single_transport_provider
from rsocket.rsocket_client import RSocketClient
from rsocket.transports.tcp import TransportTCP
async def main(server_port: int):
connection = await asyncio.open_connection('localhost', server_port)
async with RSocketClient(single_transport_provider(TransportTCP(*connection)),
metadata_encoding=WellKnownMimeTypes.MESSAGE_RSOCKET_COMPOSITE_METADATA) as client:
with open('rsocket.graphqls') as fd:
schema = build_schema(fd.read())
graphql = Client(
schema=schema,
transport=RSocketTransport(client),
)
if __name__ == '__main__':
port = sys.argv[1] if len(sys.argv) > 1 else 9191
logging.basicConfig(level=logging.DEBUG)
asyncio.run(main(port))
On the client side, an RSocket connection is first opened, and then passed as the transport to a GraphQL client (Line 22-25).
The graphql client can be used as usual, using the execute_async
and subscribe_async
methods, as in these examples:
async def subscription(graphql: Client):
async for response in graphql.subscribe_async(
document=gql("""
subscription {
greetings {message}
}
"""),
get_execution_result=True):
print(response.data)
async def greeting(graphql: Client):
response = await graphql.execute_async(
gql("""query { greeting { message } }"""),
get_execution_result=True)
assert response.data['greeting']['message'] == 'Hello world'
print(response.data)