gRPC vs. REST: Memulai dengan Protokol API Terbaik

Diterbitkan: 2022-07-22

Dalam lanskap teknologi saat ini, sebagian besar proyek memerlukan penggunaan API. API menjembatani komunikasi antar layanan yang dapat mewakili satu sistem yang kompleks tetapi juga dapat berada di mesin yang terpisah atau menggunakan beberapa jaringan atau bahasa yang tidak kompatibel.

Banyak teknologi standar menjawab kebutuhan komunikasi antar layanan dari sistem terdistribusi, seperti REST, SOAP, GraphQL, atau gRPC. Sementara REST adalah pendekatan yang disukai, gRPC adalah pesaing yang layak, menawarkan kinerja tinggi, kontrak yang diketik, dan alat yang sangat baik.

Ikhtisar REST

Representational state transfer (REST) ​​adalah sarana untuk mengambil atau memanipulasi data layanan. REST API umumnya dibangun di atas protokol HTTP, menggunakan URI untuk memilih sumber daya dan kata kerja HTTP (misalnya, GET, PUT, POST) untuk memilih operasi yang diinginkan. Badan permintaan dan tanggapan berisi data yang khusus untuk operasi, sementara headernya menyediakan metadata. Sebagai ilustrasi, mari kita lihat contoh sederhana pengambilan produk melalui REST API.

Di sini, kami meminta sumber daya produk dengan ID 11 dan mengarahkan API untuk merespons dalam format JSON:

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

Dengan permintaan ini, respons kami (tajuk yang tidak relevan dihilangkan) mungkin terlihat seperti:

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

Meskipun JSON mungkin dapat dibaca manusia, JSON tidak optimal saat digunakan antar layanan. Sifat berulang dari referensi nama properti—bahkan saat dikompresi—dapat menyebabkan pesan membengkak. Mari kita lihat alternatif untuk mengatasi masalah ini.

Ikhtisar gRPC

gRPC Remote Procedure Call (gRPC) adalah protokol komunikasi lintas platform open-source, berbasis kontrak, yang menyederhanakan dan mengelola komunikasi antar layanan dengan memaparkan serangkaian fungsi ke klien eksternal.

Dibangun di atas HTTP/2, gRPC memanfaatkan fitur seperti streaming dua arah dan Transport Layer Security (TLS) bawaan. gRPC memungkinkan komunikasi yang lebih efisien melalui muatan biner serial. Ini menggunakan buffer protokol secara default sebagai mekanismenya untuk serialisasi data terstruktur, mirip dengan penggunaan JSON oleh REST.

Tidak seperti JSON, bagaimanapun, buffer protokol lebih dari format serial. Mereka termasuk tiga bagian utama lainnya:

  • Bahasa definisi kontrak ditemukan di file .proto (Kami akan mengikuti proto3, spesifikasi bahasa buffer protokol terbaru.)
  • Kode fungsi aksesor yang dihasilkan
  • Pustaka runtime khusus bahasa

Fungsi jarak jauh yang tersedia pada layanan (didefinisikan dalam file .proto ) terdaftar di dalam node layanan dalam file buffer protokol. Sebagai pengembang, kita dapat mendefinisikan fungsi-fungsi ini dan parameternya menggunakan sistem tipe kaya buffer protokol. Sistem ini mendukung berbagai jenis numerik dan tanggal, daftar, kamus, dan nullable untuk menentukan pesan input dan output kita.

Definisi layanan ini harus tersedia untuk server dan klien. Sayangnya, tidak ada mekanisme default untuk membagikan definisi ini selain menyediakan akses langsung ke file .proto itu sendiri.

Contoh file .proto ini mendefinisikan fungsi untuk mengembalikan entri produk, dengan ID:

 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; }
Cuplikan 1: ProductCatalog Layanan Katalog Produk

Pengetikan yang ketat dan pengurutan bidang proto3 membuat deserialisasi pesan jauh lebih sedikit membebani daripada mengurai JSON.

Membandingkan REST vs. gRPC

Untuk rekap, poin paling signifikan saat membandingkan REST vs. gRPC adalah:

ISTIRAHAT gRPC
lintas platform Ya Ya
Format Pesan Kustom tetapi umumnya JSON atau XML Penyangga protokol
Ukuran Muatan Pesan Sedang/Besar Kecil
Kompleksitas Pemrosesan Lebih tinggi (penguraian teks) Lebih rendah (struktur biner yang terdefinisi dengan baik)
Dukungan Peramban Ya (asli) Ya (melalui gRPC-Web)

Di mana kontrak yang tidak terlalu ketat dan penambahan muatan yang sering diharapkan, JSON dan REST sangat cocok. Ketika kontrak cenderung tetap statis dan kecepatan adalah yang paling penting, gRPC umumnya menang. Di sebagian besar proyek yang pernah saya kerjakan, gRPC terbukti lebih ringan dan lebih berperforma daripada REST.

Implementasi Layanan gRPC

Mari kita buat proyek yang disederhanakan untuk mempelajari betapa sederhananya mengadopsi gRPC.

Membuat Proyek API

