

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Personalizar solicitações de cliente do AWS SDK para Go v2 com middleware
<a name="middleware"></a>

**Atenção**  
 A modificação do pipeline de solicitações do cliente pode resultar em solicitações malformadas/inválidas ou em erros inesperados na aplicação. Essa funcionalidade é destinada a casos de uso avançados não fornecidos pela interface do SDK por padrão. 

 Você pode personalizar as solicitações de cliente do AWS SDK para Go registrando um ou mais middlewares na [pilha](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Stack) de uma operação de serviço. A pilha é composta por uma série de etapas: inicializar, serializar, compilar, finalizar e desserializar. Cada etapa contém zero ou mais middlewares que operam nos tipos de entrada e saída dessa etapa. O diagrama e a tabela a seguir fornecem uma visão geral de como a solicitação e a resposta de uma operação percorrem a pilha. 

 ![\[Middleware\]](http://docs.aws.amazon.com/pt_br/sdk-for-go/v2/developer-guide/images/middleware.png) 


|  Etapa da pilha  |  Descrição  | 
| --- | --- | 
|  Inicializar  |  Prepara a entrada e define os parâmetros padrão conforme necessário.  | 
|  Serializar  |  Serializa a entrada em um formato de protocolo adequado para a camada de transporte de destino.  | 
|  Compilar  |  Anexe metadados adicionais à entrada serializada, como HTTP Content-Length.  | 
|  Finalizar  |  Preparação final da mensagem, incluindo novas tentativas e autenticação (assinatura do SigV4).  | 
|  Desserializar  |  Desserialize as respostas do formato do protocolo em um erro ou tipo estruturado.  | 

 Cada middleware em determinada etapa deve ter um identificador exclusivo, que é determinado pelo método `ID` do middleware. Os identificadores de middleware garantem que somente uma instância de determinado middleware seja registrada em uma etapa, e permitem que outro middleware dessa etapa seja inserido em relação a ele. 

 Você anexa o middleware da etapa usando os métodos `Insert` ou `Add` da etapa. Você usa `Add` para anexar um middleware ao início de uma etapa especificando [middleware.Before](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Before) como [RelativePosition](https://pkg.go.dev/github.com/aws/smithy-go/middleware#RelativePosition) e [middleware.After](https://pkg.go.dev/github.com/aws/smithy-go/middleware#After) para anexar ao final da etapa. Você usa `Insert` para anexar um middleware a uma etapa inserindo-o em relação ao middleware de outra etapa. 

**Atenção**  
 Você deve usar o método `Add` para inserir com segurança o middleware personalizado da etapa. O uso de `Insert` cria uma dependência entre o middleware personalizado e o middleware em relação ao qual você está fazendo a inserção. O middleware dentro de uma etapa da pilha devem ser considerados opacos para evitar que alterações causem falhas no funcionamento da aplicação. 

## Como escrever um middleware personalizado
<a name="writing-a-custom-middleware"></a>

 Cada etapa da pilha tem uma interface que você deve satisfazer para anexar um middleware a determinada etapa. Use uma das funções `StepMiddlewareFunc` fornecidas para satisfazer rapidamente essa interface. A tabela a seguir descreve as etapas, sua interface e a função auxiliar que pode ser usada para satisfazer a interface. 


|  Etapa  |  Interface  |  Função Helper  | 
| --- | --- | --- | 
|  Inicializar  |  [InitializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#InitializeMiddleware)  |  [InitializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#InitializeMiddlewareFunc)  | 
|  Compilar  |  [BuildMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#BuildMiddleware)  |  [BuildMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#BuildMiddlewareFunc)  | 
|  Serializar  |  [SerializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#SerializeMiddleware)  |  [SerializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#SerializeMiddlewareFunc)  | 
|  Finalizar  |  [FinalizeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#FinalizeMiddleware)  |  [FinalizeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#FinalizeMiddlewareFunc)  | 
|  Desserializar  |  [DeserializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#DeserializeMiddleware)  |  [DeserializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#DeserializeMiddlewareFunc)  | 

 Os exemplos a seguir mostram como criar um middleware personalizado para preencher o membro do bucket das chamadas de API `GetObject` do Amazon S3, caso ele não seja fornecido. Faremos referência a esse middleware nos exemplos seguintes para mostrar como anexar o middleware da etapa à pilha. 

```
import "github.com/aws/smithy-go/aws"
import "github.com/aws/smithy-go/middleware"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

var defaultBucket = middleware.InitializeMiddlewareFunc("DefaultBucket", func(
    ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
) (
    out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
    // Type switch to check if the input is s3.GetObjectInput, if so and the bucket is not set, populate it with
    // our default.
    switch v := in.Parameters.(type) {
    case *s3.GetObjectInput:
        if v.Bucket == nil {
            v.Bucket = aws.String("amzn-s3-demo-bucket")
        }
    }

    // Middleware must call the next middleware to be executed in order to continue execution of the stack.
    // If an error occurs, you can return to prevent further execution.
    return next.HandleInitialize(ctx, in)
})
```

## Como anexar o middleware a todos os clientes
<a name="attaching-middleware-to-all-clients"></a>

 É possível anexar o middleware personalizado da etapa a cada cliente adicionando-o por meio do membro `APIOptions` do tipo [aws.Config](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Config). Os exemplos a seguir anexam o middleware `defaultBucket` a cada cliente construído usando o objeto `aws.Config` da aplicação: 

```
import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/smithy-go/middleware"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    // handle error
}

cfg.APIOptions = append(cfg.APIOptions, func(stack *middleware.Stack) error {
    // Attach the custom middleware to the beginning of the Initialize step
    return stack.Initialize.Add(defaultBucket, middleware.Before)
})

client := s3.NewFromConfig(cfg)
```

## Como anexar o middleware a uma operação específica
<a name="attaching-middleware-to-a-specific-operation"></a>

 É possível anexar o middleware personalizado da etapa a uma operação específica do cliente modificando o membro `APIOptions` do cliente por meio da lista de argumentos variádicos de uma operação. Os exemplos a seguir associam o middleware `defaultBucket` a uma invocação de operação `GetObject` específica do Amazon S3: 

```
import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/smithy-go/middleware"

// ...

// registerDefaultBucketMiddleware registers the defaultBucket middleware with the provided stack.
func registerDefaultBucketMiddleware(stack *middleware.Stack) error {
    // Attach the custom middleware to the beginning of the Initialize step
    return stack.Initialize.Add(defaultBucket, middleware.Before)
}

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    // handle error
}

client := s3.NewFromConfig(cfg)

object, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
    Key: aws.String("my-key"),
}, func(options *s3.Options) {
    // Register the defaultBucketMiddleware for this operation only
    options.APIOptions = append(options.APIOptions, registerDefaultBucketMiddleware)
})
```

## Como passar metadados para baixo na pilha
<a name="passing-metadata-down-the-stack"></a>

 Em determinadas situações, você pode perceber que precisa que dois ou mais middlewares funcionem em conjunto, compartilhando informações ou estado. Você pode usar [context.Context](https://golang.org/pkg/context/#Context) para passar esses metadados usando [middleware.WithStackValue](https://pkg.go.dev/github.com/aws/smithy-go/middleware#WithStackValue). `middleware.WithStackValue` anexa o par de chave-valor ao contexto fornecido e limita com segurança o escopo à pilha em execução no momento. Esses valores com escopo de pilha podem ser recuperados de um contexto usando [middleware.GetStackValue](https://pkg.go.dev/github.com/aws/smithy-go/middleware#GetStackValue) e fornecendo a chave usada para armazenar o valor correspondente. As chaves devem ser comparáveis, e você deve definir seus próprios tipos como chaves de contexto para evitar colisões. Os exemplos a seguir mostram como dois middlewares podem usar `context.Context` para passar informações para baixo na pilha. 

```
import "context"
import "github.com/aws/smithy-go/middleware"

// ...

type customKey struct {}

func GetCustomKey(ctx context.Context) (v string) {
    v, _ = middleware.GetStackValue(ctx, customKey{}).(string)
    return v
}

func SetCustomKey(ctx context.Context, value string) context.Context {
    return middleware.WithStackValue(ctx, customKey{}, value)
}

// ...

var customInitalize = middleware.InitializeMiddlewareFunc("customInitialize", func(
    ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
) (
    out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
    ctx = SetCustomKey(ctx, "my-custom-value")
    
    return next.HandleInitialize(ctx, in)
})

var customBuild = middleware.BuildMiddlewareFunc("customBuild", func(
    ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
) (
    out middleware.BuildOutput, metadata middleware.Metadata, err error,
) {
    customValue := GetCustomKey(ctx)
    
    // use customValue

    return next.HandleBuild(ctx, in)
})
```

### Metadados fornecidos pelo SDK
<a name="metadata-provided-by-the-sdk"></a>

 O AWS SDK para Go fornece vários valores de metadados que podem ser recuperados do contexto fornecido. Esses valores podem ser usados para habilitar um middleware mais dinâmico que modifica seu comportamento com base no serviço em execução, na operação ou na região de destino. Algumas das chaves disponíveis são fornecidas na tabela abaixo: 


|  Chave  |  Recuperador  |  Descrição  | 
| --- | --- | --- | 
|  ServiceID  |  [GetServiceID](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/middleware#GetServiceID)  |  Recupera o identificador do serviço da pilha em execução. Isso pode ser comparado à constante ServiceID do pacote do cliente de serviço.  | 
|  OperationName  |  [GetOperationName](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/middleware#GetOperationName)  |  Recupera o nome da operação da pilha em execução.  | 
|  Logger  |  [GetLogger](https://pkg.go.dev/github.com/aws/smithy-go/middleware#GetLogger)  |  Recupera o registrador que pode ser usado para registrar em log as mensagens do middleware.  | 

## Como passar metadados para cima na pilha
<a name="passing-metadata-up-the-stack"></a>

 Você pode passar metadados para cima na pilha adicionando pares de chave e valor de metadados usando [middleware.Metadata](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Metadata). Cada etapa do middleware retorna uma estrutura de saída, metadados e um erro. O middleware personalizado deve retornar os metadados recebidos ao chamar o próximo handler na etapa. Isso garante que os metadados adicionados pelos middlewares posicionados mais abaixo na pilha sejam propagados para a aplicação que invoca a operação do serviço. Os metadados resultantes podem ser acessados pela aplicação que fez a invocação por meio da forma de saída da operação, utilizando o membro da estrutura `ResultMetadata`. 

 Os exemplos a seguir mostram como um middleware personalizado pode adicionar metadados que são retornados como parte da saída da operação. 

```
import "context"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/smithy-go/middleware"

// ...

type customKey struct{}

func GetCustomKey(metadata middleware.Metadata) (v string) {
    v, _ = metadata.Get(customKey{}).(string)
    return v
}

func SetCustomKey(metadata *middleware.Metadata, value string) {
    metadata.Set(customKey{}, value)
}

// ...

var customInitalize = middleware.InitializeMiddlewareFunc("customInitialize", func (
    ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
) (
    out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
    out, metadata, err = next.HandleInitialize(ctx, in)
    if err != nil {
        return out, metadata, err
    }
    
    SetCustomKey(&metadata, "my-custom-value")
    
    return out, metadata, nil
})

// ...

client := s3.NewFromConfig(cfg, func (options *s3.Options) {
    options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error {
        return stack.Initialize.Add(customInitalize, middleware.After)
    })
})

out, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
    // input parameters
})
if err != nil {
    // handle error
}

customValue := GetCustomKey(out.ResponseMetadata)
```