gRPC ve REST: En İyi API Protokolüne Başlarken

Yayınlanan: 2022-07-22

Günümüzün teknoloji ortamında, çoğu proje API'lerin kullanılmasını gerektirir. API'ler, tek bir karmaşık sistemi temsil edebilen, ancak ayrı makinelerde bulunabilen veya birden çok, uyumsuz ağ veya dil kullanabilen hizmetler arasındaki iletişimi köprüler.

Birçok standart teknoloji, REST, SOAP, GraphQL veya gRPC gibi dağıtılmış sistemlerin hizmetler arası iletişim ihtiyaçlarını karşılar. REST tercih edilen bir yaklaşım olsa da gRPC, yüksek performans, yazılı sözleşmeler ve mükemmel araçlar sunan değerli bir rakiptir.

REST Genel Bakış

Temsili durum aktarımı (REST), bir hizmetin verilerini almanın veya değiştirmenin bir yoludur. Bir REST API, genellikle bir kaynak seçmek için bir URI ve istenen işlemi seçmek için bir HTTP fiili (örneğin, GET, PUT, POST) kullanılarak HTTP protokolü üzerine kuruludur. İstek ve yanıt gövdeleri, işleme özgü verileri içerirken, üstbilgileri meta verileri sağlar. Örneklemek için, bir ürünü REST API aracılığıyla almanın basitleştirilmiş bir örneğine bakalım.

Burada, kimliği 11 olan bir ürün kaynağı talep ediyoruz ve API'yi JSON biçiminde yanıt vermesi için yönlendiriyoruz:

 GET /products/11 HTTP/1.1 Accept: application/json

Bu istek göz önüne alındığında, yanıtımız (alakasız başlıklar çıkarılmıştır) şöyle görünebilir:

 HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }

JSON insan tarafından okunabilir olsa da, hizmetler arasında kullanıldığında optimal değildir. Özellik adlarına atıfta bulunmanın tekrarlayan doğası - sıkıştırılmış olsa bile - şişirilmiş mesajlara yol açabilir. Bu endişeyi gidermek için bir alternatife bakalım.

gRPC'ye Genel Bakış

gRPC Uzaktan Yordam Çağrısı (gRPC), bir dizi işlevi harici istemcilere sunarak hizmetler arası iletişimi basitleştiren ve yöneten açık kaynaklı, sözleşme tabanlı, platformlar arası bir iletişim protokolüdür.

HTTP/2 üzerine inşa edilen gRPC, çift yönlü akış ve yerleşik Aktarım Katmanı Güvenliği (TLS) gibi özelliklerden yararlanır. gRPC, serileştirilmiş ikili yükler aracılığıyla daha verimli iletişim sağlar. REST'in JSON kullanımına benzer şekilde, yapılandırılmış veri serileştirme mekanizması olarak varsayılan olarak protokol arabelleklerini kullanır.

