11 Star 11 Fork 0

Gitee 极速下载 / goa

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/goadesign/goa
克隆/下载
client.go 31.00 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
package codegen
import (
"fmt"
"path/filepath"
"goa.design/goa/codegen"
"goa.design/goa/codegen/service"
"goa.design/goa/expr"
)
// ClientFiles returns the generated HTTP client files.
func ClientFiles(genpkg string, root *expr.RootExpr) []*codegen.File {
var files []*codegen.File
for _, svc := range root.API.HTTP.Services {
files = append(files, clientFile(genpkg, svc))
if f := websocketClientFile(genpkg, svc); f != nil {
files = append(files, f)
}
}
for _, svc := range root.API.HTTP.Services {
if f := clientEncodeDecodeFile(genpkg, svc); f != nil {
files = append(files, f)
}
}
return files
}
// clientFile returns the client HTTP transport file
func clientFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
data := HTTPServices.Get(svc.Name())
svcName := codegen.SnakeCase(data.Service.VarName)
path := filepath.Join(codegen.Gendir, "http", svcName, "client", "client.go")
title := fmt.Sprintf("%s client HTTP transport", svc.Name())
sections := []*codegen.SectionTemplate{
codegen.Header(title, "client", []*codegen.ImportSpec{
{Path: "context"},
{Path: "fmt"},
{Path: "io"},
{Path: "mime/multipart"},
{Path: "net/http"},
{Path: "strconv"},
{Path: "strings"},
{Path: "time"},
{Path: "github.com/gorilla/websocket"},
{Path: "goa.design/goa", Name: "goa"},
{Path: "goa.design/goa/http", Name: "goahttp"},
{Path: genpkg + "/" + svcName, Name: data.Service.PkgName},
{Path: genpkg + "/" + svcName + "/" + "views", Name: data.Service.ViewsPkg},
}),
}
sections = append(sections, &codegen.SectionTemplate{
Name: "client-struct",
Source: clientStructT,
Data: data,
FuncMap: map[string]interface{}{"hasWebSocket": hasWebSocket},
})
for _, e := range data.Endpoints {
if e.MultipartRequestEncoder != nil {
sections = append(sections, &codegen.SectionTemplate{
Name: "multipart-request-encoder-type",
Source: multipartRequestEncoderTypeT,
Data: e.MultipartRequestEncoder,
})
}
}
sections = append(sections, &codegen.SectionTemplate{
Name: "client-init",
Source: clientInitT,
Data: data,
FuncMap: map[string]interface{}{"hasWebSocket": hasWebSocket},
})
for _, e := range data.Endpoints {
sections = append(sections, &codegen.SectionTemplate{
Name: "client-endpoint-init",
Source: endpointInitT,
Data: e,
FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
})
}
return &codegen.File{Path: path, SectionTemplates: sections}
}
// clientEncodeDecodeFile returns the file containing the HTTP client encoding
// and decoding logic.
func clientEncodeDecodeFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
data := HTTPServices.Get(svc.Name())
svcName := codegen.SnakeCase(data.Service.VarName)
path := filepath.Join(codegen.Gendir, "http", svcName, "client", "encode_decode.go")
title := fmt.Sprintf("%s HTTP client encoders and decoders", svc.Name())
sections := []*codegen.SectionTemplate{
codegen.Header(title, "client", []*codegen.ImportSpec{
{Path: "bytes"},
{Path: "context"},
{Path: "fmt"},
{Path: "io"},
{Path: "io/ioutil"},
{Path: "mime/multipart"},
{Path: "net/http"},
{Path: "net/url"},
{Path: "os"},
{Path: "strconv"},
{Path: "strings"},
{Path: "unicode/utf8"},
{Path: "goa.design/goa", Name: "goa"},
{Path: "goa.design/goa/http", Name: "goahttp"},
{Path: genpkg + "/" + svcName, Name: data.Service.PkgName},
{Path: genpkg + "/" + svcName + "/" + "views", Name: data.Service.ViewsPkg},
}),
}
for _, e := range data.Endpoints {
sections = append(sections, &codegen.SectionTemplate{
Name: "request-builder",
Source: requestBuilderT,
Data: e,
})
if e.RequestEncoder != "" && e.Payload.Ref != "" {
sections = append(sections, &codegen.SectionTemplate{
Name: "request-encoder",
Source: requestEncoderT,
FuncMap: map[string]interface{}{
"typeConversionData": typeConversionData,
"mapConversionData": mapConversionData,
"goTypeRef": func(dt expr.DataType) string {
return service.Services.Get(svc.Name()).Scope.GoTypeRef(&expr.AttributeExpr{Type: dt})
},
"isBearer": isBearer,
"aliasedType": fieldType,
"isAliased": func(dt expr.DataType) bool {
_, ok := dt.(expr.UserType)
return ok
},
},
Data: e,
})
}
if e.MultipartRequestEncoder != nil {
sections = append(sections, &codegen.SectionTemplate{
Name: "multipart-request-encoder",
Source: multipartRequestEncoderT,
Data: e.MultipartRequestEncoder,
})
}
if e.Result != nil || len(e.Errors) > 0 {
sections = append(sections, &codegen.SectionTemplate{
Name: "response-decoder",
Source: responseDecoderT,
Data: e,
FuncMap: map[string]interface{}{
"goTypeRef": func(dt expr.DataType) string {
return service.Services.Get(svc.Name()).Scope.GoTypeRef(&expr.AttributeExpr{Type: dt})
},
},
})
}
if e.Method.SkipRequestBodyEncodeDecode {
sections = append(sections, &codegen.SectionTemplate{
Name: "build-stream-request",
Source: buildStreamRequestT,
Data: e,
})
}
}
for _, h := range data.ClientTransformHelpers {
sections = append(sections, &codegen.SectionTemplate{
Name: "client-transform-helper",
Source: transformHelperT,
Data: h,
})
}
return &codegen.File{Path: path, SectionTemplates: sections}
}
// typeConversionData produces the template data suitable for executing the
// "header_conversion" template.
func typeConversionData(dt, ft expr.DataType, varName string, target string) map[string]interface{} {
ut, isut := ft.(expr.UserType)
if isut {
ft = ut.Attribute().Type
}
return map[string]interface{}{
"Type": dt,
"FieldType": ft,
"VarName": varName,
"Target": target,
"IsAliased": isut,
}
}
func mapConversionData(dt, ft expr.DataType, varName, sourceVar, sourceField string, newVar bool) map[string]interface{} {
ut, isut := ft.(expr.UserType)
if isut {
ft = ut.Attribute().Type
}
return map[string]interface{}{
"Type": dt,
"FieldType": ft,
"VarName": varName,
"SourceVar": sourceVar,
"SourceField": sourceField,
"NewVar": newVar,
"IsAliased": isut,
}
}
func fieldType(ft expr.DataType) expr.DataType {
ut, isut := ft.(expr.UserType)
if isut {
return ut.Attribute().Type
}
return ft
}
// isBearer returns true if the security scheme uses a Bearer scheme.
func isBearer(schemes []*service.SchemeData) bool {
for _, s := range schemes {
if s.Name != "Authorization" {
continue
}
if s.Type == "JWT" || s.Type == "OAuth2" {
return true
}
}
return false
}
// input: ServiceData
const clientStructT = `{{ printf "%s lists the %s service endpoint HTTP clients." .ClientStruct .Service.Name | comment }}
type {{ .ClientStruct }} struct {
{{- range .Endpoints }}
{{ printf "%s Doer is the HTTP client used to make requests to the %s endpoint." .Method.VarName .Method.Name | comment }}
{{ .Method.VarName }}Doer goahttp.Doer
{{ end }}
// RestoreResponseBody controls whether the response bodies are reset after
// decoding so they can be read again.
RestoreResponseBody bool
scheme string
host string
encoder func(*http.Request) goahttp.Encoder
decoder func(*http.Response) goahttp.Decoder
{{- if hasWebSocket . }}
dialer goahttp.Dialer
configurer *ConnConfigurer
{{- end }}
}
`
// input: ServiceData
const clientInitT = `{{ printf "New%s instantiates HTTP clients for all the %s service servers." .ClientStruct .Service.Name | comment }}
func New{{ .ClientStruct }}(
scheme string,
host string,
doer goahttp.Doer,
enc func(*http.Request) goahttp.Encoder,
dec func(*http.Response) goahttp.Decoder,
restoreBody bool,
{{- if hasWebSocket . }}
dialer goahttp.Dialer,
cfn *ConnConfigurer,
{{- end }}
) *{{ .ClientStruct }} {
{{- if hasWebSocket . }}
if cfn == nil {
cfn = &ConnConfigurer{}
}
{{- end }}
return &{{ .ClientStruct }}{
{{- range .Endpoints }}
{{ .Method.VarName }}Doer: doer,
{{- end }}
RestoreResponseBody: restoreBody,
scheme: scheme,
host: host,
decoder: dec,
encoder: enc,
{{- if hasWebSocket . }}
dialer: dialer,
configurer: cfn,
{{- end }}
}
}
`
// input: EndpointData
const endpointInitT = `{{ printf "%s returns an endpoint that makes HTTP requests to the %s service %s server." .EndpointInit .ServiceName .Method.Name | comment }}
func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder }}{{ .MultipartRequestEncoder.VarName }} {{ .MultipartRequestEncoder.FuncName }}{{ end }}) goa.Endpoint {
var (
{{- if and .ClientWebSocket .RequestEncoder }}
encodeRequest = {{ .RequestEncoder }}({{ if .MultipartRequestEncoder }}{{ .MultipartRequestEncoder.InitName }}({{ .MultipartRequestEncoder.VarName }}){{ else }}c.encoder{{ end }})
{{- else }}
{{- if .RequestEncoder }}
encodeRequest = {{ .RequestEncoder }}({{ if .MultipartRequestEncoder }}{{ .MultipartRequestEncoder.InitName }}({{ .MultipartRequestEncoder.VarName }}){{ else }}c.encoder{{ end }})
{{- end }}
{{- end }}
decodeResponse = {{ .ResponseDecoder }}(c.decoder, c.RestoreResponseBody)
)
return func(ctx context.Context, v interface{}) (interface{}, error) {
req, err := c.{{ .RequestInit.Name }}(ctx, {{ range .RequestInit.ClientArgs }}{{ .Ref }}, {{ end }})
if err != nil {
return nil, err
}
{{- if .RequestEncoder }}
err = encodeRequest(req, v)
if err != nil {
return nil, err
}
{{- end }}
{{- if isWebSocketEndpoint . }}
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
if err != nil {
if resp != nil {
return decodeResponse(resp)
}
return nil, goahttp.ErrRequestError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
}
if c.configurer.{{ .Method.VarName }}Fn != nil {
conn = c.configurer.{{ .Method.VarName }}Fn(conn, cancel)
}
{{- if eq .ClientWebSocket.SendName "" }}
go func() {
<-ctx.Done()
conn.WriteControl(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, "client closing connection"),
time.Now().Add(time.Second),
)
conn.Close()
}()
{{- end }}
stream := &{{ .ClientWebSocket.VarName }}{conn: conn}
{{- if .Method.ViewedResult }}
{{- if not .Method.ViewedResult.ViewName }}
view := resp.Header.Get("goa-view")
stream.SetView(view)
{{- end }}
{{- end }}
return stream, nil
{{- else }}
resp, err := c.{{ .Method.VarName }}Doer.Do(req)
if err != nil {
return nil, goahttp.ErrRequestError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
}
{{- if .Method.SkipResponseBodyEncodeDecode }}
{{ if .Result.Ref }}res{{ else }}_{{ end }}, err := decodeResponse(resp)
if err != nil {
resp.Body.Close()
return nil, err
}
return &{{ .ServicePkgName }}.{{ .Method.ResponseStruct }}{ {{ if .Result.Ref }}Result: res.({{ .Result.Ref }}), {{ end }}Body: resp.Body}, nil
{{- else }}
return decodeResponse(resp)
{{- end }}
{{- end }}
}
}
`
// input: EndpointData
const requestBuilderT = `{{ comment .RequestInit.Description }}
func (c *{{ .ClientStruct }}) {{ .RequestInit.Name }}(ctx context.Context, {{ range .RequestInit.ClientArgs }}{{ .VarName }} {{ .TypeRef }},{{ end }}) (*http.Request, error) {
{{- .RequestInit.ClientCode }}
}
`
// input: EndpointData
const requestEncoderT = `{{ printf "%s returns an encoder for requests sent to the %s %s server." .RequestEncoder .ServiceName .Method.Name | comment }}
func {{ .RequestEncoder }}(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error {
return func(req *http.Request, v interface{}) error {
{{- if .Method.SkipRequestBodyEncodeDecode }}
data, ok := v.(*{{ .ServicePkgName }}.{{ .Method.RequestStruct }})
if !ok {
return goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .Method.Name }}", "*{{ .ServicePkgName}}.{{ .Method.RequestStruct }}", v)
}
p := data.Payload
{{- else }}
p, ok := v.({{ .Payload.Ref }})
if !ok {
return goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .Method.Name }}", "{{ .Payload.Ref }}", v)
}
{{- end }}
{{- range .Payload.Request.Headers }}
{{- if .FieldName }}
{{- if .FieldPointer }}
if p.{{ .FieldName }} != nil {
{{- else }}
{
{{- end }}
head := {{ if .FieldPointer }}*{{ end }}p.{{ .FieldName }}
{{- if (and (eq .Name "Authorization") (isBearer $.HeaderSchemes)) }}
if !strings.Contains(head, " ") {
req.Header.Set({{ printf "%q" .Name }}, "Bearer "+head)
} else {
{{- end }}
{{- if eq .Type.Name "array" }}
for _, val := range head {
{{- if eq .Type.ElemType.Type.Name "string" }}
req.Header.Add({{ printf "%q" .Name }}, val)
{{- else }}
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type (aliasedType .FieldType).ElemType.Type "valStr" "val") }}
req.Header.Add({{ printf "%q" .Name }}, valStr)
{{- end }}
}
{{- else if eq .Type.Name "string" }}
req.Header.Set({{ printf "%q" .Name }}, head)
{{- else }}
{{ template "type_conversion" (typeConversionData .Type .FieldType "headStr" "head") }}
req.Header.Set({{ printf "%q" .Name }}, headStr)
{{- end }}
{{- if (and (eq .Name "Authorization") (isBearer $.HeaderSchemes)) }}
}
{{- end }}
}
{{- end }}
{{- end }}
{{- range .Payload.Request.Cookies }}
{{- if .FieldName }}
{{- if .FieldPointer }}
if p.{{ .FieldName }} != nil {
{{- else }}
{
{{- end }}
v{{ if not (eq .Type.Name "string") }}raw{{ end }} := {{ if .FieldPointer }}*{{ end }}p.{{ .FieldName }}
{{- if not (eq .Type.Name "string" ) }}
{{ template "type_conversion" (typeConversionData .Type .FieldType "vraw" "v") }}
{{- end }}
req.AddCookie(&http.Cookie{
Name: {{ printf "%q" .Name }},
Value: v,
{{- if .MaxAge }}
MaxAge: {{ .MaxAge }},
{{- end }}
{{- if .Path }}
Path: {{ .Path }},
{{- end }}
{{- if .Domain }}
Domain: {{ .Domain }},
{{- end }}
{{- if .Secure }}
Secure: true,
{{- end }}
{{- if .HTTPOnly }}
HttpOnly: true,
{{- end }}
})
}
{{- end }}
{{- end }}
{{- if or .Payload.Request.QueryParams }}
values := req.URL.Query()
{{- end }}
{{- range .Payload.Request.QueryParams }}
{{- if .MapQueryParams }}
for key, value := range p{{ if .FieldName }}.{{ .FieldName }}{{ end }} {
{{ template "type_conversion" (typeConversionData .Type.KeyType.Type (aliasedType .FieldType).KeyType.Type "keyStr" "key") }}
{{- if eq .Type.ElemType.Type.Name "array" }}
for _, val := range value {
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type.ElemType.Type (aliasedType (aliasedType .FieldType).ElemType.Type).ElemType.Type "valStr" "val") }}
values.Add(keyStr, valStr)
}
{{- else }}
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type (aliasedType .FieldType).ElemType.Type "valueStr" "value") }}
values.Add(keyStr, valueStr)
{{- end }}
}
{{- else if .StringSlice }}
for _, value := range p{{ if .FieldName }}.{{ .FieldName }}{{ end }} {
values.Add("{{ .Name }}", value)
}
{{- else if .Slice }}
for _, value := range p{{ if .FieldName }}.{{ .FieldName }}{{ end }} {
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type (aliasedType .FieldType).ElemType.Type "valueStr" "value") }}
values.Add("{{ .Name }}", valueStr)
}
{{- else if .Map }}
{{- template "map_conversion" (mapConversionData .Type .FieldType .Name "p" .FieldName true) }}
{{- else if .FieldName }}
{{- if .FieldPointer }}
if p.{{ .FieldName }} != nil {
{{- end }}
values.Add("{{ .Name }}",
{{- if eq .Type.Name "bytes" }} string(
{{- else if not (eq .Type.Name "string") }} fmt.Sprintf("%v",
{{- end }}
{{- if .FieldPointer }}*{{ end }}p.{{ .FieldName }}
{{- if or (eq .Type.Name "bytes") (not (eq .Type.Name "string")) }})
{{- end }})
{{- if .FieldPointer }}
}
{{- end }}
{{- else }}
{{- if eq .Type.Name "string" }}
values.Add("{{ .Name }}", p)
{{- else }}
{{ template "type_conversion" (typeConversionData .Type .FieldType "pStr" "p") }}
values.Add("{{ .Name }}", pStr)
{{- end }}
{{- end }}
{{- end }}
{{- if .Payload.Request.QueryParams }}
req.URL.RawQuery = values.Encode()
{{- end }}
{{- if .MultipartRequestEncoder }}
if err := encoder(req).Encode(p); err != nil {
return goahttp.ErrEncodingError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
}
{{- else if .Payload.Request.ClientBody }}
{{- if .Payload.Request.ClientBody.Init }}
body := {{ .Payload.Request.ClientBody.Init.Name }}({{ range .Payload.Request.ClientBody.Init.ClientArgs }}{{ if .FieldPointer }}&{{ end }}{{ .VarName }}, {{ end }})
{{- else }}
body := p{{ if .Payload.Request.PayloadAttr }}.{{ .Payload.Request.PayloadAttr }}{{ end }}
{{- end }}
if err := encoder(req).Encode(&body); err != nil {
return goahttp.ErrEncodingError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
}
{{- end }}
{{- if .BasicScheme }}{{ with .BasicScheme }}
{{- if not .UsernameRequired }}
if p.{{ .UsernameField }} != nil {
{{- end }}
{{- if not .PasswordRequired }}
if p.{{ .PasswordField }} != nil {
{{- end }}
req.SetBasicAuth({{ if .UsernamePointer }}*{{ end }}p.{{ .UsernameField }}, {{ if .PasswordPointer }}*{{ end }}p.{{ .PasswordField }})
{{- if not .UsernameRequired }}
}
{{- end }}
{{- if not .PasswordRequired }}
}
{{- end }}
{{- end }}{{ end }}
return nil
}
}
{{- define "map_conversion" }}
for k{{ if not (eq .Type.KeyType.Type.Name "string") }}Raw{{ end }}, value := range {{ .SourceVar }}{{ if .SourceField }}.{{ .SourceField }}{{ end }} {
{{- if not (eq .Type.KeyType.Type.Name "string") }}
{{ template "type_conversion" (typeConversionData .Type.KeyType.Type .FieldType.KeyType.Type "k" "kRaw") }}
{{- end }}
key {{ if .NewVar }}:={{ else }}={{ end }} fmt.Sprintf("{{ .VarName }}[%s]", {{ if not .NewVar }}key, {{ end }}k)
{{- if eq .Type.ElemType.Type.Name "string" }}
values.Add(key, {{ if (isAliased .FieldType.ElemType.Type) }}string({{ end }}value{{ if (isAliased .FieldType.ElemType.Type) }}){{ end }})
{{- else if eq .Type.ElemType.Type.Name "map" }}
{{- template "map_conversion" (mapConversionData .Type.ElemType.Type .FieldType.ElemType.Type "%s" "value" "" false) }}
{{- else if eq .Type.ElemType.Type.Name "array" }}
{{- if and (eq .Type.ElemType.Type.ElemType.Type.Name "string") (not (isAliased .FieldType.ElemType.Type.ElemType.Type)) }}
values[key] = value
{{- else }}
for _, val := range value {
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type.ElemType.Type (aliasedType .FieldType.ElemType.Type).ElemType.Type "valStr" "val") }}
values.Add(key, valStr)
}
{{- end }}
{{- else }}
{{ template "type_conversion" (typeConversionData .Type.ElemType.Type .FieldType.ElemType.Type "valueStr" "value") }}
values.Add(key, valueStr)
{{- end }}
}
{{- end }}
{{- define "type_conversion" }}
{{- if eq .Type.Name "boolean" -}}
{{ .VarName }} := strconv.FormatBool({{ if .IsAliased }}bool({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }})
{{- else if eq .Type.Name "int" -}}
{{ .VarName }} := strconv.Itoa({{ if .IsAliased }}int({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }})
{{- else if eq .Type.Name "int32" -}}
{{ .VarName }} := strconv.FormatInt(int64({{ .Target }}), 10)
{{- else if eq .Type.Name "int64" -}}
{{ .VarName }} := strconv.FormatInt({{ if .IsAliased }}int64({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }}, 10)
{{- else if eq .Type.Name "uint" -}}
{{ .VarName }} := strconv.FormatUint(uint64({{ .Target }}), 10)
{{- else if eq .Type.Name "uint32" -}}
{{ .VarName }} := strconv.FormatUint(uint64({{ .Target }}), 10)
{{- else if eq .Type.Name "uint64" -}}
{{ .VarName }} := strconv.FormatUint({{ if .IsAliased }}uint64({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }}, 10)
{{- else if eq .Type.Name "float32" -}}
{{ .VarName }} := strconv.FormatFloat(float64({{ .Target }}), 'f', -1, 32)
{{- else if eq .Type.Name "float64" -}}
{{ .VarName }} := strconv.FormatFloat({{ if .IsAliased }}float64({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }}, 'f', -1, 64)
{{- else if eq .Type.Name "string" -}}
{{ .VarName }} := {{ if .IsAliased }}string({{ end }}{{ .Target }}{{ if .IsAliased }}){{ end }}
{{- else if eq .Type.Name "bytes" -}}
{{ .VarName }} := string({{ .Target }})
{{- else if eq .Type.Name "any" -}}
{{ .VarName }} := fmt.Sprintf("%v", {{ .Target }})
{{- else }}
// unsupported type {{ .Type.Name }} for field {{ .FieldName }}
{{- end }}
{{- end }}
`
// input: EndpointData
const responseDecoderT = `{{ printf "%s returns a decoder for responses returned by the %s %s endpoint. restoreBody controls whether the response body should be restored after having been read." .ResponseDecoder .ServiceName .Method.Name | comment }}
{{- if .Errors }}
{{ printf "%s may return the following errors:" .ResponseDecoder | comment }}
{{- range $gerr := .Errors }}
{{- range $errors := .Errors }}
// - {{ printf "%q" .Name }} (type {{ .Ref }}): {{ .Response.StatusCode }}{{ if .Response.Description }}, {{ .Response.Description }}{{ end }}
{{- end }}
{{- end }}
// - error: internal error
{{- end }}
func {{ .ResponseDecoder }}(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) {
return func(resp *http.Response) (interface{}, error) {
if restoreBody {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
defer func() {
resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
}()
}
{{- if not .Method.SkipResponseBodyEncodeDecode }} else {
defer resp.Body.Close()
}
{{- end }}
switch resp.StatusCode {
{{- range .Result.Responses }}
case {{ .StatusCode }}:
` + singleResponseT + `
{{- if .ResultInit }}
{{- if .ViewedResult }}
p := {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
{{- if .TagName }}
tmp := {{ printf "%q" .TagValue }}
p.{{ .TagName }} = &tmp
{{- end }}
{{- if $.Method.ViewedResult.ViewName }}
view := {{ printf "%q" $.Method.ViewedResult.ViewName }}
{{- else }}
view := resp.Header.Get("goa-view")
{{- end }}
vres := {{ if not $.Method.ViewedResult.IsCollection }}&{{ end }}{{ $.Method.ViewedResult.ViewsPkg}}.{{ $.Method.ViewedResult.VarName }}{Projected: p, View: view}
{{- if .ClientBody }}
if err = {{ $.Method.ViewedResult.ViewsPkg}}.Validate{{ $.Method.Result }}(vres); err != nil {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", err)
}
{{- end }}
res := {{ $.ServicePkgName }}.{{ $.Method.ViewedResult.ResultInit.Name }}(vres)
{{- else }}
res := {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
{{- end }}
{{- if and .TagName (not .ViewedResult) }}
{{- if .TagPointer }}
tmp := {{ printf "%q" .TagValue }}
res.{{ .TagName }} = &tmp
{{- else }}
res.{{ .TagName }} = {{ printf "%q" .TagValue }}
{{- end }}
{{- end }}
return res, nil
{{- else if .ClientBody }}
return body, nil
{{- else if .Headers }}
return {{ (index .Headers 0).VarName }}, nil
{{- else if .Cookies }}
return {{ (index .Cookies 0).VarName }}, nil
{{- else }}
return nil, nil
{{- end }}
{{- end }}
{{- range .Errors }}
case {{ .StatusCode }}:
{{- if gt (len .Errors) 1 }}
en := resp.Header.Get("goa-error")
switch en {
{{- range .Errors }}
case {{ printf "%q" .Name }}:
{{- with .Response }}
` + singleResponseT + `
{{- if .ResultInit }}
return nil, {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
{{- else if .ClientBody }}
return nil, body
{{- else }}
return nil, nil
{{- end }}
{{- end }}
{{- end }}
default:
body, _ := ioutil.ReadAll(resp.Body)
return nil, goahttp.ErrInvalidResponse({{ printf "%q" $.ServiceName }}, {{ printf "%q" $.Method.Name }}, resp.StatusCode, string(body))
}
{{- else }}
{{- with (index .Errors 0).Response }}
` + singleResponseT + `
{{- if .ResultInit }}
return nil, {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
{{- else if .ClientBody }}
return nil, body
{{- else }}
return nil, nil
{{- end }}
{{- end }}
{{- end }}
{{- end }}
default:
body, _ := ioutil.ReadAll(resp.Body)
return nil, goahttp.ErrInvalidResponse({{ printf "%q" .ServiceName }}, {{ printf "%q" .Method.Name }}, resp.StatusCode, string(body))
}
}
}
` + typeConversionT
// input: ResponseData
const singleResponseT = ` {{- if .ClientBody }}
var (
body {{ .ClientBody.VarName }}
err error
)
err = decoder(resp).Decode(&body)
if err != nil {
return nil, goahttp.ErrDecodingError("{{ $.ServiceName }}", "{{ $.Method.Name }}", err)
}
{{- if .ClientBody.ValidateRef }}
{{ .ClientBody.ValidateRef }}
if err != nil {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", err)
}
{{- end }}
{{- end }}
{{- if .Headers }}
var (
{{- range .Headers }}
{{ .VarName }} {{ .TypeRef }}
{{- end }}
{{- if not .ClientBody }}
{{- if .MustValidate }}
err error
{{- end }}
{{- end }}
)
{{- range .Headers }}
{{- if (or (eq .Type.Name "string") (eq .Type.Name "any")) }}
{{ .VarName }}Raw := resp.Header.Get("{{ .CanonicalName }}")
{{- if .Required }}
if {{ .VarName }}Raw == "" {
err = goa.MergeErrors(err, goa.MissingFieldError("{{ .Name }}", "header"))
}
{{ .VarName }} = {{ if and (eq .Type.Name "string") .Pointer }}&{{ end }}{{ .VarName }}Raw
{{- else }}
if {{ .VarName }}Raw != "" {
{{ .VarName }} = {{ if and (eq .Type.Name "string") .Pointer }}&{{ end }}{{ .VarName }}Raw
}
{{- if .DefaultValue }} else {
{{ .VarName }} = {{ if eq .Type.Name "string" }}{{ printf "%q" .DefaultValue }}{{ else }}{{ printf "%#v" .DefaultValue }}{{ end }}
}
{{- end }}
{{- end }}
{{- else if .StringSlice }}
{{ .VarName }} = resp.Header["{{ .CanonicalName }}"]
{{ if .Required }}
if {{ .VarName }} == nil {
err = goa.MergeErrors(err, goa.MissingFieldError("{{ .Name }}", "header"))
}
{{- else if .DefaultValue }}
if {{ .VarName }} == nil {
{{ .VarName }} = {{ printf "%#v" .DefaultValue }}
}
{{- end }}
{{- else if .Slice }}
{
{{ .VarName }}Raw := resp.Header["{{ .CanonicalName }}"]
{{ if .Required }} if {{ .VarName }}Raw == nil {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", goa.MissingFieldError("{{ .Name }}", "header"))
}
{{- else if .DefaultValue }}
if {{ .VarName }}Raw == nil {
{{ .VarName }} = {{ printf "%#v" .DefaultValue }}
}
{{- end }}
{{- if .DefaultValue }}else {
{{- else if not .Required }}
if {{ .VarName }}Raw != nil {
{{- end }}
{{- template "slice_conversion" . }}
{{- if or .DefaultValue (not .Required) }}
}
{{- end }}
}
{{- else }}{{/* not string, not any and not slice */}}
{
{{ .VarName }}Raw := resp.Header.Get("{{ .CanonicalName }}")
{{- if .Required }}
if {{ .VarName }}Raw == "" {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", goa.MissingFieldError("{{ .Name }}", "header"))
}
{{- else if .DefaultValue }}
if {{ .VarName }}Raw == "" {
{{ .VarName }} = {{ printf "%#v" .DefaultValue }}
}
{{- end }}
{{- if .DefaultValue }}else {
{{- else if not .Required }}
if {{ .VarName }}Raw != "" {
{{- end }}
{{- template "type_conversion" . }}
{{- if or .DefaultValue (not .Required) }}
}
{{- end }}
}
{{- end }}
{{- if .Validate }}
{{ .Validate }}
{{- end }}
{{- end }}{{/* range .Headers */}}
{{- end }}
{{- if .Cookies }}
var (
{{- range .Cookies }}
{{ .VarName }} {{ .TypeRef }}
{{ .VarName }}Raw string
{{- end }}
cookies = resp.Cookies()
{{- if not .ClientBody }}
{{- if .MustValidate }}
err error
{{- end }}
{{- end }}
)
for _, c := range cookies {
switch c.Name {
{{- range .Cookies }}
case {{ printf "%q" .Name }}:
{{ .VarName }}Raw = c.Value
{{- end }}
}
}
{{- range .Cookies }}
{{- if (or (eq .Type.Name "string") (eq .Type.Name "any")) }}
{{- if .Required }}
if {{ .VarName }}Raw == "" {
err = goa.MergeErrors(err, goa.MissingFieldError("{{ .Name }}", "cookie"))
}
{{ .VarName }} = {{ if and (eq .Type.Name "string") .Pointer }}&{{ end }}{{ .VarName }}Raw
{{- else }}
if {{ .VarName }}Raw != "" {
{{ .VarName }} = {{ if and (eq .Type.Name "string") .Pointer }}&{{ end }}{{ .VarName }}Raw
}
{{- if .DefaultValue }} else {
{{ .VarName }} = {{ if eq .Type.Name "string" }}{{ printf "%q" .DefaultValue }}{{ else }}{{ printf "%#v" .DefaultValue }}{{ end }}
}
{{- end }}
{{- end }}
{{- else }}{{/* not string and not any */}}
{
{{- if .Required }}
if {{ .VarName }}Raw == "" {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", goa.MissingFieldError("{{ .Name }}", "cookie"))
}
{{- else if .DefaultValue }}
if {{ .VarName }}Raw == "" {
{{ .VarName }} = {{ printf "%#v" .DefaultValue }}
}
{{- end }}
{{- if .DefaultValue }}else {
{{- else if not .Required }}
if {{ .VarName }}Raw != "" {
{{- end }}
{{- template "type_conversion" . }}
{{- if or .DefaultValue (not .Required) }}
}
{{- end }}
}
{{- end }}
{{- if .Validate }}
{{ .Validate }}
{{- end }}
{{- end }}{{/* range .Cookies */}}
{{- end }}
{{- if .MustValidate }}
if err != nil {
return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", err)
}
{{- end }}
`
// input: multipartData
const multipartRequestEncoderTypeT = `{{ printf "%s is the type to encode multipart request for the %q service %q endpoint." .FuncName .ServiceName .MethodName | comment }}
type {{ .FuncName }} func(*multipart.Writer, {{ .Payload.Ref }}) error
`
// input: multipartData
const multipartRequestEncoderT = `{{ printf "%s returns an encoder to encode the multipart request for the %q service %q endpoint." .InitName .ServiceName .MethodName | comment }}
func {{ .InitName }}(encoderFn {{ .FuncName }}) func(r *http.Request) goahttp.Encoder {
return func(r *http.Request) goahttp.Encoder {
body := &bytes.Buffer{}
mw := multipart.NewWriter(body)
return goahttp.EncodingFunc(func(v interface{}) error {
p := v.({{ .Payload.Ref }})
if err := encoderFn(mw, p); err != nil {
return err
}
r.Body = ioutil.NopCloser(body)
r.Header.Set("Content-Type", mw.FormDataContentType())
return mw.Close()
})
}
}
`
// input: streamRequestData
const buildStreamRequestT = `// {{ printf "%s creates a streaming endpoint request payload from the method payload and the path to the file to be streamed" .BuildStreamPayload | comment }}
func {{ .BuildStreamPayload }}({{ if .Payload.Ref }}payload interface{}, {{ end }}fpath string) (*{{ .ServicePkgName }}.{{ .Method.RequestStruct }}, error) {
f, err := os.Open(fpath)
if err != nil {
return nil, err
}
return &{{ .ServicePkgName }}.{{ .Method.RequestStruct }}{
{{- if .Payload.Ref }}
Payload: payload.({{ .Payload.Ref }}),
{{- end }}
Body: f,
}, nil
}
`
1
https://gitee.com/mirrors/goa.git
git@gitee.com:mirrors/goa.git
mirrors
goa
goa
v2.2.5

搜索帮助

53164aa7 5694891 3bd8fe86 5694891