FowApps
Published in

FowApps

Photo by Vishal Jadhav on Unsplash

Hook Operasyonları-Entegrasyon Sihirbazı🧙‍♂️(Iron Hook🪝)

Özellikle SaaS modelini benimseyen ürünlerde hook veya web hook kavramları her zaman ön planda tutulmuştur. Hook kelimesinin arkasında bulunan temel espiri, önceden tanımlanmış bir olay gerçekleştiğinde belirli bir servise veya servislere haber verilmesidir. Belirli bir operasyonu yönetmek için kullandığınız bir üründe ilk aramanız gereken özellik hook operasyonları olmalıdır. Eğer kullandığınız bu ürün tüm olayları kendi içerisinde tutuyor ve kendisinde olmayan servislere bildirmiyorsa entegrasyon anlamında işinizi oldukça zorlaştıracaktır. FowApps ürün ailesi içerisinde geliştirmekte olduğumuz ürünler için entegrasyon oldukça önemli bir süreçtir. Bu sihirli kelimeyi biraz daha açalım ve Entegrasyon süreçlerine bir deep-dive gerçekleştirelim.

Entegrasyon kelimesinin her domainde veya her üründe farklı bir tanımı olabilir. Bu kelimeye ilkel bir bakış açısıyla yaklaşacak olursak; sistem üzerinde gerçekleşen olayların, iki taraflı tüketilmesi veya kullanılması olarak tanımlayabiliriz.

Bir ürün geliştirdiğinizi düşünün. Domain bazında olması gereken onlarca belki yüzlerce endpoint yani uç noktanız olacaktır. Bu uç noktaları customer create , customer update ve customer delete olarak sınırlandıralım. Bu uç noktaların tetiklenmesi ilk aşamada kullanıcının gerçekleştirdiği bir aksiyon sonucunda oluşacaktır. Adım adım bu aksiyonu inceleyelim;

  • Kullanıcı Email , Password gibi bilgileri belirlenen arayüzden doldurur ve sisteme giriş yapar.
  • Sağ üst köşede bulunan ➕ simgesine tıklayarak Customer Create formunu açar.
  • Zorunlu alanları doldurur.
  • Kaydet butonuna tıklar.

Kullanıcının yaptığı bu aksiyon arka tarafta kullanıcının bilmediği customer create uç noktasını tetikler ve süreç tamamlanır.

Bu hikaye, hepimizin bildiği ve sistem içerisindeki bir uç noktayı tetikleyebileceğimiz en ilkel yöntemdir. Şimdi geliştirdiğimiz bu ürünün farklı ürünlerle nasıl entegrasyon sağlayabileceğini düşünelim.

Son kullanıcımız kendi sisteminde gerçekleşen bir aksiyon sonucunda ürünümüzde bulunan customer create uç noktasını tetiklemek ve süreci tamamlamak istiyor. Bu örnekte odaklanmamız gereken nokta istenilen entegrasyonun yön bilgisi olmalıdır. Entegrasyon süreçlerini yönetmek istiyorsak sormamız gereken ilk soru “Entegrasyonun yönü nedir?” olmalıdır.

Entegrasyon Süreçlerinde Yön Kavramı

Entegrasyon, gerçekten havalı bir isim. Aslında bu kelimenin sırrı veri paylaşmaktır. Her entegrasyon sürecinde bir miktar veri bir sistemden bir başka sisteme doğru yolculuğa başlar. Bu yolculuğun nereden nereye olacağı bizim için oldukça önemli. Bu yönleri listeleyecek olursak;

  • ▶️Bizden dışarıya
  • ⬅️ Dışarıdan bize
  • 💘 Çift yönlü

maddelerini söyleyebiliriz.

Yönler belirlendikten sonra entegrasyonu başlatacak taraf belirlenmelidir.
Tanımlanan entegrasyon her zaman iki nokta arasında gerçekleşmez. Bazen dört veya beş taraflı bir entegrasyon yapmamız gerekebilir. Örneğin kredi kartı ile ödeme entegrasyonu yaparken genelde tercih ettiğiniz provider ile aranızda bir entegrasyon gerçekleştirirsiniz. Ancak ödeme ekranında kullanıcıdan fatura bilgileri alıp bu bilgileri anlık bir sağlayıcıdan doğruluyorsanız entegrasyon taraflarınız ve maliyetiniz artmış olur.

Eğer entegrasyonu başlatacak taraf siz değilseniz o zaman karşı tarafın entegrasyonu kolay bir şekilde tamamlaması için aşağıdaki adımları uygulamalısınız;

  • Authentication (Mandotary)
  • Api Documentation (Mandotary)
  • Validation Rules (Mandotary)
  • Api Credit (Optional)
  • Limit Rules (Optional)

