

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Personalización de las solicitudes de cliente de AWS SDK para Go v2 con middleware
<a name="middleware"></a>

**aviso**  
 La modificación de la canalización de solicitudes de cliente puede generar solicitudes no válidas o con formato incorrecto, o puede provocar errores de aplicación inesperados. Esta funcionalidad está pensada para casos de uso avanzados que la interfaz del SDK no proporciona de forma predeterminada. 

 Puede personalizar las solicitudes de cliente de AWS SDK para Go mediante el registro de middleware (uno o más) en la [pila](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Stack) de una operación de servicio. La pila se compone de una serie de pasos: Initialize, Serialize, Build, Finalize y Deserialize. El middleware (cero o más) que contiene cada paso opera en los tipos de entrada y salida de ese paso. El diagrama y la tabla siguientes proporcionan información general sobre cómo la solicitud y la respuesta de una operación recorren la pila: 

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


|  Paso de la pila  |  Descripción  | 
| --- | --- | 
|  Initialize  |  Prepara la entrada y establece los parámetros predeterminados según sea necesario.  | 
|  Serialize  |  Serializa la entrada en un formato de protocolo adecuado para la capa de transporte de destino.  | 
|  Build  |  Asocie metadatos adicionales a la entrada serializada, como la longitud del contenido HTTP.  | 
|  Finalize  |  Preparación del mensaje final, incluidos los reintentos y la autenticación (firma de SiGv4).  | 
|  Deserialize  |  Deserialice las respuestas del formato de protocolo en un error o tipo estructurado.  | 

 Cada middleware de un paso determinado debe tener un identificador único, que viene determinado por el método `ID` del middleware. Los identificadores de middleware garantizan que solo se registre una instancia de un middleware determinado en un paso y permiten insertar otro middleware de paso en relación con este. 

 Para asociar middleware de paso, use los métodos `Insert` o `Add` de un paso. Use `Add` para asociar middleware al principio de un paso al especificar [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), y [middleware.After](https://pkg.go.dev/github.com/aws/smithy-go/middleware#After) para asociarlo al final del paso. Use `Insert` para asociar middleware a un paso con la inserción del middleware relativo a otro middleware de paso. 

**aviso**  
 Debe utilizar el método `Add` para insertar middleware de paso personalizado de forma segura. El uso de `Insert` crea una dependencia entre su middleware personalizado y aquel relacionado que inserta. El middleware incluido en un paso de pila debe considerarse opaco para evitar que se produzcan cambios importantes en la aplicación. 

## Escritura de un middleware personalizado
<a name="writing-a-custom-middleware"></a>

 Cada paso de pila tiene una interfaz que debe cumplirse para poder asociar un middleware a un paso determinado. Puede utilizar una de las funciones `StepMiddlewareFunc` proporcionadas para cumplir rápidamente con esta interfaz. En la tabla siguiente se describen los pasos, su interfaz y la función auxiliar que se puede utilizar para cumplir con la interfaz. 


|  Paso  |  Interfaz  |  Función Helper  | 
| --- | --- | --- | 
|  Initialize  |  [InitializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#InitializeMiddleware)  |  [InitializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#InitializeMiddlewareFunc)  | 
|  Build  |  [BuildMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#BuildMiddleware)  |  [BuildMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#BuildMiddlewareFunc)  | 
|  Serialize  |  [SerializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#SerializeMiddleware)  |  [SerializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#SerializeMiddlewareFunc)  | 
|  Finalize  |  [FinalizeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#FinalizeMiddleware)  |  [FinalizeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#FinalizeMiddlewareFunc)  | 
|  Deserialize  |  [DeserializeMiddleware](https://pkg.go.dev/github.com/aws/smithy-go/middleware#DeserializeMiddleware)  |  [DeserializeMiddlewareFunc](https://pkg.go.dev/github.com/aws/smithy-go/middleware#DeserializeMiddlewareFunc)  | 

 En los ejemplos siguientes se muestra cómo puede escribir un middleware personalizado para rellenar el miembro Bucket de las llamadas a la API `GetObject` de Amazon S3 en caso de que no se proporcione uno. Se hará referencia a este middleware en ejemplos posteriores para mostrar cómo asociar middleware de un paso a la pila. 

```
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)
})
```

## Cómo asociar middleware a todos los clientes
<a name="attaching-middleware-to-all-clients"></a>

 Para asociar su middleware de paso personalizado a cada uno de los clientes, añada el middleware mediante el miembro `APIOptions` del tipo [aws.Config](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Config). En los ejemplos siguientes se asocia el middleware `defaultBucket` a todos los clientes creados con el objeto `aws.Config` de sus aplicaciones: 

```
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)
```

## Cómo asociar middleware a una operación específica
<a name="attaching-middleware-to-a-specific-operation"></a>

 Para asociar su middleware de paso personalizado a una operación de cliente específica, modifique el miembro `APIOptions` del cliente con la lista de argumentos variádicos de una operación. En los ejemplos siguientes se asocia el middleware `defaultBucket` a la invocación de una operación `GetObject` de Amazon S3 específica: 

```
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)
})
```

## Transferencia de metadatos descendente en la pila
<a name="passing-metadata-down-the-stack"></a>

 En determinadas situaciones, puede que necesite utilizar dos o más middlewares a la par mediante el intercambio de información o del estado. Puede usar [context.Context](https://golang.org/pkg/context/#Context) para pasar estos metadatos mediante [middleware.WithStackValue](https://pkg.go.dev/github.com/aws/smithy-go/middleware#WithStackValue). `middleware.WithStackValue` asocia el par clave-valor determinado al contexto proporcionado y limita de forma segura el alcance a la pila en ejecución. Estos valores para la pila se pueden recuperar de un contexto mediante [middleware.GetStackValue](https://pkg.go.dev/github.com/aws/smithy-go/middleware#GetStackValue) y con la clave usada para almacenar el valor correspondiente. Las claves deben ser comparables y debe definir sus propios tipos como claves de contexto para evitar conflictos. En los ejemplos siguientes se muestra cómo dos middleware pueden utilizar `context.Context` para realizar una transferencia de información descendente en la pila. 

```
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)
})
```

### Metadatos proporcionados por el SDK
<a name="metadata-provided-by-the-sdk"></a>

 AWS SDK para Go proporciona varios valores de metadatos que se pueden recuperar del contexto proporcionado. Estos valores pueden utilizarse para habilitar un middleware más dinámico que modifique su comportamiento en función de la región de destino, la operación o el servicio en ejecución. En la tabla siguiente se proporcionan algunas de las claves disponibles: 


|  Clave  |  Recuperador  |  Descripción  | 
| --- | --- | --- | 
|  ServiceID  |  [GetServiceID](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/middleware#GetServiceID)  |  Recupera el identificador de servicio para la pila en ejecución. Esto puede compararse con la constante ServiceID del paquete de clientes de servicio.  | 
|  OperationName  |  [GetOperationName](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/middleware#GetOperationName)  |  Recupera el nombre de la operación para la pila en ejecución.  | 
|  Logger  |  [GetLogger](https://pkg.go.dev/github.com/aws/smithy-go/middleware#GetLogger)  |  Recupera el registrador que se puede usar para registrar mensajes del middleware.  | 

## Transferencia de metadatos ascendente en la pila
<a name="passing-metadata-up-the-stack"></a>

 Puede realizar una transferencia de metadatos ascendente en la pila mediante la adición de pares clave-valor de los metadatos con [middleware.Metadata](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Metadata). Cada paso de middleware devuelve una estructura de salida, metadatos y un error. Su middleware personalizado debe devolver los metadatos recibidos al llamar al siguiente controlador del paso. Esto garantiza que los metadatos agregados por el middleware descendente se propaguen a la aplicación que invoca la operación de servicio. La aplicación que realiza la invocación puede acceder a los metadatos resultantes mediante la forma de salida de la operación a través del miembro de la estructura `ResultMetadata`. 

 En los ejemplos siguientes se muestra cómo un middleware personalizado puede agregar metadatos que se devuelven como parte del resultado de la operación. 

```
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)
```