Skip to content

feat(grpc-transcode): resolve service and method from google.api.http annotations - #13812

Open
alirezashamsabad wants to merge 4 commits into
apache:masterfrom
alirezashamsabad:feat/grpc-transcode-http-annotations
Open

feat(grpc-transcode): resolve service and method from google.api.http annotations#13812
alirezashamsabad wants to merge 4 commits into
apache:masterfrom
alirezashamsabad:feat/grpc-transcode-http-annotations

Conversation

@alirezashamsabad

Copy link
Copy Markdown

Description

Today a Route using grpc-transcode is bound to exactly one gRPC method through
service and method, so a service with ten methods needs ten Routes. That duplicates
configuration the proto usually already declares via google.api.http annotations.

This adds an optional use_http_annotations flag. When enabled, the plugin reads those
annotations and selects the method whose path template and HTTP method match the request.
One Route can then serve a whole annotated service:

{
  "uri": "/api/v1/*",
  "plugins": {
    "grpc-transcode": { "proto_id": "1", "use_http_annotations": true }
  },
  "upstream": { "scheme": "grpc", "type": "roundrobin", "nodes": { "127.0.0.1:50051": 1 } }
}

GET /api/v1/items/42 reaches ItemService/GetItem with id bound to 42, and
POST /api/v1/items reaches ItemService/CreateItem, without per-method Routes.

Which issue(s) this PR fixes:

Relates to #3406, which was closed as
not planned before any implementation existed. This PR provides one, with tests and
documentation, so the trade-offs can be judged concretely.

What is supported

  • Path templates per the google.api.http grammar: literals, {var}, {var=*},
    {var=a/*/b}, **, nested field paths such as {user.id}, and a trailing :verb
  • additional_bindings
  • body semantics: omitted means the payload is not read; "*" means the whole payload
    is the message; "<field>" maps the payload to that field and leaves siblings to the
    query string
  • Path-captured values override query or body values for the same field
  • Match precedence: more literal segments, then fewer variables, then service/method name.
    :verb is matched separately and is not part of the ranking
  • While the flag is on, configured service and method are ignored

Backwards compatibility

The flag defaults to false. When it is off, service and method stay mandatory, so
existing configs and validation errors are unchanged.

Behavior change in both modes: access returns 503 when the proto cannot be loaded.
Previously the request was forwarded untranscoded and often surfaced as a confusing
upstream 405. The gateway now fails closed and logs the reason.

Notes for reviewers

  • Binary descriptor sets only. Annotations are preserved only in a descriptor set from
    protoc --include_imports --descriptor_set_out=.... A plain .proto uploaded to
    /apisix/admin/protos cannot resolve google/api/annotations.proto.
  • No new dependency. Pinned lua-protobuf 0.5.3 exposes the extension as
    method.options.http.
  • Vendored test protos. t/grpc_server_example/proto/google/api/{annotations,http}.proto
    are checked in for the fixture descriptor set (Apache-2.0 under Google's copyright;
    listed in LICENSE and ignored in .licenserc.yaml).
  • Limitation: body supports a top-level field name only (not body: "item.nested").
  • Out of scope: an intermittent failed to find proto by id can still occur while
    the etcd config sync is in flight. It reproduces on legacy service/method routes
    as well, and its cause is distinct from the type mismatch in
    #8952. I have not root-caused it, so
    it is not addressed here.

Tests

t/plugin/grpc-transcode-http-annotations.t covers path-template parsing and rejection,
end-to-end routing, body modes, :verb, path-over-query/body, 404, 405 with
Allow, 400, 503, proxy-rewrite, and rebuilding the table after proto replacement.
t/plugin/grpc-transcode*.t passes (297 assertions).

Developed with AI assistance; design decisions, review and testing are my own.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If it is not backward compatible, please discuss on the APISIX mailing list first)

@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. enhancement New feature or request labels Aug 12, 2026
@alirezashamsabad

Copy link
Copy Markdown
Author

For anyone triaging the size:XXL label: of the 3,196 added lines, 1,160 are
generated .pb.go, 401 are the vendored google/api protos, and 799 are tests and
fixtures.The hand-written plugin change is 567 lines across four files.

Related: #13811 fixes a separate pre-existing bug in the same plugin
(grpc-transcode/proto.lua). The two branches are independent and do not conflict.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant