From 9c0e65b6da348aad1db4fc50d4ce63082d79afed Mon Sep 17 00:00:00 2001 From: jbeisley Date: Tue, 12 Nov 2024 09:12:44 +0000 Subject: [PATCH] doc: document the Delimited and StreamContentType interfaces --- docs/docs/mapping/custom_marshalers.md | 72 +++++++++++++++++++ docs/docs/mapping/customizing_your_gateway.md | 4 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/docs/mapping/custom_marshalers.md diff --git a/docs/docs/mapping/custom_marshalers.md b/docs/docs/mapping/custom_marshalers.md new file mode 100644 index 00000000000..4a469638a9e --- /dev/null +++ b/docs/docs/mapping/custom_marshalers.md @@ -0,0 +1,72 @@ +--- +layout: default +title: Custom marshalers +nav_order: 6 +parent: Mapping +--- + +# Custom marshalers + +[`Marshaler`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#Marshaler) +implementations can implement optional additional methods to customize their +behaviour beyond the methods required by the core interface. + +## Stream delimiters + +By default, a streamed response delimits each response body with a single +newline (`"\n"`). You can change this delimiter by having your marshaler +implement +[`Delimited`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#Delimited). + +For example, to separate each entry with a pipe (`"|"`) instead: + +```go +type YourMarshaler struct { + // ... +} + +// ... + +func (*YourMarshaler) Delimited() []byte { + return []byte("|") +} +``` + +## Stream content type + +By default, a streamed response emits a `Content-Type` header that is the same +for a unary response, from the `ContentType()` method of the +[`Marshaler`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#Marshaler) +interface. + +If you require the server to declare a distinct content type for stream +responses versus unary responses, the marshaler must implement +[`StreamContentType`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#StreamContentType). +This provides the MIME type when specifically responding to a streaming +response. + +For example, by default the +[`JSONPb`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#JSONPb) +marshaler results in `application/json` for its `Content-Type` response header, +irrespective of unary versus streaming. This can be changed for streaming +endpoints by wrapping the marshaler with a custom marshaler that implements +[`StreamContentType`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#StreamContentType) +to return the [NDJSON](https://github.com/ndjson/ndjson-spec) MIME type for +streaming response endpoints: + +```go +type CustomJSONPb struct { + runtime.JSONPb +} + +func (*CustomJSONPb) Delimited() []byte { + // Strictly speaking this is already the default delimiter for JSONPb, but + // providing it here for completeness with an NDJSON marshaler all in one + // place. + return []byte("\n") +} + +func (*CustomJSONPb) StreamContentType(interface{}) string { + return "application/x-ndjson" +} +``` diff --git a/docs/docs/mapping/customizing_your_gateway.md b/docs/docs/mapping/customizing_your_gateway.md index b5c0f08def0..dbfc96ca6d9 100644 --- a/docs/docs/mapping/customizing_your_gateway.md +++ b/docs/docs/mapping/customizing_your_gateway.md @@ -13,7 +13,9 @@ parent: Mapping You might want to serialize request/response messages in MessagePack instead of JSON, for example: -1. Write a custom implementation of [`Marshaler`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#Marshaler). +1. Write a custom implementation of + [`Marshaler`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#Marshaler). + See [Custom marshalers](custom_marshalers.md) for examples. 2. Register your marshaler with [`WithMarshalerOption`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithMarshalerOption).