Skip to main content

Working with gRPC-Gateway

Last updated on April 25, 2024
info

Extend is in Open Beta for AGS Premium Clients! This means that the Extend add-on is available for you to try in your development environment. You can submit your feedback via our Extend Open Beta feedback form.

Overview

This guide is designed to provide in-depth coverage on the implementation of gRPC-Gateway. The primary focus is on providing insights into what gRPC-Gateway is, its core components, and its workflow within a service.

Why gRPC-Gateway?

  1. Versatility: Enables your service to be accessed both via HTTP/REST and gRPC.
  2. Type Safety: Leverages gRPC's strong typing. While also generate OpenAPI spec.
  3. Efficiency: Takes advantage of HTTP/2 for better performance.

Prerequisites

This guide assumes to be used for:

Workflow with sample app

Write the API definition in .proto file

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;
}

}

// OpenAPI options for the entire API.
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";
}
}
};
};

Explanation

  • Import statements

    1. google/api/annotations.proto: Required for Google's HTTP annotations, such as google.api.http.
    2. protoc-gen-openapiv2/options/annotations.proto: Required for OpenAPI annotations.
    3. permission.proto: Custom import, likely used to define scope permission.
  • Service definition

    This part defines a gRPC service with one RPC method named CreateOrUpdateGuildProgress.

    service Service {

    rpc CreateOrUpdateGuildProgress (CreateOrUpdateGuildProgressRequest) returns (CreateOrUpdateGuildProgressResponse) {
    // Various annotation here
    }

    message CreateOrUpdateGuildProgressRequest {
    string namespace = 1;
    GuildProgress guild_progress = 2;
    }

    message CreateOrUpdateGuildProgressResponse {
    GuildProgress guild_progress = 1;
    }

    }
  • Swagger configuration

    This section of the .proto file is used to configure the Swagger or OpenAPI output:


    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
    info: {
    title: "Service API";
    version: "1.0";
    };

    // The rest of configuration

    }

    1. info: Sets the title and version of the API.
    2. schemes: Specifies the supported schemes.
    3. security_definitions: Configures the security scheme, which is the Bearer token in this case.
    • Permission control via permission.proto Annotations for fine-grained access control:

      • permission.action: it can be either READ, CREATE, UPDATE, DELETE
      • permission.resource: Defines scope-based access control (e.g., ADMIN:NAMESPACE:{namespace}:CLOUDSAVE:RECORD).

    These permission annotations allow for more granular control over access to specific parts of your service.

    To learn more about how permission is structured, see Introduction to Authorization.

Generate the code from the proto file

Run this command to generate the code from the proto file:

make proto    # Generate protobuf code, gateway code, and swagger JSON

Integrate the generated stub

To set up our generate stub into the service, we'll first create a structure that embeds the UnimplementedGuildServiceServer. This stub was named by the protobuf code generator.

import pb "extend-custom-guild-service/pkg/pb"

type MyServiceServerImpl struct {
pb.UnimplementedGuildServiceServer
// Other fields
}


func (g MyServiceServerImpl) CreateOrUpdateGuildProgress(
ctx context.Context, req *pb.CreateOrUpdateGuildProgressRequest,
) (*pb.CreateOrUpdateGuildProgressResponse, error) {

// Your implementation

}