Previous articles are "Open Chat", this means "Not authenticated users can post and read".
Then, this article shows "Closed Chat".
First, we just use @auth
directive.
Second, we add a Subscription type with an argument.
Third, we update both @auth
directive and a Subscription type.
TOC
Section | Title |
---|---|
3.1 | Use @auth directive and perform Authentication |
3.2 | Add a Subscription type with an argument |
3.3 | Closed post, Open read chat (Update both @auth directive and a Subscription) |
3.1 Use @auth
directive and perform Authentication
Add and use auth
$ amplify add auth
Scanning for plugins...
Plugin scan successful
Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Username
Do you want to configure advanced settings? No, I am done.
Successfully added auth resource sampleamplifysubscriXXXXXXXX locally
Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
$
And, push project.
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ---------------------------- | --------- | ----------------- |
| Auth | sampleamplifysubscriXXXXXXXX | Create | awscloudformation |
| Api | sampleamplifysubscri | No Change | awscloudformation |
? Are you sure you want to continue? Yes
⠙ Updating resources in the cloud. This may take a few minutes...
(snip)
✔ All resources are updated in the cloud
$
Then, update api.
$ amplify update api
? Please select from one of the below mentioned services: GraphQL
? Select from the options below Update auth settings
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? No
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
The API_KEY auth type has been removed from the API.
If other resources depend on this API, run "amplify update <category>" and reselect this API to remove the dependency on the API key.
⚠️ This must be done before running "amplify push" to prevent a push failure
Successfully updated resource
$
This mean, we can use @auth
directive and can only use userPools
.
Update graphql schema file.
amplify/backend/api/sampleamplifysubscri/schema.graphql
type CloseRoomChat
@model
@auth(rules: [{ allow: owner, provider: userPools }]) {
id: ID!
roomName: String!
message: String!
}
And, push project again.
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ---------------------------- | --------- | ----------------- |
| Api | sampleamplifysubscri | Update | awscloudformation |
| Auth | sampleamplifysubscriXXXXXXXX | No Change | 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
$
Implement Sign-in page.
Please see official document.
https://docs.amplify.aws/ui/auth/authenticator/q/framework/vue
And this code.
src/views/SignIn.vue
Implement Closed Chat page.
<template>
<v-container>
<v-row>
<v-col cols="12">
<v-card>
<v-card-title>Multi-room Close Chat</v-card-title>
<v-card-text
>Only authenticated users can use this chat. All subscriptions are
received.
</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 { Auth, API, graphqlOperation } from 'aws-amplify'
import { createCloseRoomChat } from '@/graphql/mutations'
import { onCreateCloseRoomChat } from '@/graphql/subscriptions'
import ChatList from '@/components/ChatList'
export default {
components: { ChatList },
data: function() {
return {
user: null,
roomName: null,
inputMessage: '',
rooms: ['room1', 'room2'],
messages: {
room1: [],
room2: [],
},
subscriptionMessages: {
room1: [],
room2: [],
},
onCreateMultiRoomChatSubscriptions: {
room1: null,
room2: null,
},
}
},
created: async function() {
this.user = await Auth.currentUserInfo()
this.setSubscribeByRoomName('room1')
},
beforeDestroy: function() {
this.clearSubscriptions()
},
methods: {
sendMessage: async function() {
const message = await API.graphql(
graphqlOperation(createCloseRoomChat, {
input: { message: this.inputMessage, roomName: this.roomName },
}),
)
console.log(message)
this.messages[this.roomName].push(message.data.createCloseRoomChat)
this.inputMessage = ''
},
setSubscribeByRoomName(roomName) {
this.clearSubscriptions()
this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql(
graphqlOperation(onCreateCloseRoomChat, { owner: this.user.username }),
).subscribe({
next: ({ provider, value }) => {
console.log({ provider, value })
this.subscriptionMessages[
value.data.onCreateCloseRoomChat.roomName
].push(value.data.onCreateCloseRoomChat)
},
})
},
clearSubscriptions() {
this.rooms.forEach(room => {
if (this.onCreateMultiRoomChatSubscriptions[room]) {
this.onCreateMultiRoomChatSubscriptions[room].unsubscribe()
}
this.onCreateMultiRoomChatSubscriptions[room] = null
})
},
},
}
</script>
<style></style>
See other files:
https://github.com/tacck/sample-amplify-subscriptions/tree/3-1-close-chat
The important point is here.
(snip)
import { Auth, API, graphqlOperation } from 'aws-amplify'
import { createCloseRoomChat } from '@/graphql/mutations'
import { onCreateCloseRoomChat } from '@/graphql/subscriptions'
(snip)
created: async function() {
this.user = await Auth.currentUserInfo()
this.setSubscribeByRoomName('room1')
},
(snip)
sendMessage: async function() {
const message = await API.graphql(
graphqlOperation(createCloseRoomChat, {
...
this.messages[this.roomName].push(message.data.createCloseRoomChat)
...
(snip)
setSubscribeByRoomName(roomName) {
this.clearSubscriptions()
this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql(
graphqlOperation(onCreateCloseRoomChat, { owner: this.user.username }),
...
this.subscriptionMessages[
value.data.onCreateCloseRoomChat.roomName
].push(value.data.onCreateCloseRoomChat)
...
(snip)
createCloseRoomChat
use same as createRoomChat
used previous article.
onCreateCloseRoomChat
use instead of onCreateRoomChat
used previous article.
And, onCreateCloseRoomChat
needs with argument owner
.
owner
information is got like this.
this.user = await Auth.currentUserInfo()
this.user.username // your sign-in username
Anyway, now we can check our first "Closed Chat".
But when you try this, You may be a little disappointed.
You post message and receive your own message.
Next, you open another browser, sign-in another user, open "Closed Chat", then post message.
You can't receive another message on original browser.
3.2 Add a Subscription type with an argument
Update graphql schema
So, we add a Subscription type with an argument roomName
like onCreateRoomChatByRoomName
that added by previous article.
Update graphql schema file.
amplify/backend/api/sampleamplifysubscri/schema.graphql
type Subscription {
onCreateRoomChatByRoomName(roomName: String!): RoomChat
@aws_subscribe(mutations: ["createRoomChat"])
onCreateCloseRoomChatByRoomName(roomName: String!): CloseRoomChat
@aws_subscribe(mutations: ["createCloseRoomChat"])
}
And, push project.
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ---------------------------- | --------- | ----------------- |
| Api | sampleamplifysubscri | Update | awscloudformation |
| Auth | sampleamplifysubscriXXXXXXXX | No Change | 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)
✔ All resources are updated in the cloud
GraphQL endpoint: https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql
$
Update Closed Chat
<template>
<v-container>
<v-row>
<v-col cols="12">
<v-card>
<v-card-title>Multi-room Close Chat</v-card-title>
<v-card-text
>Only authenticated users can use this chat. All subscriptions are
received.
</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 { Auth, API, graphqlOperation } from 'aws-amplify'
import { createCloseRoomChat } from '@/graphql/mutations'
import { onCreateCloseRoomChatByRoomName } from '@/graphql/subscriptions'
import ChatList from '@/components/ChatList'
export default {
components: { ChatList },
data: function() {
return {
user: null,
roomName: null,
inputMessage: '',
rooms: ['room1', 'room2'],
messages: {
room1: [],
room2: [],
},
subscriptionMessages: {
room1: [],
room2: [],
},
onCreateMultiRoomChatSubscriptions: {
room1: null,
room2: null,
},
}
},
created: async function() {
this.user = await Auth.currentUserInfo()
this.setSubscribeByRoomName('room1')
},
beforeDestroy: function() {
this.clearSubscriptions()
},
methods: {
sendMessage: async function() {
const message = await API.graphql(
graphqlOperation(createCloseRoomChat, {
input: { message: this.inputMessage, roomName: this.roomName },
}),
)
console.log(message)
this.messages[this.roomName].push(message.data.createCloseRoomChat)
this.inputMessage = ''
},
setSubscribeByRoomName(roomName) {
this.clearSubscriptions()
this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql(
graphqlOperation(onCreateCloseRoomChatByRoomName, {
roomName: roomName,
}),
).subscribe({
next: ({ provider, value }) => {
console.log({ provider, value })
this.subscriptionMessages[
value.data.onCreateCloseRoomChatByRoomName.roomName
].push(value.data.onCreateCloseRoomChatByRoomName)
},
})
},
clearSubscriptions() {
this.rooms.forEach(room => {
if (this.onCreateMultiRoomChatSubscriptions[room]) {
this.onCreateMultiRoomChatSubscriptions[room].unsubscribe()
}
this.onCreateMultiRoomChatSubscriptions[room] = null
})
},
},
}
</script>
<style></style>
See other files:
https://github.com/tacck/sample-amplify-subscriptions/tree/3-2-multi-room-close-chat
The important point is here.
(snip)
import { onCreateCloseRoomChatByRoomName } from '@/graphql/subscriptions'
(snip)
setSubscribeByRoomName(roomName) {
...
this.onCreateMultiRoomChatSubscriptions[roomName] = API.graphql(
graphqlOperation(onCreateCloseRoomChatByRoomName, {
roomName: roomName,
}),
...
this.subscriptionMessages[
value.data.onCreateCloseRoomChatByRoomName.roomName
].push(value.data.onCreateCloseRoomChatByRoomName)
...
(snip)
onCreateCloseRoomChatByRoomName
use same as onCreateRoomChatByRoomName
used previous article.
And, onCreateRoomChatByRoomName
needs with argument roomName
.
You try this program, you can receive another user's message.
This mean, "only authorized users can post and read this chat room."
3.3 Closed post, Open read chat (Update both @auth
directive and a Subscription)
Previous program is not bad.
But, we often use "authorized users can post but all users can read" system.
So, we make it.
Update api for multi-authorization
Previously, we use only Amazon Cognito User Pool
.
Here, we use Amazon Cognito User Pool
and API key
.
$ amplify update api
? Please select from one of the below mentioned services: GraphQL
? Select from the options below Update auth settings
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API API key
API key configuration
? Enter a description for the API key:
? After how many days from now the API key should expire (1-365): 365
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
The API_KEY auth type has been added to the API.
⚠️ If other resources depend on this API and need access to the API key, run "amplify update <category>" and reselect this API as a dependency to add the API key dependency.
Successfully updated resource
$
Then, update graphql schema file.
amplify/backend/api/sampleamplifysubscri/schema.graphql
type CloseRoomChat
@model
@auth(
rules: [
{ allow: owner, provider: userPools }
{ allow: public, provider: apiKey, operations: [read] }
]
) {
id: ID!
roomName: String!
message: String!
}
type Subscription {
onCreateRoomChatByRoomName(roomName: String!): RoomChat
@aws_subscribe(mutations: ["createRoomChat"])
onCreateCloseRoomChatByRoomName(roomName: String!): CloseRoomChat
@aws_subscribe(mutations: ["createCloseRoomChat"])
@aws_api_key
}
Notice:
@aws_api_key
is not in "Amplify docs".
https://docs.amplify.aws/This appears in "AppSync docs".
https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html#using-additional-authorization-modes
And, push project.
$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ---------------------------- | --------- | ----------------- |
| Api | sampleamplifysubscri | Update | awscloudformation |
| Auth | sampleamplifysubscriXXXXXXXX | No Change | 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)
✔ All resources are updated in the cloud
GraphQL endpoint: https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.ap-northeast-1.amazonaws.com/graphql
GraphQL API KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
$
Finally, we get "authorized users can post but all users can read" chat system.
You open a browser and open "Closed Chat" (use not authorized user).
Then, you open another browser, sign-in another user, open "Closed Chat", then post message.
You can receive the message on original browser!
Top comments (0)