DEV Community

Kihara, Takuya
Kihara, Takuya

Posted on

AWS Amplify Subscriptions Usage / 2. Multi-Room Chat

We can use the Subscriptions feature with AWS Amplify.
It's easy for us to get started, but it can be complicated.

Previous article, I show Open Chat.

In this article, I'll show you Multi-Room Chat sample.
And, there are two way implementations, one is "Easy" way, and another is "Efficient" way.

My repository:

GitHub logo tacck / sample-amplify-subscriptions

Sample code for this article. https://dev.to/tacck/series/11192

TOC


2.1 Implementations for "Easy" way

Edit GraphQL scheme file

Add a type for Multi-Room Chat.

amplify/backend/api/sampleamplifysubscri/schema.graphql

type RoomChat @model { id: ID! roomName: String! message: String! } 
Enter fullscreen mode Exit fullscreen mode

And, push project.

$ amplify push Initializing new Amplify CLI version... Done initializing new version. Scanning for plugins... Plugin scan successful ✔ Successfully pulled backend environment dev from the cloud. Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | -------------------- | --------- | ----------------- | | Api | sampleamplifysubscri | Update | awscloudformation | ? Are you sure you want to continue? Yes The following types do not have '@auth' enabled. Consider using @auth with @model - OpenChat - RoomChat Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/auth GraphQL schema compiled successfully. Edit your schema at /[YOUR_DIRECTORY]/sample-amplify-subscriptions/amplify/backend/api/sampleamplifysubscri/schema.graphql or place .graphql files in a directory at /[YOUR_DIRECTORY]/sample-amplify-subscriptions/amplify/backend/api/sampleamplifysubscri/schema ? Do you want to update code for your updated GraphQL API Yes ? Do you want to generate GraphQL statements (queries, mutations and subscription) based on your s chema types? This will overwrite your current graphql queries, mutations and subscriptions Yes ⠼ Updating resources in the cloud. This may take a few minutes... (snip) ✔ Generated GraphQL operations successfully and saved at src/graphql ✔ All resources are updated in the cloud GraphQL endpoint: https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql GraphQL API KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $  
Enter fullscreen mode Exit fullscreen mode

Write Multi-room Open Chat for "Easy" way

src/views/OpenChat.vue

<template> <v-container> <v-row> <v-col cols="12"> <v-card> <v-card-title>Multi-room Open Chat</v-card-title> <v-card-text >Anyone can use this chat. All subscriptions are receved, and received messages are set in the message list for each room.</v-card-text > </v-card> </v-col> </v-row> <v-row> <v-col cols="12"> <v-text-field v-model="inputMessage" label="New Message" outlined clearable append-outer-icon="mdi-send" @click:append-outer="sendMessage" ></v-text-field> </v-col> </v-row> <v-tabs v-model="roomName" background-color="primary" center-active centered dark > <v-tab href="#room1">room1</v-tab> <v-tab href="#room2">room2</v-tab> </v-tabs> <v-card flat> <v-tabs-items v-model="roomName"> <v-tab-item value="room1"> <v-row class="pa-2"> <v-col cols="6"> <ChatList title="Input" :list="messages.room1"></ChatList> </v-col> <v-col cols="6"> <ChatList title="Subscriptions" :list="subscriptionMessages.room1" ></ChatList> </v-col> </v-row> </v-tab-item> <v-tab-item value="room2"> <v-row class="pa-2"> <v-col cols="6"> <ChatList title="Input" :list="messages.room2"></ChatList> </v-col> <v-col cols="6"> <ChatList title="Subscriptions" :list="subscriptionMessages.room2" ></ChatList> </v-col> </v-row> </v-tab-item> </v-tabs-items> </v-card> </v-container> </template> <script> import { API, graphqlOperation } from 'aws-amplify' import { createRoomChat } from '@/graphql/mutations' import { onCreateRoomChat } from '@/graphql/subscriptions' import ChatList from '@/components/ChatList' export default { components: { ChatList }, data: function() { return { roomName: null, inputMessage: '', messages: { room1: [], room2: [], }, subscriptionMessages: { room1: [], room2: [], }, onCreateOpenChatSubscription: null, } }, created: function() { this.onCreateOpenChatSubscription = API.graphql( graphqlOperation(onCreateRoomChat), ).subscribe({ next: ({ provider, value }) => { console.log({ provider, value }) this.subscriptionMessages[value.data.onCreateRoomChat.roomName].push( value.data.onCreateRoomChat, ) }, }) }, beforeDestroy: function() { if (this.onCreateOpenChatSubscription) { this.onCreateOpenChatSubscription.unsubscribe() this.onCreateOpenChatSubscription = null } }, methods: { sendMessage: async function() { const message = await API.graphql( graphqlOperation(createRoomChat, { input: { message: this.inputMessage, roomName: this.roomName }, }), ) console.log(message) this.messages[this.roomName].push(message.data.createRoomChat) this.inputMessage = '' }, }, } </script> <style></style> 
Enter fullscreen mode Exit fullscreen mode

