Skip to content

Commit

Permalink
allow annotation to be config
Browse files Browse the repository at this point in the history
  • Loading branch information
cl1337 committed Feb 5, 2018
1 parent 258e9f2 commit 08159ae
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 59 deletions.
2 changes: 2 additions & 0 deletions backend/repository/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ func (r *Repository) newGatewayConfig() (configuration *Config, cfgErr error) {
EndpointConfigDir: cfg.MustGetString("endpointConfig"),
MiddlewareConfigDir: cfg.MustGetString("middlewareConfig"),
}
annotationPrefix := cfg.MustGetString("annotationPrefix")
pkgHelper, err := codegen.NewPackageHelper(
config.PackageRoot,
config.ManagedThriftFolder,
Expand All @@ -219,6 +220,7 @@ func (r *Repository) newGatewayConfig() (configuration *Config, cfgErr error) {
config.GenCodePackage,
config.TargetGenDir,
"",
annotationPrefix,
)
if err != nil {
return nil, errors.Wrapf(err, "failed to create package helper")
Expand Down
2 changes: 2 additions & 0 deletions backend/repository/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (m *Manager) IDLThriftService(path string) (map[string]*ThriftService, erro
"idl-registry/gen-code", // genCodePackage
"./build", // targetGenDir
"", // copyrightHeader
"zanzibar",
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -295,6 +296,7 @@ func (m *Manager) Validate(r *Repository, req *UpdateRequest) error {
cfg.GenCodePackage,
"./build",
"",
"zanzibar",
)
if err != nil {
return err
Expand Down
133 changes: 80 additions & 53 deletions codegen/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ import (
"go.uber.org/thriftrw/compile"
)

const (
antHTTPMethod = "%s.http.method"
antHTTPPath = "%s.http.path"
antHTTPStatus = "%s.http.status"
antHTTPReqHeaders = "%s.http.reqHeaders"
antHTTPResHeaders = "%s.http.resHeaders"
antHTTPRef = "%s.http.ref"
antMeta = "%s.meta"
antHandler = "%s.handler"

// AntHTTPReqDefBoxed annotates a method so that the genereted method takes
// generated argument directly instead of a struct that warps the argument.
// The annotated method should have one and only one argument.
AntHTTPReqDefBoxed = "%s.http.req.def"
)

// PathSegment represents a part of the http path.
type PathSegment struct {
Type string
Expand Down Expand Up @@ -57,10 +73,11 @@ type MethodSpec struct {
Name string
HTTPMethod string
// Used by edge gateway to generate endpoint.
EndpointName string
HTTPPath string
PathSegments []PathSegment
IsEndpoint bool
EndpointName string
HTTPPath string
PathSegments []PathSegment
annotationMap annotationMap
IsEndpoint bool

// Statements for reading query parameters.
ParseQueryParamGoStatements []string
Expand Down Expand Up @@ -119,6 +136,18 @@ type MethodSpec struct {
RequestParamGoStatements []string
}

type annotationMap struct {
HTTPMethod string
HTTPPath string
HTTPStatus string
HTTPReqHeaders string
HTTPResHeaders string
HTTPRef string
Meta string
Handler string
HTTPReqDefBoxed string
}

// StructSpec specifies a Go struct to be generated.
type StructSpec struct {
Type string
Expand All @@ -132,22 +161,6 @@ type StatusCode struct {
Message string
}

const (
antHTTPMethod = "zanzibar.http.method"
antHTTPPath = "zanzibar.http.path"
antHTTPStatus = "zanzibar.http.status"
antHTTPReqHeaders = "zanzibar.http.reqHeaders"
antHTTPResHeaders = "zanzibar.http.resHeaders"
antHTTPRef = "zanzibar.http.ref"
antMeta = "zanzibar.meta"
antHandler = "zanzibar.handler"

// AntHTTPReqDefBoxed annotates a method so that the genereted method takes
// generated argument directly instead of a struct that warps the argument.
// The annotated method should have one and only one argument.
AntHTTPReqDefBoxed = "zanzibar.http.req.def"
)

// NewMethod creates new method specification.
func NewMethod(
thriftFile string,
Expand All @@ -157,14 +170,28 @@ func NewMethod(
isEndpoint bool,
thriftService string,
) (*MethodSpec, error) {
method := &MethodSpec{}
var (
err error
ok bool
ant = packageHelper.annotationPrefix
method = &MethodSpec{}
)
method.CompiledThriftSpec = funcSpec
var err error
var ok bool
method.Name = funcSpec.MethodName()
method.IsEndpoint = isEndpoint
method.WantAnnot = wantAnnot
method.ThriftService = thriftService
method.annotationMap = annotationMap{
HTTPMethod: fmt.Sprintf(antHTTPMethod, ant),
HTTPPath: fmt.Sprintf(antHTTPPath, ant),
HTTPStatus: fmt.Sprintf(antHTTPStatus, ant),
HTTPReqHeaders: fmt.Sprintf(antHTTPReqHeaders, ant),
HTTPResHeaders: fmt.Sprintf(antHTTPResHeaders, ant),
HTTPRef: fmt.Sprintf(antHTTPRef, ant),
Meta: fmt.Sprintf(antMeta, ant),
Handler: fmt.Sprintf(antHandler, ant),
HTTPReqDefBoxed: fmt.Sprintf(AntHTTPReqDefBoxed, ant),
}

method.GenCodePkgName, err = packageHelper.TypePackageName(thriftFile)
if err != nil {
Expand All @@ -186,20 +213,20 @@ func NewMethod(
return nil, err
}

method.ReqHeaders = headers(funcSpec.Annotations[antHTTPReqHeaders])
method.ResHeaders = headers(funcSpec.Annotations[antHTTPResHeaders])
method.ReqHeaders = headers(funcSpec.Annotations[method.annotationMap.HTTPReqHeaders])
method.ResHeaders = headers(funcSpec.Annotations[method.annotationMap.HTTPResHeaders])

if !wantAnnot {
return method, nil
}

if method.HTTPMethod, ok = funcSpec.Annotations[antHTTPMethod]; !ok {
return nil, errors.Errorf("missing annotation '%s' for HTTP method", antHTTPMethod)
if method.HTTPMethod, ok = funcSpec.Annotations[method.annotationMap.HTTPMethod]; !ok {
return nil, errors.Errorf("missing annotation '%s' for HTTP method", method.annotationMap.HTTPMethod)
}

method.EndpointName = funcSpec.Annotations[antHandler]
method.EndpointName = funcSpec.Annotations[method.annotationMap.Handler]

err = method.setOKStatusCode(funcSpec.Annotations[antHTTPStatus])
err = method.setOKStatusCode(funcSpec.Annotations[method.annotationMap.HTTPStatus])
if err != nil {
return nil, err
}
Expand All @@ -221,9 +248,9 @@ func NewMethod(
}

var httpPath string
if httpPath, ok = funcSpec.Annotations[antHTTPPath]; !ok {
if httpPath, ok = funcSpec.Annotations[method.annotationMap.HTTPPath]; !ok {
return nil, errors.Errorf(
"missing annotation '%s' for HTTP path", antHTTPPath,
"missing annotation '%s' for HTTP path", method.annotationMap.HTTPPath,
)
}
method.setHTTPPath(httpPath, funcSpec)
Expand All @@ -246,7 +273,7 @@ func NewMethod(
return method, nil
}

func scanForNonParams(funcSpec *compile.FunctionSpec) bool {
func (ms *MethodSpec) scanForNonParams(funcSpec *compile.FunctionSpec) bool {
hasNonParams := false

visitor := func(
Expand All @@ -258,7 +285,7 @@ func scanForNonParams(funcSpec *compile.FunctionSpec) bool {
return false
}

param, ok := field.Annotations[antHTTPRef]
param, ok := field.Annotations[ms.annotationMap.HTTPRef]
if !ok || param[0:6] != "params" {
hasNonParams = true
return true
Expand All @@ -280,7 +307,7 @@ func (ms *MethodSpec) setRequestType(curThriftFile string, funcSpec *compile.Fun
return nil
}
var err error
if isRequestBoxed(funcSpec) {
if ms.isRequestBoxed(funcSpec) {
ms.RequestBoxed = true
ms.RequestType, err = packageHelper.TypeFullName(funcSpec.ArgsSpec[0].Type)
if err == nil && IsStructType(funcSpec.ArgsSpec[0].Type) {
Expand Down Expand Up @@ -340,7 +367,7 @@ func (ms *MethodSpec) RefResponse(respVar string) string {

func (ms *MethodSpec) setOKStatusCode(statusCode string) error {
if statusCode == "" {
return errors.Errorf("no http OK status code set by annotation '%s' ", antHTTPStatus)
return errors.Errorf("no http OK status code set by annotation '%s' ", ms.annotationMap.HTTPStatus)
}

code, err := strconv.Atoi(statusCode)
Expand Down Expand Up @@ -403,19 +430,19 @@ func (ms *MethodSpec) setExceptions(
continue
}

code, err := strconv.Atoi(e.Annotations[antHTTPStatus])
code, err := strconv.Atoi(e.Annotations[ms.annotationMap.HTTPStatus])
if err != nil {
return errors.Wrapf(
err,
"cannot parse the annotation %s for exception %s", antHTTPStatus, e.Name,
"cannot parse the annotation %s for exception %s", ms.annotationMap.HTTPStatus, e.Name,
)
}

if seenStatusCodes[code] && !isEndpoint {
return errors.Wrapf(
err,
"cannot have duplicate status code %s for exception %s",
antHTTPStatus,
ms.annotationMap.HTTPStatus,
e.Name,
)
}
Expand All @@ -438,15 +465,15 @@ func (ms *MethodSpec) setExceptions(
return nil
}

func findParamsAnnotation(
func (ms *MethodSpec) findParamsAnnotation(
fields compile.FieldGroup, paramName string,
) (string, bool, bool) {
var identifier string
var required bool
visitor := func(
goPrefix string, thriftPrefix string, field *compile.FieldSpec,
) bool {
if param, ok := field.Annotations[antHTTPRef]; ok {
if param, ok := field.Annotations[ms.annotationMap.HTTPRef]; ok {
if param == "params."+paramName[1:] {
identifier = goPrefix + "." + pascalCase(field.Name)
required = field.Required
Expand Down Expand Up @@ -587,7 +614,7 @@ func (ms *MethodSpec) setEndpointRequestHeaderFields(
return false
}

if param, ok := field.Annotations[antHTTPRef]; ok {
if param, ok := field.Annotations[ms.annotationMap.HTTPRef]; ok {
if param[0:8] == "headers." {
headerName := param[8:]
camelHeaderName := camelCase(headerName)
Expand Down Expand Up @@ -681,7 +708,7 @@ func (ms *MethodSpec) setResponseHeaderFields(
visitor := func(
goPrefix string, thriftPrefix string, field *compile.FieldSpec,
) bool {
if param, ok := field.Annotations[antHTTPRef]; ok {
if param, ok := field.Annotations[ms.annotationMap.HTTPRef]; ok {
if param[0:8] == "headers." {
headerName := param[8:]
ms.ResHeaderFields[headerName] = HeaderFieldInfo{
Expand Down Expand Up @@ -723,7 +750,7 @@ func (ms *MethodSpec) setClientRequestHeaderFields(
return false
}

if param, ok := field.Annotations[antHTTPRef]; ok {
if param, ok := field.Annotations[ms.annotationMap.HTTPRef]; ok {
if param[0:8] == "headers." {
headerName := param[8:]
bodyIdentifier := goPrefix + "." + pascalCase(field.Name)
Expand Down Expand Up @@ -783,11 +810,11 @@ func (ms *MethodSpec) setHTTPPath(httpPath string, funcSpec *compile.FunctionSpe
if ms.RequestBoxed {
// Boxed requests mean first arg is struct
structType := funcSpec.ArgsSpec[0].Type.(*compile.StructSpec)
fieldSelect, required, ok = findParamsAnnotation(
fieldSelect, required, ok = ms.findParamsAnnotation(
structType.Fields, segment,
)
} else {
fieldSelect, required, ok = findParamsAnnotation(
fieldSelect, required, ok = ms.findParamsAnnotation(
compile.FieldGroup(funcSpec.ArgsSpec), segment,
)
}
Expand Down Expand Up @@ -1012,12 +1039,12 @@ func (ms *MethodSpec) setWriteQueryParamStatements(
return false
}

httpRefAnnotation := field.Annotations[antHTTPRef]
httpRefAnnotation := field.Annotations[ms.annotationMap.HTTPRef]
if httpRefAnnotation != "" && !strings.HasPrefix(httpRefAnnotation, "query") {
return false
}

longQueryName := getLongQueryName(field, thriftPrefix)
longQueryName := ms.getLongQueryName(field, thriftPrefix)
identifierName := camelCase(longQueryName) + "Query"

if !hasQueryFields {
Expand Down Expand Up @@ -1081,7 +1108,7 @@ func (ms *MethodSpec) setParseQueryParamStatements(
) bool {
realType := compile.RootTypeSpec(field.Type)
longFieldName := goPrefix + "." + pascalCase(field.Name)
longQueryName := getLongQueryName(field, thriftPrefix)
longQueryName := ms.getLongQueryName(field, thriftPrefix)

if len(stack) > 0 {
if !strings.HasPrefix(longFieldName, stack[len(stack)-1]) {
Expand Down Expand Up @@ -1121,7 +1148,7 @@ func (ms *MethodSpec) setParseQueryParamStatements(

identifierName := camelCase(longQueryName) + "Query"

httpRefAnnotation := field.Annotations[antHTTPRef]
httpRefAnnotation := field.Annotations[ms.annotationMap.HTTPRef]
if httpRefAnnotation != "" && !strings.HasPrefix(httpRefAnnotation, "query") {
return false
}
Expand Down Expand Up @@ -1181,11 +1208,11 @@ func (ms *MethodSpec) setParseQueryParamStatements(
return nil
}

func getLongQueryName(field *compile.FieldSpec, thriftPrefix string) string {
func (ms *MethodSpec) getLongQueryName(field *compile.FieldSpec, thriftPrefix string) string {
var longQueryName string

queryName := field.Name
queryAnnotation := field.Annotations[antHTTPRef]
queryAnnotation := field.Annotations[ms.annotationMap.HTTPRef]
if strings.HasPrefix(queryAnnotation, "query.") {
// len("query.") == 6
queryName = queryAnnotation[6:]
Expand All @@ -1202,8 +1229,8 @@ func getLongQueryName(field *compile.FieldSpec, thriftPrefix string) string {
return longQueryName
}

func isRequestBoxed(f *compile.FunctionSpec) bool {
boxed, ok := f.Annotations[AntHTTPReqDefBoxed]
func (ms *MethodSpec) isRequestBoxed(f *compile.FunctionSpec) bool {
boxed, ok := f.Annotations[ms.annotationMap.HTTPReqDefBoxed]
if ok && boxed == "true" {
return true
}
Expand Down
4 changes: 4 additions & 0 deletions codegen/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type PackageHelper struct {
testConfigsRootDir string
// String containing copyright header to add to generated code.
copyrightHeader string
// annotation prefix to parse for thrift schema
annotationPrefix string
// The middlewares available for the endpoints
middlewareSpecs map[string]*MiddlewareSpec
}
Expand All @@ -63,6 +65,7 @@ func NewPackageHelper(
genCodePackage string,
relTargetGenDir string,
copyrightHeader string,
annotationPrefix string,
) (*PackageHelper, error) {
absConfigRoot, err := filepath.Abs(configRoot)
if err != nil {
Expand All @@ -89,6 +92,7 @@ func NewPackageHelper(
targetGenDir: filepath.Join(absConfigRoot, relTargetGenDir),
copyrightHeader: copyrightHeader,
middlewareSpecs: middlewareSpecs,
annotationPrefix: annotationPrefix,
}
return p, nil
}
Expand Down
1 change: 1 addition & 0 deletions codegen/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func newPackageHelper(t *testing.T) *codegen.PackageHelper {
"github.com/uber/zanzibar/examples/example-gateway/build/gen-code",
tmpDir,
testCopyrightHeader,
"zanzibar",
)
if !assert.NoError(t, err, "failed to create package helper") {
return nil
Expand Down

0 comments on commit 08159ae

Please sign in to comment.