Using AWS as a Back End: The Data Store API
In this tutorial, you’ll extend the Isolation Nation app from the previous tutorial, adding analytics and real-time chat functionality using AWS Pinpoint and AWS Amplify DataStore. By Tom Elliott.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Using AWS as a Back End: The Data Store API
40 mins
Replying to Messages
The changes needed for replying to messages are almost identical to those for sending messages. If you want to build a fully-functional chat app, then read on! You'll cover the ground quickly, since it's so similar to the coding above. But if you're more interested in learning, feel free to skip this section.
Open RepliesScreenViewModel.swift and import Amplify at the top of the file:
import Amplify
Next, add the model conversion code as an extension at the bottom:
// MARK: AWS Model to Model conversions
extension Reply {
func asModel() -> ReplyModel {
return ReplyModel(
id: id,
body: body,
authorName: author.username,
messageId: message?.id,
createdAt: createdAt.foundationDate
)
}
}
Replace the stub implementation in fetchReplies()
with a DataStore query:
Amplify.DataStore
.query(Message.self, byId: messageID) { [self] messageResult in
switch messageResult {
case .failure(let error):
logger?.
logError("Error fetching replies for message \(messageID): \(error)")
replyListState = .errored(error)
return
case .success(let message):
self.message = message?.asModel()
replyList = message?.replies?.sorted { $0.createdAt < $1.createdAt }
.map({ $0.asModel() }) ?? []
replyListState = .loaded(replyList)
}
}
In addReply()
, add an implementation to create a reply:
guard let author = userSession.loggedInUser else {
return
}
Amplify.DataStore.query(Message.self, byId: messageID) { [self] messageResult in
switch messageResult {
case .failure(let error):
logger?.logError("Error fetching message \(messageID): \(error)")
replyListState = .errored(error)
return
case .success(let message):
var newReply = Reply(
author: author,
body: input.body,
createdAt: Temporal.DateTime.now())
newReply.message = message
Amplify.DataStore.save(newReply) { saveResult in
switch saveResult {
case .failure(let error):
logger?.logError("Error saving reply: \(error)")
replyListState = .errored(error)
case .success:
replyList.append(newReply.asModel())
replyListState = .loaded(replyList)
return
}
}
}
}
Add the scaffolding for handling subscriptions:
var fetchReplySubscription: AnyCancellable?
private func subscriptionCompletionHandler(
completion: Subscribers.Completion<DataStoreError>
) {
if case .failure(let error) = completion {
logger?.logError("Error fetching replies for message \(messageID): \(error)")
replyListState = .errored(error)
}
}
Finally, implement subscribe()
:
fetchReplySubscription = Amplify.DataStore.publisher(for: Reply.self)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: subscriptionCompletionHandler) { [self] changes in
do {
let reply = try changes.decodeModel(as: Reply.self)
guard
let replyMessageID = reply.message?.id,
replyMessageID == messageID
else {
return
}
replyListState = .updating(replyList)
let isNewReply = replyList.filter { $0.id == reply.id }.isEmpty
if isNewReply {
replyList.append(reply.asModel())
}
replyListState = .loaded(replyList)
} catch {
logger?.logError("\(error.localizedDescription)")
replyListState = .errored(error)
}
}
Whoa, that was speedy!
Build and run on both simulators. Tap the thread to see the messages, then tap a message to view the replies. Send some replies back and forth between your users. Isn't it lovely how well they get along? :]
Congratulations! You have a working chat app!
Where to Go From Here?
In this two-part tutorial series, you've created a fully-functioning chat app using AWS Amplify as a back end. Here are some links to documentation that will help you lock down the knowledge you've gained in this tutorial:
If you'd like to review the complete code, download the final project using the Download Materials button at the top or bottom of this article.
You can learn more about Amplify from the Amplify Docs. These include libraries for the web and Android. If you want to add extra functionality to your app, you could look into using S3 to save static data like user images. Or you could use the @auth
GraphQL directive to add object-level or field-level authentication to your model data.
AWS contains a bewildering number of services and products to help you build your dream app, and you've only just scratched the surface. Good luck! :]