Skip to content

Goa v3.33.0

Latest

Choose a tag to compare

@raphael raphael released this 04 Oct 19:17
· 8 commits to v3 since this release
ba2bef1

Goa v3.33.0 adds HTTP parameters within path segments and fixes generated
types, conversions, validation, and result views. gRPC clients preserve local
validation failures and the original cause of remote generic errors.

This release also intentionally breaks merged-error and joined gRPC error
behavior within the v3 module path.
Goa's
release policy
keeps major version 3; the minor version does not make those changes backward
compatible. Review the upgrade actions below before deploying.

More expressive HTTP routes

Routes such as /files/{name}.json, /user/@{username}, and
/{month}-{day}-{year} now recognize every parameter within a segment.
Generated clients construct the corresponding URL, and OpenAPI documents
every parameter. Existing whole-segment and catch-all routes remain supported.
Parameterized API prefixes are removed from OpenAPI v2 operation paths once,
avoiding duplicated prefixes.
(#3994)

Generated code that preserves your design

  • Shared and relocated types now keep declarations, imports, and conversions
    consistent across services. Package placement passes to descendants unless
    they declare their own package. Conflicts and required import cycles fail
    during generation instead of producing invalid Go.
  • Named maps, slices, unions, and external ConvertTo/CreateFrom types retain
    their declared representations. Mapped HTTP and JSON-RPC body fields keep
    the service field's validation and defaults.
  • Validation and command generation handle inherited required fields, named
    scalar defaults, headers, and map flags correctly. Small MaxLength values
    no longer cause example-generation panics.
  • HTTP clients with selectable result views now include the import needed to
    report an unknown view. Object-valued maps receive their required nested
    validators.
  • Result views containing named unions from another generated package now
    generate and compile correctly. View layouts report their actual pointer
    fields. A service returning a missing object without an error receives a
    Goa internal fault before view conversion; valid empty collections remain
    accepted.

Regenerate affected output and update handwritten imports if generated types
move. See #4002,
#4005,
#4010,
#4016,
#4014, and
#4017.

gRPC failures callers can inspect

Generated clients return request-encoding and successful-response decoding
errors with their original types and validation details. Only the RPC call
uses the existing single-retry policy for idempotent unary methods, so an
invalid successful response is no longer retried. Streams and non-idempotent
calls gain no retries.

Generic remote ServiceError values retain the original RPC error as their
cause, allowing status.Code, errors.Is, and errors.As to inspect it.
Received detail fields and the first-detail decoding rule remain authoritative.
Declared custom errors retain their existing constructors.

Required protobuf collections retain valid empty values after decoding.
Streaming clients obtain the server's final status after an initial send
returns io.EOF, and avoid unary metadata-capture options when opening streams.
(#4000,
#4001,
#4010)

Breaking error changes

For two nonnil inputs, goa.MergeErrors returns a fresh ServiceError
without modifying either input. Always store or return its result:

err = goa.MergeErrors(err, next)

Code that ignored the return value must change. Retained inputs and earlier
merge results no longer accumulate later messages. Nil operands still return
the other input exactly. Existing ID/name selection, whole-result Field
pointer, and trait-combination rules remain. Do not rely on the result being
the left input.

ServiceError.History() returns detached original contributions in order,
including duplicates and singleton histories. Editing a returned entry or its
Field does not affect later reads. Set contribution fields before merging,
and read each history entry once. Do not recursively call History() on
returned entries to find a singleton by pointer equality. gRPC history details
carry original messages rather than accumulated messages. Caller-owned causes remain shared;
this does not repair pre-existing cycles.

An independent joined gRPC failure without an outer error supplying the
complete response now receives generic details for the whole failure:
fault, a fresh ID, the exact joined text, Fault: true, and false Timeout
and Temporary. Matching branch status codes are retained; disagreement
returns Unknown regardless of branch order. Raw Go context errors remain
Unknown unless an explicit status supplies the complete result.

For example, joining a temporary declared error with an independent Canceled
status no longer sends one child's shorter message, name, ID, or temporary
flag. Callers may observe different status codes, custom types, fields, and
retry behavior. Direct and ordinarily wrapped declared errors retain their
designed responses. An outer named error may supply its own complete custom
value; a complete explicit status before or on that named error takes precedence.
(#4012)

Upgrade and rollout

  1. Select matching v3.33.0 module and command versions, regenerate the complete
    generated tree, and compile and test the application. Migrate ignored
    MergeErrors returns and recursive or identity-based History readers in
    the same application change. Runtime updates activate those two contracts
    even without regeneration.
  2. Update runtime and generator together and rebuild servers to obtain the
    complete joined-error behavior. Prepare callers for both old and new
    server outcomes before deployment, including changed retry decisions.
    Old generated servers with the new runtime change shared generic details
    but retain old declared-code and custom selection; new generated servers
    with the old runtime do not establish the complete behavior.
  3. Regenerate clients with the matching runtime for cause retention and local
    error/retry corrections. These client changes do not require a server
    upgrade.
  4. Plugin authors must use keyed GoTypePlanOptions literals, emit every
    conversion helper returned by the planners, and use the reported view
    representations. Generation.UserTypes() enumerates registered types
    per owning package; cross-package validation calls require exported,
    finalized names.
  5. Retain previous binaries, design, dependencies, module/command versions,
    and generated output. For rollback, restore runtime, generated servers,
    and dependent error-reader changes together. Callers must tolerate both
    versions while servers converge.

There is no protobuf field-number, wire-shape, or stored-data migration.
Existing peers can decode the unchanged shapes, but changed error meaning is
not behavioral compatibility. Other generation fixes require regeneration,
with no coordinated peer rollout. Documentation-only changes need no
application action. External applications' reliance on the old contracts is
unknown; review your own callers.

The upgrade guide
contains the detailed contracts and installation steps.

Dependencies and companion repositories

Goa updates x/tools to v0.51.0, the RPC genproto revision, and OpenAPI
processing dependencies, including kin-openapi v0.149.0.
Examples and plugins update OpenTelemetry to v1.47.0; plugins update
AWS Lambda to v1.55.1. The declared Go minimum remains 1.26.0.

The examples and
plugins releases use
Goa v3.33.0 and include regenerated output.

Contributors

Thanks to @raphael, @dvjn, @egandro, @tchssk, and @ikawaha.

All changes since v3.32.0