See other files:
https://github.com/tacck/sample-amplify-subscriptions/tree/2-1-multiroom-chat-filter

The important point is here.

(snip) created: function() { this.onCreateOpenChatSubscription = API.graphql( graphqlOperation(onCreateRoomChat), ).subscribe({ next: ({ provider, value }) => { console.log({ provider, value }) this.subscriptionMessages[value.data.onCreateRoomChat.roomName].push( value.data.onCreateRoomChat, ) }, }) }, (snip) methods: { sendMessage: async function() { const message = await API.graphql( graphqlOperation(createRoomChat, { input: { message: this.inputMessage, roomName: this.roomName }, }), ) console.log(message) this.messages[this.roomName].push(message.data.createRoomChat) this.inputMessage = '' }, }, (snip) 
Enter fullscreen mode Exit fullscreen mode

In sendMessage function, send message with roomName and set message in this.messages[this.roomName] list.

In created function, received message by subscription and set message in this.subscriptionMessages[value.data.onCreateRoomChat.roomName] list.

It's just filtering by roomName.
Very Easy way 😃.

However, there is a problem with this way.

We receive messages for "ALL" rooms.
When you see "Room2", you will not want to receive "Room1"'s messages.

Then, We implement for "Efficient" way.


2.2 Implementations for "Efficient" way

Edit GraphQL scheme file

Add a type Subscription.

amplify/backend/api/sampleamplifysubscri/schema.graphql

type Subscription { onCreateRoomChatByRoomName(roomName: String!): RoomChat @aws_subscribe(mutations: ["createRoomChat"]) } 
Enter fullscreen mode Exit fullscreen mode

This mean: When you use "createRoomChat", the server return data RoomChat that you created.

You can use onCreateRoomChatByRoomName instead of onCreateOpenChat.

And, push project.

$ amplify push Scanning for plugins... Plugin scan successful ✔ Successfully pulled backend environment dev from the cloud. Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | -------------------- | --------- | ----------------- | | Api | sampleamplifysubscri | Update | awscloudformation | ? Are you sure you want to continue? Yes The following types do not have '@auth' enabled. Consider using @auth with @model - OpenChat - RoomChat Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/auth GraphQL schema compiled successfully. Edit your schema at /[YOUR_DIRECTORY]/sample-amplify-subscriptions/amplify/backend/api/sampleamplifysubscri/schema.graphql or place .graphql files in a directory at /[YOUR_DIRECTORY]/sample-amplify-subscriptions/amplify/backend/api/sampleamplifysubscri/schema ? Do you want to update code for your updated GraphQL API Yes ? Do you want to generate GraphQL statements (queries, mutations and subscription) based on your schema types? This will overwrite your current graphql queries, mutations and subscriptions Yes ⠸ Updating resources in the cloud. This may take a few minutes... (snip) ✔ Generated GraphQL operations successfully and saved at src/graphql ✔ All resources are updated in the cloud GraphQL endpoint: https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql GraphQL API KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $ 
Enter fullscreen mode Exit fullscreen mode

