10 Dakikada Serverless ChatApp

Halil Tuğcan Özaktaş
MagicLab
Published in
4 min readMar 17, 2022

Hayatımızda yaygın olarak kullanmaya başladığımız serverless kavramı ile AWS’nin alt yapı gücünden yararlanarak bu hikayede bir servis inşa edelim.

Bu app’i yaparken AWS AppSync ve içinde bulunan GraphQL yeteneklerinden faydalanacağız. Ve neredeyse kod yazmadan bunu yapacağız. En güzeli de serverless mimari olacağından autoscale, deployment vs. süreçlerimiz hiç olmayacak.

AWS AppSync

AWS AppSync, AWS DynamoDB, Lambda ve diğerleri gibi veri kaynaklarına güvenli bir şekilde bağlanmanın getirdiği ağır yük ile başa çıkarak GraphQL API’ler geliştirmeyi kolaylaştıran, tam olarak yönetilen bir hizmettir.

Öncelikle AWS üzerinden kendimize bir AppSync hizmeti başlatmalıyız. App oluştuktan sonra aşağıda verdiğim GraphQL şemamızı sol menüde yer alan Schema alanına gelerek var olan şemamızı güncellemeliyiz.

type Message {
roomId: String
message: String
}
type Mutation {
sendMessage(roomId: ID!, message: String!): Message
}
type Query {
getMessages(roomId: ID!): [Message]
}
type Subscription {
messageSent(roomId: ID!): Message @aws_subscribe(mutations: ["sendMessage"])
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}

Şimdi ise yukarıda yazılanları kısaca özetliyorum;

Query alanı içinde yazılan fieldlar bağlı olduğu yerden veri okumamızı sağlar. Mutation alanı ise verilerde değişiklik yaptığımız fieldları yazdığımız alandır. Değişiklik derken ekleme, silme, güncelleme gibi işlemler. Subscription alanı ise isminden de anlaşıldığı gibi bir abonelik başlatıp, bağlı olduğu field’a gelen istekleri anlık dinlemeye başlar, o alana publish edilen bir veriyi anında size döner. Query ile Subscription farkı query çalışıp önceden girilmiş verileri okur döner çalışmasını bitirir, subscription ise bir veri akışını anlık izler siz durdurana kadar çalışmasına devam eder.

Veriler nasıl işlenip nasıl saklanacak ?

ChatApp

Görüldüğü gibi graphQL sorgularımız AppSync’e iletiliyor. AppSync schema’mızda yer alan field lara göre bir resolverdan geçirip, arkada koyduğumuz data source’a kayıt ettiriyor. Yani verilerimizi saklamamız için bir dynamodb tablosuna ihtiyacımız var. Hemen şuradan kendimize bir table yaratalım. Ve AppSync den ChatApp’imizi inşa etmeye devam edelim. Dynamodb table’ımız hazır olduğuna göre AppSync sol menüden bir Data Source alanına gelip New DataSource butonu ile bir datasource yaratalım. Aşağıdaki görseli takip edebilirsiniz, table name alanına az önce yarattığımız table’ı bulup seçiniz.

new data source

Artık tek yapamamız gereken oluşturduğumuz parçaları birbirine bağlamak sonrasında ChatApp’imiz hazır olacaktır.

Schema alanına geri geliyoruz, graphQL şemamızın sağında resolvers alanını göreceksiniz. Burada sendMessage fieldımızı bulup attach diyerek data source’umuzu bağlayacağız. Şimdi burada dikkat edilecek bir nokta resolver data source olarak bir dynamodb tablosunu kullandığımız biçin resolver’ımızın içersine de dynamodb functionları yazacak olmamız. Ama aws bunun için örnek templateleri bize sunduğu için extra bir öğrenime çok fazla ihtiyac duymayacağız. sendMessage field’ı bizim için yeni mesajları gönderdiğimiz yer olacağından, başka bir deyiş ile veri girişi alanı olacağından. Dynamodb nin PutItem methodunu kullanacağız. Aşağıdaki görsele bakarsanız, PutItem template’i seçili ve örnek bir template oluşturmuş gelecektir.

put item example

Template alanında gördüğümüz JSON formatında alan AWS nin resolverların da kullandığı VTL denilen bir template dilidir. VTL dökümanına şuradan bakabilirsiniz.

Yukarıda ki request template’imiz ne yapıyor kısaca anlatırsak; dynamodb putItem methodunu çalıştıyor. Database PK mız id olduğu için otomatik bir uid oluşturup veriyor. attributeValues kısmına ise $ctx olarak gördüğümüz request context’in argumentlerini içine aktarıyor. Argumentler nedir derseniz. sendMessage(roomId: ID!, message: String!) methodumuzun içerisinde yer alan roomId, message verileridir. toMapValuesJson la ise veriyi dynamodb’nin okuyabileceği formatta map’liyor. Response resolver kısmında bişey yapmamıza gerek yok. Default halini bırakıp kayıt edebiliriz.

Ayrıca ek bilgi olarak resolver içine ihtiyaca göre VTL formatında eklemeler yapabilirsiniz. Örneğin, aşağıda basit bir if ekleyip, sorguyu çalıştırmadan istemediğimiz bir durumu engellemiş error fırlatmış olabiliriz.

#if( $ctx.args.roomId == "" )
$util.error("roomID is empty")
#end
{
"operation" : "PutItem",
"key" : {
## If object "id" should come from GraphQL arguments, change to $util.dynamodb.toDynamoDBJson($ctx.args.id)
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}

Not: Her data source tipinin resolver syntax’ı birbirinden farklıdır. Data source örneğin lambda tipinde olsaydı, bu template’i kullanamazdık. Lambdanın resolver dökümanına şuradan bakabilirsiniz.

Şu an ChatApp’imiz çalışır duruma geldi. messageSent field’ımıza subscription olduğumuz anda, sendMessage mutation’ı her tetiklendiğinde realtime veri akışımız başlayacaktır. Yani oluşan her Message type roomId’lere göre ayırt edilerek size messageSent(roomId: ID!) dinleyicisi ile sunulacaktır. Her yeni mesaj tek bir veri haline size dönecektir. Başka bir söylemle sendMessage’in yarattığı her mesaj bir kez messageSent’a subscrip olacaktır.

messageSent(roomId: ID!): Message

“: Message” olan kısım dönüş değeridir.

Clientlara nasıl servis edebiliriz ?

AppSync dashboard’umuzun setting menüsünde bize api url olarak bir endpoint verecektir. Buradaki endpoint’e herhangi bir graphQL client’ı ile bağlanıp çalışabilirsiniz. Dikkat edilmesi gereken tek bir konu bu servis için zorunlu olarak bir Auth methodu seçmeniz gerekli, en basit yöntem olan apiKey yönetimini seçip istekleriniz header’ında göndererek AppSync’e gelen istekleri doğrulayabilirsiniz.

AppSync Setting

Ya da custom domain names alanından kendi domain’iniz ile “www.aaaa.com” gibi bir isimle graphQL apinizi servis edebilirsiniz.

Maliyet Ne Kadar Olacak ?

Maliyet olarak sistem serverless çalışacağı için ne kadar istek, o kadar para olarak karşınıza gelecek olsada maliyet çok düşük seviyelerde olacaktır. Şu an kurduğumuz yapı 1 milyon mesaj trafiğin de dynamodb ve appsync toplamı olarak 4-6 dolar arası aylık bir fatura oluşturacaktır. Kişisel kullanımızı önden hesaplamak için buraya bakabilirsiniz. https://calculator.aws/#/

--

--