The AWS Middleware doc is quite good, so I just give an overview here.

  • This is work in progress-

The generation of an AWS API call has several steps:


The Application corresponds with the stack.

Stack Step Description
Initialize Prepares the input, and sets any default parameters as needed.
Serialize Serializes the input to a protocol format suitable for the target transport layer.
Build Attach additional metadata to the serialized input, such as HTTP Content-Length.
Finalize Final message preparation, including retries and authentication (SigV4 signing).
Deserialize Deserialize responses from the protocol format into a structured type or error.

Inside the stack the request is transformed and generated.

Let`s go through them with an example:

Application code snippet:

parms := &lambda.GetFunctionInput{
    FunctionName: aws.String("simple"),

resp, err := client.GetFunction(context.TODO(), parms)

Inside the library the following steps are called:

  • api_op_GetFunction.go
    • GetFunction
    • invokeOperation
      • api_client.go
        • invokeOperation
          • Init Middleware Stack
            • clearStack
            • new stack -Install inserted handler functions
            • DecorateHandler

Smithy-go executes all steps from the stack above:

In Middleware-HandleMiddleware

func (s *Stack) HandleMiddleware(ctx context.Context, input interface{}, next Handler) (
	output interface{}, metadata Metadata, err error,
) {
	h := DecorateHandler(next,

	return h.Handle(ctx, input)

What we can do to manipulate the steps is to add functionality before or after these steps. An example would be to look kat the original XML which S3 and EC2 are sending. Maybe you did not know that, because the stack transforms in for you.

Some date which is handled in the steps:

Initialize steps_initialize.go

  • Service Name
  • Operation Name
  • Logger
  • Region
  • Parameter Validation

Serialize `steps_serialize.go``

Now the input has to be translated to what the API needs


func (s *SerializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) (


Lambda API (

Request Syntax

GET /2015-03-31/functions/FunctionName?Qualifier=Qualifier HTTP/1.1

Request Method: Get Host: “” Path “/2015-03-31/functions/simple”


Middleware step_build.go

 func (s *BuildStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) (
  • Invokation ID invocationID, err := smithyrand.NewUUID(rand.Reader).GetUUID()
    • const invocationIDHeader = "Amz-Sdk-Invocation-Id"

// HandleBuild compute the payload hash for the request payload ctx = SetPayloadHash(ctx, hex.EncodeToString(hash.Sum(nil)))



func (s *FinalizeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) (

// Record the metadata for the for attempt being started. // HandleFinalize attaches the SDK request metric header to the transport layer get credentials signthttp


Call api HandleDeserialize

middleware `steps_deserialize.go`` Response status 200 ok

Back to finalize

Response data as interface

Back to build

Back to serialize

Only Lambda knows how to do that => SDK go v2 lambda -> serializer.go

Back to init

Last step lamba service api:op:getFunction

	result, metadata, err := c.invokeOperation(ctx, "GetFunction", params, optFns, c.addOperationGetFunctionMiddlewares)
	if err != nil {
		return nil, err

	out := result.(*GetFunctionOutput)