Write Multi-room Open Chat for "Efficient" way

src/views/OpenChat.vue

<template> <v-container> <v-row> <v-col cols="12"> <v-card> <v-card-title>Multi-room Open Chat</v-card-title> <v-card-text >Anyone can use this chat. Now, we receive messages only selected room. </v-card-text> </v-card> </v-col> </v-row> <v-row> <v-col cols="12"> <v-text-field v-model="inputMessage" label="New Message" outlined clearable append-outer-icon="mdi-send" @click:append-outer="sendMessage" ></v-text-field> </v-col> </v-row> <v-tabs v-model="roomName" background-color="primary" center-active centered dark > <v-tab v-for="(room, index) in rooms" :key="index" :href="'#' + room" @click="setSubscribeByRoomName(room)" >{{ room }}</v-tab > </v-tabs> <v-card flat> <v-tabs-items v-model="roomName"> <v-tab-item v-for="(room, index) in rooms" :key="index" :value="room"> <v-row class="pa-2"> <v-col cols="6"> <ChatList title="Input" :list="messages[room]"></ChatList> </v-col> <v-col cols="6"> <ChatList title="Subscriptions" :list="subscriptionMessages[room]" ></ChatList> </v-col> </v-row> </v-tab-item> </v-tabs-items> </v-card> </v-container> </template> <script> import { API, graphqlOperation } from 'aws-amplify' import { createRoomChat } from '@/graphql/mutations' import { onCreateRoomChatByRoomName } from '@/graphql/subscriptions' import ChatList from '@/components/ChatList' export default { components: { ChatList }, data: function() { return { roomName: null, inputMessage: '', rooms: ['room1', 'room2'], messages: { room1: [], room2: [], }, subscriptionMessages: { room1: [], room2: [], }, onCreateMultiRoomChatSubscriptions: { room1: null, room2: null, }, } }, created: function() { this.setSubscribeByRoomName('room1') }, beforeDestroy: function() { this.clearSubscriptions() }, methods: { sendMessage: async function() { const message = await API.graphql( graphqlOperation(createRoomChat, { input: { message: this.inputMessage, roomName: this.roomName }, }), ) console.log(message) this.messages[this.roomName].push(message.data.createRoomChat) this.inputMessage = '' }, setSubscribeByRoomName(roomName) { this.clearSubscriptions() this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql( graphqlOperation(onCreateRoomChatByRoomName, { roomName: roomName }), ).subscribe({ next: ({ provider, value }) => { console.log({ provider, value }) this.subscriptionMessages[ value.data.onCreateRoomChatByRoomName.roomName ].push(value.data.onCreateRoomChatByRoomName) }, }) }, clearSubscriptions() { this.rooms.forEach(room => { if (this.onCreateMultiRoomChatSubscriptions[room]) { this.onCreateMultiRoomChatSubscriptions[room].unsubscribe() } this.onCreateMultiRoomChatSubscriptions[room] = null }) }, }, } </script> <style></style> 
Enter fullscreen mode Exit fullscreen mode

See other files:
https://github.com/tacck/sample-amplify-subscriptions/tree/2-2-multiroom-chat-subscription

The important point is here.

(snip) <v-tab v-for="(room, index) in rooms" :key="index" :href="'#' + room" @click="setSubscribeByRoomName(room)" >{{ room }}</v-tab > (snip) setSubscribeByRoomName(roomName) { this.clearSubscriptions() this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql( graphqlOperation(onCreateRoomChatByRoomName, { roomName: roomName }), ).subscribe({ next: ({ provider, value }) => { console.log({ provider, value }) this.subscriptionMessages[ value.data.onCreateRoomChatByRoomName.roomName ].push(value.data.onCreateRoomChatByRoomName) }, }) }, (snip) 
Enter fullscreen mode Exit fullscreen mode

In setSubscribeByRoomName function, we use onCreateMultiRoomChatSubscriptions with roomName.

Only this change, we receive selected room messages.

Very simple but efficient way.

Next, we see subscriptions with @auth directive.

Top comments (0)