## gRPC transcoding

gRPC transcoding allows your services to accept both gRPC and HTTP/JSON (accepting/replying the application/json content type) requests, providing greater flexibility. This feature is particularly useful when:

- You want to expose your gRPC services to clients that don’t support gRPC

- You need to support both traditional REST APIs and gRPC endpoints

- You want to leverage gRPC’s efficiency while maintaining HTTP/JSON compatibility

You do not need specific configuration for gRPC transcoding since it is serves HTTP protocol.

Services are transcoded out of the box, however you will get the best of transcoding with additional configuration such as the mount path to have transcoding operational.

| transcoding is in tech preview in Vert.x 5.0 until the API becomes stable.

### Using transcoding

To use Vert.x gRPC transcoding, add the following dependency to the dependencies section of your build descriptor:

- Maven (in your `pom.xml`):

    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-grpc-transcoding</artifactId>
      <version>5.0.2</version>
    </dependency>

- Gradle (in your `build.gradle` file):

    dependencies {
      compile 'io.vertx:vertx-grpc-transcoding:5.0.2'
    }

### Idiomatic transcoding generation

The Vert.x gRPC protoc plugin generates transcoding definitions for the gRPC services.

The plugin supports generating transcoding definitions for the gRPC services via http.proto.

The `google.api.http` annotation allows you to map gRPC methods to HTTP endpoints, enabling your service to handle both gRPC and HTTP/REST requests. The plugin supports various HTTP methods (GET, POST) and custom methods.

Example of the gRPC transcoding definition

    syntax = "proto3";

    import "google/api/http.proto";

    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/v1/hello"
          additional_bindings {
            get: "/v1/hello/{name}"
          }
        };
      }
    }

    message HelloRequest {
      string name = 1;
    }

    message HelloReply {
      string message = 1;
    }

Transcoding service methods are generated by the Vert.x gRPC protoc plugin, when the service declares an `HttpRule`:

    Service service = new GreeterGrpcService() {
      @Override
      public Future<HelloReply> sayHello(HelloRequest request) {
        return Future.succeededFuture(HelloReply.newBuilder().setMessage("Hello " + request.getName()).build());
      }
    };

    server.addService(service);

| the service responds to all the server enabled protocols, by default that is `application/grpc`, `application/grpc+json`, `application/grpc-web`, `application/grpc-web-text` and of course `application/json`

To test gRPC transcoding, you can use a tool like `curl` to send HTTP requests to your gRPC service.

    curl -X POST -H "Content-Type: application/json" -d '{"name":"vert.x"}' http://localhost:8080/v1/hello

And you can also request the path mapped version:

    curl -X GET -H "Content-Type: application/json" http://localhost:8080/v1/hello/vert.x

### Automatic HTTP mapping

When a gRPC service is deployed without specific transcoding configuration, the service is mapped to HTTP `POST`, request/response body will be converted to the service message by the transcoder.

### Basic HTTP mappings

    service Greeter {
      // Maps a GET endpoint with a URL parameter
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          get: "/v1/hello/{name}"
          additional_bindings {
            post: "/v1/hello"  // Alternative POST endpoint
          }
        };
      }

      // Maps a POST endpoint with an alternative GET binding
      rpc SayHelloAgain (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/v2/hello"
          additional_bindings {
            get: "/v2/hello/{name}"
          }
        };
      }
    }

### Advanced Configurations

#### Custom Methods

    service Greeter {
      // Define custom HTTP methods
      rpc SayHelloCustom (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          custom: {
            kind: "ACL"
            path: "/v1/hello/custom/{name}"
          }
        };
      }
    }

#### Request Body Handling

    service Greeter {
      // Specify which field should be mapped to the HTTP request body
      rpc SayHelloWithBody (HelloBodyRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/v1/hello/body"
          body: "request"  // Maps the "request" field to the request body
        };
      }
    }

    message HelloBodyRequest {
      HelloRequest request = 1;
    }

    message HelloRequest {
      string name = 1;
    }

    message HelloReply {
      string reply = 1;
    }

#### Response Body Mapping

    service Greeter {
      // Configure which field should be used as the HTTP response body
      rpc SayHelloWithResponseBody (HelloRequest) returns (HelloBodyResponse) {
        option (google.api.http) = {
          post: "/v1/hello/body/response"
          response_body: "response"  // Maps the "response" field to the response body
        };
      }
    }

    message HelloRequest {
      string name = 1;
    }

    message HelloBodyResponse {
      HelloResponse response = 1;
    }

    message HelloResponse {
      string reply = 1;
    }

### Transcoding error handling

If an error occurs during transcoding, the server will return an HTTP error response with the appropriate status code. Most grpc status codes are mapped to the corresponding HTTP status codes on best effort basis. If the status code is not mapped, the server will return a 500 Internal Server Error.

gRPC Status Code | HTTP Status Code | Description
OK | 200 | The operation completed successfully.
CANCELLED | 408 | The operation was cancelled (typically by the caller).
UNKNOWN | 500 | Unknown error.
INVALID_ARGUMENT | 400 | Client specified an invalid argument.
DEADLINE_EXCEEDED | 504 | Deadline expired before operation could complete.
NOT_FOUND | 404 | Some requested entity (e.g., file or directory) was not found.
ALREADY_EXISTS | 409 | Some entity that we attempted to create (e.g., file or directory) already exists.
PERMISSION_DENIED | 403 | The caller does not have permission to execute the specified operation.
RESOURCE_EXHAUSTED | 429 | Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.
FAILED_PRECONDITION | 400 | Operation was rejected because the system is not in a state required for the operation’s execution
ABORTED | 409 | The operation was aborted, typically due to a concurrency issue like sequencer check failures, transaction aborts, etc.
OUT_OF_RANGE | 400 | Operation was attempted past the valid range.
UNIMPLEMENTED | 501 | Operation is not implemented or not supported/enabled in this service.
INTERNAL | 500 | Internal errors. This means that some invariants expected by the underlying system have been broken.
UNAVAILABLE | 503 | The service is currently unavailable.
DATA_LOSS | 500 | Unrecoverable data loss or corruption.
UNAUTHENTICATED | 401 | The request does not have valid authentication credentials for the operation.