goa v1.4.0

Announcing goa v1.4.0

It’s been almost a year since the last official release of goa. During that year many contributions have been made including both new features and bug fixes. The team has also been hard at work on v2 making good progress there but this post is about the latest v1 release: goa v1.4.0.

New Features

Multipart Form Encoding

Taichi Sasaki (@tchssk) added native support for multipart form encoding as described in the HTML 4 Specification. The new MultipartForm function can be used in an action design as follows:

var _ = Resource("profiles", func() {
	Action("submit", func() {
		Routing(POST("profiles"))
		Payload(ProfilePayload)
		MultipartForm() // Uses "multipart/form-data" encoding
		Description("Post accepts a multipart form encoded request")
		Response(OK, ResultMedia)
	})
})

The Multipart Form Encoding example provides a complete design and example implementation.

Add support for multipart form requests #1606 - Taichi Sasaki

Primitive File Type

Taichi Sasaki (@tchssk) also added the ability to map payload attributes to multipart files making it convenient to implement file upload in goa. The new File type can be used in combination with MultipartForm() as follows:

var _ = Resource("profiles", func() {
	Action("submit", func() {
		Routing(POST("profiles"))
		Payload(ProfilePayload)
		MultipartForm() // Uses "multipart/form-data" encoding
		Description("Post accepts a multipart form encoded request")
		Response(OK, ResultMedia)
	})
})

var ProfilePayload = Type("ProfilePayload", func() {
	Attribute("name", String, "Name")
	Attribute("birthday", DateTime, "Birthday")
	Attribute("icon", File, "Icon") // Attribute "icon" contains a file
	Required("name", "birthday", "icon")
})

The controller can then simply access the file content as follows:

	file, err := ctx.Payload.Icon.Open()
	if err != nil {
		return err
	}
	defer file.Close()
	f, err := os.OpenFile("./icons/"+ctx.Payload.Icon.Filename, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("failed to save file: %s", err) // causes a 500 response
	}
	defer f.Close()
	io.Copy(f, file)

The Multipart Form Encoding example provides a complete design and example implementation.

Add a primitive type File #1642 - Taichi Sasaki

Sensitive Headers Suppression

Adam Hanna (@adam-hanna) made it possible to identify header values that should not be logged by the LogRequest middleware. The names of the corresponding headers should be given to the new variadic middleware constructor parameter:

middleware.LogRequest(true, "Authorization", "Api-Key", "Owner-Email")

Add ability to suppress sensitive headers from log #1691 - Adam Hanna

OpenAPI Specification Read-Only Fields

Daniel I. Khan Ramiro (@dikhan) added the ability to specify read-only attributes. Such attributes are marked as read-only in the generated OpenAPI specification and behave like other attributes otherwise.

var TypeWithReadOnlyAttributes = Type("Foo", func() {
	Attribute("standard", String)
	Attribute("read-only", String, func() {
		ReadOnly()
	})
})

Add support for readonly attributes #1776 - Daniel I. Khan Ramiro

Support for RFC3339 Date Format

Konstantin Lepa (@k-lepa) added support for date only format. goa had support for the RFC3339 DateTime format this PR adds support for the RFC3339 Date format, eg: 2017-11-16.

var TypeWithDate = Type("Foo", func() {
	Attribute("date", String, func() {
		Format("date")
	})
})

Add RFC3339 date format #1787 - Konstantin Lepa

Support JWT Authorization via Query String

Jie Kang (@jiekang) made it possible for clients to provide the JWT token used for authorization in the HTTP request query string parameters (on top of HTTP headers).

Add support for JWT Token authorization via query parameter #1800 - Jie Kang

Bug Fixes

As noted in the introduction this release comes with many bug fixes as well:

  • Properly format JavaScript generator Go example code #1497 - Raphael Simon
  • Properly test for required attributes when unmarshaling #1521 - Raphael Simon
  • Remove the unused valiable #1550 - @ikawaha
  • Prevent “Any” fields from pointing to *interface{} #1591 - Alex Brausewetter
  • Prevent pointer to ‘*interface{}’ in user types #1611 - Alex Brausewetter
  • Fix MuxHandler initialization race #1627 - Robert Wooley
  • Validate different wildcards only if request method is the same #1583 - Egor Kovetskiy
  • Make sure to finalize parent resources first. #1655 - Raphael Simon
  • Fix serialization of default values for non string and non integer attributes. #1681 - Raphael Simon
  • Properly generate validation for URL parameter arrays #1721 - Raphael Simon
  • Add a yaml tag to generated types fields #1733
  • Make request header logging order consistent #1748 - Raphael Simon
  • Fix for v1 multipart/form-data Swagger semantic error #1744 - Mark Songhurst
  • Make sure default output dir is set #1751 - Raphael Simon
  • Fix gocyclo dependency #1772 - Konstantin Lepa & Raphael Simon
  • Fix minItems/maxItems for array type #1775 - Konstantin Lepa
  • Fix recursive types #1774 - Konstantin Lepa
  • Fix client tests when GOPATH is /go #1773
  • Fix design.HasFile for recursive user types #1791 - Konstantin Lepa

Thank You!

A big thank you to all the contributors! A special thank you to Jie Kang who helped put together these release notes.

As we look ahead for goa the big ticket item is the release of v2. v2 is being used in production in a few sites already, the last pieces needed before it can be released (i.e. made the default version) are the gRPC transport and better documentation. Head over to the repo and check out the README for more information.