Şimdiye kadar belirtilen kavramların tamamı entegrasyon sürecini anlamak içindi. Şimdi odağımızı biraz daha teknik tarafa çevireceğiz. Asp.Net Core ile geliştirdiğimiz api tabanlı uygulamalarımızda “Entegrasyon maliyetini nasıl minimuma indirebiliriz?” sorusuna cevap arayacağız. Ek olarak bu süreci otomatikleştirmek için bir library tasarlayacağız ve Plug-Play felsefesi ile tasarladığımız bu kütüphaneyi kullanacağız. Hadi öğrenelim. 🥸

Entegrasyon sürecinde ilk adımın tanımlamalar olduğunu artık biliyoruz.

Bu tanımlamaları gerçekleştirmek için Hook.cs isimli bir class oluşturalım.

Hook.cs

Odak noktamız SaaS uygulamalarda entegrasyon süreci olduğu için Tenant bilgisi bizim için önemli. Her tenant kendi entegrasyon tanımlarını yapabilir.

Key bilgisiyle ilerleyen süreçlerde gerçekleştirilen bu tanımları tetikleyeceğiz.

Gerçekleştireceğimiz uygulama şimdilik entegrasyonu HTTP üzerinden sağlayacaktır. Bu sebeple yapılan bu tanımlamalar Url , Method ve Header gibi bilgileri içermelidir. Bu bilgiler için HookRequest.cs isimli bir class oluşturalım.

HookRequest.cs

Veri tabanı olarak PostgreSql kullanacağımız için tanımlanan Header bilgilerini string olarak saklayabiliriz. Entegrasyonun çalışacağı kısımlarda, bu bilgi gerekli objeye convert edilerek kullanılacaktır.

Entegrasyon tanımlamaları için Hook ve HookRequest varlıkları yeterli olacaktır. Şimdi yapılan bu tanımlamaları çalıştıralım.

Entegrasyon tanımları yapılırken girilen bilgiler doğrultusunda basit bir HTTP request operasyonu gerçekleştiren HttpHookOperator.cs sınıfı ile entegrasyonu gerçekleştirebiliriz. Teorik bilgiler kafamızı biraz karıştırmış olabilir. Bazı görsel çizimlerle kurguladığımız bu yapıyı nasıl kullanabileceğimizi özetleyelim. Sonra FowApps ekibi olarak bu yapının doğru abstraction tekniklerinin uygulanmış sürümü olan IronHook kütüphanesini inceleyeceğiz ve geliştirdiğimiz kütüphaneyi uygulamalarımızda nasıl kullanacağımızı öğreneceğiz.

Geliştirdiğimiz uygulamalarda genellikle domain nesnelerimiz bulunur. Kurguladığımız bu yapı veya IronHook entegrasyon sürecinin uygulamamızda gerçekleşen olaylar sonucunda oluşan veriyi dışarıda bulunan bir servise bildirme işlemini gerçekleştirdiğini hatırlatalım.

HookScreen

customer.created yani sistem üzerinde bir müşteri yaratıldığında, şekilde gösterilen bilgiler kullanılarak entegrasyon süreci başlayacak ve oluşturulan customer bilgisi dış bir kaynağa gönderilecektir.

Sistem içerisinde gerçekleşen bir olayı ve o olaya ait olan bilgiyi dış bir kaynak ile paylaşmak Hookolarak isimlendirilebilir. FowApps ekibi olarak IronHook isimli bir kütüphane geliştirdik. Hadi bu kütüphaneyi kullanarak bir web api projesi geliştirelim.

IronHook şimdilik PostgreSql ve Sql Server veri tabanlarını destekler. Bu yazıda PostgreSql sürümünü kullanacağız.

IronHook.PostgreSql kütüphanesini Nuget üzerinden indirelim.

Install-Package IronHook.PostgreSql -Version 2.0.0

Ardından IServiceCollection üzerinde bulunan AddIronHook extension metodunu kullanalım. IronHook alt yapısının çalışacağı veri tabanının connection string bilgisini bu extension metodu içerisinde ayarlayacağız.

services.AddIronHook(options =>
{
options.UseNpgsql("{YOUR_CONNECTION_STRING}", opts => opts.UseIronHookNpgsqlMigrations());
});

IronHook kullandığınız veri tabanında kendi şemasında işlem yapar. Her yeni sürümde veri tabanı varlıkları üzerinde değişiklik veya yeni eklenen yapılar olabilir. Bu sebeple migrationların otomatik gerçekleştirilmesi için Dotnet5 üzerinde IApplicationBuilder Dotnet6 üzerinde ise IHost üzerinde bulunan MigrateIronHook extension metodunu kullanabilirsiniz.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.MigrateIronHook();
// ...
}

