github.com/aavshr/aws-sdk-go@v1.41.3/private/model/api/operation.go (about)

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