@carlosdp/socket-io-graphql-client

Execute GraphQL operations against a @n1ru4l/socket-io-graphql-server instance.

Usage no npm install needed!

<script type="module">
  import carlosdpSocketIoGraphqlClient from 'https://cdn.skypack.dev/@carlosdp/socket-io-graphql-client';
</script>

README

@n1ru4l/socket-io-graphql-client

npm version npm downloads

Execute GraphQL operations against a @n1ru4l/socket-io-graphql-server instance.

If you want to see usage we recommend checking out the example clients for relay, apollo and urql!

Install Instructions

yarn add -E @n1ru4l/socket-io-graphql-client

API

createSocketIOGraphQLClient

import { io } from "socket.io-client";
import { createSocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
const socket = io();
const socketIOGraphQLClient = createSocketIOGraphQLClient(socket);

{
  // execute returns a AsyncIterable that will publish the values for the operation
  const asyncIterator = socketIOGraphQLClient.execute({
    operation: /* GraphQL */ `
      query messages {
        id
        content
      }
    `,
  });

  for await (const value of asyncIterator) {
    console.log(value);
  }
}

{
  const asyncIterator = socketIOGraphQLClient.execute({
    operation: /* GraphQL */ `
      query messages @live {
        id
        content
      }
    `,
  });

  for await (const value of asyncIterator) {
    console.log(value);
  }
}

{
  const asyncIterator = socketIOGraphQLClient.execute(
    {
      operation: /* GraphQL */ `
        subscription onNewMessage {
          onNewMessage {
            id
            content
          }
        }
      `,
    }
  );

  // dispose subscription in 5 seconds
  setTimeout(() => asyncIterator.return.?(), 5000);

  for await (const value of asyncIterator) {
    console.log(value);
  }
}

Recipes

GraphiQL Fetcher

import { io } from "socket.io-client";
import { createSocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import "graphiql/graphiql.css";
import GraphiQL from "graphiql";

const socket = io();
const socketIOGraphQLClient = createSocketIOGraphQLClient(socket);

const fetcher: Fetcher = ({ query: operation, ...restGraphQLParams }: any) =>
 socketIOGraphQLClient.execute({
   operation,
   ...restGraphQLParams,
 });

export const LiveGraphiQL = (): React.ReactElement => (
  <GraphiQL fetcher={fetcher} />
);

Relay Environment

As used in the relay todo example app(https://github.com/n1ru4l/graphql-live-queries/tree/main/packages/todo-example/client-relay).

import { SocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import {
  Environment,
  Network,
  RecordSource,
  Store,
  Observable,
  GraphQLResponse,
  RequestParameters,
  Variables,
} from "relay-runtime";

export const createRelayEnvironment = (
  networkInterface: SocketIOGraphQLClient<GraphQLResponse, Error>
) => {
  const execute = (request: RequestParameters, variables: Variables) => {
    if (!request.text) throw new Error("Missing document.");
    const { text: operation, name } = request;

    return Observable.create<GraphQLResponse>((sink) =>
      applyAsyncIterableIteratorToSink(
        networkInterface.execute({
          operation,
          variables,
          operationName: name,
        }),
        sink
      )
    );
  };

  const network = Network.create(execute, execute);
  const store = attachNotifyGarbageCollectionBehaviourToStore(
    new Store(new RecordSource())
  );

  return new Environment({
    network,
    store,
  });
};

Apollo Client

As used in the apollo client todo example app(https://github.com/n1ru4l/graphql-live-queries/tree/main/packages/todo-example/client-apollo).

import { SocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import {
  ApolloClient,
  InMemoryCache,
  ApolloLink,
  Operation,
  Observable,
  FetchResult,
  Observable,
} from "@apollo/client";
import { print } from "graphql";

class SocketIOGraphQLApolloLink extends ApolloLink {
  private networkLayer: SocketIOGraphQLClient;
  constructor(networkLayer: SocketIOGraphQLClient) {
    super();
    this.networkLayer = networkLayer;
  }

  public request(operation: Operation): Observable<FetchResult> | null {
    return new Observable((sink) =>
      applyAsyncIterableIteratorToSink(
        this.networkLayer.execute({
          operationName: operation.operationName,
          operation: print(operation.query),
          variables: operation.variables,
        }),
        sink
      )
    );
  }
}

export const createApolloClient = (networkInterface: SocketIOGraphQLClient) => {
  return new ApolloClient({
    link: new SocketIOGraphQLApolloLink(networkInterface),
    cache: new InMemoryCache(),
  });
};

Urql

As used in the urql todo example app(https://github.com/n1ru4l/graphql-live-queries/tree/main/packages/todo-example/client-urql).

import { SocketIOGraphQLClient } from "@n1ru4l/socket-io-graphql-client";
import { applyAsyncIterableIteratorToSink } from "@n1ru4l/push-pull-async-iterable-iterator";
import {
  Client,
  dedupExchange,
  cacheExchange,
  subscriptionExchange,
  ExecutionResult,
} from "urql";

export const createUrqlClient = (
  networkInterface: SocketIOGraphQLClient<ExecutionResult>
) => {
  return new Client({
    url: "noop",
    exchanges: [
      dedupExchange,
      cacheExchange,
      subscriptionExchange({
        forwardSubscription: (operation) => ({
          subscribe: (sink) => ({
            unsubscribe: applyAsyncIterableIteratorToSink(
              networkInterface.execute({
                operation: operation.query,
                variables: operation.variables,
              }),
              sink
            ),
          }),
        }),
        enableAllOperations: true,
      }),
    ],
  });
};