# A gRPC upstream

> Goal: serve a gRPC service to gRPC clients, to a browser (gRPC-Web) and in REST/JSON, from its .proto alone.

Guide - Since version 1.1.0 - Flexway v1.6.3 - https://flexway.io/en/docs/operations-grpc/

> Operations guide: configure, deploy and observe the gateway. What the capability does, product side: [product guide](https://flexway.io/en/docs/product-overview/); calling it: [developer guide](https://flexway.io/en/docs/developer-overview/).

**Goal**: serve a gRPC service to gRPC clients, to a browser (gRPC-Web) and in REST/JSON, from its
`.proto` alone.

**Command** - the upstream's team annotates its `.proto`: the standard REST mapping
(`google.api.http`) and what Flexway needs beyond it (`flexway.v1.operation`, the counterpart of
`x-flexway-*`). Then it builds the descriptor set:

```proto
syntax = "proto3";
package shop.v1;                          // the gRPC name is shop.v1.Orders/GetOrder

import "flexway/v1/options.proto";       // copy it from the tag you run: services/gateway/api/flexway/v1/options.proto
import "google/api/annotations.proto";   // from buf.build/googleapis/googleapis, below

service Orders {
  rpc GetOrder(GetOrderRequest) returns (Order) {
    option (google.api.http) = { get: "/v1/shop/orders/{id}" };
    option (flexway.v1.operation) = { upstream: "orders" security: [ { scopes: ["orders:read"] } ] };
  }
}
```

```bash
v=<version>   # the Flexway you run
mkdir -p flexway/v1 && curl -fsSLo flexway/v1/options.proto \
  "https://raw.githubusercontent.com/flexwiz/flexway/v$v/services/gateway/api/flexway/v1/options.proto"
cat > buf.yaml <<'YAML'
version: v2
deps: [buf.build/googleapis/googleapis]
YAML
buf dep update
buf build -o orders.binpb       # or: protoc --include_imports --descriptor_set_out=orders.binpb ...
```

```yaml
contracts:
  protobuf: [./orders.binpb]
upstreams:
  orders: { url: http://orders.internal:9000, protocol: grpc }   # h2c inside a mesh
```

**Check**:

```bash
grpcurl -plaintext -protoset orders.binpb -H "authorization: Bearer $TOKEN" \
  -d '{"id":"42"}' localhost:8080 shop.v1.Orders/GetOrder               # gRPC, on the traffic port
curl -H "authorization: Bearer $TOKEN" localhost:8080/v1/shop/orders/42  # the same operation in REST
```

Both calls are **one operation**, `shop.v1.Orders/GetOrder`: same identity, same rate, same quota,
same audit line. A refusal reaches a gRPC client as a `google.rpc.Status` (the problem code in
`ErrorInfo.reason`), a REST client as RFC 9457. An error of the upstream reaches a REST client as an
`upstream_status` problem, its gRPC status in the `grpc` extension. A server stream is a
`text/event-stream` in REST.

> For a **browser** (gRPC-Web), the `cors` policy exposes `grpc-status`, `grpc-message` and
> `grpc-status-details-bin` (`expose_headers`) and accepts `x-grpc-web`, `x-user-agent` and
> `grpc-timeout` (`allow_headers`): without them, the browser cannot read a refusal. Refused at load
> at this version: a variable spanning segments (`{name=shelves/*}`), a wildcard, a verb
> (`:cancel`), `google.api.http` on a client or bidirectional stream - those stay served in gRPC only.
