Goa v3.2.0
Announcing Goa v3.2.0
- July 11, 2020
- Raphael Simon
I am very excited to announce the release of Goa v3.2.0! This release includes a few key improvements as well as many bug fixes.
HTTP Cookies
v3.2.0 adds native support for HTTP cookies in Goa designs. Prior to this release cookies could be read and written by Goa services using HTTP middlewares that would read (or inject) the values from (into) the context. For example:
// NOT NECESSARY ANYMORE
package cookie
type cookieKeyType int // private so key is unique
var CookieKey cookieKeyType = iota + 1
// ReadCookie returns a HTTP middleware that reads the value of the cookie with
// the given name and adds it to the request context under cookiectx.CookieKey.
func ReadCookie(name string) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := req.Cookie(name)
if err != nil {
goto skip
}
ctx := context.WithValue(r.Context(), cookiectx.CookieKey, c.Value)
r = r.WithContext(ctx)
skip:
h.ServeHTTP(w, r)
})
}
}
// Usage:
// Mount middleware when creating the server:
srv := calcsvr.New(calcEndpoints, mux, dec, enc, eh, nil)
srv.Use(cookie.ReadCookie("session_uid"))
// Use the value from the context in the service methods:
func (s *Service) Endpoint(ctx context.Context, p *Payload) (*Result, error) {
sessionUID := ctx.Value(cookie.CookieKey)
// ...
}
Goa now makes it possible to provide the same functionality by simply adding the following to the HTTP expression of the method:
// DO THIS INSTEAD
var _ = Service("session", func() {
Method("use_session", func() {
Payload(func() {
Attribute("session_uid", String, "Session ID")
})
HTTP(func() {
GET("/")
Cookie("session_uid") // Load session ID from "SID" cookie
})
})
})
Note that the generated code does NOT make use of the context but instead
properly decodes the cookie into the payload (server side) or result (client
side). Cookie
also makes it possible to write cookies into HTTP responses
(and read them client side).
See the example and DSL doc for additional information.
OpenAPI v3
This release also adds support for the
OpenAPI v3.0.3
specification. The goa gen
tool now generates openapi3.yaml
and
openapi3.json
files under the gen/http/
folder. This is in addition to
the already generated openapi.yaml
and openapi.json
files that contain
the OpenAPI v2 specification.
A big thank you to Nitin Mohan and Neenu Ann Varghese for their help in putting this together!
API Level Errors
As a convenience Goa now makes it possible to define the transport specific
details of errors in the API expression. This makes it possible to provide
such details once and reuse them in multiple methods. Note that the services
and/or methods still need to explicitly declare the error (similar semantic
to Reference
). For example:
var _ = API("test", func() {
Error("bad_request")
HTTP(func() {
Response(StatusBadRequest, "bad_request")
})
})
Service("Service", func() {
Method("Method", func() {
Error("bad_request") // No need to define transport details again
Error("internal_error") // Method specific error, requires transport details
HTTP(func() {
GET("/one/two")
Response("internal_error", StatusInternalServerError) // transport details
})
})
})
And a lot more
The complete list
of changes from v3.1.0
to v3.2.0
includes many other improvements and
fixes, in particular:
- Nitin Mohan fixed an issue with cyclic result
type definitions that could cause the
goa
tool to crash. (#2517) - @ikawaha fixed an issue with trailing slashes
appearing in the generated path functions. The fix makes sure that if a
relative path ends with
/
then it is preserved except in the case where the relative path is just/
. In this case the slash is not added to the base path. The slash can be added in this case by using./
instead of/
. (#2530) (#2557). - Taichi Sasaki helped finalize the setup of GitHub
actions as a replacement for TravisCI on the
v3
branch. (#2529) (#2533) - @achow-flexera helped fix issues with the
recently added
SkipRequestEncodeDecode
. (#2532) (#2543) - Taichi Sasaki also fixed the value of the Content-Type header used in HTTP responses that correspond to errors so that it would correctly honor any content type specified in the design via ContentType. (#2566)
- Nitin Mohan fixed an issue where the generated clients could not properly set the authorization bearer token. (#2563)
- Nitin Mohan also fixed an issue where the conversions between snake_case and CamelCase could be inconsistent which could affect ConvertTo and CreateFrom. (#2568)
- @mrsndmn fixed an issue where the
struct:field:name
tag would not work when used in conjunction witherror:field:name
. (#2596) - Yamamoto Shun fixed an issue with the example code generated to handle graceful shutdown. (#2603)
- Yamamoto Shun also made sure the example code
properly handles
SIGTERM
on top ofSIGINT
to trigger graceful shutdown. (#2604)
Thank you to all the contributors! Come by the Goa slack channel (invite here) for any question or just to say hi!