.NET İle Amazon API Gateway – AWS Lambda & DynamoDB Entegrasyonu
AWS’ye dair bir önceki .NET 7 – AWS Lambda İle Serverless Computing başlıklı makalemizde temel seviyede AWS Lambda servisini incelemiştik. Bu içeriğimizde ise AWS Lambda’yı geliştirdiğimiz uygulamalar gibi dış servisler tarafından nasıl çağrılıp, kullanılabileceğini inceliyor olacağız. Tabi bunun yanında içeriğimizi DynamoDB ile zenginleştirecek ve Cloudwatch mekanizması ile genel manada loglama çalışması gerçekleştireceğiz. O halde bu heyecanlı sürece buyurun başlayalım.
Amazon API Gateway Nedir?
Amazon API Gateway, geliştiricilerin kolaylıkla ölçeklenebilir API’ler oluşturmasını ve yayınlamasını(publish) sağlayan, bu API’ler üzerinde bakım(maintain) ve izleme(monitor) işlemlerine imkan veren güvenli(secure) bir servistir. Amazon API Gateway ile, AWS veya diğer web servislerine erişebilir veya AWS Cloud’da depolanan verilere erişebilen API’ler oluşturabilirsiniz.
Amazon API Gateway oldukça basit ve esnek bir arayüz sayesinde gerçek zamanlı(real-time) çift yönlü iletişim sağlayan(two-way communication) REST ve WebSocket API’leri oluşturabilir, AWS Lambda Function’ları veya diğer AWS kaynakları gibi endpoint’lere erişim sağlayabilen ve yüzbinlerce request’i asenkron olarak işleyebilen uygulamalar geliştirebilirsiniz. Amazon API Gateway, tüm bu süreçteki trafik yönetimini, yetkilendirmeyi ve erişim kontrollerini monitoring ederek, otomatize etmenize yardımcı olacaktır.
Amazon API Gateway, AWS IAM(AWS Identity and Access Management) ve Amazon Cognito gibi çeşitli yetkilendirme yöntemlerini desteklemekte ve monitoring için CloudWatch, denetim için ise AWS CloudTrail gibi diğer AWS servisleriyle entegre edilebilir bir nitelik sergilemektedir.Yukarıdaki görsel üzerinden de yapıyı anlamaya çalışırsak eğer türlü client’ların AWS Lambda Function‘lar da ki business logic’i kullanma ihtiyacı söz konusu olduğu durumlarda, gerekli erişim Amazon API Gateway üzerinden gerçekleşecektir. Buradaki erişim aşağıdakilere benzer endpoint’ler üzerinden gerçekleştirilecektir;
- www.<aws-gateway-url>/test -> ‘test’ isimli lambda function’a request atacaktır.
- www.<aws-gateway-url>/get-students -> ‘get-students’ isimli lambda function’a request atacaktır.
Amazon API Gateway, dış servislerden AWS servislerine erişimi kolaylaştırdığı için AWS Serverless ekosisteminin hayati bir parçası konumundadır.
AWS REST API İle HTTP API’ı Karşılaştıralım
AWS, Amazon API Gateway‘ın AWS REST API ve HTTP API olmak üzere iki türlü API sürümünü desteklemektedir. Bu iki API sürümünün isimleri her ne kadar farklıymış gibi görünse de her ikisi de REST kurallarını izleyen HTTP protokolü üzerine kurgulanmıştır ve davranışsal nüanslara sahip olan protokollerdir.
AWS’de; REST API v1, HTTP API ise v2 olarak adlandırılmaktadır.
REST API ile HTTP API arasındaki temel farka değinmemiz gerekirse eğer, REST API daha geniş bir özellik setine sahipken HTTP API ise daha az özellik içermektedir ve genellikle hafif yükleri işlemek amacıyla kullanılmaktadır. Yani REST API ile; HTTP protokolünün tüm özellikleri kullanılmakta ve bunun yanı sıra güvenlik, yetkilendirme, kimlik doğrulama vs. gibi işlevler söz konusu olurken HTTP API’de ise sadece GET ve POST istekleri desteklenmekte ve JSON türünden response’lar elde edilmektedir. Bundan dolayı REST API yetenekleri doğrultusunda genellikle web uygulamaları için tercih edilirken, HTTP API ise daha az kaynak gerektiren mobil yahut IoT cihazları gibi hafif yükleri işlemeyi amaçlayan sistemler için kullanılmaktadır.
Haliyle bu API sürümleri arasında performans, fiyatlandırma ve geliştirme deneyimi açısından oldukça önemli farklar mevcuttur. Şöyle ki;
- HTTP API, REST API’a nazaran %10-15’lik daha fazla performans sergilemektedir.
- Fiyatlandırma açısından ise 300 milyon request için HTTP API 1 USD’ye mal olurken, aynı request hacmi için REST API’ler ise 3,5 USD’ye mal olmaktadır. Azımsanmayacak bir fark olduğu aşikardır.
Bu sebeplerden ötürü çoğu zaman HTTP API tercihiniz olmalıdır ki bizler bu içeriğimizde HTTP API kullanıyor olacağız.
Bir Lambda Function İçin API Gateway Nasıl Oluşturulur İnceleyelim?
Şimdi içeriğimizin esas mevzusuna gelirsek eğer dış servisler tarafından lambda function’lara erişim gösterilebilmesi için örnek bir uygulama geliştirmeye başlayalım. Tabi bunun için aşağıdaki adımların sırasıyla takip edilmesinde fayda vardır. O halde buyurun başlayalım…
- Adım 1 (AWS Lambda Oluşturma ve Publish Etme)
Her şeyden önce dış servisler tarafından erişim gösterilecek olan lambda function’ı oluşturarak başlayalım. Bu işlem için .NET 7 – AWS Lambda İle Serverless Computing başlıklı makalemizden destek alabilirsiniz.Bu lambda function’ı geliştirirken bir yandan da AWS lambda function’larının Amazon API Gateway ile ilişkili olarak çalışmasını sağlayacak olan sözleşmeleri(
contracts
) içeren Amazon.Lambda.APIGatewayEvents paketinin de projeye yüklenmesi gerekmektedir. Bu paket, API Gateway ile lambda function arasında bir bağlantı kurulmasını ve ilgili function’ın API Gateway üzerinden çağrılabilir olmasını sağlamaktadır.Şimdi lambda function’ı aşağıdaki gibi hasbel kader geliştirelim.
using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.Core; [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] namespace AWS.API.Gateway.Example.Lambda; public class Function { public APIGatewayHttpApiV2ProxyResponse FunctionHandler(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { request.QueryStringParameters.TryGetValue("name", out var name); return new() { Body = $"Merhaba {name ?? "Gençay YILDIZ"}", StatusCode = 200 }; } }
Yukarıdaki kod bloğunu incelerseniz eğer dış dünyadan gelecek olan istekler API Gateway aracılığıyla lambda function’a ilgili kütüphanede bulunan
APIGatewayHttpApiV2ProxyRequest
türünden nesne ile gelmektedir. Benzer mantıkla function operasyon neticesini yine API Gateway aracılığıyla dış dünyayaAPIGatewayHttpApiV2ProxyResponse
nesnesi olarak döndürmektedir. Tabi buradaAPIGatewayHttpApiV2ProxyResponse
nesnesi yerine herhangi bir objeyi de return edebileceğinizi bilmenizde fayda vardır ki ilerdeki satırlarda bu durumu da tecrübe ediyor olacağız.Velhasıl, yukarıdaki çalışmada query string’den gelecek olan ‘name’ parametresi beklenmekte ve bu değeri belirli metinsel formatta ‘200’ status code’u eşliğinde return etmekteyiz. ‘name’ parametresi null geldiği taktirde default olarak ‘Gençay YILDIZ’ değeri döndürülmektedir.
İlk etapta oluşturacağımız lambda function’ımız bu kadar olacaktır. Şimdi bu function’ı publish ederek devam edelim.Publish sürecinde gerekli function adı, description vs. gibi bilgileri girdikten sonra ‘Next’ deyiniz.Burada dikkat edilmesi gereken tek husus doğru rolün verilmesidir. Bizler AWS Cloudwatch‘a logları yazabilmesi için gerekli izinleri barındıran AWSLambdaBasicExecutionRole rolünü seçerek devam edelim.
Bu adımdan sonra ‘Upload’ butonuna tıklayarak ilgili function’ı AWS’ye gönderelim ve yükleme tamamlandıktan sonra AWS üzerinden function’ın oluşturulduğunu doğrulayalım.
- Adım 2 (Oluşturulan Lambda Function’ı Test Edelim)
Şimdi oluşturduğumuz lambda function’ı test edebilmek için Visual Studio üzerinden ‘AWS Explorer’ penceresinde açalım ve ilgili pencerede aşağıdaki gibi yapılandırmada bulunarak testimizi gerçekleştirelim.Görselde görüldüğü üzere ‘Example Request’ kısmında ‘API Gateway AWS Proxy’ sekmesini seçip, ardından ‘queryStringParameters’ içerisinde gerekli query string parametrelerini tanımlayarak istekte bulunabilirsiniz.Evet, ilgili function’ı test ettiğimize göre bu aşamadan sonra bu function’a Visual Studio Debugger’ının dışında farklı servislerinde erişim gösterebilmesi için bir endpoint tasarlamamız gerekecektir. İşte tam da bu noktada Amazon API Gateway devreye girecektir.
- Adım 3 (.NET İle Amazon API Gateway Oluşturma)
Bu adımda Amazon API Gateway’i tasarlamaya başlayalım. Bunun için ilk olarak AWS Console’da aşağıdaki ekran kaydında olduğu gibi ‘API Gateway’ı arayarak ilgili servise gidelim ve sunulan API seçeneklerinden HTTP API’ın Build butonuna tıklayarak devam edelim.Açılan sayfada aşağıdaki gibi ‘Integrations’ kısmında ‘Lambda’ olacak şekilde gerekli konfigürasyonları gerçekleştirelim. Bu API Gateway üzerinden erişim gösterilecek function bilgilerinin özellikle birebir aynı olduğuna hassasiyetle dikkatinizi çekerim. Devamında ise function’a erişim ile ilgili route’u aşağıdaki gibi yapılandıralım.Tabi burada görüldüğü üzere birden fazla route şeması tanımlayabileceğinizi bilmenizde fayda vardır. Devam edersek eğer wizard bizden dev, prod ve staging gibi stage’lere deploy gerçekleştirebilmemiz için stages oluşturmamızı isteyecektir. Şimdilik bu kısmı tüm HTTP API’lerin de varsayılan olarak gelen$default
değerinde bırakıp devam edelim.Sonraki adımda oluşturduğumuz API Gateway’e dair gelecek olan ‘Review and create’ bölümünde yapılan işlemleri gözden geçirebilir ve nihai olarak API Gateway’i oluşturabilirsiniz.Yukarıdaki görselde ‘Invoke URL’ kısmında API Gateway için oluşturulan endpoint’i görebilmekteyiz. Artık bu endpoint’e aşağıdaki görselde olduğu gibi Postman’den, browser’lardan yahut herhangi bir servisten uygun isteklerde bulunabilir ve response’u elde edebiliriz.
API Gateway oluşturmak işte bu kadar… 🙂
Şimdi API Gateway’in nasıl çalıştığına dair temel bir anlayışa sahip olduğumuza göre içeriğimizi daha da zenginleştirebilmek için AWS Lambda servisinde multiple function handlers eşliğinde Cloudwatch ve DynamoDB’i entegre eden gelişmiş bir çalışma gerçekleştirelim.
Gelişmiş Bir Lambda Function Örneklendirmesi
Burada basit düzeyde DynamoDB’ye veri ekleyecek ve verileri okuyacak ayrı lambda function’lar geliştiriyor olacağız. Bu function’ların hepsi aynı AWS Lambda projesi içerisinde tanımlanacaktırlar. Tabi ki de sizler function’ların her biri için ayrı projeler oluşturmakta da özgürsünüz lakin bizler bir yandan burada bir önceki satırda bahsedildiği üzere multiple function handlers durumunu yani birden fazla function’ı tek bir proje üzerinden işlemeyi tecrübe etmek niyetinde olacağız. Velhasıl, bu sürece aşağıdaki adımları sırasıyla seyrederek eşlik edebilirsiniz;
- Adım 1 (AWS Lambda Oluşturma ve Gerekli Kütüphaneleri Yükleme)
İlk olarak tüm işlemleri yürüteceğimiz AWS Lambda projesi oluşturalım ve ardından aşağıdaki kütüphaneleri yükleyerek işlemlere hazır bir vaziyete getirelim. - Adım 2 (DynamoDB’deki Tablonun Entity’sini Hazırlama ve Tabloyu Oluşturma)
DynamoDB’ye eklenecek ve yeri geldiğinde read edilecek verilerin entity’sini hazırlayalım. Bu veriler misal olarak aşağıdaki gibi ‘Person’ verileri olabilir.[DynamoDBTable("persons")] public class Person { [DynamoDBHashKey("id"), JsonPropertyName("id")] public int? Id { get; set; } [DynamoDBProperty("name"), JsonPropertyName("name")] public string? Name { get; set; } [DynamoDBProperty("surname"), JsonPropertyName("surname")] public string? Surname { get; set; } }
Ve ardından AWS DynamoDB’ye giderek bu entity’e karşılık tabloyu oluşturalım.
- Adım 3 (Veri Ekleyen Function’ı Geliştirme)
Şimdi de DynamoDB’de oluşturulan tabloya ‘Person’ türünden verileri ekleyen function’ı tasarlayalım. Bunun için oluşturulan AWS Lambda projesi içerisindeki ‘Function.cs’ dosyası içerisindeki default gelen ‘FunctionHandler’ metodunu silerek yerine aşağıdaki gibi amacımıza hizmet eden bir function oluşturalım.public class Function { public async Task<APIGatewayHttpApiV2ProxyResponse> CreatePersonAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { //Post edilen person data 'Person' türünden nesneye deserialize edilmektedir. Person? person = JsonSerializer.Deserialize<Person>(request.Body); AmazonDynamoDBClient dynamoDBClient = new(); DynamoDBContext dynamoDBContext = new(dynamoDBClient); await dynamoDBContext.SaveAsync(person); string message = $"Person created. Name : {person.Name}"; LambdaLogger.Log(message); return new() { Body = message, StatusCode = 200 }; } }
Burada özellikle 11. satırda
LambdaLogger.Log(...)
ile ‘Cloudwatch’ servisine bir log attığımıza dikkatinizi çekerim. - Adım 4 (Verileri Çeken Function’ı Geliştirme)
Benzer şekilde person verilerini okuyacakGetAllPersonsAsync
veGetPersonByIdAsync
function’larını yine ‘Function.cs’ dosyasına aşağıdaki gibi ekleyelim.public class Function { public async Task<APIGatewayHttpApiV2ProxyResponse> CreatePersonAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { . . . } public async Task<List<Person>> GetAllPersonsAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { AmazonDynamoDBClient dynamoDBClient = new(); DynamoDBContext dynamoDBContext = new(dynamoDBClient); List<Person> persons = await dynamoDBContext.ScanAsync<Person>(default).GetRemainingAsync(); return persons; } public async Task<Person> GetPersonByIdAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { AmazonDynamoDBClient dynamoDBClient = new(); DynamoDBContext dynamoDBContext = new(dynamoDBClient); int personId = int.Parse(request.PathParameters["id"]); Person person = await dynamoDBContext.LoadAsync<Person>(personId); if (person == null) throw new Exception("Person not found!"); return person; } }
- Adım 5 (Oluşturulan Function’ları Publish Etme)
Artık tüm function’ları hazırladığımıza göre bunları deploy edebiliriz. Bunun için ilgili projeye sağ tıklayarak ‘Publish to AWS Lambda…’ sekmesine tıklayalım ve ardından tüm fonksiyonlar için aşağıdaki gibi konfigürasyonları sağlayarak deploy yapalım.Ve özellikle tüm deploy süreçlerinde bizden isteyeceği ‘Role Name’ bilgisine karşılık ‘AWSLambdaBasicExecutionRole‘ü veriniz.Nihai olarak deploy’ları gerçekleştirdikten sonra AWS Lambda servisi üzerinden function’lara göz atabilirsiniz.
- Adım 6 (DynamoDB İzinlerini Yapılandırma)
Şimdi ise DynamoDB ile ilgili izinleri konfigüre edelim. Bunun için AWS IAM servisindeki ‘policies’ kategorisinden aşağıdaki gibi yeni bir policy üretelim.Tabi ki de gerçek bir çalışmada tüm izinlerin bu şekilde verilmesinin iyi bir fikir olmadığını ve sadece gerekli izinlerin verilmesi gerektiğini unutmamak gerekmektedir. Bizler örneklendirmedeki işleri basit tutmak için bu şekilde bir aksiyonda bulunuyoruz. Velhasıl, bir sonraki adımda bu policy’e aşağıdaki gibi bir isim vererek oluşturalım.Son olarak oluşturulan policy’i rollere eklememiz gerekmektedir. Bunun için de AWS IAM üzerinden ilgili policy’i seçip ‘Actions’ kısmından ‘Attach’ sekmesine tıklanması yeterlidir.Ardından açılan sayfada ‘lambda_exec_create-person‘, ‘lambda_exec_get-all-persons‘ ve ‘lambda_exec_get-person-by-id‘ rollerini seçip, ekleyerek politikayla ilişkilendirelim.Neden bu rolleri seçiyoruz? diye sorarsanız eğer publish sürecinde function’lara karşılık rolleri seçerken ‘AWSLambdaBasicExecutionRole’ü vermemiz neticesinde her bir function için bu isim formatında bir rol üretilmektedir. Bu sebepten dolayı oluşturduğumuz politikayı tüm lambda function’lara özel rollerle ilişkilendirip yetkilendirmeyi gerçekleştiriyoruz.AWS Lambda’da, tüm lambda function’ların kullandığı rolü oluşturduğumuz bir politikayla ilişkilendirerek yetkilendirme gerçekleştirilmekte ve böylece rollerin erişim sınırlılığı politikalarla belirlenmektedir!
Böylece oluşturulan AWS Lambda’ların DynamoDB’ye erişim yetkisini belirleyebilecek bir politika hazırlamış ve bu politikayı da function’ların rolleriyle ilişkilendirerek gerekli yetkilendirmeyi gerçekleştirmiş bulunuyoruz.
- Adım 7 (Oluşturulan Function’lar İçin Amazon API Gateway Oluşturma)
Son olarak oluşturulan bu lambda function’ların tetiklenebilmesi için birer endpoint tanımlanmalı ve bunun için de bir API Gateway oluşturulmalıdır. Bundan dolayı AWS Console’dan ‘API Gateway’ servisine gelelim ve yeni bir API Gateway create edelim.Görüldüğü üzere tüm function’larımızı ‘person’ API name’ine karşılık API Gateway’e entegre etmiş bulunuyoruz. Devamında ise endpoint route’ları yapılandırıyor olacağız.Burada ‘Resource path’ kısmını kendi inisiyatifinize kalmış bir şekilde manuel yapılandırmanızı tavsiye ederim. Bizler yukarıdaki gibi basit düzeyde bir route şeması oluşturmuş bulunuyoruz.Bir sonraki adımda gelecek olan ‘Define stages’ kısmında ise
$default
olacak şekilde yapılandırmayı bırakarak API Gateway’i create edebiliriz.İşte bu kadar… Görüldüğü üzere function’lara erişim gösterecek endpoint’imizi almış bulunuyoruz. Artık testimizi gerçekleştirebiliriz. - Adım 8 (Test Etme)
Şimdi oluşturduğumuz lambda function’ları sırasıyla test edelim;Ve ayriyeten Cloudwatch servisini de kontrol ederek logların tutulup tutulmadığını gözlemleyelim.Dikkat ederseniz endpoint’ler üzerinden yapılan tüm lambda tetiklemeleri ilgili servis tarafından loglanmakta ve süreçte varsa hata rahatlıklı çözüme giden yol bu loglar arasından bulunmaktadır.
Muhtemelen sizlerin bu endpoint’lere her selamın aleyküm diyenin erişebileceğinden kuşku duyduğunuzu sezer gibiyim. Merak etmeyin bir sonraki içeriğimizde AWS Lambda servisinde üretilen bir function’a erişim için oluşturduğumuz API Gateway’in nasıl authorize edileceğine dair detaylı bir incelemede bulunuyor olacağız. Bizler bu kapsamlı içerikle API Gateway mantığını ve AWS Lambda function’larına API Gateway üzerinden nasıl erişim gösterilebileceğini incelemiş bulunuyoruz ve yazımızı burada noktalıyoruz.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
Not : Örnek çalışmayı aşağıdaki github adresinden edinebilirsiniz.
https://github.com/gncyyldz/AWS.API.Gateway.Example
Selamlar, tamda bugün buna bakınıyordum çok iyi oldu eline sağlık