Goa v3.1 released: Primitive user types and HTTP streaming!

Raphael Simon
Goa Design
Published in
3 min readMar 9, 2020

Goa v3.1 comes 9 months after v3.0. This release includes contributions from 22 authors and focuses on stability with most commits consisting of bug fixes. This release also introduces a few new features detailed below.

Support for gRPC Server Reflection Protocol

Taichi Sasaki (tchssk) added built-in support for the gRPC server reflection protocol in PR #2422. This means that clients of gRPC services built using Goa can dynamically introspect the list of methods that a server export and for each method figure out how to call it. In particular this makes it possible to use generic gRPC clients such as grpc_cli. See the gRPC tutorial on server reflection for more information.

Built-in Support for Text Encoding

Taichi Sasaki (tchssk) also added support for encoding and decoding the text/html and text/plain mime types to the Goa built-in encoder and decoder. Goa makes it possible to provide arbitrary encoders and decoders when creating HTTP endpoints. This change adds plain text to the list of mime types supported by the encoder and decoder provided with the Goa HTTP package.

Attribute Level OpenAPI Extensions

K.Furukawa (townewgokgok) made it possible to define OpenAPI extensions directly on attributes. Given the following design:

var PayloadT = Type("Payload", func() {
Attribute("string", String, func() {
Example("")
Meta("swagger:extension:x-test-schema", "Payload") // <-
})
})

Goa generates the following OpenAPI definition:

definitions:
TestServiceTestEndpointRequestBody:
title: TestServiceTestEndpointRequestBody
type: object
properties:
string:
example: ""
type: string
x-test-schema: Payload # <-
example:
string: ""

Primitive User Types

Nitin Mohan (nitinmohan87) made it possible to define user types that aliases primitive types. Consider the following example:

var ID = Type("ID", String, func() {
Description("ID represents an identifier")
Format(FormatUUID)
})

Other type definitions may leverage this new type for all identifier attributes:

var MyType = Type("MyType", func() {
Attribute("id", ID)
Attribute("name", String)
Required("id", "name")
})

There are many ways in which primitive user types can be taken advantage of making this contribution very exciting!

Streaming HTTP Upload and Download

Another newly introduced feature worth mentioning is the ability to define HTTP streaming endpoints directly in the design. Note that Goa already supports the ability to define streaming payloads and results for any method using StreamingPayload and StreamingResult respectively. These functions make it possible to implement streaming independently of the underlying transport and rely on WebSockets for the HTTP transport. The generated code encodes and decodes each streamed message and provides user code with instances of the corresponding structs.

Sometimes it is desirable to bypass encoding and decoding entirely to instead access the underlying stream (io.Writer and io.Reader) directly. This makes it possible to upload and download big files without having to first load the entire content in memory. For this use case v3.1 introduces two new DSL functions: SkipRequestBodyEncodeDecode and SkipResponseBodyEncodeDecode. As the names suggest they allow bypassing the encoding and decoding of the request and response bodies respectively.

The upload/download example illustrates how to use these functions, go check it out!.

Thank You!

Thank you to the all the contributors for the many bug fixes, a special mention goes to ikawaha, Tim Adam, CuBiC, Jesús García Crespo, Ruggero and Michael Urman for reporting and fixing many non-trivial issues!

--

--