Introduction GraphQL with WebSocket
GraphQL is a great way to write customizable API's and combine numerous services into one endpoint. Mainly, the idea has a single endpoint, but getting the different combinations of models is amazing, mostly for the organizations working with large-scale multi-platform applications with various developers and designers.What is a Web-Socket?
According to MDN, " The WebSocket API is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply."Real-time data, Connections, Scalability, fan-out and broadcasting are all handled by Intelligent Client Libraries and AppSync. Source: New features that will enhance your Real-Time experienceWebSocket is a protocol that gives a way to exchange data between browsers and servers over a persistent connection. It's very beneficial for applications that need continuous data exchange, for example- real-time systems, online games, and many more. A new WebSocket connection is opened by using a special WebSocket protocol in the regular URL.
What is a GraphQL Subscription?
Subscriptions are a technique to fetch data, just like queries. But, subscriptions maintain an active connection to the GraphQL server through WebSocket. This allows the server to push updates to the subscription's result over time. They are very helpful in notifying the client about any updates to the real-time requests. Whenever the backend data changes, the client will automatically get notified through the active server connection.How to implement?
Here Apollo Client comes into the picture. The Apollo Client is a comprehensive state management library for JavaScript, enabling a user to organize both local and remote data with GraphQL. It is used to fetch, modify, and cache application data while automatically updating the user interface. The core @apollo/client library gives built-in integration with React js, and the larger Apollo community supports integrations for the other popular view layers. Hence it is comfortable for all those developers searching to control its data in the Front-End.A query based language for REST APIs used to retrieve the exact data needed. Click to explore about our, Apollo GraphQL Features
What is a Subscriber?
Subscriber has to be defined both on the client-side also on the server-side. But, for now, we will handle the subscriber on the client-side because server-side subscriber configuration might vary depending on projects to projects. A server-side subscriber can be served through GoLang, Node JS and many more libraries, but the client-side handling mostly remains the same for various frameworks, libraries, and tools. You can use any open source project to handle client-side subscriptions with Apollo, but here in this, I will use an open-source project named LitmusChaos.Defining a Subscriber
In this project, we are going to deal with various Workflow Data. We have set up the Subscriber in such a way that we can listen to the Workflow Events and receive several necessary parameters that are required for Workflow Representation Data and many more.const WORKFLOW_EVENTS = gql`
subscription workflowEvents($projectID: String!) {
workflowEventListener(project_id: $projectID) {
workflow_id
workflow_name
workflow_run_id
execution_data
project_id
cluster_name
last_updated
}
}`;
Whenever an Apollo Client performs the workflow events subscription, it connects to the GraphQL server and listens for response data. But like a query, it doesn't anticipate that the server will operate at once and return a response. Instead, our server only pushes data to the client whenever a particular event takes place at the backend.
Subscriber Execution
Apollo gives us various hooks like Subscription, user query, and many more, making life more comfortable while performing and executing queries from a GraphQL server. Here we will be executing a previously defined subscription to listen for an event and keep the frontend up to date with any data changes at the backend when we are subscribed in that respective workflow. In Apollo Client, whenever a query returns a result, it contains a subscriber more function.const { subscribeToMore, error, data } = useQuery( WORKFLOW_DETAILS,
{
variables: { projectID: selectedProjectID },
fetchPolicy: 'cache-and-network',
}
);
// Using subscription to get real-time data
subscribeToMore({
document: WORKFLOW_EVENTS,
variables: { projectID: selectedProjectID },
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
const modifiedWorkflows = prev.getWorkFlowRuns.slice();
return { ...prev, getWorkFlowRuns: modifiedWorkflows };
},
});
This subscription is making a query of the data at the start and then listening to the server for further updates on the same Workflow Event if any new data is generated. Hence the subscriber updates the old data with the latest information is generated.
Setting the transport
Subscriptions keep a constant connection. Accordingly, Apollo Client subscriptions regularly communicate over WebSocket through the community-maintained subscriptions-transport-ws library. Here we need to install some libraries. npm install @apollo/client subscriptions-transport-ws
Then import and initialize a WebSocketLink where the ApolloClient is initialized before. import { WebSocketLink } from '@apollo/client/link/ws';
const wsLink = new WebSocketLink({
uri: `ws:<GraphQL Endpoint>`,
options: {
reconnect: true,
lazy: true
}
});
In this project, our use case allows us to handle both WebSocket and HTTP requests hence our code look like. import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
split,
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import * as React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import config from './config'; // Stores the GraphQL Configuration
import App from './containers/app/App';
import configureStore from './redux/configureStore';
import getToken from './utils/getToken';
const { persistor, store } = configureStore();
// HTTP Link
const httpLink = new HttpLink({
uri: `${config.grahqlEndpoint}/query`,
});
// Adds Authentication Headers on HTTP as well as was requests
const authLink = setContext((_, { headers }) => {
const token = getToken();
return {
headers: {
...headers,
authorization: token,
},
};
});
// WebSocket Link
const wsLink = new WebSocketLink({
uri: `${config.grahqlEndpointSubscription}/query`,
options: {
reconnect: true,
lazy: true,
},
});
// Send query request based on type
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
authLink.concat(wsLink),
authLink.concat(httpLink)
);
// Apollo Client
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
});
const ReduxRoot = () => {
return (
<ApolloProvider client={client}>
<Provider store={store}>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</Provider>
</ApolloProvider>
);
};
export default ReduxRoot;
The fusion of digital technology into all industry sides, changing how you use and convey it to customers. Download to explore the potential of Digital Transformation
Conclusion
Using this logic, mutations and queries will use HTTP as normal, and subscriptions will use WebSocket. There is no limitation, and you can extend this configuration and create anything your like. Do check this doc for more information.- Read more about API Testing Tools and Best Practises
- Click to know more about Scalable Data Visualization using GraphQL and ReactJS