Uygulamanızı çalıştırdıktan sonra veri tabanınızı kontrol ederseniz iron-hook şemasının içerisinde ilgili veri tabanı tablolarını bulabilirsiniz.

Eğer Dotnet6 kullanıyorsanız IApplicationBuilder yerine IHost üzerinde bulunan extension metodu kullanabilirsiniz.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddIronHook(opts =>
{
opts.UseNpgsql(
"{YOUR_CONNECTION_STRING}",
opts =>opts.UseIronHookNpgsqlMigrations()
);
});

var app = builder.Build();

app.MigrateIronHook();

Konfigürasyon adımı tamamlandı artık kullanabiliriz.

İlk olarak kullanıcının entegrasyon tanımlarını nasıl yapabileceğini öğrenelim.

Öncelikle IHookService arayüzünü constructor üzerinden alalım.

Define Hook

var hook = new Hook
{
TenantId = "xx",
Key = "hook.key",
Name = "name of hook",
HookRequests = new List<HookRequest>
{
new HookRequest
{
Url = "https://google.com/search?q=ironhook",
MaxRetryCount = 3,
NotifiyEmail = "mail@ironhook.com",
Method = "GET",
Headers = JsonSerializer.Serialize(new List<HeaderParameter>
{
new HeaderParameter
{
Name = "Authorization",
Value = "Bearer xxx"
},
new HeaderParameter
{
Name = "ApiKey",
Value = "xxxxx"
},
})
},
new HookRequest
{
Url = "https://google.com/search?q=github",
MaxRetryCount = 4,
NotifiyEmail = "help@github.com",
Method = "GET",
Headers = JsonSerializer.Serialize(new List<HeaderParameter>
{
new HeaderParameter
{
Name = "Authorization",
Value = "Bearer xxx"
}
})
}
}
};

await hookService.AddAsync(hook);

Tanımlanan entegrasyonları çalıştırmak için RaiseHook yöntemini kullanacağız.

Bu örnekte tanımlanan entegrasyonları bir endpoint’in arkasında çalıştıracağım. Best practice nedir diye sorarsanız, tanımlanan bu entegrasyonların backgrounda çalışması olacaktır. Tanımlanan entegrasyonlar uzun sürebilir veya hata verebilir bu sebeple business logic içerisinde bulunmaması gerekir.

Raise Hook

/// <summary>
/// Customers Endpoint
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
private readonly SampleDbContext sampleDbContext;
private readonly IHookService hookService;

/// <summary>
/// Ctor
/// </summary>
/// <param name="sampleDbContext">
/// Sample Database Context
/// </param>
/// <param name="hookService">
/// Hook Service
/// </param>
public CustomersController(SampleDbContext sampleDbContext, IHookService hookService)
{
this.sampleDbContext = sampleDbContext;
this.hookService = hookService;
}
/// <summary>
/// Customer Create
/// </summary>
/// <returns></returns>
[HttpPost(Name = "AddCustomer")]
[ProducesResponseType(typeof(HookResponse[]),200)]
public async Task<IActionResult> AddCustomerAsync([FromBody] CustomerRequestDto model)
{
var entity = await sampleDbContext.Customers.AddAsync(new Customer
{
Name = model.Name,
Surname = model.Surname,
Phone = model.Phone
});
await sampleDbContext.SaveChangesAsync();
var response = await hookService.RaiseHookAsync(EventNames.CUSTOMER_CREATED, "1", entity.Entity); // <---
return Ok(response);
}
}

İşte bu kadar. IronHook sizlere belirli arayüzler sunuyor eğer isterseniz onu customize etmenizi de sağlıyor. Temel olarak tanımlanan entegrasyon tanımlarını HTTP üzerinden gerçekleştiriyor. İlerleyen aşamalarda farklı kanalları da destekleyebilir.

Daha detaylı bilgi ve örnek projeler için IronHook github reposunu takip edebilirsiniz.

Yazdığınız kodlar production ortamında hatasız koşsun. Testler sizi korusun. 🙏

FowApps is a spinoff of BilgeAdam Technologies which has over 24 years of experience, 1,000+ full-time employees including 600+ highly qualified engineers, serving 900+ highly satisfied global / national companies and governmental agencies.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Furkan Güngör

Furkan Güngör

Solution Developer — I want to change the world, give me the source code.

More from Medium

Introduction to Lightning, the TV-app development framework

Micro Frontends — How to Encapsulate Your Styles Between Projects

How to secure SPAs with Asgardeo

Setting up eslint, prettier, airbnb-base and typescript