# gRPC

Source: https://gortexa.sheng.page/en/transports/grpc/

gRPC is Gortexa's native protocol. External connections arrive on the same h2c port; the mux dispatches on `Content-Type: application/grpc` to grpc-go's `ServeHTTP` mode.

## Service definition and generated code

Services are defined in proto. The built-in sample resource:

```protobuf
service ResourceService {
  rpc CreateResource(CreateResourceRequest) returns (Resource);
  rpc GetResource(GetResourceRequest) returns (Resource);
  rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse);
  rpc UpdateResource(UpdateResourceRequest) returns (Resource);
  rpc DeleteResource(DeleteResourceRequest) returns (google.protobuf.Empty);
}
```

`gortexa regen` writes stubs to `gen/`; logic implementations live in internal packages. The two never mix.

## Calling the service

For local grpcurl testing, enable reflection first (it is off by default):

```bash
GORTEXA_SERVER__REFLECTION=true gortexa run
```

```bash
grpcurl -plaintext \
  -H 'authorization: Bearer <token>' \
  -d '{"id":"x"}' \
  localhost:8080 myapp.resource.v1.ResourceService/GetResource
```

`myapp` is the scaffolded project's proto namespace (derived from the module path since v0.28.0, see [Create a project](https://gortexa.sheng.page/en/quickstart/#create-a-project)); when running the sample inside a framework checkout the service is `resource.v1.ResourceService`.

Without a token you get `UNAUTHENTICATED`: auth treats all three protocols the same way.

## Health

The three-state health model maps to the standard gRPC Health protocol. Register real dependency checks with `app.Health().Register(...)` so `/readyz` and gRPC Health reflect actual DB, cache and MQ reachability. Each check runs under a 5-second timeout, so one slow dependency cannot stall the whole query. `Health.Watch` is exempt from both auth and load shedding (a probe must still answer while the server sheds), so it carries its own ceiling: at most 1,024 concurrent watch streams, beyond which `Watch` returns `RESOURCE_EXHAUSTED`. All watchers share one registry evaluation per one-second interval, so N streams do not mean N dependency pings. Registering the same check name twice panics — a boot-time wiring mistake should be loud rather than silently leaving a dependency unmonitored; use `Replace(name, check)` when substitution is the actual intent.

## Reflection

gRPC reflection is off by default. Enable it via config or an environment variable when needed:

```bash
GORTEXA_SERVER__REFLECTION=true
```

Enabling it exempts `/grpc.reflection.` from **both** auth and the in-flight budget (a stream holds its slot for its whole lifetime; exempting auth but not the count would let an unauthenticated client pin the budget). Keep it off in production — see [Deployment](https://gortexa.sheng.page/en/deployment/).

## FAQ

### Can I run gRPC without TLS (h2c) in Go?

Yes. Since Go 1.24, `http.Server.Protocols` supports h2c natively, and that is what Gortexa uses — no deprecated `x/net/http2/h2c` wrapper. Terminate TLS in front of it in production.

### Should gRPC reflection be enabled in production?

No. Enabling it exempts `/grpc.reflection.` from both auth and the in-flight budget, which publishes your full service schema to unauthenticated callers. It is off by default and intended for dev tooling such as `buf curl --reflect`.

### Why do my keepalive settings have no effect?

External gRPC on the shared h2c port runs in grpc-go's `ServeHTTP` handler mode, where transport-level options (`KeepaliveParams`, `MaxStreams` and friends) are inert. Split gRPC onto its own listener if you need keepalive enforcement.