Untuk memulai, kita akan membuat proyek .NET 6 di Visual Studio 2022 Community Edition (VS). Kami akan memilih template ASP.NET Core gRPC Service dan memberi nama proyek (kami akan menggunakan InventoryAPI ) dan solusi pertama kami di dalamnya ( Inventory ) .

Dialog "Konfigurasikan proyek baru Anda" dalam Visual Studio 2022. Di layar ini kami mengetik "InventoryAPI" di bidang Nama proyek, kami memilih "C:\MyInventoryService" di bidang Lokasi, dan mengetik "Inventaris" di bidang Nama solusi . Kami membiarkan "Tempatkan solusi dan proyek di direktori yang sama" tidak dicentang.

Sekarang, mari kita pilih. Opsi .NET 6.0 (Dukungan jangka panjang) untuk kerangka kerja kami:

Dialog informasi tambahan dalam Visual Studio 2022. Di layar ini kami memilih ".NET 6.0 (Dukungan jangka panjang)" dari dropdown Framework. Kami membiarkan "Aktifkan Docker" tidak dicentang.

Mendefinisikan Layanan Produk Kami

Sekarang setelah kita membuat proyek, VS menampilkan contoh layanan definisi prototipe gRPC bernama Greeter . Kami akan menggunakan kembali file inti Greeter agar sesuai dengan kebutuhan kami.

  • Untuk membuat kontrak kita, kita akan mengganti isi dari greet.proto dengan Snippet 1, mengganti nama file product.proto .
  • Untuk membuat layanan kami, kami akan mengganti konten file GreeterService.cs dengan Cuplikan 2, mengganti nama file ProductCatalogService.cs .
 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" } }); } } }
Cuplikan 2: ProductCatalogService

Layanan sekarang mengembalikan produk hardcoded. Untuk membuat layanan berfungsi, kita hanya perlu mengubah pendaftaran layanan di Program.cs untuk merujuk nama layanan baru. Dalam kasus kami, kami akan mengganti nama app.MapGrpcService<GreeterService>(); ke app.MapGrpcService<ProductCatalogService>(); untuk membuat API baru kami dapat dijalankan.

Peringatan Adil: Bukan Tes Protokol Standar Anda

Meskipun kami mungkin tergoda untuk mencobanya, kami tidak dapat menguji layanan gRPC kami melalui browser yang ditujukan untuk titik akhirnya. Jika kami mencoba ini, kami akan menerima pesan kesalahan yang menunjukkan bahwa komunikasi dengan titik akhir gRPC harus dilakukan melalui klien gRPC.

Membuat Klien

Untuk menguji layanan kami, mari gunakan template Aplikasi Konsol dasar VS dan buat klien gRPC untuk memanggil API. Saya menamai InventoryApp milik saya.

Untuk kemanfaatan, mari merujuk ke jalur file relatif yang dengannya kita akan membagikan kontrak kita. Kami akan menambahkan referensi secara manual ke file .csproj . Kemudian, kami akan memperbarui jalur dan mengatur mode Client . Catatan: Saya sarankan Anda mengenal dan yakin dengan struktur folder lokal Anda sebelum menggunakan referensi relatif.

Berikut adalah referensi .proto , seperti yang muncul di file proyek layanan dan klien:

File Proyek Layanan
(Kode untuk disalin ke file proyek klien)
File Proyek Klien
(Setelah menempel dan mengedit)
 <ItemGroup> <Content Update="Protos\product.proto" GrpcServices="Server" /> </ItemGroup>
 <ItemGroup> <Protobuf Include="..\InventoryAPI\Protos\product.proto" GrpcServices="Client" /> </ItemGroup>

Sekarang, untuk memanggil layanan kami, kami akan mengganti konten Program.cs . Kode kami akan mencapai sejumlah tujuan:

  1. Buat saluran yang mewakili lokasi titik akhir layanan (port dapat bervariasi, jadi lihat file launchsettings.json untuk nilai sebenarnya).
  2. Buat objek klien.
  3. Buat permintaan sederhana.
  4. Kirim permintaan.
 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();
Cuplikan 3: Program.cs

Mempersiapkan Peluncuran

Untuk menguji kode kami, di VS, kami akan mengklik kanan solusi dan memilih Set Startup Projects . Dalam dialog Halaman Properti Solusi, kita akan:

  • Pilih tombol radio di samping Beberapa proyek startup , dan di menu tarik-turun Tindakan, atur kedua proyek ( InventoryAPI dan InventoryApp ) ke Mulai .
  • Klik Oke .

Sekarang kita dapat memulai solusi dengan mengklik Mulai di toolbar VS (atau dengan menekan tombol F5 ). Dua jendela konsol baru akan ditampilkan: satu untuk memberi tahu kami bahwa layanan sedang mendengarkan, yang lain untuk menunjukkan kepada kami detail produk yang diambil.

Berbagi Kontrak gRPC