Ancak JSON'dan farklı olarak, protokol arabellekleri serileştirilmiş bir formattan daha fazlasıdır. Bunlar diğer üç ana bölümü içerir:

  • .proto dosyalarında bulunan bir sözleşme tanımlama dili (En son protokol arabelleği dili belirtimi olan proto3'ü izleyeceğiz.)
  • Oluşturulan erişimci işlev kodu
  • Dile özgü çalışma zamanı kitaplıkları

Bir hizmette bulunan (bir .proto dosyasında tanımlanan) uzak işlevler, protokol arabellek dosyasındaki hizmet düğümünün içinde listelenir. Geliştiriciler olarak, protokol arabelleklerinin zengin tip sistemini kullanarak bu işlevleri ve parametrelerini tanımlıyoruz. Bu sistem, giriş ve çıkış mesajlarımızı tanımlamak için çeşitli sayısal ve tarih türlerini, listeleri, sözlükleri ve boş değerleri destekler.

Bu hizmet tanımlarının hem sunucu hem de istemci tarafından kullanılabilir olması gerekir. Ne yazık ki, .proto dosyasının kendisine doğrudan erişim sağlamanın yanı sıra bu tanımları paylaşmak için varsayılan bir mekanizma yoktur.

Bu örnek .proto dosyası, bir kimlik verilen bir ürün girişi döndürmek için bir işlevi tanımlar:

 syntax = "proto3"; package product; service ProductCatalog { rpc GetProductDetails (ProductDetailsRequest) returns (ProductDetailsReply); } message ProductDetailsRequest { int32 id = 1; } message ProductDetailsReply { int32 id = 1; string name = 2; string sku = 3; Price price = 4; } message Price { float amount = 1; string currencyCode = 2; }
Snippet 1: ProductCatalog Hizmet Tanımı

Proto3'ün katı bir şekilde yazılması ve alan sıralaması, iletinin seri durumdan çıkarılmasını JSON'u ayrıştırmaktan çok daha az vergilendirme yapar.

REST ile gRPC'yi karşılaştırma

Özetlemek gerekirse, REST ile gRPC'yi karşılaştırırken en önemli noktalar şunlardır:

DİNLENME gRPC
Çapraz platform Evet Evet
Mesaj Formatı Özel ancak genellikle JSON veya XML Protokol arabellekleri
Mesaj Yük Boyutu Orta Büyük Küçük
İşleme Karmaşıklığı Daha yüksek (metin ayrıştırma) Alt (iyi tanımlanmış ikili yapı)
Tarayıcı Desteği Evet (yerli) Evet (gRPC-Web aracılığıyla)

Daha az katı sözleşmelerin ve yüke sık sık eklemelerin beklendiği durumlarda, JSON ve REST çok uygundur. Sözleşmeler daha statik kalma eğiliminde olduğunda ve hız son derece önemli olduğunda, gRPC genellikle kazanır. Üzerinde çalıştığım çoğu projede gRPC, REST'ten daha hafif ve daha performanslı olduğunu kanıtladı.

gRPC Hizmet Uygulaması

gRPC'yi benimsemenin ne kadar basit olduğunu keşfetmek için basitleştirilmiş bir proje oluşturalım.

API Projesi Oluşturma

Başlamak için Visual Studio 2022 Community Edition'da (VS) bir .NET 6 projesi oluşturacağız. ASP.NET Core gRPC Service şablonunu seçeceğiz ve hem projeyi ( InventoryAPI kullanacağız) hem de içindeki ilk çözümümüzü ( Inventory ) adlandıracağız.

Visual Studio 2022 içerisinde "Configure your new project" diyalog kutusu. Bu ekranda Project name alanına "InventoryAPI" yazdık, Location alanına "C:\MyInventoryService" seçtik ve Solution name alanına "Inventory" yazdık. . "Çözüm ve projeyi aynı dizine yerleştir" seçeneğini işaretlemeden bıraktık.

Şimdi seçelim. çerçevemiz için NET 6.0 (Uzun vadeli destek) seçeneği:

Visual Studio 2022 içinde bir Ek bilgi iletişim kutusu. Bu ekranda Framework açılır menüsünden ".NET 6.0 (Uzun vadeli destek)" seçeneğini seçtik. "Docker'ı Etkinleştir" seçeneğini işaretlemeden bıraktık.

Ürün Hizmetimizi Tanımlama

Projeyi oluşturduğumuza göre, VS, Greeter adlı örnek bir gRPC prototip tanımlama hizmeti görüntüler. Greeter çekirdek dosyalarını ihtiyaçlarımıza uyacak şekilde yeniden kullanacağız.

  • Sözleşmemizi oluşturmak için, greet.proto içeriğini Snippet 1 ile değiştirerek, product.proto dosyasını yeniden adlandıracağız.
  • Hizmetimizi oluşturmak için GreeterService.cs dosyasının içeriğini Snippet 2 ile değiştirerek ProductCatalogService.cs dosyasını yeniden adlandıracağız.
 using Grpc.Core; using Product; namespace InventoryAPI.Services { public class ProductCatalogService : ProductCatalog.ProductCatalogBase { public override Task<ProductDetailsReply> GetProductDetails( ProductDetailsRequest request, ServerCallContext context) { return Task.FromResult(new ProductDetailsReply { Id = request.Id, Name = "Purple Bowtie", Sku = "purbow", Price = new Price { Amount = 100, CurrencyCode = "USD" } }); } } }
Snippet 2: ProductCatalogService

Hizmet artık sabit kodlanmış bir ürün döndürür. Hizmetin çalışması için, yeni hizmet adına başvurmak için yalnızca Program.cs hizmet kaydını değiştirmemiz gerekir. Bizim durumumuzda, app.MapGrpcService<GreeterService>(); app.MapGrpcService<ProductCatalogService>(); yeni API'mizi çalıştırılabilir hale getirmek için.

Adil Uyarı: Standart Protokol Testiniz Değil

Denemek için cazip gelsek de, gRPC hizmetimizi uç noktasına yönelik bir tarayıcı aracılığıyla test edemeyiz. Bunu deneseydik, gRPC uç noktalarıyla iletişimin bir gRPC istemcisi aracılığıyla yapılması gerektiğini belirten bir hata mesajı alırdık.

İstemci Oluşturma

Hizmetimizi test etmek için VS'nin temel Konsol Uygulaması şablonunu kullanalım ve API'yi çağırmak için bir gRPC istemcisi oluşturalım. Madeni InventoryApp olarak adlandırdım.

Uygunluk için, sözleşmemizi paylaşacağımız göreli bir dosya yoluna başvuralım. Referansı .csproj dosyasına manuel olarak ekleyeceğiz. Ardından yolu güncelleyeceğiz ve Client modunu ayarlayacağız. Not: Göreceli referanslamayı kullanmadan önce yerel klasör yapınıza aşina olmanızı ve güvenmenizi öneririm.

Hem hizmet hem de istemci proje dosyalarında göründükleri .proto referansları şunlardır:

Hizmet Proje Dosyası
(Müşteri proje dosyasına kopyalanacak kod)
İstemci Proje Dosyası
(Yapıştırıp düzenledikten sonra)
 <ItemGroup> <Content Update="Protos\product.proto" GrpcServices="Server" /> </ItemGroup>
 <ItemGroup> <Protobuf Include="..\InventoryAPI\Protos\product.proto" GrpcServices="Client" /> </ItemGroup>

Şimdi, servisimizi aramak için Program.cs içeriğini değiştireceğiz. Kodumuz bir dizi hedefi gerçekleştirecektir:

  1. Hizmet uç noktasının konumunu temsil eden bir kanal oluşturun (bağlantı noktası değişebilir, bu nedenle gerçek değer için launchsettings.json dosyasına bakın).
  2. İstemci nesnesini oluşturun.
  3. Basit bir istek oluşturun.
  4. İsteği gönderin.
 using System.Text.Json; using Grpc.Net.Client; using Product; var channel = GrpcChannel.ForAddress("https://localhost:7200"); var client = new ProductCatalog.ProductCatalogClient(channel); var request = new ProductDetailsRequest { Id = 1 }; var response = await client.GetProductDetailsAsync(request); Console.WriteLine(JsonSerializer.Serialize(response, new JsonSerializerOptions { WriteIndented = true })); Console.ReadKey();
Snippet 3: Yeni Program.cs

Lansman için hazırlanıyor

VS'de kodumuzu test etmek için çözüme sağ tıklayıp Set Startup Projects öğesini seçeceğiz. Çözüm Özellik Sayfaları iletişim kutusunda şunları yaparız:

  • Birden çok başlangıç ​​projesinin yanındaki radyo düğmesini seçin ve Eylem açılır menüsünde her iki projeyi de ( InventoryAPI ve InventoryApp ) Başlat olarak ayarlayın.
  • Tamam'ı tıklayın.

Şimdi VS araç çubuğunda Başlat'a tıklayarak (veya F5 tuşuna basarak) çözümü başlatabiliriz. İki yeni konsol penceresi görüntülenecek: biri bize hizmetin dinlediğini söyleyecek, diğeri bize alınan ürünün ayrıntılarını gösterecek.

gRPC Sözleşme Paylaşımı

Şimdi gRPC istemcisini hizmetimizin tanımına bağlamak için başka bir yöntem kullanalım. Müşteri tarafından en erişilebilir sözleşme paylaşımı çözümü, tanımlarımızı bir URL aracılığıyla kullanılabilir hale getirmektir. Diğer seçenekler ya çok kırılgandır (bir yol üzerinden paylaşılan dosya) ya da daha fazla çaba gerektirir (bir yerel paket aracılığıyla paylaşılan sözleşme). Bir URL üzerinden paylaşım (SOAP ve Swagger/OpenAPI'nin yaptığı gibi) esnektir ve daha az kod gerektirir.

Başlamak için .proto dosyasını statik içerik olarak kullanılabilir hale getirin. Oluşturma işlemindeki kullanıcı arayüzü "Protobuf Derleyici" olarak ayarlandığından kodumuzu manuel olarak güncelleyeceğiz. Bu değişiklik, derleyiciyi bir web adresinden sunulabilmesi için .proto dosyasını kopyalamaya yönlendirir. Bu ayar VS UI aracılığıyla değiştirilirse yapı bozulur. O halde ilk adımımız InventoryAPI.csproj dosyasına Snippet 4'ü eklemektir:

 <ItemGroup> <Content Update="Protos\product.proto"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <Content Include="Protos\product.proto" CopyToPublishDirectory="PreserveNewest" /> </ItemGroup>
Snippet 4: InventoryAPI Hizmet Proje Dosyasına Eklenecek Kod

Ardından, .proto dosyamızı döndürmek üzere bir uç nokta ayarlamak için kodu ProductCatalogService.cs dosyasının üst kısmındaki Snippet 5'e ekliyoruz:

 using System.Net.Mime; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.FileProviders;
Snippet 5: Namespace İçe Aktarmaları

Ve şimdi, ayrıca ProductCatalogService.cs dosyasına app.Run() 'dan hemen önce Snippet 6'yı ekliyoruz:

 var provider = new FileExtensionContentTypeProvider(); provider.Mappings.Clear(); provider.Mappings[".proto"] = MediaTypeNames.Text.Plain; app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "Protos")), RequestPath = "/proto", ContentTypeProvider = provider }); app.UseRouting();
