- 著者は|モハマド·ローランド
- 翻訳者。|チャン·ウェイビン
- 計画する。|ティン·シャオ
基本的に、APIはサーバーとクライアント間のプロトコルであり、サーバーがクライアントからのリクエストに基づいて特定のデータを提供する方法を指定します。

APIを構築する際には、さまざまなテクノロジーを考えます。ニーズに応じて、APIを開発するために選択するテクノロジーも変わります。現在、APIを作成するために使用される技術は主に2つあります。
- gRPC
- REST
どちらの技術もトランスポートメカニズムとしてHTTPを使用します。基本的なトランスポートメカニズムは同じですが、実装は全く異なります。
g RPCを深く掘り下げる前に、2つの技術を比較してみましょう。
REST
RESTは、プロトコルや標準ではなく、アーキテクチャ上の制約のセットです。API開発者は様々な方法でRESTを実装できます。
APIがRESTfulと見なされるためには、いくつかの制約に従う必要があります。
クライアント-サーバアーキテクチャ:すべてのリクエストはHTTPを転送メカニズムとして使用する必要があります。
ステートレス:APIはステートレスでなければなりません。つまり、サーバーはクライアントセッションの状態をサーバー側に保存してはいけません。クライアントからサーバへのすべてのリクエストには、リクエストを理解するために必要なすべての情報が含まれています。サーバーはサーバー側に保存されたコンテキストを使用できません。
キャッシュ可能:クライアントとサーバ間を流れるすべてのデータはキャッシュ可能でなければなりません。つまり、後で取得して使用できるように保存できます。
統一インタフェース:クライアントとサーバの間には、標準形式で情報を転送できるようにインタフェースが必要です。
階層型システム:クライアント側のリクエストとサーバ側のレスポンスの間に関与するすべてのサーバは、リクエストやレスポンスに影響を与えないように、その責任に従って組織化されなければなりません。
gRPC
g RPCはRPC(Remote Procedure Call)プロトコルの強固な基盤の上に構築されており、APIの領域にも参入しています。g RPCはGoogleによって開発されたフリーでオープンソースのフレームワークで、API 通信にHTTP/2を使用し、API設計者からHTTP実装を隠している。
g RPCは、マイクロサービスとWeb/モバイルAPI 通信の両方において、次世代のWebアプリケーションの基盤となる多くの機能を備えています。
相互運用性Interoperability:現在のHTTPバージョンが何であれ、インフラストラクチャがどのように変更されても(例えば、HTTP 2からHTTP 3へのアップグレード)、プロトコルは適応し、変更できる必要があります。
階層アーキテクチャ:テクノロジースタックのコアは、それを使用するアプリケーションを破壊することなく、独立して進化およびアップグレードできる必要があります。
ペイロードの中立性Agnosticサービスによって異なるメッセージタイプやエンコーディングが必要になる場合があります。例えば、Protobuf Protocol buffer、JSON、XMLなどです。g RPCはこれらすべてのフォーマットをサポートし、プラグイン可能な圧縮メカニズムを使用して負荷を圧縮できます。
ストリーム:g RPCは、大規模なデータセットをサーバからクライアントにストリーミングすることを可能にします。
プラグイン可能Pluggable gRPCは、ヘルスチェック、フェイルバック、ロードバランシングなど、さまざまな機能やサービスをオンデマンドでプラグインできるようにします。フレームワーク実装は、これらの機能を挿入できる拡張ポイントを提供します。
dockerやkubernetesと同様に、gはCloud Native Foundation CNCFの一部である。
簡単に言えば、g RPCの利点は以下のとおりです。
モダンで速い。
オープンソースソース
HTTP/2の使用
言語中立性
認定、ログの追加が容易
g RPCを使う場合:
メッセージとサービスを定義するにはProtobuf(プロトコルバッファ)が必要です。
g RPCコードは自動的に生成され、実装を提供する必要があります。
サーバー側とクライアント側の両方で、.protoファイルは12の異なる言語をサポートします。
デフォルトでは、g RPCは構造化データのシリアル化にGoogleのオープンソースプロトコルバッファメカニズムを使用します。
言語中立です。
現代のプログラミング言語のコードを生成する能力
データ転送はバイナリで効率的
非常に拡張可能
大量のデータを送信できます
APIの拡張と進化を可能にする