Sekarang mari kita gunakan metode lain untuk menghubungkan klien gRPC ke definisi layanan kita. Solusi berbagi kontrak yang paling dapat diakses klien adalah dengan membuat definisi kami tersedia melalui URL. Opsi lain sangat rapuh (file dibagikan melalui jalur) atau memerlukan lebih banyak upaya (kontrak dibagikan melalui paket asli). Berbagi melalui URL (seperti yang dilakukan SOAP dan Swagger/OpenAPI) fleksibel dan membutuhkan lebih sedikit kode.

Untuk memulai, buat file .proto tersedia sebagai konten statis. Kami akan memperbarui kode kami secara manual karena UI pada tindakan build diatur ke "Protobuf Compiler." Perubahan ini mengarahkan kompiler untuk menyalin file .proto sehingga dapat disajikan dari alamat web. Jika pengaturan ini diubah melalui UI VS, build akan rusak. Langkah pertama kita adalah menambahkan Cuplikan 4 ke file InventoryAPI.csproj :

 <ItemGroup> <Content Update="Protos\product.proto"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <Content Include="Protos\product.proto" CopyToPublishDirectory="PreserveNewest" /> </ItemGroup>
Cuplikan 4: Kode untuk Ditambahkan ke File Proyek Layanan InventoryAPI

Selanjutnya, kami memasukkan kode dalam Cuplikan 5 di bagian atas file ProductCatalogService.cs untuk menyiapkan titik akhir untuk mengembalikan file .proto kami:

 using System.Net.Mime; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.FileProviders;
Cuplikan 5: Impor Namespace

Dan sekarang, kami menambahkan Cuplikan 6 tepat sebelum app.Run() , juga di file ProductCatalogService.cs :

 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();
Cuplikan 6: Kode untuk Membuat File .proto Dapat Diakses Melalui API

Dengan menambahkan Cuplikan 4-6, konten file .proto akan terlihat di browser.

Klien Uji Baru

Sekarang kami ingin membuat klien konsol baru yang akan kami sambungkan ke server kami yang ada dengan VS's Dependency Wizard. Masalahnya adalah wizard ini tidak berbicara HTTP/2. Oleh karena itu, kita perlu menyesuaikan server kita untuk berbicara melalui HTTP/1 dan memulai server. Dengan server kami sekarang membuat file .proto tersedia, kami dapat membangun klien uji baru yang terhubung ke server kami melalui wizard gRPC.

  1. Untuk mengubah server kami untuk berbicara melalui HTTP/1, kami akan mengedit file JSON appsettings.json kami:
    1. Sesuaikan bidang Protocol (dapat ditemukan di jalur Kestrel.EndpointDefaults.Protocols ) untuk membaca Https .
    2. Simpan file.
  2. Agar klien baru kami dapat membaca informasi proto ini, server harus berjalan. Awalnya, kami memulai klien sebelumnya dan server kami dari dialog Set Startup Projects VS. Sesuaikan solusi server untuk memulai hanya proyek server, lalu mulai solusi. (Sekarang kami telah memodifikasi versi HTTP, klien lama kami tidak dapat lagi berkomunikasi dengan server.)
  3. Selanjutnya, buat klien pengujian baru. Luncurkan instance lain dari VS. Kami akan mengulangi langkah-langkah seperti yang dijelaskan di bagian Membuat Proyek API , tetapi kali ini, kami akan memilih template Aplikasi Konsol . Kami akan memberi nama proyek dan solusi kami InventoryAppConnected .
  4. Dengan sasis klien dibuat, kami akan terhubung ke server gRPC kami. Perluas proyek baru di VS Solution Explorer.
    1. Klik kanan Dependensi dan, di menu konteks, pilih Kelola Layanan Terhubung .
    2. Pada tab Layanan Terhubung, klik Tambahkan referensi layanan dan pilih gRPC .
    3. Dalam dialog Tambahkan Referensi Layanan, pilih opsi URL dan masukkan versi http dari alamat layanan (ingat untuk mengambil nomor port yang dibuat secara acak dari launchsettings.json ) .
    4. Klik Selesai untuk menambahkan referensi layanan yang dapat dipelihara dengan mudah.

Jangan ragu untuk memeriksa pekerjaan Anda dengan kode sampel untuk contoh ini. Karena, di bawah tenda, VS telah menghasilkan klien yang sama yang kami gunakan dalam pengujian putaran pertama kami, kami dapat menggunakan kembali konten file Program.cs dari layanan sebelumnya verbatim.

Saat mengubah kontrak, kita perlu memodifikasi definisi gRPC klien agar sesuai dengan definisi .proto yang diperbarui. Untuk melakukannya, kita hanya perlu mengakses Layanan Terhubung VS dan menyegarkan entri layanan yang relevan. Sekarang, proyek gRPC kami telah selesai, dan sangat mudah untuk menjaga sinkronisasi layanan dan klien kami.

Kandidat Proyek Anda Berikutnya: gRPC

Implementasi gRPC kami memberikan gambaran langsung tentang manfaat penggunaan gRPC. REST dan gRPC masing-masing memiliki kasus penggunaan idealnya sendiri tergantung pada jenis kontrak. Namun, ketika kedua opsi cocok, saya mendorong Anda untuk mencoba gRPC—ini akan menempatkan Anda di depan kurva di masa depan API.