Snippet 6: .proto Dosyalarını API Aracılığıyla Erişilebilir Yapacak Kod

Snippets 4-6 eklendiğinde, .proto dosyasının içeriği tarayıcıda görünür olmalıdır.

Yeni Bir Test İstemcisi

Şimdi VS'nin Bağımlılık Sihirbazı ile mevcut sunucumuza bağlanacağımız yeni bir konsol istemcisi oluşturmak istiyoruz. Sorun şu ki, bu sihirbaz HTTP/2 konuşmuyor. Bu nedenle sunucumuzu HTTP/1 üzerinden konuşacak şekilde ayarlayıp sunucuyu başlatmamız gerekiyor. Sunucumuz artık .proto dosyasını kullanıma sunarken, gRPC sihirbazı aracılığıyla sunucumuza bağlanan yeni bir test istemcisi oluşturabiliriz.

  1. Sunucumuzu HTTP/1 üzerinden konuşacak şekilde değiştirmek için appsettings.json JSON dosyamızı düzenleyeceğiz:
    1. Protocol alanını ( Kestrel.EndpointDefaults.Protocols yolunda bulunur) Https okumak için ayarlayın.
    2. Dosya 'yı kaydet.
  2. Yeni istemcimizin bu proto bilgilerini okuması için sunucunun çalışıyor olması gerekir. Başlangıçta, hem önceki istemciyi hem de sunucumuzu VS'nin Başlangıç ​​Projelerini Ayarla iletişim kutusundan başlattık. Yalnızca sunucu projesini başlatmak için sunucu çözümünü ayarlayın, ardından çözümü başlatın. (Artık HTTP sürümünü değiştirdiğimiz için eski istemcimiz artık sunucuyla iletişim kuramıyor.)
  3. Ardından, yeni test istemcisini oluşturun. Başka bir VS örneğini başlatın. API Projesi Oluşturma bölümünde ayrıntılı olarak açıklanan adımları tekrarlayacağız, ancak bu sefer Konsol Uygulaması şablonunu seçeceğiz. Projemizi ve çözümümüzü InventoryAppConnected adlandıracağız.
  4. Oluşturulan istemci kasası ile gRPC sunucumuza bağlanacağız. VS Solution Explorer'da yeni projeyi genişletin.
    1. Bağımlılıklar'a sağ tıklayın ve içerik menüsünde Bağlı Hizmetleri Yönet'i seçin.
    2. Bağlı Hizmetler sekmesinde, Hizmet referansı ekle'yi tıklayın ve gRPC'yi seçin.
    3. Hizmet Referansı Ekle iletişim kutusunda, URL seçeneğini seçin ve hizmet adresinin http sürümünü girin (rastgele oluşturulmuş bağlantı noktası numarasını launchsettings.json almayı unutmayın) .
    4. Kolayca korunabilecek bir hizmet referansı eklemek için Bitir'e tıklayın.

Çalışmanızı bu örnek için örnek koda göre kontrol etmekten çekinmeyin. Başlık altında, VS, ilk test turumuzda kullandığımız aynı istemciyi oluşturduğundan, önceki hizmetten alınan Program.cs dosyasının içeriğini yeniden kullanabiliriz.

Bir sözleşmeyi değiştirdiğimizde, istemci gRPC tanımımızı güncellenmiş .proto tanımıyla eşleşecek şekilde değiştirmemiz gerekir. Bunu yapmak için yalnızca VS'nin Bağlı Hizmetlerine erişmemiz ve ilgili hizmet girişini yenilememiz gerekiyor. Artık gRPC projemiz tamamlandı ve hizmetimizi ve müşterimizi senkronize tutmak çok kolay.

Bir Sonraki Proje Adayınız: gRPC

gRPC uygulamamız, gRPC kullanmanın faydalarına ilk elden bir bakış sağlar. REST ve gRPC'nin her birinin, sözleşme türüne bağlı olarak kendi ideal kullanım durumları vardır. Ancak, her iki seçenek de uygun olduğunda, gRPC'yi denemenizi tavsiye ederim; bu, API'lerin geleceğinde sizi eğrinin önüne geçirecektir.