Hello World! Introducing the Momento Web SDK
Say hello to instant notifications and easy cache access like never before. With our new Web SDK, developers can effortlessly integrate powerful real-time features, bringing faster performance and new capabilities to your end users.
You know what’s nice? Working with powerful SDKs in your front end applications. Every time I use an SDK that “just works” and does most of the work for me, I’m overjoyed. Building a delightful user experience is hard enough as it is, so why make it harder reinventing things yourself?
That was our thought as we were building our latest offering – the Momento Web SDK! Designed with versatility and performance in mind, our aim is to bring Momento Cache and Topics closer to your end users than ever before. We crafted it to function seamlessly in your browser environment, ensuring a smooth and consistent development experience.
Excited? So are we! Check out some of these cool new capabilities we unlocked with this release 👇
- Channel-based WebSockets
- Shared cache between client and server
- Browser-to-browser communication
- Programmatic generation of API tokens
Newly opened doors
To me, those are pretty nifty capabilities. But they don’t quite have a resounding impact until we talk about how you can use them in real life. So let’s talk about how we just changed the game.
Over the past couple of months, we’ve created some content on how easy it is to build a chat application on Momento. With the release of the Web SDK it’s even easier.
Forget implementing server-side APIs – keep chat completely contained in Momento. Momento handles the management of the WebSocket connections, delivery of the data, and the temporary storage for the chat history.
But before we get into the demo, we need to talk about the elephant in the room: auth.
Auth on the web
One of the key challenges with web development is ensuring secure and efficient authentication. Passing a long-lived API token to a browser is a big no-no. Malicious users could intercept the token and get free reign of your account for perpetuity. We don’t want that. Nobody wants that.
Prior to today, users could login to the Momento Console and generate an API token with an expiration date via the user interface. After a configurable amount of time, say 1 hour, the API token invalidates and is no longer usable. While this type of token is the answer for web development, obtaining these tokens manually through the console is not.
To support secure token usage in a browser, we updated our Node.js SDKto enable programmatic refresh of expiring tokens. Not only are these tokens set to invalidate at your leisure, they also are scoped with a limited set of permissions to keep malicious users at bay. Tokens generated programmatically will not be able to access control plane operations like creating a cache, deleting a cache, and creating other API tokens. This enhances security, giving you peace of mind about the safety of your user data.
Now when building applications on Momento you can create a token vending machine (TVM) that disburses short-lived, limited permission tokens for individual user sessions.
The easiest way to chat
Ok, time for the good stuff. I built an example chat app using our brand new Web SDK to show you just how easy it is to add instant messaging into your app.
When you load the homepage of the application, a call goes out to our token vending machine to get a Momento API token for our session. We add the token and its expiration time in a claims object we return back to the user.
async function getClaims(ip) {
let claims = {};
const cacheClient = await getCacheClient();
const response = await cacheClient.get('user', `${ip}-claims`);
if (response instanceof CacheGet.Hit) {
claims.momento = JSON.parse(response.valueString());
} else {
const authClient = getAuthClient();
const token = await authClient.generateAuthToken(AllDataReadWrite, ExpiresIn.seconds(3600));
if(token instanceof GenerateAuthToken.Success){
claims.momento = {
token: token.authToken,
exp: token.expiresAt.epoch
};
await cacheClient.set('user', `${ip}-claims`, JSON.stringify(claims.momento), { ttl: 3600 });
}
}
return claims;
};
This code runs in a Lambda function that backs a /userinfo endpoint. It uses the Node.js SDK, which is intended for server-side operations. We cache the generated auth token by IP address so if we receive multiple calls from the same IP, we can reuse the credentials and prevent generating tokens unnecessarily.
That is the only server-side code we generate for our chat app! Everything else lives in our front-end application and communicates directly with the Momento servers via the Web SDK. Let’s take a look at the code when we open up a chat room.
useEffect(() => {
async function setupMomento() {
initializeTopicClient();
initializeCacheClient();
loadChatHistory();
}
if (credentials) {
setupMomento();
}
}, [credentials, router]);
const initializeTopicClient = async () => {
if (!topicClient && router.query.room) {
topicClient = new TopicClient({
configuration: Configurations.Browser.v1(),
credentialProvider: CredentialProvider.fromString({ authToken: credentials.user.claims.momento.token })
});
updateTopicClient(topicClient);
await topicClient.subscribe('chat', `${router.query.room}-chat`, {
onItem: async (data) => await saveMessage(data.value()),
onError: (err) => console.log(err)
});
}
};
const loadChatHistory = async () => {
const chatHistoryResponse = await cacheClient.listFetch('chat', router.query.room);
if (chatHistoryResponse instanceof CacheListFetch.Hit) {
const history = chatHistoryResponse.valueListString().map(msg => JSON.parse(msg));
updateMessages(history);
}
};
In our Next.js chat app, we run a script in the browser whenever the credentials are set. This script will initialize the TopicClient from the Momento Web SDK and subscribe to a dynamic topic, `${router.query.room}-chat`. This establishes a connection to the channel dedicated to that chat room, which will pick up all messages going back and forth.
We also load the chat history from the cache. Much like our prior implementations, all chat messages are saved in a Momento list, which is an ordered set of strings. As chat messages are sent, they are pushed to the list so anyone who joins can have full access to the chat history in the order they were sent.
But what happens when we send a message now? Before we published a message over a WebSocket connection that went to a WebSocket server we managed. Surely that’s still a thing?
Nope. It’s way easier now.
const sendMessage = async (event) => {
event.preventDefault();
const msg = JSON.stringify({ username: name, message: message });
topicClient.publish('chat', `${router.query.room}-chat`, msg);
cacheClient.listPushFront('chat', router.query.room, msg);
setMessage("");
};
That’s it. Those 5 lines of codes are all you need. This runs when you hit the “Send” button or press Enter in our chat application. We make a JSON object with your username and message, then publish it to the chat room topic. After we publish, we add it to the chat history and we’re done!
Receiving a message is just as easy, take a look.
const saveMessage = async (newMessage) => {
const detail = JSON.parse(newMessage);
updateMessages([detail, ...messagesRef.current]);
};
This is the event handler we set up when subscribing to the chat room topic. It doesn’t do much besides add the new message to our state object and render it on screen. Pretty dang cool!
I highly recommend checking out the full source code in GitHub for the full implementation.
Other cool things you can do
Now that you can directly connect your server-side code with the browser, there’s a ton of cool new things you can take advantage of, management-free:
- Location tracking
- Realtime data updates
- Online presence indicators
- Live stat tracking
We are super excited at Momento to bring you our new Web SDK and open the doors to many new possibilities and use cases. Stay tuned as we continue to bring you cutting edge serverless solutions with pricing so simple it fits in a tweet.