事例学習:
今日のテクノロジートレンドでは、マイクロサービスを構築することがより現代的な方法です。この例では、航空券システムを構築するプロセスを見てみましょう。

上の図はマイクロサービスベースの航空券システムを示しています。ここでは、このタイプのアーキテクチャに関連するいくつかの重要な点に注意が必要です。
マイクロサービスは通常異なる言語で構築される。予約管理サービスは. NETベースで構築でき、支払い処理はJavaベースで、乗客情報はNode.jsを使用していると言えます。
サービスごとに異なるビジネス機能があります。
異なる言語で書かれたマイクロサービスがあり、互いに通信しているとします。これらのマイクロサービスが情報を交換したい場合、次のようなことについて合意する必要があります。
データ交換のAPI。
データ形式
間違った形式
アクセス速度の制限
RESTはAPIを構築する最も一般的な方法です。しかし、この決定は、実装に関連する多くのアーキテクチャ上の考慮事項に依存します。
設計データモデルの種類;
終点はどのように見えるか。
エラーへの対処方法;
クライアントが実行できる呼び出しの数;
権限の行使方法。
これらを念頭に置いて、g RPCとRESTの違いを見てみましょう。
gRPC
Contract First API開発のアプローチ:Contract(サービスとメッセージ)は*.protoファイルで定義され、g RPCの中核となります。これは言語に依存しない方法でAPIを定義することです。これらのファイルは、他のプログラミング言語(強型付きクライアントやメッセージクラスなど)でコードを生成するために使用される。
HTTP/2とProtobufはバイナリプロトコルであり、コンテンツはコンピュータと高性能のために設計されています。
g RPCの設計は遠隔操作の複雑さを隠している。g RPCライブラリと関連するコード生成を使用することで、ルーティング、ヘッダ情報、シリアライズなどの問題を気にする必要はありません。クライアント側でメソッドを呼び出す必要がある場合は、対応するメソッドを呼び出すだけで済みます。
g RPCは双方向の非同期ストリームをサポートしており、g RPC呼び出しがストリームを確立すると、クライアントとサーバはいつでも非同期ストリームを互いに送信することができる。サーバストリームとクライアントサイドストリーム(この場合、レスポンスまたはリクエストのどちらか一方だけがストリームになります)もサポートされます。
g RPCは、分散アプリケーションの高性能と生産性のために設計されています。
REST API
コンテンツファーストのAPI開発アプローチ(URL、HTTPメソッド、JSON):可読性とフォーマットに焦点を当てます。
コンテンツはテキストベース(HTTP 1.1とJSON)なので、人間が読めるようになります。その結果、デバッグには最適ですが、パフォーマンスには優しくありません。
HTTPを強化する。低レベルの問題を考慮する必要があります。HTTPリクエストをかなり制御できるので、これは良いことです。
CRUDへ。
最も幅広いオーディエンス:すべてのコンピュータでHTTP/1.1とJSONを使用でき、使いやすいです。
これらの比較から、両方のアプローチには利点があることがわかります。しかし、g RPCはマイクロサービスベースのシナリオに強力な機能セットを提供することがわかります。
g RPCを使用したサーバ-クライアントアプリケーションの作成
コーディングを始める前に、以下のソフトウェアをコンピュータにインストールします。
ソフトウェアのインストールが完了したら、プロジェクト構造を作成する必要があります(この記事では、ターミナル/コマンドラインから直接dotnetコマンドを使用します)。
dotnet new grpc -n GrpcService
SSL信頼を設定する必要があります。
dotnet dev-certs https --trust
次に、VS Codeで新しいプロジェクトを開き、作成されたものを見てみましょう。自動的に次のようなものが表示されます:
Protosフォルダの作成
Servicesフォルダ
Protosフォルダにはgreet.protoファイルがあります。前述したように、.protoは言語に依存しない方法でAPIを定義できます。
このファイルから、GreeterサービスとSayHelloメソッドが含まれていることがわかります。Greeterサービスをコントローラと考え、SayHelloメソッドをアクションと考えることができます。protoファイルの内容は次の通りです。
// 声明我们可以使用的最新模式
syntax = "proto3";
// 为该 proto 定义命名空间,通常与我们的 Grpc 服务器相同
option csharp_namespace = "GrpcService";
package greet;
// 我们可以把一个服务看做一个类
service Greeter {
// 发送问候语
rpc SayHello (HelloRequest) returns (HelloReply);
}
// 请求消息类似于 C# 中的一个模型,其中会定义属性
// 这里的数字用来对属性进行排序
message HelloRequest {
string name = 1;
}
// 响应消息包含了问候语
message HelloReply {
string message = 1;
}
SayHelloメソッドはHelloRequest(これはメッセージ)を受け取り、HelloReply(これもメッセージ)を返す。
GreeterServiceファイルには、.protoファイルによって自動的に生成されたGreeterBaseから継承されたGreeterServiceクラスがあることがわかります。
SayHelloメソッドでは、リクエスト(HelloRequest)を受信し、レスポンス(HelloReply)を返します。また、.protoファイルから自動的に生成されます。
コードの自動生成は、.protoファイルに基づいて必要なファイルを生成します。g RPCは、コード生成、ルーティング、シリアル化の面倒な作業をすべて行ってくれます。基本クラスを実装し、メソッドの実装をオーバーライドするだけです。
次に、g RPCサービスを実行します。
dotnet run
自動生成されたエンドポイントの結果から、RESTのクライアントとしてWebブラウザを使用するようにg RPCを使用することはできません。この場合、サービスと通信するためのg RPCクライアントを作成する必要があります。g RPCはコントラクトファーストのRPCフレームワークであるため、クライアント側では.protoファイルも必要です。現在、ウェブブラウザはクライアントについて何も知らないので(.protoファイルはありません)、リクエストを処理する方法を知りません。
customers.protoというカスタム.protoファイルを作成します。このファイルはProtosフォルダに作成する必要があり、その内容は以下のとおりです。
syntax = "proto3";
option csharp_namespace = "GrpcService";
package customers;
service Customer {
rpc GetCustomerInfo (CustomerFindModel) returns (CustomerDataModel);
}
message CustomerFindModel {
int32 userId = 1; // bool, int32, float, double, string
}
message CustomerDataModel {
string firstName = 1;
string lastName = 2;
}
上記のファイルを保存したら、.csprojファイルに追加する必要があります。
<ItemGroup>
<Protobuf Include="Protos\\customers.proto" GrpcServices="Server" />
</ItemGroup>
次に、アプリケーションを構築する必要があります:
dotnet build
次のステップは、Customer ServiceクラスをServicesフォルダに追加し、以下のように内容を更新することです。
public class CustomerService : Customer.CustomerBase
{
private readonly ILogger<CustomerService> _logger;
public CustomerService(ILogger<CustomerService> logger)
{
_logger = logger;
}
public override Task<CustomerDataModel> GetCustomerInfo(CustomerFindModel request, ServerCallContext context)
{
CustomerDataModel result = new CustomerDataModel();
// 这是一个用于演示的代码
// 在实际的场景中,这些信息应该从数据库中获取
// 应用中的数据不应该被硬编码
if(request.UserId == 1) {
result.FirstName = "Mohamad";
result.LastName = "Lawand";
} else if(request.UserId == 2) {
result.FirstName = "Richard";
result.LastName = "Feynman";
} else if(request.UserId == 3) {
result.FirstName = "Bruce";
result.LastName = "Wayne";
} else {
result.FirstName = "James";
result.LastName = "Bond";
}
return Task.FromResult(result);
}
}

