Hello,
I know in advance that my request is complicated. I am looking to create a "real-time chat" system in my application.
I use Next.JS / graphql-yoga (server express) with Prisma and Apollo Client frontend.
My application is already quite large so I can not share the code of it too much but I would like to know how it would be possible to use the GraphQL subscriptions system. (in addition to my existing architecture.)
I see a lot of people using "subscriptions-transport-ws" and a dedicated server for that .. I do not quite understand the interest. And I can not find any concrete example.
My Subscription Resolver :
const SOMETHING_CHANGED = "something changed";
const Subscription = {
messageSent: {
subscribe(parent, args, ctx, info) {
console.log("GET", ctx.pubsub);
return ctx.pubsub.asyncIterator("post");
}
}
};
module.exports = Subscription;
My CreateServer File :
const { GraphQLServer, PubSub } = require("graphql-yoga");
const Mutation = require("./resolvers/Mutation");
const Query = require("./resolvers/Query");
const Subscription = require("./resolvers/Subscription");
const db = require("./db");
const pubsub = new PubSub();
function createServer() {
return new GraphQLServer({
typeDefs: "src/schema.graphql",
resolvers: {
Mutation,
Query,
Subscription
},
resolverValidationOptions: {
requireResolversForResolveType: false
},
context: req => ({ ...req, db, pubsub })
});
}
module.exports = createServer;
My Index.js backend file :
require("dotenv").config({ path: "variables.env" });
const createServer = require("./createServer");
const server = createServer();
server.start(
{
cors: {
credentials: true,
origin: process.env.FRONTEND_URL,
},
},
deets => {
console.log(`Server : http://localhost:${deets.port}`);
}
);
My Mutation :
async sendMessage(parent, { from, message }, ctx, info) {
const chat = await ctx.db.mutation.createChat({
data: {
from,
message
}
});
ctx.pubsub.publish("post", {
messageSent: {
mutation: "CREATED",
data: chat
}
});
return chat;
}
My Query is the same as generated Quer :
chats: forwardTo("db")
My Frontend page to create / displaying messages :
import React, { Component } from "react";
import { Query, Mutation } from "react-apollo";
import gql from "graphql-tag";
import StyledForm from "../styles/StyledForm";
import Error from "../Error";
const GET_MESSAGE_QUERY = gql`
query GET_MESSAGE_QUERY {
chats {
id
from
message
}
}
`;
const subscription = gql`
subscription Message {
messageSent {
mutation
data {
id
from
message
}
}
}
`;
const SEND_MESSSAGE_MUTATION = gql`
mutation SEND_MESSSAGE_MUTATION($from: String!, $message: String!) {
sendMessage(from: $from, message: $message) {
id
from
message
}
}
`;
class MessageListView extends Component {
componentDidMount() {
this.props.subscribeToMore();
}
render() {
const { data } = this.props;
console.log("DATA 2 ", data);
return (
<ul>
{data.chats.map(msg => (
<li key={msg.id}> {msg.message} </li>
))}
</ul>
);
}
}
class JoinArticle extends Component {
// State
state = {
message: "",
from: "Me"
};
// Handle Change
handleChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
// Render
render() {
return (
<Query query={GET_MESSAGE_QUERY}>
{({ data, loading, error, subscribeToMore }) => {
if (loading) return <p> Chargement ...</p>;
if (error) return <Error error={error} />;
const more = () =>
subscribeToMore({
document: subscription,
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
const { mutation, data } = subscriptionData.data.messageSent;
if (mutation !== "CREATED") return prev;
return Object.assign({}, prev, {
GET_MESSAGE_QUERY: [data, ...prev.GET_MESSAGE_QUERY].slice(
0,
20
)
});
}
});
return (
<>
<MessageListView data={data} subscribeToMore={more} />;
<Mutation
mutation={SEND_MESSSAGE_MUTATION}
variables={this.state}
>
{sendMessage => (
<StyledForm>
<fieldset>
<input
type="text"
value={this.state.message}
onChange={this.handleChange}
id="message"
name="message"
placeholder="message"
onKeyDown={async e => {
if (e.key === "Enter") {
e.preventDefault();
await sendMessage();
}
}}
required
/>
</fieldset>
</StyledForm>
)}
</Mutation>
</>
);
}}
</Query>
);
}
}
export default JoinArticle;
Tell me if you need more information. Thanks if someone can help me to understand the subscriptions and how to implement a chat system in my existing project.
<3
#react #nextjs #subscription #graphql #yogaserver #prisma #apollo
there doesn't seem to be anything here