

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.

# Uso del SDK de
<a name="using"></a>

En esta sección se proporciona la información básica necesaria para utilizar el AWS SDK para Kotlin.

**Topics**
+ [Hacer solicitudes](making-requests.md)
+ [Corrutinas](coroutines.md)
+ [Operaciones de streaming](streaming-ops.md)
+ [Paginación](pagination.md)
+ [Esperadores](waiters.md)
+ [Gestión de errores](error-handling.md)
+ [Solicitudes de prefirma](presign-requests.md)
+ [Solución de problemas FAQs](troubleshooting-faqs.md)
+ [Burlándose en el AWS SDK para Kotlin](mocking.md)

# Hacer solicitudes
<a name="making-requests"></a>

Utilice un cliente de servicio para realizar solicitudes a un Servicio de AWS. AWS SDK para Kotlin Proporciona idiomas específicos de dominio (DSLs) que siguen un patrón de creación [de tipos seguros](https://kotlinlang.org/docs/type-safe-builders.html) para crear solicitudes. También se puede acceder a las estructuras anidadas de las solicitudes a través de sus. DSLs

El siguiente ejemplo muestra cómo crear una entrada de operación CreateTable de Amazon [DynamoDB](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/dynamodb/aws.sdk.kotlin.services.dynamodb/create-table.html):

```
val ddb = DynamoDbClient.fromEnvironment()

val req = CreateTableRequest {
    tableName = name
    keySchema = listOf(
        KeySchemaElement {
            attributeName = "year"
            keyType = KeyType.Hash
        },
        KeySchemaElement {
            attributeName = "title"
            keyType = KeyType.Range
        }
    )

    attributeDefinitions = listOf(
        AttributeDefinition {
            attributeName = "year"
            attributeType = ScalarAttributeType.N
        },
        AttributeDefinition {
            attributeName = "title"
            attributeType = ScalarAttributeType.S
        }
    )
    
    // You can configure the `provisionedThroughput` member
    // by using the `ProvisionedThroughput.Builder` directly:
    provisionedThroughput {
        readCapacityUnits = 10
        writeCapacityUnits = 10
    }
}

val resp = ddb.createTable(req)
```

## Sobrecargas de la interfaz de servicio (DSL)
<a name="service-interface-dsl-overloads"></a>

Cada operación no relacionada con la transmisión en la interfaz del cliente del servicio tiene una sobrecarga de DSL, por lo que no es necesario crear una solicitud independiente.

Ejemplo de creación de un depósito de Amazon Simple Storage Service (Amazon S3) con la función de sobrecarga:

```
s3Client.createBucket {    // this: CreateBucketRequest.Builder
    bucket = newBucketName
}
```

Equivale a:

```
val request = CreateBucketRequest {    // this: CreateBucketRequest.Builder 
    bucket = newBucketName 
}

s3client.createBucket(request)
```

## Solicitudes sin entradas obligatorias
<a name="requests-no-required-inputs"></a>

Se puede llamar a las operaciones que no tienen entradas obligatorias sin tener que pasar un objeto de solicitud. Esto suele ser posible con operaciones de tipo lista, como la operación de la `listBuckets` API Amazon S3.

 Por ejemplo, las tres declaraciones siguientes son equivalentes: 

```
s3Client.listBuckets(ListBucketsRequest {
  // Construct the request object directly.
})
s3Client.listBuckets {
  // DSL builder without explicitly setting any arguments.
}
s3Client.listBuckets()
```

# Corrutinas
<a name="coroutines"></a>

El AWS SDK para Kotlin es asíncrono de forma predeterminada. El SDK para Kotlin usa `suspend` funciones para todas las operaciones, que deben invocarse desde una corrutina. 

Para obtener una guía más detallada sobre las corrutinas, consulta la documentación [oficial](https://kotlinlang.org/docs/coroutines-overview.html) de Kotlin.

## Realización de solicitudes simultáneas
<a name="making-concurrent-requests"></a>

El generador de corrutinas [asíncronas](https://kotlinlang.org/docs/composing-suspending-functions.html#concurrent-using-async) se puede utilizar para lanzar solicitudes simultáneas cuando le interesen los resultados. `async`devuelve un [Deferred](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html), que representa un futuro ligero y sin bloqueos que representa la promesa de ofrecer un resultado más adelante.

Si no te importan los resultados (solo que se haya completado una operación), puedes usar el generador de corrutinas de [lanzamiento](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html). `launch`es conceptualmente similar a. `async` La diferencia es que launch devuelve un [Job](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html) y no contiene ningún valor resultante, mientras que `async` devuelve un`Deferred`.

El siguiente es un ejemplo de cómo realizar solicitudes simultáneas a Amazon S3 mediante la operación [headObject](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3/head-object.html) para obtener el tamaño del contenido de dos claves:

```
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis
import aws.sdk.kotlin.services.s3.S3Client


fun main(): Unit = runBlocking {

    val s3 = S3Client { region = "us-east-2" }
    
    val myBucket = "<your-bucket-name-here>"
    val key1 = "<your-object-key-here>"
    val key2 = "<your-second-object-key-here>"

    val resp1 = async {
        s3.headObject{
            bucket = myBucket
            key = key1
        }
    }

    val resp2 = async {
        s3.headObject{
            bucket = myBucket
            key = key2
        }
    }


    val elapsed = measureTimeMillis {
        val totalContentSize = resp1.await().contentLength + resp2.await().contentLength
        println("content length of $key1 + $key2 = $totalContentSize")
    }

    println("requests completed in $elapsed ms")

}
```

## Realizar solicitudes de bloqueo
<a name="making-clocking-requests"></a>

Para realizar llamadas de servicio desde el código existente que no usa corrutinas e implementa un modelo de subprocesos diferente, puedes usar el generador de corrutinas [RunBlocking](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html). Un ejemplo de un modelo de subprocesamiento diferente es el uso del enfoque tradicional de Java. executors/futures Es posible que necesites usar este enfoque si vas a combinar código o bibliotecas de Java y Kotlin. 

Como su nombre indica, este `runBlocking` generador lanza una nueva corrutina y bloquea el hilo actual hasta que se complete. 

**aviso**  
 `runBlocking`por lo general, no debe usarse desde una corrutina. Está diseñado para vincular el código de bloqueo normal con las bibliotecas que están escritas en forma suspensiva (por ejemplo, en las funciones principales y las pruebas). 

# Operaciones de streaming
<a name="streaming-ops"></a>

En el AWS SDK para Kotlin, los datos binarios (flujos) se representan como un [https://docs.aws.amazon.com/smithy-kotlin/api/latest/runtime-core/aws.smithy.kotlin.runtime.content/-byte-stream/index.html](https://docs.aws.amazon.com/smithy-kotlin/api/latest/runtime-core/aws.smithy.kotlin.runtime.content/-byte-stream/index.html)tipo, que es un flujo abstracto de bytes de solo lectura.

## Respuestas de transmisión
<a name="streaming-responses"></a>

Las respuestas con un flujo binario (como la operación de la API Amazon Simple Storage Service (Amazon [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)S3)) se gestionan de forma diferente a la de otros métodos. Estos métodos utilizan una función lambda que gestiona la respuesta en lugar de devolverla directamente. Esto limita el alcance de la respuesta a la función y simplifica la administración del ciclo de vida tanto de la persona que llama como del entorno de ejecución del SDK.

Cuando se devuelve la función lambda, se liberan todos los recursos, como la conexión HTTP subyacente. (No se `ByteStream` debe acceder a él después de que la lambda regrese y no se debe desconectar del cierre). El resultado de la llamada es lo que devuelva la lambda.

El siguiente ejemplo de código muestra que la función [GetObject](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3/-s3-client/get-object.html) recibe un parámetro lambda, que gestiona la respuesta.

```
val s3Client = S3Client.fromEnvironment()
val req = GetObjectRequest { ... }

val path = Paths.get("/tmp/download.txt")

// S3Client.getObject has the following signature:
// suspend fun <T> getObject(input: GetObjectRequest, block: suspend (GetObjectResponse) -> T): T

val contentSize = s3Client.getObject(req) { resp ->
    // resp is valid until the end of the block.
    // Do not attempt to store or process the stream after the block returns.
    
    // resp.body is of type ByteStream.
    val rc = resp.body?.writeToFile(path)
    rc
}
println("wrote $contentSize bytes to $path")
```

El `ByteStream` tipo tiene las siguientes extensiones para las formas habituales de consumirlo:
+ `ByteStream.writeToFile(file: File): Long`
+ `ByteStream.writeToFile(path: Path): Long`
+ `ByteStream.toByteArray(): ByteArray`
+ `ByteStream.decodeToString(): String`

Todas ellas están definidas en el `aws.smithy.kotlin.runtime.content` paquete.

## Solicitudes de streaming
<a name="streaming-requests"></a>

Para suministrar un`ByteStream`, también hay varios métodos prácticos, incluidos los siguientes:
+ `ByteStream.fromFile(file: File)`
+ `File.asByteStream(): ByteStream`
+ `Path.asByteStream(): ByteStream`
+ `ByteStream.fromBytes(bytes: ByteArray)`
+ `ByteStream.fromString(str: String)`

Todos ellos están definidos en el `aws.smithy.kotlin.runtime.content` paquete.

El siguiente ejemplo de código muestra el uso de métodos `ByteStream` prácticos que proporcionan la propiedad body en la creación de un [PutObjectRequest](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.model/-put-object-request/index.html):

```
val req = PutObjectRequest {
    ...
    body = ByteStream.fromFile(file)
    // body = ByteStream.fromBytes(byteArray)
    // body = ByteStream.fromString("string")
    // etc
}
```

# Paginación
<a name="pagination"></a>

Muchas AWS operaciones devuelven resultados paginados cuando la carga útil es demasiado grande para devolverlos en una sola respuesta. AWS SDK para Kotlin Incluye [extensiones de](https://kotlinlang.org/docs/extensions.html) la interfaz del cliente de servicio que paginan automáticamente los resultados por usted. Solo tiene que escribir el código que procesa los resultados.

La paginación se presenta como un [flujo](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) <T>para que puedas aprovechar las transformaciones idiomáticas de Kotlin para colecciones asíncronas (como, y). `map` `filter` `take` Las excepciones son transparentes, lo que hace que la gestión de errores parezca una llamada normal a la API, y la cancelación se basa en la cancelación cooperativa general de las corrutinas. Para obtener más información, consulta [los flujos](https://kotlinlang.org/docs/flow.html) y las [excepciones de flujo](https://kotlinlang.org/docs/flow.html#flow-exceptions) en la guía oficial.

**nota**  
Los siguientes ejemplos utilizan Amazon S3. Sin embargo, los conceptos son los mismos para cualquier servicio que tenga uno o más paginados APIs. Todas las extensiones de paginación se definen en el `aws.sdk.kotlin.services.<service>.paginators` paquete (por ejemplo,). `aws.sdk.kotlin.services.dynamodb.paginators` 

El siguiente ejemplo de código muestra cómo se puede procesar la respuesta paginada de la llamada a la función [ListObjectsV2Paginated](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.paginators/list-objects-v2-paginated.html). 

**Importaciones**

```
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.paginators.listObjectsV2Paginated
import kotlinx.coroutines.flow.*
```

**Código**

```
val s3 = S3Client.fromEnvironment()
val req = ListObjectsV2Request {
    bucket = "amzn-s3-demo-bucket"
    maxKeys = 1
}

s3.listObjectsV2Paginated(req)  // Flow<ListObjectsV2Response>
    .transform { it.contents?.forEach { obj -> emit(obj) } }
    .collect { obj ->
        println("key: ${obj.key}; size: ${obj.size}")
    }
```

# Esperadores
<a name="waiters"></a>

Los esperadores son una abstracción del cliente que se utilizan para sondear un recurso hasta que se alcance el estado deseado o se determine que el recurso no entrará en el estado deseado. Esta es una tarea habitual cuando se trabaja con servicios que finalmente son coherentes, como Amazon Simple Storage Service (Amazon S3), o servicios que crean recursos de forma asíncrona, como Amazon EC2. 

Escribir lógica para sondear continuamente el estado de un recurso puede resultar engorroso y aumentar la probabilidad de errores. El objetivo de los camareros es trasladar esta responsabilidad del código del cliente a una empresa que tenga un conocimiento profundo de los AWS SDK para Kotlin aspectos relacionados con los plazos de la operación. AWS 

**nota**  
Los siguientes ejemplos utilizan Amazon S3. Sin embargo, los conceptos son los mismos para todos los Servicio de AWS que tengan uno o más esperadores definidos. Todas las extensiones se definen en el `aws.sdk.kotlin.services.<service>.waiters` paquete (por ejemplo,`aws.sdk.kotlin.services.dynamodb.waiters`). También siguen una convención de nomenclatura estándar (`waitUntil<Condition>`).

El siguiente ejemplo de código muestra el uso de una función de camarero que permite evitar escribir la lógica de las votaciones.

**Importaciones**

```
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.waiters.waitUntilBucketExists
```

**Código**

```
val s3 = S3Client.fromEnvironment()

// This initiates creating an S3 bucket and potentially returns before the bucket exists.
s3.createBucket { bucket = "amzn-s3-demo-bucket" }

// When this function returns, the bucket either exists or an exception
// is thrown.
s3.waitUntilBucketExists { bucket = "amzn-s3-demo-bucket" }

// The bucket now exists.
```

**nota**  
Cada método de espera devuelve una `Outcome` instancia que se puede utilizar para obtener la respuesta final que corresponde a alcanzar la condición deseada. El resultado también contiene detalles adicionales, como el número de intentos realizados para alcanzar el estado deseado.

# Gestión de errores
<a name="error-handling"></a>

Entender cómo y cuándo se AWS SDK para Kotlin producen excepciones es importante para crear aplicaciones de alta calidad con el SDK. En las siguientes secciones se describen los diferentes casos de excepciones que produce el SDK y cómo tratarlas correctamente.

## Excepciones de servicio
<a name="service-exceptions"></a>

La excepción más común es `AwsServiceException` aquella de la que se heredan todas las excepciones específicas de un servicio (por ejemplo`S3Exception`). Esta excepción representa una respuesta de error de un servicio de Servicio de AWS. Por ejemplo, si intentas cerrar una EC2 instancia de Amazon que no existe, Amazon EC2 devuelve una respuesta de error. Los detalles de la respuesta al error se incluyen en el mensaje `AwsServiceException` que aparece. 

Si encuentras un mensaje`AwsServiceException`, significa que tu solicitud se envió correctamente Servicio de AWS , pero no se pudo procesar. Esto puede ser debido a errores en los parámetros de la solicitud o a problemas en el servicio.

## Excepciones de clientes
<a name="client-exceptions"></a>

`ClientException`indica que se ha producido un problema en el código del AWS SDK para Kotlin cliente, ya sea al intentar enviar una solicitud AWS o al intentar analizar una respuesta desde él AWS. Por lo general, A `ClientException` es más grave que a `AwsServiceException` e indica que un problema importante es impedir que el cliente procese las llamadas de servicio a Servicios de AWS. Por ejemplo, AWS SDK para Kotlin lanza un `ClientException` si no puede analizar la respuesta de un servicio.

## Metadatos de error
<a name="error-metadata"></a>

Cada excepción de servicio y excepción de cliente tiene la `sdkErrorMetadata` propiedad. Se trata de una bolsa de propiedades mecanografiada que se puede utilizar para recuperar detalles adicionales sobre el error.

Existen varias extensiones predefinidas para el `AwsErrorMetadata` tipo directamente, incluidas, entre otras, las siguientes:
+ `sdkErrorMetadata.requestId`— el identificador único de la solicitud
+ `sdkErrorMetadata.errorMessage`— el mensaje legible por humanos (normalmente coincide con el`Exception.message`, pero puede contener más información si el servicio desconoce la excepción)
+ `sdkErrorMetadata.protocolResponse`— La respuesta del protocolo sin procesar

En el siguiente ejemplo, se muestra el acceso a los metadatos del error.

```
try {
    s3Client.listBuckets { ... }
} catch (ex: S3Exception) {
    val awsRequestId = ex.sdkErrorMetadata.requestId
    val httpResp = ex.sdkErrorMetadata.protocolResponse as? HttpResponse

    println("requestId was: $awsRequestId")
    println("http status code was: ${httpResp?.status}")
}
```

# Solicitudes de prefirma
<a name="presign-requests"></a>

Puedes prefirmar las solicitudes de algunas operaciones de la AWS API para que otra persona que llame pueda utilizar la solicitud más adelante sin tener que presentar sus propias credenciales. 

Por ejemplo, supongamos que Alice tiene acceso a un objeto del Amazon Simple Storage Service (Amazon S3) y quiere compartir temporalmente el acceso al objeto con Bob. Alice puede generar una `GetObject` solicitud prefirmada para compartirla con Bob, de forma que pueda descargar el objeto sin necesidad de acceder a las credenciales de Alice.

## Conceptos básicos sobre la firma previa
<a name="presign-requests-basics"></a>

El SDK para Kotlin proporciona métodos de extensión para que los clientes del servicio firmen previamente las solicitudes. Todas las solicitudes prefirmadas requieren una duración que representa el tiempo de validez de la solicitud firmada. Una vez finalizada la duración, la solicitud prefirmada caduca y, si se ejecuta, genera un error de autenticación.

El código siguiente muestra un ejemplo que crea una `GetObject` solicitud prefirmada para Amazon S3. La solicitud es válida durante 24 horas después de su creación.

```
val s3 = S3Client.fromEnvironment()

val unsignedRequest = GetObjectRequest {
    bucket = "foo"
    key = "bar"
}

val presignedRequest = s3.presignGetObject(unsignedRequest, 24.hours)
```

El método [https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.presigners/presign-get-object.html](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.presigners/presign-get-object.html)de extensión devuelve un [https://docs.aws.amazon.com/smithy-kotlin/api/latest/http/aws.smithy.kotlin.runtime.http.request/-http-request/index.html](https://docs.aws.amazon.com/smithy-kotlin/api/latest/http/aws.smithy.kotlin.runtime.http.request/-http-request/index.html)objeto. El objeto de solicitud contiene la URL prefirmada donde se puede invocar la operación. Otra persona que llame puede usar la URL (o toda la solicitud) en una base de código o entorno de lenguaje de programación diferente.

Tras crear la solicitud prefirmada, utilice un cliente HTTP para invocarla. La API para invocar una solicitud HTTP GET depende del cliente HTTP. En el siguiente ejemplo, se utiliza el método Kotlin [https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.net.-u-r-l/read-text.html](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.net.-u-r-l/read-text.html).

```
val objectContents = URL(presignedRequest.url.toString()).readText()
println(objectContents)
```

## Configuración avanzada de prefirma
<a name="presign-requests-conf-advanced"></a>

En el SDK, cada método que puede prefirmar las solicitudes tiene una sobrecarga que puede utilizar para proporcionar opciones de configuración avanzadas, como la implementación de un firmante específico o parámetros de firma detallados.

El siguiente ejemplo muestra una `GetObject` solicitud de Amazon S3 que utiliza la variante de firmante CRT y especifica una fecha de firma futura.

```
val s3 = S3Client.fromEnvironment()

val unsignedRequest = GetObjectRequest {
    bucket = "foo"
    key = "bar"
}

val presignedRequest = s3.presignGetObject(unsignedRequest, signer = CrtAwsSigner) {
    signingDate = Instant.now() + 24.hours
    expiresAfter = 8.hours
}
```

La solicitud prefirmada devuelta tiene una fecha de reenvío de 24 horas y no es válida antes de esa fecha. Expira 8 horas después.

## Prefirmar las solicitudes POST y PUT
<a name="presign-requests-post-put"></a>

Muchas operaciones que se pueden prefirmar solo requieren una URL y deben ejecutarse como solicitudes HTTP GET. Sin embargo, algunas operaciones ocupan un cuerpo y, en algunos casos, deben ejecutarse como una solicitud HTTP POST o HTTP PUT junto con encabezados. Prefirmar estas solicitudes es idéntico a prefirmar las solicitudes GET, pero invocar la solicitud prefirmada es más complicado.

Este es un ejemplo de prefirma de una solicitud de S3: `PutObject`

```
val s3 = S3Client.fromEnvironment()

val unsignedRequest = PutObjectRequest {
    bucket = "foo"
    key = "bar"
}

val presignedRequest = s3.presignPutObject(unsignedRequest, 24.hours)
```

El valor devuelto `HttpRequest` tiene un valor de método de `HttpMethod.PUT` e incluye una URL y encabezados que deben incluirse en la futura invocación de la solicitud HTTP. Puede pasar esta solicitud a la persona que llama para que la ejecute en una base de código o entorno de lenguaje de programación diferente.

Después de crear la solicitud POST o PUT prefirmada, usa un cliente HTTP para invocar una solicitud. La API para invocar una URL de solicitud POST o PUT depende del cliente HTTP utilizado. El siguiente ejemplo usa un [cliente OkHttp HTTP](https://square.github.io/okhttp) e incluye un cuerpo que contiene`Hello world`.

```
val putRequest = Request
    .Builder()
    .url(presignedRequest.url.toString())
    .apply {
        presignedRequest.headers.forEach { key, values ->
            header(key, values.joinToString(", "))
        }
    }
    .put("Hello world".toRequestBody())
    .build()

val response = okHttp.newCall(putRequest).execute()
```

## Operaciones que el SDK puede prefirmar
<a name="presign-ops-supported"></a>

Actualmente, el SDK para Kotlin admite la prefirma de las siguientes operaciones de API a las que es necesario llamar con el método HTTP asociado.


| Servicio de AWS | Operación | Método de extensión del SDK | Utilice el método HTTP | 
| --- | --- | --- | --- | 
| Amazon S3 | GetObject | [presignGetObject](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.presigners/presign-get-object.html) |  HTTP GET  | 
| Amazon S3 | PutObject | [presignPutObject](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.presigners/presign-put-object.html) |  HTTP PUT  | 
| Amazon S3 | UploadPart |  [presignUploadPart](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/s3/aws.sdk.kotlin.services.s3.presigners/presign-upload-part.html)  |  HTTP PUT  | 
| AWS Security Token Service | GetCallerIdentity |  [presignGetCallerIdentidad](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/sts/aws.sdk.kotlin.services.sts.presigners/presign-get-caller-identity.html)  |  PUBLICACIÓN HTTP  | 
| Amazon Polly | SynthesizeSpeech |  [presignSynthesizeSpeech](https://docs.aws.amazon.com/sdk-for-kotlin/api/latest/polly/aws.sdk.kotlin.services.polly.presigners/presign-synthesize-speech.html)  |  PUBLICACIÓN HTTP  | 

# Solución de problemas FAQs
<a name="troubleshooting-faqs"></a>

A medida que lo utilice AWS SDK para Kotlin en sus aplicaciones, es posible que encuentre algunos de los problemas enumerados en este tema. Utilice las siguientes sugerencias para ayudar a descubrir la causa raíz y resolver el error.

## ¿Cómo soluciono los problemas de «conexión cerrada»?
<a name="ts-faq-connection-closed"></a>

Es posible que se produzcan problemas de «conexión cerrada» como excepciones, como alguno de los siguientes tipos: 
+ `IOException: unexpected end of stream on <URL>`
+ `EOFException: \n not found: limit=0`
+ `HttpException: AWS_ERROR_HTTP_CONNECTION_CLOSED: The connection has closed or is closing.; crtErrorCode=2058; HttpErrorCode(CONNECTION_CLOSED)`

Estas excepciones indican que una conexión TCP del SDK a un servicio se cerró o restableció inesperadamente. Es posible que el host, el AWS servicio o un intermediario, como una puerta de enlace NAT, un proxy o un balanceador de carga, hayan cerrado la conexión.

Estos tipos de excepciones se vuelven a intentar automáticamente, pero es posible que sigan apareciendo en los registros del SDK, según la configuración de registro. Si incluyes la excepción en tu código, esto indica que la estrategia de reintentos activa ha agotado los límites configurados, como el número máximo de intentos o el número de reintentos. Consulta la [Se vuelve a intentar en AWS SDK para Kotlin](retries.md) sección de esta guía para obtener más información sobre las estrategias de reintentos. Véase también [¿Por qué se lanzan las excepciones antes de alcanzar el número máximo de intentos?](#ts-faq-exceptions-before-max).

### Supervisión de conexiones inactivas con el OkHttpEngine
<a name="ts-faq-connection-closed-okhttp"></a>

Si utilizas las `IOException: unexpected end of stream on <URL>` excepciones `OkHttpEngine` y las encuentras con frecuencia, [considera habilitar la supervisión de las conexiones inactivas](http-client-config.md#http-idle-connection-monitoring). Esta función detecta si los servidores remotos tienen conexiones cerradas que aún se encuentran en el grupo de conexiones, lo que puede reducir la aparición de estas excepciones.

## ¿Por qué se lanzan las excepciones antes de alcanzar el número máximo de intentos?
<a name="ts-faq-exceptions-before-max"></a>

A veces, es posible que veas excepciones que esperabas que se volvieran a intentar, pero que en su lugar se han lanzado. En estas situaciones, los siguientes pasos pueden ayudar a resolver el problema.
+ **Compruebe que la excepción se puede volver a intentar.** Algunas excepciones no se pueden volver a intentar, como las que indican una solicitud de servicio con un formato incorrecto, falta de permisos o recursos inexistentes, por ejemplo. El SDK no vuelve a intentar automáticamente este tipo de excepciones. Para obtener información sobre cómo comprobar si hay excepciones que se puedan volver a intentar, consulte. [Comprueba si una excepción se puede volver a intentar](retries.md#retries-check-exception-retryable)
+ **Compruebe que la excepción esté incluida en el código.** Algunas excepciones aparecen en los mensajes de registro como información, pero en realidad no se incluyen en el código. Por ejemplo, las excepciones que se pueden volver a intentar, como los errores de limitación, pueden registrarse, ya que el SDK funciona automáticamente durante varios ciclos. backoff-and-retry La invocación de una operación del SDK genera una excepción solo si no se ha gestionado con los ajustes de reintento configurados.
+ **Verifica los ajustes de reintento configurados.** Consulte la [Se vuelve a intentar en AWS SDK para Kotlin](retries.md) sección de esta guía para obtener más información sobre las estrategias y políticas de reintentos. Asegúrese de que el código utilice la configuración esperada o los valores predeterminados automáticos.
+ **Considera la posibilidad de ajustar la configuración de reintentos.** Tras comprobar los elementos anteriores, pero el problema no se haya resuelto, podría plantearse ajustar la configuración de los reintentos.
  + **Aumente el número máximo de intentos.** De forma predeterminada, el número máximo de intentos de una operación es 3. Si considera que esto no es suficiente y se siguen produciendo excepciones con la configuración predeterminada, considere la posibilidad de aumentar la `retryStrategy.maxAttempts` propiedad en la configuración del cliente. Para obtener más información, consulte [Configura el número máximo de intentos](retries.md#retires-max-attempts).
  + **Aumente la configuración de retardo.** Es posible que algunas excepciones se vuelvan a intentar con demasiada rapidez antes de que la afección subyacente haya tenido la oportunidad de resolverse. Si sospecha que es así, considere la posibilidad de aumentar las `retryStrategy.delayProvider.maxBackoff` propiedades `retryStrategy.delayProvider.initialDelay` o en la configuración de su cliente. Para obtener más información, consulte [Configure los retrasos y los retrasos](retries.md#retries-delays-backoff).
  + **Desactive el modo de disyuntor.** De forma predeterminada, el SDK mantiene un conjunto de fichas para cada cliente de servicio. Cuando el SDK intenta realizar una solicitud y se produce un error con una excepción que se puede volver a intentar, el recuento de fichas disminuye; cuando la solicitud es correcta, el recuento de fichas aumenta. 

    De forma predeterminada, si este depósito de fichas alcanza los 0 fichas restantes, el circuito se interrumpe. Cuando se interrumpe el circuito, el SDK deshabilita los reintentos y cualquier solicitud actual o posterior que falle en el primer intento genera inmediatamente una excepción. El SDK vuelve a habilitar los reintentos después de que los intentos iniciales exitosos devuelvan suficiente capacidad al depósito de fichas. Este comportamiento es intencional y está diseñado para evitar una gran cantidad de reintentos durante las interrupciones del servicio y la recuperación del servicio.

    Si prefiere que el SDK siga reintentándolo hasta alcanzar el máximo de intentos configurados, considere la posibilidad de deshabilitar el modo de disyuntor estableciendo la `retryStrategy.tokenBucket.useCircuitBreakerMode` propiedad en false en la configuración de su cliente. Con esta propiedad establecida en false, el cliente del SDK espera a que el depósito de fichas alcance la capacidad suficiente en lugar de abandonar los reintentos posteriores, lo que podría provocar una excepción cuando queden 0 fichas.

## ¿Cómo puedo corregir `NoSuchMethodError` o? NoClassDefFoundError
<a name="ts-faq-nusuchmethod"></a>

Por lo general, estos errores se deben a dependencias faltantes o conflictivas. Para obtener más información, consulte [¿Cómo resuelvo los conflictos de dependencia?](ts-faq-dep-conflict-resolution.md).

### Veo un formulario `NoClassDefFoundError` `okhttp3/coroutines/ExecuteAsyncKt`
<a name="ts-faq-nusuchmethod-okhttp"></a>

Esto indica un problema de dependencia OkHttp específicamente. Para obtener más información, consulte [Resolver conflictos de OkHttp versiones en la aplicación](ts-faq-dep-conflict-resolution.md#okhttp-dep-conflicts).

# ¿Cómo resuelvo los conflictos de dependencia?
<a name="ts-faq-dep-conflict-resolution"></a>

Cuando lo usa AWS SDK para Kotlin, necesita dependencias determinadas AWS y de terceros para funcionar correctamente. Si faltan estas dependencias o aparecen versiones inesperadas en tiempo de ejecución, es posible que veas errores como `NoSuchMethodError` o. `NoClassDefFoundError` Estos problemas de dependencia suelen clasificarse en dos grupos:
+ Conflictos de dependencia entre SDK/Smithy
+ Conflictos de dependencia de terceros

Cuando compiles tu aplicación de Kotlin, es probable que utilices Gradle para administrar las dependencias. Si agregas una dependencia de un cliente de servicio del SDK a tu proyecto, se incluyen automáticamente todas las dependencias relacionadas necesarias. Sin embargo, si tu aplicación tiene otras dependencias, es posible que entren en conflicto con las que requiere el SDK. Por ejemplo, el SDK se basa en OkHttp un popular cliente HTTP que también podría utilizar tu aplicación. Para ayudarte a detectar estos conflictos, Gradle ofrece una práctica tarea en la que se enumeran las dependencias de tu proyecto:

```
./gradlew dependencies
```

Cuando te encuentres con conflictos de dependencia, es posible que tengas que tomar medidas. Puedes especificar una versión concreta de una dependencia o ocultar dependencias en un espacio de nombres local. *La resolución de dependencias de Gradle es un tema complejo que se analiza en las siguientes secciones del manual del usuario de Gradle:*
+ [Entender la resolución de dependencias](https://docs.gradle.org/current/userguide/dependency_resolution.html)
+ [Restricciones de dependencia y resolución de conflictos](https://docs.gradle.org/current/userguide/dependency_constraints_conflicts.html)
+ [Alineación de las versiones de dependencia](https://docs.gradle.org/current/userguide/dependency_version_alignment.html)

## Administrar las dependencias del SDK y Smithy en tu proyecto
<a name="sdk-smithy-dep-conflicts"></a>

Cuando utilices el SDK, ten en cuenta que sus módulos suelen depender de otros módulos del SDK con números de versión coincidentes. Por ejemplo, `aws.sdk.kotlin:s3:1.2.3` depende de`ws.sdk.kotlin:aws-http:1.2.3`, que depende de`aws.sdk.kotlin:aws-core:1.2.3`, y así sucesivamente.

Los módulos del SDK también utilizan versiones específicas del módulo Smithy. Si bien las versiones de los módulos de Smithy no se sincronizan con los números de versión del SDK, deben coincidir con la versión prevista del SDK. Por ejemplo, `aws.sdk.kotlin:s3:1.2.3` puede depender de`aws.smithy.kotlin:serde:1.1.1`, de qué depende`aws.smithy.kotlin:runtime-core:1.1.1`, etc.

Para evitar conflictos de dependencias, actualiza todas las dependencias del SDK a la vez y haz lo mismo con cualquier dependencia explícita de Smithy. Considera la posibilidad de usar nuestro [catálogo de versiones de Gradle](setup-create-project-file.md) para mantener las versiones sincronizadas y eliminar las conjeturas a la hora de mapear entre las versiones del SDK y de Smithy.

[Recuerda que las actualizaciones menores de las versiones de SDK/Smithy los módulos pueden incluir cambios importantes, tal y como se describe en nuestra política de control de versiones.](https://github.com/awslabs/aws-sdk-kotlin/blob/main/VERSIONING.md#versioning-policy) Al actualizar entre versiones secundarias, revise detenidamente los registros de cambios y compruebe minuciosamente el comportamiento en tiempo de ejecución.

## Resolver conflictos de OkHttp versiones en la aplicación
<a name="okhttp-dep-conflicts"></a>

[OkHttp](https://square.github.io/okhttp/)es un popular motor HTTP que el SDK utiliza de forma predeterminada en la JVM. La aplicación puede incluir otras dependencias o marcos que incluyan una versión diferente OkHttp . Esto puede provocar que aparezcan `NoClassDefFoundError` clases en el espacio de `okhttp3` nombres, como o. `okhttp/coroutines/ExecuteAsyncKt` `okhttp3/ConnectionListener` Cuando esto sucede, por lo general, debe elegir la versión más reciente para resolver los conflictos. Para ayudarte a rastrear las fuentes de estos conflictos, Gradle ofrece una tarea útil. Para hacer una lista de todas las dependencias, ejecuta lo siguiente:

```
./gradlew dependencies
```

Por ejemplo, si el SDK depende OkHttp `5.0.0-alpha.14` de otra dependencia, como Spring Boot OkHttp `4.12.0`, entonces debes usar el`5.0.0-alpha.14 version`. Puedes hacerlo con un `constraints` bloque en Gradle:

```
dependencies {
    constraints {
        implementation("com.squareup.okhttp3:okhttp:4.12.0")
    }
}
```

Como alternativa, si debes usar la versión OkHttp 4.x, el SDK proporciona una. `OkHttp4Engine` Consulta la [documentación](https://github.com/smithy-lang/smithy-kotlin/tree/main/runtime/protocol/http-client-engines/http-client-engine-okhttp4) para obtener información sobre cómo configurar Gradle y usarlo `OkHttp4Engine` en tu código.

# Burlándose en el AWS SDK para Kotlin
<a name="mocking"></a>

Los desarrolladores pueden usar varios marcos para realizar simulaciones en las pruebas con. AWS SDK para Kotlin Este tema documenta la configuración adicional o las consideraciones especiales que requieren algunos marcos.

## MockK
<a name="mockk-consideration"></a>

[Al simular funciones de extensión de todo el módulo con [MockK](https://mockk.io/), es necesario realizar una configuración adicional.](https://mockk.io/#extension-functions) En el SDK para Kotlin, los paginadores, los camareros y los prefirmantes son ejemplos de funciones de extensión, por lo que, si quieres burlarte de su comportamiento, necesitarás una configuración adicional.

Debes llamar antes de preparar tus simulacros. `mockkStatic("<MODULE_CLASS_NAME>")` Como regla general, los nombres de las clases de los módulos son: 
+ **Paginadores**: `aws.sdk.kotlin.services.<service>.paginators.PaginatorsKt`
+ **Camareros:** `aws.sdk.kotlin.services.<service>.waiters.WaitersKt`
+ **Prefirmantes**: `aws.sdk.kotlin.services.<service>.presigners.PresignersKt`

Por ejemplo, en la siguiente prueba, que incluye la simulación (una función de extensión del paginador`listBucketsPaginated`), añadimos: `mockkStatic("aws.sdk.kotlin.services.s3.paginators.PaginatorsKt")`

```
    @Test
    fun testPaginatedListBuckets() = runTest {

        mockkStatic("aws.sdk.kotlin.services.s3.paginators.PaginatorsKt")
        val s3Client: S3Client = mockk()
        val s3BucketLister = S3BucketLister(s3Client)

        val expectedBuckets = listOf(
            Bucket { name = "bucket1" },
            Bucket { name = "bucket2" }
        )

        val response = ListBucketsResponse { buckets = expectedBuckets }
        coEvery { s3Client.listBucketsPaginated() } returns flowOf(response)

        val result = s3BucketLister.getAllBucketNames()

        assertEquals(listOf("bucket1", "bucket2"), result)
    }
```

Sin ella, aparece `mockkStatic` el siguiente error:

```
Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
    at io.mockk.impl.recording.states.StubbingState.checkMissingCalls(StubbingState.kt:14)
    at io.mockk.impl.recording.states.StubbingState.recordingDone(StubbingState.kt:8)
    at io.mockk.impl.recording.CommonCallRecorder.done(CommonCallRecorder.kt:47)
    at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
    at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    at io.mockk.MockKDsl.internalCoEvery(API.kt:100)
    at io.mockk.MockKKt.coEvery(MockK.kt:174)
```

En el caso de una función de extensión de presigner sin ella`mockkStatic`, es posible que veas:

```
key is bound to the URI and must not be null
java.lang.IllegalArgumentException: key is bound to the URI and must not be null
    at aws.sdk.kotlin.services.s3.serde.GetObjectOperationSerializer.serialize(GetObjectOperationSerializer.kt:26)
    at aws.sdk.kotlin.services.s3.presigners.PresignersKt.presignGetObject(Presigners.kt:49)
    at aws.sdk.kotlin.services.s3.presigners.PresignersKt.presignGetObject$default(Presigners.kt:40)
    at aws.sdk.kotlin.services.s3.presigners.PresignersKt.presignGetObject-exY8QGI(Presigners.kt:30)
```

### Todos los artefactos de ejemplo
<a name="mockk-full-example"></a>

#### Código bajo prueba
<a name="mockk-example-code-under-test"></a>

```
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.paginators.listBucketsPaginated
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.runBlocking
import org.slf4j.Logger
import org.slf4j.LoggerFactory

fun main() {
    val logger: Logger = LoggerFactory.getLogger(::main.javaClass)

    // Create an S3Client
    S3Client { region = "us-east-1" }.use { s3Client ->
        // Create service instance
        val bucketLister = S3BucketLister(s3Client)
        // Since getAllBucketNames is a suspend function, you'll need to run it in a coroutine scope
        runBlocking {
            val bucketNames = bucketLister.getAllBucketNames()
            logger.info("Found buckets: $bucketNames")
        }
    }
}

class S3BucketLister(private val s3Client: S3Client) {
    suspend fun getAllBucketNames(): List<String> {
        return s3Client.listBucketsPaginated()
            .transform { response ->
                response.buckets?.forEach { bucket ->
                    emit(bucket.name ?: "")
                }
            }
            .filter { it.isNotEmpty() }
            .toList()
    }
}
```

#### Clase de prueba
<a name="mockk-example-test-code"></a>

```
import aws.sdk.kotlin.services.s3.S3Client
import aws.sdk.kotlin.services.s3.model.Bucket
import aws.sdk.kotlin.services.s3.model.ListBucketsResponse
import aws.sdk.kotlin.services.s3.paginators.listBucketsPaginated
import io.mockk.coEvery
import io.mockk.mockk
import io.mockk.mockkStatic
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class S3BucketListerTest {

    @Test
    fun testPaginatedListBuckets() = runTest {

        mockkStatic("aws.sdk.kotlin.services.s3.paginators.PaginatorsKt")
        val s3Client: S3Client = mockk()
        val s3BucketLister = S3BucketLister(s3Client)

        val expectedBuckets = listOf(
            Bucket { name = "bucket1" },
            Bucket { name = "bucket2" }
        )

        val response = ListBucketsResponse { buckets = expectedBuckets }
        coEvery { s3Client.listBucketsPaginated() } returns flowOf(response)

        val result = s3BucketLister.getAllBucketNames()

        assertEquals(listOf("bucket1", "bucket2"), result)
    }
}
```

#### build.gradle.kts
<a name="mockk-example-gradle-build"></a>

```
plugins {
    kotlin("jvm") version "2.1.20"
    application
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation(platform(awssdk.bom))
    implementation(platform("org.apache.logging.log4j:log4j-bom:2.24.3"))

    implementation(awssdk.services.s3)
    implementation("org.apache.logging.log4j:log4j-slf4j2-impl")

    // Testing Dependencies
    testImplementation(platform("org.junit:junit-bom:5.11.0"))
    testImplementation("org.junit.jupiter:junit-jupiter")
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
    testImplementation("io.mockk:mockk:1.14.0")
}

tasks.test {
    useJUnitPlatform()
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

application {
    mainClass = "org.example.S3BucketService"
}
```

#### settings.gradle.kts
<a name="mockk-example-settings-build"></a>

```
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0"
}
rootProject.name = "mockK-static"

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }

    versionCatalogs {
        create("awssdk") {
            from("aws.sdk.kotlin:version-catalog:1.4.69")
        }
    }
}
```