Service Extension アプリの作成
注釈:本資料はAI技術を用いて翻訳されています。
概要
Extend Service Extensionアプリは、gRPC ServerとgRPC Gatewayを含むスタックを使用して作成されたRESTful Webサービスです。
一般的に、このスタックを使用してRESTful Webサービスをゼロから構築する手順は次のとおりです。
- protobuf(
*.proto)ファイルを使用してgRPCサーバーを定義します。 *.protoファイルからスタブを生成し、gRPC Serverを実装します。*.protoファイルからgRPC Gatewayコードを生成し、そのエントリーポイントを記述します。*.protoファイルからOpenAPI 2.0仕様を生成します。
ただし、Service Extension appテンプレートを使用すると、手順1と2のみを実行する必要があります。残りの手順は、ビルド時に自動的に実行されるようにパッケージ化されています。このアプリテンプレートには、認証が必要なRESTfulエンドポイントの作成を支援するgRPCサーバーインターセプターも付属しています。さらに、可観測性のための組み込みインストルメンテーションが付属しており、デプロイ時にメトリクスとログが利用可能になります。
この記事では、Extend Service Extension appテンプレートを変更し、要件に合った独自のアプリに変換する方法について説明します。
前提条件
Extend Service Extension appテンプレートをクローンしていること。
- C#
- Go
- Java
- Python
git clone https://github.com/AccelByte/extend-service-extension-csharp
git clone https://github.com/AccelByte/extend-service-extension-go
git clone https://github.com/AccelByte/extend-service-extension-java
git clone https://github.com/AccelByte/extend-service-extension-python
プロジェクト構造
- C#
- Go
- Java
- Python
Extend Service Extensionアプリをカスタマイズするには、service.protoとMyService.csファイルを変更します。アプリはProgram.csでgRPCサーバーなどの主要コンポーネントを初期化します。RESTfulエンドポイントにリクエストが行われると、gRPC gatewayがそれを処理し、対応するgRPCメソッドに転送します。myService.csがリクエストに基づいてカスタムロジックを実行する前に、authServerInterceptor.csがまずリクエストに必要なアクセストークンと認証があることを確認します。さらなるカスタマイズが必要でない限り、他のファイルを変更する必要はありません。
.
├── src
│ ├── AccelByte.Extend.ServiceExtension.Server
│ │ ├── AccelByte.Extend.ServiceExtension.Server.csproj
│ │ ├── Classes
│ │ │ ├── AuthorizationInterceptor.cs # gRPC server interceptor for access token authentication and authorization
│ │ │ └── ...
│ │ ├── Program.cs # App starts here
│ │ ├── Protos
│ │ │ ├── service.proto # gRPC server protobuf with additional options for exposing as RESTful web service
│ │ │ └── ...
│ │ ├── Services
│ │ │ └── MyService.cs # gRPC server implementation containing the custom logic
│ └── extend-service-extension-server.sln
└── ...
Extend Service Extensionアプリをカスタマイズするには、service.protoとmyService.goファイルを変更します。アプリはmain.goでgRPCサーバーなどの主要コンポーネントを初期化します。RESTfulエンドポイントにリクエストが行われると、gRPC gatewayがそれを処理し、対応するgRPCメソッドに転送します。myService.goがリクエストに基づいてカスタムロジックを実行する前に、authServerInterceptor.goがまずリクエストに必要なアクセストークンと認証があることを確認します。さらなるカスタマイズが必要でない限り、他のファイルを変更する必要はありません。
.
├── main.go # App starts here
├── pkg
│ ├── common
│ │ ├── authServerInterceptor.go # gRPC server interceptor for access token authentication and authorization
│ │ ├── ...
│ ├── pb # gRPC stubs generated from gRPC server protobuf
│ │ └── ...
│ ├── proto
│ │ ├── service.proto # gRPC server protobuf with additional options for exposing as RESTful web service
│ │ └── ...
│ ├── service
│ │ ├── myService.go # gRPC server implementation containing the custom logic
│ │ └── ...
│ └── ...
└── ...
Extend Service Extensionアプリをカスタマイズするには、service.protoとMyService.javaファイルを変更します。アプリはApplication.javaでgRPCサーバーなどの主要コンポーネントを初期化します。RESTfulエンドポイントにリクエストが行われると、gRPC gatewayがそれを処理し、対応するgRPCメソッドに転送します。MyService.javaがリクエストに基づいてカスタムロジックを実行する前に、AuthServerInterceptor.javaがまずリクエストに必要なアクセストークンと認証があることを確認します。さらなるカスタマイズが必要でない限り、他のファイルを変更する必要はありません。
.
├── src
│ ├── main
│ │ ├── java
│ │ │ └── net
│ │ │ └── accelbyte
│ │ │ └── extend
│ │ │ └── serviceextension
│ │ │ ├── Application.java # App starts here
│ │ │ ├── grpc
│ │ │ │ ├── AuthServerInterceptor.java # gRPC server interceptor for access token authentication and authorization
│ │ │ │ └── ...
│ │ │ ├── service
│ │ │ │ └── MyService.java # gRPC server implementation containing the custom logic
│ │ │ └── ...
│ │ ├── proto
│ │ │ ├── service.proto # gRPC server protobuf with additional options for exposing as RESTful web service
│ │ │ └── ...
│ │ └── ...
│ └── ...
└── ...
Extend Service Extensionアプリをカスタマイズするには、service.protoとmy_service.pyファイルを変更します。アプリは__main__.pyでgRPCサーバーなどの主要コンポーネントを初期化します。RESTfulエンドポイントにリクエストが行われると、gRPC gatewayがそれを処理し、対応するgRPCメソッドに転送します。my_service.pyがリクエストに基づいてカスタムロジックを実行する前に、authorization.pyがまずリクエストに必要なアクセストークンと認証があることを確認します。さらなるカスタマイズが必要でない限り、他のファイルを変更する必要はありません。
.
├── proto
│ ├── app
│ │ ├── service.proto # gRPC server protobuf with additional options for exposing as RESTful web service
│ │ └── ...
│ ├── ...
├── src
│ ├── accelbyte_grpc_plugin
│ │ ├── interceptors
│ │ │ ├── authorization.py # gRPC server interceptor for access token authentication and authorization
│ │ │ └── ...
│ │ └── ...
│ ├── app
│ │ ├── __main__.py # App starts here
│ │ ├── services
│ │ │ ├── my_service.py # gRPC server implementation containing the custom logic
│ │ │ └── ...
│ │ └── ...
│ └── ...
└── ...
protobufの変更
- C#
- Go
- Java
- Python
アプリテンプレートでは、ファイルはsrc/AccelByte.Extend.ServiceExtension.Server/Protos/service.protoにあります。
アプリテンプレートでは、ファイルはpkg/proto/service.protoにあります。
アプリテンプレートでは、ファイルはsrc/main/proto/service.protoにあります。
アプリテンプレートでは、ファイルはproto/app/service.protoにあります。
import "google/api/annotations.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "permission.proto";
service Service {
rpc CreateOrUpdateGuildProgress (CreateOrUpdateGuildProgressRequest) returns (CreateOrUpdateGuildProgressResponse) {
option (permission.action) = CREATE;
option (permission.resource) = "ADMIN:NAMESPACE:{namespace}:CLOUDSAVE:RECORD";
option (google.api.http) = {
post: "/v1/admin/namespace/{namespace}/progress"
body: "*"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Update Guild progression"
description: "Update Guild progression if not existed yet will create a new one"
security: {
security_requirement: {
key: "Bearer"
value: {}
}
}
};
}
message CreateOrUpdateGuildProgressRequest {
string namespace = 1;
GuildProgress guild_progress = 2;
}
message CreateOrUpdateGuildProgressResponse {
GuildProgress guild_progress = 1;
}
}
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Service API";
version: "1.0";
};
schemes: HTTP;
schemes: HTTPS;
base_path: "/service";
security_definitions: {
security: {
key: "Bearer";
value: {
type: TYPE_API_KEY;
in: IN_HEADER;
name: "Authorization";
}
}
};
};
Extend Service Extensionのservice.protoファイルは、基本的に追加オプションを持つ通常のgRPCサーバー定義です。
-
option (google.api.http)gRPCメソッドとRESTfulエンドポイント間の関係を記述します。詳細については、gRPC-Gatewayドキュメントを参照してください。
-
option (permission.resource)とoption (permission.action)各RESTfulエンドポイントを呼び出すために必要な権限リソースとアクションを記述します。これにより、有効なAGSアクセストークンと権限を必要とするエンドポイントを作成できます。
権限リソースとアクション値は、含まれているgRPCサーバーインターセプターによって認証を実行するために使用されます。
-
option (permission.resource): AGS形式を使用して、ここに権限リソース文字列を配置できます。 -
option (permission.action): このオプションの有効な値は、CREATE、READ、UPDATE、またはDELETEです。詳細については、AGS権限アクションを参照してください。
備考AGS Private Cloudでは、カスタム権限リソースを作成できますが、AGS Shared Cloudでは、利用可能なものから選択することに制限されます。
-
-
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger)とoption (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation)OpenAPI 2.0仕様を生成するための情報を提供します。詳細については、gRPC-Gatewayドキュメントを参照してください。
protobufからスタブを生成
- C#
- Go
- Java
- Python
次のコマンドを実行して、protoファイルからスタブを生成します。
make proto # gatewayコードとswagger JSONを生成
make build # 一部のprotobufコードはビルド中にオンザフライで生成されます
次のコマンドを実行して、protoファイルからスタブを生成します。
make proto # protobufコード、gatewayコード、swagger JSONを生成
次のコマンドを実行して、protoファイルからスタブを生成します。
make proto # gatewayコードとswagger JSONを生成
make build # 一部のprotobufコードはビルド中にオンザフライで生成されます
次のコマンドを実行して、protoファイルからスタブを生成します。
make proto # protobufコード、gatewayコード、swagger JSONを生成
service.protoファイルを変更した後は、常に上記のコマンドを実行してスタブを再生成してください。
リクエストハンドラーの実装
- C#
- Go
- Java
- Python
アプリプロジェクトでは、次のファイルがsrc/AccelByte.Extend.ServiceExtension.Server/Services/MyService.csにあります。
サービスをセットアップするには、Service.ServiceBaseから派生したクラスを作成します。このクラスがサービス実装として機能します。
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Grpc.Core;
using AccelByte.Sdk.Api;
using AccelByte.Extend.ServiceExtension.Server.Model;
namespace AccelByte.Extend.ServiceExtension.Server.Services
{
public class MyService : Service.ServiceBase
{
public MyService()
{
}
// Implement your service logic in here
}
}
CreateOrUpdateGuildProgress関数を実装するには、次のようにメソッドをオーバーライドできます。
public override Task<CreateOrUpdateGuildProgressResponse> CreateOrUpdateGuildProgress(CreateOrUpdateGuildProgressRequest request, ServerCallContext context)
{
// 実装をここに記述
}
GetGuildProgress関数も同様です。
public override Task<GetGuildProgressResponse> GetGuildProgress(GetGuildProgressRequest request, ServerCallContext context)
{
// 実装をここに記述
}
アプリプロジェクトでは、次のファイルがsrc/master/pkg/service/myService.goにあります。
サービスをセットアップするには、UnimplementedServiceServerを埋め込んだ構造体を作成します。
import pb "extend-custom-guild-service/pkg/pb"
type MyServiceServerImpl struct {
pb.UnimplementedServiceServer
// Other fields
}
CreateOrUpdateGuildProgress関数は次のように実装されます。
func (g MyServiceServerImpl) CreateOrUpdateGuildProgress(
ctx context.Context, req *pb.CreateOrUpdateGuildProgressRequest,
) (*pb.CreateOrUpdateGuildProgressResponse, error) {
// 実装をここに記述
}
GetGuildProgress関数も同様です。
func (g MyServiceServerImpl) GetGuildProgress(
ctx context.Context, req *pb.GetGuildProgressRequest,
) (*pb.GetGuildProgressResponse, error) {
// 実装をここに記述
}
アプリプロジェクトでは、次のファイルがsrc/main/java/net/accelbyte/extend/serviceextension/service/MyService.javaにあります。
サービスをセットアップするには、ServiceGrpc.ServiceImplBaseから派生したクラスを作成します。このクラスがサービス実装として機能します。
import lombok.extern.slf4j.Slf4j;
import net.accelbyte.extend.serviceextension.*;
import net.accelbyte.sdk.core.AccelByteSDK;
import org.lognet.springboot.grpc.GRpcService;
@GRpcService
@Slf4j
public class MyService extends ServiceGrpc.ServiceImplBase {
// Implementation goes here
}
CreateOrUpdateGuildProgress関数を実装するには、次のようにメソッドをオーバーライドできます。
public void createOrUpdateGuildProgress(
CreateOrUpdateGuildProgressRequest request, StreamObserver<CreateOrUpdateGuildProgressResponse> responseObserver
) {
// 実装をここに記述
}
GetGuildProgress関数も同様にできます。
public void getGuildProgress(
GetGuildProgressRequest request, StreamObserver<GetGuildProgressResponse> responseObserver
) {
// 実装をここに記述
}
アプリプロジェクトでは、次のファイルがsrc/master/src/app/services/my_service.pyにあります。
サービスをセットアップするには、まずServiceServicerから派生したクラスを作成します。
このクラスがサービス実装として機能します。
from ..proto.service_pb2 import (
CreateOrUpdateGuildProgressRequest,
CreateOrUpdateGuildProgressResponse,
GetGuildProgressRequest,
GetGuildProgressResponse,
DESCRIPTOR,
)
from ..proto.service_pb2_grpc import ServiceServicer
class AsyncService(ServiceServicer):
full_name: str = DESCRIPTOR.services_by_name["Service"].full_name
# Implement your service logic in here.
CreateOrUpdateGuildProgress関数を実装するには、次のようにメソッドをオーバーライドできます。
async def CreateOrUpdateGuildProgress(
self, request: CreateOrUpdateGuildProgressRequest, context: Any
) -> CreateOrUpdateGuildProgressResponse:
...
GetGuildProgress関数も同様です。
async def GetGuildProgress(
self, request: GetGuildProgressRequest, context: Any
) -> GetGuildProgressResponse:
...
gRPCリクエスト処理の詳細については、こちらを参照してください。