A view days ago AWS released the L2 CDK construct for the new AppSync Events API.
With this serverless WebSocket API we can build a simple chat application with just a few lines of code.
Infrastructure
Our architecture diagram is not extensive. We use the mentioned AppSync Events API, an S3 Bucket for storing our React application and CloudFront as CDN.
CDK
AppSync Events API
We create an AppSync Events API with the new EventsApi
construct. For simplicity we keep all the defaults, including API Key as auth provider. In a, lets say, more real-world use case, you probably would choose Cognito which is also supported by AppsSync Events out of the box.
We also create a namespace for our chat application: chat
. Channel namespaces provide a scalable way to structure our API. Later in this article we will use this feature to handle multiple chatrooms, like e.g. chat/gardening
.
// Events Api
const eventsApi = new appsync.EventApi(this, "EventsApi", {
apiName: "EventsChat",
});
// Channel
eventsApi.addChannelNamespace("chat");
S3 & CloudFront
For our user interface which will be implemented as a React application we create a S3 Bucket and a CloudFront distribution.
// S3
const clientBucket = new Bucket(this, "ClientBucket", {
accessControl: BucketAccessControl.PRIVATE,
});
new BucketDeployment(this, "ClientDeployment", {
destinationBucket: clientBucket,
sources: [
Source.asset(path.resolve(__dirname, "[path-to-your-client]")),
],
});
// CloudFront
new aws_cloudfront.Distribution(this, "Distribution", {
defaultRootObject: "index.html",
errorResponses: [
{
httpStatus: 403,
responseHttpStatus: 200,
responsePagePath: "/index.html",
},
{
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: "/index.html",
},
],
defaultBehavior: {
origin:
aws_cloudfront_origins.S3BucketOrigin.withOriginAccessControl(
clientBucket
),
},
});
UI
I recommend setting up a fresh React application with Vite. Additionally I use tailwindcss to implement the UI.
In the following steps I just show the relevant parts. Of course there is some more code for rendering and handling stuff like e.g. focus. See the full example on GitHub.
We use the Amplify library which provides a very easy way to interact with the Events API. The following code is quite close to the official documentation.
Data structure
The data model for the events we will subscribe to consists of id
, type
and event
which stands for the payload.
For this example our payload includes the text of the chat message and information about the author of it.
type Event = {
id: string;
type: string;
event: {
text: string;
author: {
id: string;
name: string;
};
};
};
Subscription
As I already mentioned we can support dynamic chat rooms via channel namespaces. Therefore we simply use the URL pathname. So for the mentioned "gardening" example that could be something like https://www.my-chat-app.com/gardening
.
With the following code we can subscribe for messages in our chat room and store those in a React state.
const chatRoom = window.location.pathname;
const [messages, setMessages] = useState<Event[]>([]);
useEffect(() => {
let channel: EventsChannel;
const connectAndSubscribe = async () => {
channel = await events.connect(`chat${chatRoom}`);
channel.subscribe({
next: (data: Event) => {
setMessages((prev) => [...prev, data]);
},
error: (err) => console.error("error", err),
});
};
connectAndSubscribe();
return () => channel && channel.close();
}, [chatRoom]);
Publishing
Also publishing chat messages is very easy with Amplify.
async function publishMessage(text: string) {
await events.post(`chat${chatRoom}`, {
text,
author: {
name: user.name,
id: user.id,
},
});
}
Persistence
A note regarding persistence. For now our chat application does not include any persistence layer. That means all chat message just live in the users browser and are gone after closing it. Of course there are multiple ways to add this feature with AWS Services. Since this post is about AppSync Events (in other words: WebSockets 🙂), I won't go into this in depth.
Conclusion
Its great to see what can be achieved just by using those powerful AWS Services, the official code examples and some time playing around with tailwindcss 😁
Full example
You can find the full code example on GitHub.
Suggestions or feedback
If you got any kind of feedback, suggestions or ideas - feel free and write a comment below this article. There is always space for improvement!
Top comments (0)