1// +build codegen
2
3package api
4
5import (
6	"bytes"
7	"fmt"
8	"regexp"
9	"sort"
10	"strings"
11	"text/template"
12)
13
14// An Operation defines a specific API Operation.
15type Operation struct {
16	API                 *API `json:"-"`
17	ExportedName        string
18	Name                string
19	Documentation       string
20	HTTP                HTTPInfo
21	Host                string     `json:"host"`
22	InputRef            ShapeRef   `json:"input"`
23	OutputRef           ShapeRef   `json:"output"`
24	ErrorRefs           []ShapeRef `json:"errors"`
25	Paginator           *Paginator
26	Deprecated          bool     `json:"deprecated"`
27	DeprecatedMsg       string   `json:"deprecatedMessage"`
28	AuthType            AuthType `json:"authtype"`
29	imports             map[string]bool
30	CustomBuildHandlers []string
31
32	EventStreamAPI *EventStreamAPI
33
34	IsEndpointDiscoveryOp bool               `json:"endpointoperation"`
35	EndpointDiscovery     *EndpointDiscovery `json:"endpointdiscovery"`
36	Endpoint              *EndpointTrait     `json:"endpoint"`
37}
38
39// EndpointTrait provides the structure of the modeled enpdoint trait, and its
40// properties.
41type EndpointTrait struct {
42	// Specifies the hostPrefix template to prepend to the operation's request
43	// endpoint host.
44	HostPrefix string `json:"hostPrefix"`
45}
46
47// EndpointDiscovery represents a map of key values pairs that represents
48// metadata about how a given API will make a call to the discovery endpoint.
49type EndpointDiscovery struct {
50	// Required indicates that for a given operation that endpoint is required.
51	// Any required endpoint discovery operation cannot have endpoint discovery
52	// turned off.
53	Required bool `json:"required"`
54}
55
56// OperationForMethod returns the API operation name that corresponds to the
57// client method name provided.
58func (a *API) OperationForMethod(name string) *Operation {
59	for _, op := range a.Operations {
60		for _, m := range op.Methods() {
61			if m == name {
62				return op
63			}
64		}
65	}
66
67	return nil
68}
69
70// A HTTPInfo defines the method of HTTP request for the Operation.
71type HTTPInfo struct {
72	Method       string
73	RequestURI   string
74	ResponseCode uint
75}
76
77// Methods Returns a list of method names that will be generated.
78func (o *Operation) Methods() []string {
79	methods := []string{
80		o.ExportedName,
81		o.ExportedName + "Request",
82		o.ExportedName + "WithContext",
83	}
84
85	if o.Paginator != nil {
86		methods = append(methods, []string{
87			o.ExportedName + "Pages",
88			o.ExportedName + "PagesWithContext",
89		}...)
90	}
91
92	return methods
93}
94
95// HasInput returns if the Operation accepts an input paramater
96func (o *Operation) HasInput() bool {
97	return o.InputRef.ShapeName != ""
98}
99
100// HasOutput returns if the Operation accepts an output parameter
101func (o *Operation) HasOutput() bool {
102	return o.OutputRef.ShapeName != ""
103}
104
105// AuthType provides the enumeration of AuthType trait.
106type AuthType string
107
108// Enumeration values for AuthType trait
109const (
110	NoneAuthType           AuthType = "none"
111	V4UnsignedBodyAuthType AuthType = "v4-unsigned-body"
112)
113
114// GetSigner returns the signer that should be used for a API request.
115func (o *Operation) GetSigner() string {
116	buf := bytes.NewBuffer(nil)
117
118	switch o.AuthType {
119	case NoneAuthType:
120		o.API.AddSDKImport("aws/credentials")
121
122		buf.WriteString("req.Config.Credentials = credentials.AnonymousCredentials")
123	case V4UnsignedBodyAuthType:
124		o.API.AddSDKImport("aws/signer/v4")
125
126		buf.WriteString("req.Handlers.Sign.Remove(v4.SignRequestHandler)\n")
127		buf.WriteString("handler := v4.BuildNamedHandler(\"v4.CustomSignerHandler\", v4.WithUnsignedPayload)\n")
128		buf.WriteString("req.Handlers.Sign.PushFrontNamed(handler)")
129	}
130
131	buf.WriteString("\n")
132	return buf.String()
133}
134
135// operationTmpl defines a template for rendering an API Operation
136var operationTmpl = template.Must(template.New("operation").Funcs(template.FuncMap{
137	"GetCrosslinkURL":       GetCrosslinkURL,
138	"EnableStopOnSameToken": enableStopOnSameToken,
139	"GetDeprecatedMsg":      getDeprecatedMessage,
140}).Parse(`
141const op{{ .ExportedName }} = "{{ .Name }}"
142
143// {{ .ExportedName }}Request generates a "aws/request.Request" representing the
144// client's request for the {{ .ExportedName }} operation. The "output" return
145// value will be populated with the request's response once the request completes
146// successfully.
147//
148// Use "Send" method on the returned Request to send the API call to the service.
149// the "output" return value is not valid until after Send returns without error.
150//
151// See {{ .ExportedName }} for more information on using the {{ .ExportedName }}
152// API call, and error handling.
153//
154// This method is useful when you want to inject custom logic or configuration
155// into the SDK's request lifecycle. Such as custom headers, or retry logic.
156//
157//
158//    // Example sending a request using the {{ .ExportedName }}Request method.
159//    req, resp := client.{{ .ExportedName }}Request(params)
160//
161//    err := req.Send()
162//    if err == nil { // resp is now filled
163//        fmt.Println(resp)
164//    }
165{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.ExportedName -}}
166{{ if ne $crosslinkURL "" -}}
167//
168// See also, {{ $crosslinkURL }}
169{{ end -}}
170{{- if .Deprecated }}//
171// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg .ExportedName }}
172{{ end -}}
173func (c *{{ .API.StructName }}) {{ .ExportedName }}Request(` +
174	`input {{ .InputRef.GoType }}) (req *request.Request, output {{ .OutputRef.GoType }}) {
175	{{ if (or .Deprecated (or .InputRef.Deprecated .OutputRef.Deprecated)) }}if c.Client.Config.Logger != nil {
176		c.Client.Config.Logger.Log("This operation, {{ .ExportedName }}, has been deprecated")
177	}
178	op := &request.Operation{ {{ else }} op := &request.Operation{ {{ end }}
179		Name:       op{{ .ExportedName }},
180		{{ if ne .HTTP.Method "" }}HTTPMethod: "{{ .HTTP.Method }}",
181		{{ end }}HTTPPath: {{ if ne .HTTP.RequestURI "" }}"{{ .HTTP.RequestURI }}"{{ else }}"/"{{ end }},
182		{{ if .Paginator }}Paginator: &request.Paginator{
183				InputTokens: {{ .Paginator.InputTokensString }},
184				OutputTokens: {{ .Paginator.OutputTokensString }},
185				LimitToken: "{{ .Paginator.LimitKey }}",
186				TruncationToken: "{{ .Paginator.MoreResults }}",
187		},
188		{{ end }}
189	}
190
191	if input == nil {
192		input = &{{ .InputRef.GoTypeElem }}{}
193	}
194
195	output = &{{ .OutputRef.GoTypeElem }}{}
196	req = c.newRequest(op, input, output)
197	{{ if ne .AuthType "" }}{{ .GetSigner }}{{ end }}
198	{{- if .ShouldDiscardResponse -}}
199		{{- $_ := .API.AddSDKImport "private/protocol" -}}
200		{{- $_ := .API.AddSDKImport "private/protocol" .API.ProtocolPackage -}}
201		req.Handlers.Unmarshal.Swap({{ .API.ProtocolPackage }}.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
202	{{ else if .OutputRef.Shape.EventStreamsMemberName -}}
203		{{- $_ := .API.AddSDKImport "private/protocol" .API.ProtocolPackage -}}
204		{{- $_ := .API.AddSDKImport "private/protocol/rest" -}}
205		req.Handlers.Send.Swap(client.LogHTTPResponseHandler.Name, client.LogHTTPResponseHeaderHandler)
206		req.Handlers.Unmarshal.Swap({{ .API.ProtocolPackage }}.UnmarshalHandler.Name, rest.UnmarshalHandler)
207		req.Handlers.Unmarshal.PushBack(output.runEventStreamLoop)
208		{{ if eq .API.Metadata.Protocol "json" -}}
209			req.Handlers.Unmarshal.PushBack(output.unmarshalInitialResponse)
210		{{ end -}}
211	{{ end -}}
212	{{ if .EndpointDiscovery -}}
213		{{if not .EndpointDiscovery.Required -}}
214			if aws.BoolValue(req.Config.EnableEndpointDiscovery) {
215		{{end -}}
216		de := discoverer{{ .API.EndpointDiscoveryOp.Name }}{
217			Required: {{ .EndpointDiscovery.Required }},
218			EndpointCache: c.endpointCache,
219			Params: map[string]*string{
220				"op": aws.String(req.Operation.Name),
221				{{ range $key, $ref := .InputRef.Shape.MemberRefs -}}
222				{{ if $ref.EndpointDiscoveryID -}}
223				"{{ $ref.OrigShapeName }}": input.{{ $key }},
224				{{ end -}}
225				{{- end }}
226			},
227			Client: c,
228		}
229
230		for k, v := range de.Params {
231			if v == nil {
232				delete(de.Params, k)
233			}
234		}
235
236		req.Handlers.Build.PushFrontNamed(request.NamedHandler{
237			Name: "crr.endpointdiscovery",
238			Fn: de.Handler,
239		})
240		{{if not .EndpointDiscovery.Required -}}
241			}
242		{{ end -}}
243	{{ end -}}
244	{{- range $_, $handler := $.CustomBuildHandlers -}}
245		req.Handlers.Build.PushBackNamed({{ $handler }})
246	{{ end -}}
247	return
248}
249
250// {{ .ExportedName }} API operation for {{ .API.Metadata.ServiceFullName }}.
251{{ if .Documentation -}}
252//
253{{ .Documentation }}
254{{ end -}}
255//
256// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
257// with awserr.Error's Code and Message methods to get detailed information about
258// the error.
259//
260// See the AWS API reference guide for {{ .API.Metadata.ServiceFullName }}'s
261// API operation {{ .ExportedName }} for usage and error information.
262{{ if .ErrorRefs -}}
263//
264// Returned Error Codes:
265{{ range $_, $err := .ErrorRefs -}}
266//   * {{ $err.Shape.ErrorCodeName }} "{{ $err.Shape.ErrorName}}"
267{{ if $err.Docstring -}}
268{{ $err.IndentedDocstring }}
269{{ end -}}
270//
271{{ end -}}
272{{ end -}}
273{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.ExportedName -}}
274{{ if ne $crosslinkURL "" -}}
275// See also, {{ $crosslinkURL }}
276{{ end -}}
277{{- if .Deprecated }}//
278// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg .ExportedName }}
279{{ end -}}
280func (c *{{ .API.StructName }}) {{ .ExportedName }}(` +
281	`input {{ .InputRef.GoType }}) ({{ .OutputRef.GoType }}, error) {
282	req, out := c.{{ .ExportedName }}Request(input)
283	return out, req.Send()
284}
285
286// {{ .ExportedName }}WithContext is the same as {{ .ExportedName }} with the addition of
287// the ability to pass a context and additional request options.
288//
289// See {{ .ExportedName }} for details on how to use this API operation.
290//
291// The context must be non-nil and will be used for request cancellation. If
292// the context is nil a panic will occur. In the future the SDK may create
293// sub-contexts for http.Requests. See https://golang.org/pkg/context/
294// for more information on using Contexts.
295{{ if .Deprecated }}//
296// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg (printf "%s%s" .ExportedName "WithContext") }}
297{{ end -}}
298func (c *{{ .API.StructName }}) {{ .ExportedName }}WithContext(` +
299	`ctx aws.Context, input {{ .InputRef.GoType }}, opts ...request.Option) ` +
300	`({{ .OutputRef.GoType }}, error) {
301	req, out := c.{{ .ExportedName }}Request(input)
302	req.SetContext(ctx)
303	req.ApplyOptions(opts...)
304	return out, req.Send()
305}
306
307{{ if .Paginator }}
308// {{ .ExportedName }}Pages iterates over the pages of a {{ .ExportedName }} operation,
309// calling the "fn" function with the response data for each page. To stop
310// iterating, return false from the fn function.
311//
312// See {{ .ExportedName }} method for more information on how to use this operation.
313//
314// Note: This operation can generate multiple requests to a service.
315//
316//    // Example iterating over at most 3 pages of a {{ .ExportedName }} operation.
317//    pageNum := 0
318//    err := client.{{ .ExportedName }}Pages(params,
319//        func(page {{ .OutputRef.Shape.GoTypeWithPkgName }}, lastPage bool) bool {
320//            pageNum++
321//            fmt.Println(page)
322//            return pageNum <= 3
323//        })
324//
325{{ if .Deprecated }}//
326// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg (printf "%s%s" .ExportedName "Pages") }}
327{{ end -}}
328func (c *{{ .API.StructName }}) {{ .ExportedName }}Pages(` +
329	`input {{ .InputRef.GoType }}, fn func({{ .OutputRef.GoType }}, bool) bool) error {
330	return c.{{ .ExportedName }}PagesWithContext(aws.BackgroundContext(), input, fn)
331}
332
333// {{ .ExportedName }}PagesWithContext same as {{ .ExportedName }}Pages except
334// it takes a Context and allows setting request options on the pages.
335//
336// The context must be non-nil and will be used for request cancellation. If
337// the context is nil a panic will occur. In the future the SDK may create
338// sub-contexts for http.Requests. See https://golang.org/pkg/context/
339// for more information on using Contexts.
340{{ if .Deprecated }}//
341// Deprecated: {{ GetDeprecatedMsg .DeprecatedMsg (printf "%s%s" .ExportedName "PagesWithContext") }}
342{{ end -}}
343func (c *{{ .API.StructName }}) {{ .ExportedName }}PagesWithContext(` +
344	`ctx aws.Context, ` +
345	`input {{ .InputRef.GoType }}, ` +
346	`fn func({{ .OutputRef.GoType }}, bool) bool, ` +
347	`opts ...request.Option) error {
348	p := request.Pagination {
349		{{ if EnableStopOnSameToken .API.PackageName -}}EndPageOnSameToken: true,
350		{{ end -}}
351		NewRequest: func() (*request.Request, error) {
352			var inCpy {{ .InputRef.GoType }}
353			if input != nil  {
354				tmp := *input
355				inCpy = &tmp
356			}
357			req, _ := c.{{ .ExportedName }}Request(inCpy)
358			req.SetContext(ctx)
359			req.ApplyOptions(opts...)
360			return req, nil
361		},
362	}
363
364	cont := true
365	for p.Next() && cont {
366		cont = fn(p.Page().({{ .OutputRef.GoType }}), !p.HasNextPage())
367	}
368	return p.Err()
369}
370{{ end }}
371
372{{ if .IsEndpointDiscoveryOp -}}
373
374type discoverer{{ .ExportedName }} struct {
375	Client *{{ .API.StructName }}
376	Required bool
377	EndpointCache *crr.EndpointCache
378	Params map[string]*string
379	Key string
380}
381
382func (d *discoverer{{ .ExportedName }}) Discover() (crr.Endpoint, error) {
383	input := &{{ .API.EndpointDiscoveryOp.InputRef.ShapeName }}{
384		{{ if .API.EndpointDiscoveryOp.InputRef.Shape.HasMember "Operation" -}}
385		Operation: d.Params["op"],
386		{{ end -}}
387		{{ if .API.EndpointDiscoveryOp.InputRef.Shape.HasMember "Identifiers" -}}
388		Identifiers: d.Params,
389		{{ end -}}
390	}
391
392	resp, err := d.Client.{{ .API.EndpointDiscoveryOp.Name }}(input)
393	if err != nil {
394		return crr.Endpoint{}, err
395	}
396
397	endpoint := crr.Endpoint{
398		Key: d.Key,
399	}
400
401	for _, e := range resp.Endpoints {
402		if e.Address == nil {
403			continue
404		}
405
406		cachedInMinutes := aws.Int64Value(e.CachePeriodInMinutes)
407		u, err := url.Parse(*e.Address)
408		if err != nil {
409			continue
410		}
411
412		addr := crr.WeightedAddress{
413			URL: u,
414			Expired:  time.Now().Add(time.Duration(cachedInMinutes) * time.Minute),
415		}
416
417		endpoint.Add(addr)
418	}
419
420	d.EndpointCache.Add(endpoint)
421
422	return endpoint, nil
423}
424
425func (d *discoverer{{ .ExportedName }}) Handler(r *request.Request) {
426	endpointKey := crr.BuildEndpointKey(d.Params)
427	d.Key = endpointKey
428
429	endpoint, err := d.EndpointCache.Get(d, endpointKey, d.Required)
430	if err != nil {
431		r.Error = err
432		return
433	}
434
435	if endpoint.URL != nil && len(endpoint.URL.String()) > 0 {
436		r.HTTPRequest.URL = endpoint.URL
437	}
438}
439{{ end -}}
440
441`))
442
443// GoCode returns a string of rendered GoCode for this Operation
444func (o *Operation) GoCode() string {
445	var buf bytes.Buffer
446
447	if len(o.OutputRef.Shape.EventStreamsMemberName) != 0 {
448		o.API.AddSDKImport("aws/client")
449		o.API.AddSDKImport("private/protocol")
450		o.API.AddSDKImport("private/protocol/rest")
451		o.API.AddSDKImport("private/protocol", o.API.ProtocolPackage())
452	}
453
454	if o.API.EndpointDiscoveryOp != nil {
455		o.API.AddSDKImport("aws/crr")
456		o.API.AddImport("time")
457		o.API.AddImport("net/url")
458	}
459
460	if o.Endpoint != nil && len(o.Endpoint.HostPrefix) != 0 {
461		setupEndpointHostPrefix(o)
462	}
463
464	err := operationTmpl.Execute(&buf, o)
465	if err != nil {
466		panic(err)
467	}
468
469	return strings.TrimSpace(buf.String())
470}
471
472// tplInfSig defines the template for rendering an Operation's signature within an Interface definition.
473var tplInfSig = template.Must(template.New("opsig").Parse(`
474{{ .ExportedName }}({{ .InputRef.GoTypeWithPkgName }}) ({{ .OutputRef.GoTypeWithPkgName }}, error)
475{{ .ExportedName }}WithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, ...request.Option) ({{ .OutputRef.GoTypeWithPkgName }}, error)
476{{ .ExportedName }}Request({{ .InputRef.GoTypeWithPkgName }}) (*request.Request, {{ .OutputRef.GoTypeWithPkgName }})
477
478{{ if .Paginator -}}
479{{ .ExportedName }}Pages({{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool) error
480{{ .ExportedName }}PagesWithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool, ...request.Option) error
481{{- end }}
482`))
483
484// InterfaceSignature returns a string representing the Operation's interface{}
485// functional signature.
486func (o *Operation) InterfaceSignature() string {
487	var buf bytes.Buffer
488	err := tplInfSig.Execute(&buf, o)
489	if err != nil {
490		panic(err)
491	}
492
493	return strings.TrimSpace(buf.String())
494}
495
496// tplExample defines the template for rendering an Operation example
497var tplExample = template.Must(template.New("operationExample").Parse(`
498func Example{{ .API.StructName }}_{{ .ExportedName }}() {
499	sess := session.Must(session.NewSession())
500
501	svc := {{ .API.PackageName }}.New(sess)
502
503	{{ .ExampleInput }}
504	resp, err := svc.{{ .ExportedName }}(params)
505
506	if err != nil {
507		// Print the error, cast err to awserr.Error to get the Code and
508		// Message from an error.
509		fmt.Println(err.Error())
510		return
511	}
512
513	// Pretty-print the response data.
514	fmt.Println(resp)
515}
516`))
517
518// Example returns a string of the rendered Go code for the Operation
519func (o *Operation) Example() string {
520	var buf bytes.Buffer
521	err := tplExample.Execute(&buf, o)
522	if err != nil {
523		panic(err)
524	}
525
526	return strings.TrimSpace(buf.String())
527}
528
529// ExampleInput return a string of the rendered Go code for an example's input parameters
530func (o *Operation) ExampleInput() string {
531	if len(o.InputRef.Shape.MemberRefs) == 0 {
532		if strings.Contains(o.InputRef.GoTypeElem(), ".") {
533			o.imports[SDKImportRoot+"service/"+strings.Split(o.InputRef.GoTypeElem(), ".")[0]] = true
534			return fmt.Sprintf("var params *%s", o.InputRef.GoTypeElem())
535		}
536		return fmt.Sprintf("var params *%s.%s",
537			o.API.PackageName(), o.InputRef.GoTypeElem())
538	}
539	e := example{o, map[string]int{}}
540	return "params := " + e.traverseAny(o.InputRef.Shape, false, false)
541}
542
543// ShouldDiscardResponse returns if the operation should discard the response
544// returned by the service.
545func (o *Operation) ShouldDiscardResponse() bool {
546	s := o.OutputRef.Shape
547	return s.Placeholder || len(s.MemberRefs) == 0
548}
549
550// A example provides
551type example struct {
552	*Operation
553	visited map[string]int
554}
555
556// traverseAny returns rendered Go code for the shape.
557func (e *example) traverseAny(s *Shape, required, payload bool) string {
558	str := ""
559	e.visited[s.ShapeName]++
560
561	switch s.Type {
562	case "structure":
563		str = e.traverseStruct(s, required, payload)
564	case "list":
565		str = e.traverseList(s, required, payload)
566	case "map":
567		str = e.traverseMap(s, required, payload)
568	case "jsonvalue":
569		str = "aws.JSONValue{\"key\": \"value\"}"
570		if required {
571			str += " // Required"
572		}
573	default:
574		str = e.traverseScalar(s, required, payload)
575	}
576
577	e.visited[s.ShapeName]--
578
579	return str
580}
581
582var reType = regexp.MustCompile(`\b([A-Z])`)
583
584// traverseStruct returns rendered Go code for a structure type shape.
585func (e *example) traverseStruct(s *Shape, required, payload bool) string {
586	var buf bytes.Buffer
587
588	if s.resolvePkg != "" {
589		e.imports[s.resolvePkg] = true
590		buf.WriteString("&" + s.GoTypeElem() + "{")
591	} else {
592		buf.WriteString("&" + s.API.PackageName() + "." + s.GoTypeElem() + "{")
593	}
594
595	if required {
596		buf.WriteString(" // Required")
597	}
598	buf.WriteString("\n")
599
600	req := make([]string, len(s.Required))
601	copy(req, s.Required)
602	sort.Strings(req)
603
604	if e.visited[s.ShapeName] < 2 {
605		for _, n := range req {
606			m := s.MemberRefs[n].Shape
607			p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming)
608			buf.WriteString(n + ": " + e.traverseAny(m, true, p) + ",")
609			if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
610				buf.WriteString(" // Required")
611			}
612			buf.WriteString("\n")
613		}
614
615		for _, n := range s.MemberNames() {
616			if s.IsRequired(n) {
617				continue
618			}
619			m := s.MemberRefs[n].Shape
620			p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming)
621			buf.WriteString(n + ": " + e.traverseAny(m, false, p) + ",\n")
622		}
623	} else {
624		buf.WriteString("// Recursive values...\n")
625	}
626
627	buf.WriteString("}")
628	return buf.String()
629}
630
631// traverseMap returns rendered Go code for a map type shape.
632func (e *example) traverseMap(s *Shape, required, payload bool) string {
633	var buf bytes.Buffer
634
635	t := ""
636	if s.resolvePkg != "" {
637		e.imports[s.resolvePkg] = true
638		t = s.GoTypeElem()
639	} else {
640		t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1")
641	}
642	buf.WriteString(t + "{")
643	if required {
644		buf.WriteString(" // Required")
645	}
646	buf.WriteString("\n")
647
648	if e.visited[s.ShapeName] < 2 {
649		m := s.ValueRef.Shape
650		buf.WriteString("\"Key\": " + e.traverseAny(m, true, false) + ",")
651		if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
652			buf.WriteString(" // Required")
653		}
654		buf.WriteString("\n// More values...\n")
655	} else {
656		buf.WriteString("// Recursive values...\n")
657	}
658	buf.WriteString("}")
659
660	return buf.String()
661}
662
663// traverseList returns rendered Go code for a list type shape.
664func (e *example) traverseList(s *Shape, required, payload bool) string {
665	var buf bytes.Buffer
666	t := ""
667	if s.resolvePkg != "" {
668		e.imports[s.resolvePkg] = true
669		t = s.GoTypeElem()
670	} else {
671		t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1")
672	}
673
674	buf.WriteString(t + "{")
675	if required {
676		buf.WriteString(" // Required")
677	}
678	buf.WriteString("\n")
679
680	if e.visited[s.ShapeName] < 2 {
681		m := s.MemberRef.Shape
682		buf.WriteString(e.traverseAny(m, true, false) + ",")
683		if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
684			buf.WriteString(" // Required")
685		}
686		buf.WriteString("\n// More values...\n")
687	} else {
688		buf.WriteString("// Recursive values...\n")
689	}
690	buf.WriteString("}")
691
692	return buf.String()
693}
694
695// traverseScalar returns an AWS Type string representation initialized to a value.
696// Will panic if s is an unsupported shape type.
697func (e *example) traverseScalar(s *Shape, required, payload bool) string {
698	str := ""
699	switch s.Type {
700	case "integer", "long":
701		str = `aws.Int64(1)`
702	case "float", "double":
703		str = `aws.Float64(1.0)`
704	case "string", "character":
705		str = `aws.String("` + s.ShapeName + `")`
706	case "blob":
707		if payload {
708			str = `bytes.NewReader([]byte("PAYLOAD"))`
709		} else {
710			str = `[]byte("PAYLOAD")`
711		}
712	case "boolean":
713		str = `aws.Bool(true)`
714	case "timestamp":
715		str = `aws.Time(time.Now())`
716	default:
717		panic("unsupported shape " + s.Type)
718	}
719
720	return str
721}
722