Skip to content

Commit

Permalink
Add support for multiple exceptions with the same status code (#565)
Browse files Browse the repository at this point in the history
* Add client files.

* Compile withExceptions code.

* Add exceptions by status code to pave the way for updating the template.

* Update logic for exceptions handling in HTTP clients.

* Add withexceptions sample endpoint.

* Run go fmt.

* Fix tests.

* Run gofmt.

* Update after generate.

* Add sort to preserve ordering.

* Update example endpoint and client to avoid test failures.

* Switch to use multierr.

* Shorten log statement per review request.

* Remove "= nil" from var initialization.
  • Loading branch information
gjtrowbridge authored Feb 21, 2019
1 parent a57c485 commit a389a84
Show file tree
Hide file tree
Showing 37 changed files with 3,785 additions and 128 deletions.
58 changes: 33 additions & 25 deletions codegen/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package codegen

import (
"fmt"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -101,14 +102,15 @@ type MethodSpec struct {
// ResHeaders needed, generated from "zanzibar.http.resHeaders"
ResHeaders []string

RequestType string
ShortRequestType string
ResponseType string
ShortResponseType string
OKStatusCode StatusCode
Exceptions []ExceptionSpec
ExceptionsIndex map[string]ExceptionSpec
ValidStatusCodes []int
RequestType string
ShortRequestType string
ResponseType string
ShortResponseType string
OKStatusCode StatusCode
Exceptions []ExceptionSpec
ExceptionsByStatusCode map[int][]ExceptionSpec
ExceptionsIndex map[string]ExceptionSpec
ValidStatusCodes []int
// Additional struct generated from the bundle of request args.
RequestBoxed bool
// Thrift service name the method belongs to.
Expand Down Expand Up @@ -388,12 +390,16 @@ func (ms *MethodSpec) setOKStatusCode(statusCode string) error {
}

func (ms *MethodSpec) setValidStatusCodes() {
ms.ValidStatusCodes = make([]int, len(ms.Exceptions)+1)
ms.ValidStatusCodes = []int{
ms.OKStatusCode.Code,
}

ms.ValidStatusCodes[0] = ms.OKStatusCode.Code
for i := 0; i < len(ms.Exceptions); i++ {
ms.ValidStatusCodes[i+1] = ms.Exceptions[i].StatusCode.Code
for code := range ms.ExceptionsByStatusCode {
ms.ValidStatusCodes = append(ms.ValidStatusCodes, code)
}

// Prevents non-deterministic builds
sort.Ints(ms.ValidStatusCodes)
}

func (ms *MethodSpec) setExceptions(
Expand All @@ -402,13 +408,11 @@ func (ms *MethodSpec) setExceptions(
resultSpec *compile.ResultSpec,
h *PackageHelper,
) error {
seenStatusCodes := map[int]bool{
ms.OKStatusCode.Code: true,
}
ms.Exceptions = make([]ExceptionSpec, len(resultSpec.Exceptions))
ms.ExceptionsIndex = make(
map[string]ExceptionSpec, len(resultSpec.Exceptions),
)
ms.ExceptionsByStatusCode = map[int][]ExceptionSpec{}

for i, e := range resultSpec.Exceptions {
typeName, err := h.TypeFullName(e.Type)
Expand All @@ -430,6 +434,13 @@ func (ms *MethodSpec) setExceptions(
}
ms.Exceptions[i] = exception
ms.ExceptionsIndex[e.Name] = exception
if _, exists := ms.ExceptionsByStatusCode[exception.StatusCode.Code]; !exists {
ms.ExceptionsByStatusCode[exception.StatusCode.Code] = []ExceptionSpec{}
}
ms.ExceptionsByStatusCode[exception.StatusCode.Code] = append(
ms.ExceptionsByStatusCode[exception.StatusCode.Code],
exception,
)
continue
}

Expand All @@ -441,16 +452,6 @@ func (ms *MethodSpec) setExceptions(
)
}

if seenStatusCodes[code] && !isEndpoint {
return errors.Wrapf(
err,
"cannot have duplicate status code %s for exception %s",
ms.annotations.HTTPStatus,
e.Name,
)
}
seenStatusCodes[code] = true

exception := ExceptionSpec{
StructSpec: StructSpec{
Type: typeName,
Expand All @@ -464,6 +465,13 @@ func (ms *MethodSpec) setExceptions(
}
ms.Exceptions[i] = exception
ms.ExceptionsIndex[e.Name] = exception
if _, exists := ms.ExceptionsByStatusCode[exception.StatusCode.Code]; !exists {
ms.ExceptionsByStatusCode[exception.StatusCode.Code] = []ExceptionSpec{}
}
ms.ExceptionsByStatusCode[exception.StatusCode.Code] = append(
ms.ExceptionsByStatusCode[exception.StatusCode.Code],
exception,
)
}
return nil
}
Expand Down
1 change: 1 addition & 0 deletions codegen/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ func (system *ModuleSystem) ResolveModules(

classConfigPath, _, _ := getConfigFilePath(moduleDirAbs, className)
if classConfigPath == "" {
fmt.Printf(" no class config found in %s directory\n", moduleDirAbs)
// No class config found in this directory, skip over it
continue
}
Expand Down
30 changes: 19 additions & 11 deletions codegen/template_bundle/template_files.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 18 additions & 10 deletions codegen/templates/http_client.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -288,14 +288,18 @@ func (c *{{$clientName}}) {{$methodName}}(
}

return respHeaders, nil
{{range $idx, $exception := .Exceptions}}
case {{$exception.StatusCode.Code}}:
var exception {{$exception.Type}}
err = res.ReadAndUnmarshalBody(&exception)
{{range $code, $exceptions := .ExceptionsByStatusCode -}}
case {{$code}}:
allOptions := []interface{}{
{{range $idx, $exception := $exceptions -}}
&{{$exception.Type}}{},
{{- end}}
}
v, err := res.ReadAndUnmarshalBodyMultipleOptions(allOptions)
if err != nil {
return respHeaders, err
}
return respHeaders, &exception
return respHeaders, v.(error)
{{end}}
default:
_, err = res.ReadAll()
Expand All @@ -317,14 +321,18 @@ func (c *{{$clientName}}) {{$methodName}}(
{{- end}}

return {{if isPointerType .ResponseType}}&{{end}}responseBody, respHeaders, nil
{{range $idx, $exception := .Exceptions}}
case {{$exception.StatusCode.Code}}:
var exception {{$exception.Type}}
err = res.ReadAndUnmarshalBody(&exception)
{{range $code, $exceptions := .ExceptionsByStatusCode -}}
case {{$code}}:
allOptions := []interface{}{
{{range $idx, $exception := $exceptions -}}
&{{$exception.Type}}{},
{{- end}}
}
v, err := res.ReadAndUnmarshalBodyMultipleOptions(allOptions)
if err != nil {
return defaultRes, respHeaders, err
}
return defaultRes, respHeaders, &exception
return defaultRes, respHeaders, v.(error)
{{end}}
default:
_, err = res.ReadAll()
Expand Down
72 changes: 40 additions & 32 deletions examples/example-gateway/build/clients/bar/bar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a389a84

Please sign in to comment.