ここで、Startup.csクラスを更新して、新しく作成したサービスに新しいエンドポイントがあることをアプリケーションに通知する必要があります。これを行うには、Configureメソッド(app.UserEndpoints内)に次のコードを追加する必要があります。
endpoints.MapGrpcService<CustomerService>();
macOSの注意事項:
因为 MacOS 不支持 TLS 之上的 HTTP/2,所以我们需要采用如下的方案来更新 Program.cs 文件:
webBuilder.ConfigureKestrel(options =>
{
// 设置无需 TLS 的 HTTP/2 端点
options.ListenLocalhost(5000, o => o.Protocols =
HttpProtocols.Http2);
});
次のステップは、クライアントアプリケーションの作成です。
dotnet new console -o GrpcGreeterClient
次に、g RPCを認識するために必要なパッケージをクライアントコンソールアプリケーションに追加する必要があります。これはGrpcGreeterClientクラスで行うことができます。
dotnet add package Grpc.Net.Client
dotnet add package Google.Protobuf
dotnet add package Grpc.Tools
クライアントはサーバーと同じコントラクトを持つ必要があるため、前のステップで作成した.protoファイルをクライアントアプリケーションに追加する必要があります。これを達成するには:
まず、Protosという名前のフォルダをクライアントプロジェクトに追加する必要があります。
g RPC greeterサービス内のProtosフォルダの内容をg RPCクライアントプロジェクトにコピーする必要があります。
greet.proto
customers.proto
- ファイルを貼り付けた後、名前空間を更新してクライアントアプリケーションと同じにする必要があります。
c GrpcGreeterClient.csprojファイルを更新して、新しく追加した.protoファイルを知らせる必要があります。
<ItemGroup>
<Protobuf Include="Protos\\greet.proto" GrpcServices="Client" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\\customers.proto" GrpcServices="Client" />
</ItemGroup>
このProtobuf要素は、コードが.protoファイルを理解する機能を自動的に生成する方法です。上記の変更により、クライアントが新しく追加した.protoファイルを使用することをここで示します。
クライアントを構築し、すべてを成功させる必要があります。
dotnet run
次に、サーバー側を簡単に呼び出すためにコンソールアプリケーションにコードを追加します。Program.csファイルで、以下の変更を加える必要があります:
// 我们创建一个通道,它代表了客户端到服务器的连接
// 我们在这里添加的 URL 是由服务器的 Kestrel 所提供的
var channel = GrcpChannel.ForAddress("<https://localhost:5001>");
// 这个强类型的客户端是当我们添加.proto 文件时,由代码生成功能所创建的
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest
{
Name = "Mohamad"
});
Console.WriteLine("From Server: " + response.Message);
var customerClient = new Customer.CustomerClient(channel);
var result = await customerClient.GetCustomerInfoAsync(new CustomerFindModel()
{
UserId = 1
});
Console.WriteLine($"First Name: {result.FirstName} - Last Name: {result.LastName}");
次に、アプリケーションにストリーム処理機能を追加します。
customers.protoファイルに戻り、Customerサービスにストリームメソッドを追加します。
// 我们要返回一个消费者的列表
// 但是在 gRPC 中我们不能返回列表,而是需要返回一个流
rpc GetAllCustomers (AllCustomerModel) returns (stream CustomerDataModel);
ご覧のように、returnにstreamキーワードを追加しています。つまり、“複数の”レスポンスで構成されるストリームを追加しています。
空のメッセージを追加する必要があります。
// 在 gRPC 中,我们不能定义具有空参数的方法
// 所以,我们定义一个空消息
message AllCustomerModel {
}
このメソッドを実装するには、Servicesフォルダの下に移動し、Customer Serviceクラスに次のコードを追加します。
public override async Task GetAllCustomers(AllCustomerModel request, IServerStreamWriter<CustomerDataModel> responseStream, ServerCallContext context)
{
var allCustomers = new List<CustomerDataModel>();
var c1 = new CustomerDataModel();
c1.Name = "Mohamad Lawand";
c1.Email = "mohamad@mail.com";
allCustomers.Add(c1);
var c2 = new CustomerDataModel();
c2.Name = "Richard Feynman";
c2.Email = "richard@physics.com";
allCustomers.Add(c2);
var c3 = new CustomerDataModel();
c3.Name = "Bruce Wayne";
c3.Email = "bruce@gotham.com";
allCustomers.Add(c3);
var c4 = new CustomerDataModel();
c4.Name = "James Bond";
c4.Email = "007@outlook.com";
allCustomers.Add(c4);
foreach(var item in allCustomers)
{
await responseStream.WriteAsync(item);
}
}
次に、サーバー側のcustomers.protoファイルの変更をクライアント側のcustomers.protoファイルにコピーする必要があります。
service Customer {
rpc GetCustomerInfo (CustomerFindModel) returns (CustomerDataModel);
// 我们要返回一个消费者的列表
// 但是在 gRPC 中我们不能返回列表,而是需要返回一个流
rpc GetAllCustomers (AllCustomerModel) returns (stream CustomerDataModel);
}
// 在 gRPC 中,我们不能定义具有空参数的方法
// 所以,我们定义一个空消息
message AllCustomerModel {
}
もう一度アプリケーションを構築する必要があります。
dotnet build
次に、GrpcClientAppのProgram.csファイルを更新して、新しいストリームメソッドを処理する必要があります。
var customerCall = customerClient.GetAllCustomers(new AllCustomerModel());
await foreach(var customer in customerCall.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"{customer.Name} {customer.Email}");
}
GrpcGreeterに戻り、greet.protoファイルを更新してstreamメソッドを追加します:
rpc SayHelloStream(HelloRequest) returns (stream HelloReply);
ご覧の通り、returnにストリームキーワードを追加しています。つまり、“複数の”レスポンスからなるストリームを追加しています。このメソッドを実装するには、Servicesフォルダに移動し、GreeterServiceに以下を追加する必要があります。
public override async Task SayHelloStream(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
for (int i = 0; i < 10; i ++)
{
await responseStream.WriteAsync(new HelloReply
{
Message = "Hello " + request.Name + " " + i
});
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
ここで、greet.protoファイルの変更をサーバ侧からクライアントにコピーしてビルドする必要があります。クライアントアプリケーションのgreet.protoファイルに、次の行を追加します。
rpc SayHelloStream(HelloRequest) returns (stream HelloReply);
protoファイルを保存した後で、アプリケーションをビルドしてください。
dotnet build
これでProgram.csを開き、新しいメソッドを使用できます:
var call = client.SayHelloStream(new HelloRequest
{
Name = "Mohamad"
});
await foreach(var item in call.ResponseStream.ReadAllAsync())
{
Console.WriteLine("Result " + item.Message);
}
この例では、. NET 5でg RPCのクライアントサーバアプリケーションを実装する方法を示します。
総結点は
アプリケーションを構築する際にg RPCの力を見ることができますが、g RPCサービスを構築するにはセットアップ時間とクライアントとサーバの調整が必要なため、その力を活用するのは簡単ではありません。RESTでは、エンドポイントの消費を開始するためにセットアッププロセスはほとんど必要ありません。
どちらのテクノロジーにも特定のユースケースがあるため、g RPCは必ずしもRESTを置き換えるものではない。お客様のビジネスシナリオやニーズに基づいて、プロジェクトに適したテクノロジーを選択してください。
** 著者のプロフィール:**
Mohamad Lawand 是一位坚定的、具有前瞻性的技术架构师,拥有 13 年以上的工作经验,工作范围涉及从金融机构到政府实体等众多行业。他积极主动,适应性强,擅长跨多平台的 SaaS 和区块链技术。Mohamad 还拥有一个 Youtube 频道,他会在那里分享自己的知识。
** オリジナルのリンク:**