

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS SDK for Go 사용
<a name="using"></a>

애플리케이션에서 AWS SDK for Go를 사용하여 일반적으로 권장되는 프로그래밍 방법을 알아봅니다.

**Topics**
+ [서비스 클라이언트 구성](#constructing-a-service-client)
+ [서비스 작업 직접 호출](#calling-service-operations)
+ [서비스 클라이언트 동시 사용](#concurrently-using-service-clients)
+ [작업 페이지네이터 사용](#using-operation-paginators)
+ [웨이터 사용](#using-waiters)
+ [SDK에서 오류 처리](handle-errors.md)

## 서비스 클라이언트 구성
<a name="constructing-a-service-client"></a>

 서비스 클라이언트는 서비스 클라이언트의 Go 패키지에서 사용할 수 있는 `New` 또는 `NewFromConfig` 함수를 사용하여 구성할 수 있습니다. 각 함수는 서비스 API를 간접 호출하는 메서드가 포함된 `Client` 구조체 유형을 반환합니다. `New` 및 `NewFromConfig` 각각은 서비스 클라이언트를 구성하기 위해 동일한 구성 가능한 옵션 세트를 제공하지만, 다음 섹션에서 살펴볼 약간 다른 구성 패턴을 제공합니다.

### NewFromConfig
<a name="newfromconfig"></a>

 `NewFromConfig` 함수는 [aws.Config](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Config)를 사용하여 서비스 클라이언트를 구성하기 위한 일관된 인터페이스를 제공합니다. [config.LoadDefaultConfig](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#LoadDefaultConfig)를 사용하여 `aws.Config`를 로드할 수 있습니다. `aws.Config` 구성에 대한 자세한 내용은 [SDK 구성](configure-gosdk.md) 섹션을 참조하세요. 다음 예제에서는 `aws.Config` 및 `NewFromConfig` 함수를 사용하여 Amazon S3 서비스 클라이언트를 구성하는 방법을 보여줍니다.

```
import "context"
    import "github.com/aws/aws-sdk-go-v2/config"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        panic(err)
    }
    
    client := s3.NewFromConfig(cfg)
```

#### 구성 재정의
<a name="overriding-configuration"></a>

 `NewFromConfig`는 클라이언트의 구성 `Options` 구조를 변경할 수 있는 하나 이상의 기능적 인수를 취할 수 있습니다. 이렇게 하면 리전 변경 또는 Amazon S3 `UseAccelerate` 옵션과 같은 서비스별 옵션 수정과 같은 특정 재정의를 수행할 수 있습니다. 예: 

```
import "context"
    import "github.com/aws/aws-sdk-go-v2/config"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        panic(err)
    }
    
    client := s3.NewFromConfig(cfg, func(o *s3.Options) {
        o.Region = "us-west-2"
        o.UseAccelerate = true
    })
```

 클라이언트 `Options` 값에 대한 재정의는 함수 인수가 `NewFromConfig`에 부여되는 순서에 따라 결정됩니다.

### New
<a name="new"></a>

**참고**  
 `New`는 클라이언트 구성의 고급 형태로 간주됩니다. `aws.Config` 구조체를 사용하여 구성할 수 있으므로 클라이언트 구성에 `NewFromConfig`를 사용하는 것이 좋습니다. 이렇게 하면 애플리케이션에 필요한 각 서비스 클라이언트에 대한 `Options` 구조체 인스턴스를 구성할 필요가 없습니다.

 `New` 함수는 클라이언트의 구성 옵션을 정의하기 위한 클라이언트 패키지 `Options` 구조만 사용하여 클라이언트를 구성하기 위한 인터페이스를 제공하는 클라이언트 생성자입니다. 예를 들어 `New`를 사용하여 Amazon S3 클라이언트를 구성하려면 다음을 수행합니다.

```
import "github.com/aws/aws-sdk-go-v2/aws"
    import "github.com/aws/aws-sdk-go-v2/credentials"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    client := s3.New(s3.Options{
        Region:      "us-west-2",
        Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
    })
```

#### 구성 재정의
<a name="overriding-configuration-1"></a>

 `New`는 클라이언트의 구성 `Options` 구조를 변경할 수 있는 하나 이상의 기능적 인수를 취할 수 있습니다. 이렇게 하면 리전 변경 또는 Amazon S3 `UseAccelerate` 옵션과 같은 서비스별 옵션 수정과 같은 특정 재정의를 수행할 수 있습니다. 예: 

```
import "github.com/aws/aws-sdk-go-v2/aws"
    import "github.com/aws/aws-sdk-go-v2/credentials"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    options := s3.Options{
        Region:      "us-west-2",
        Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
    }
    
    client := s3.New(options, func(o *s3.Options) {
        o.Region = "us-east-1"
        o.UseAccelerate = true
    })
```

 클라이언트 `Options` 값에 대한 재정의는 함수 인수가 `New`에 부여되는 순서에 따라 결정됩니다.

## 서비스 작업 직접 호출
<a name="calling-service-operations"></a>

 서비스 클라이언트 인스턴스가 있으면 이를 사용하여 서비스 작업을 직접적으로 호출할 수 있습니다. 예를 들어 Amazon S3 `GetObject` 작업을 직접 호출하려면 다음을 수행합니다.

```
response, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("obj-key"),
    })
```

 서비스 작업을 직접 호출하면 SDK는 입력을 동기적으로 검증하고, 요청을 직렬화하고, 자격 증명으로 서명하여 AWS로 전송한 다음 응답 또는 오류를 역직렬화합니다. 대부분의 경우 서비스 작업을 직접 호출할 수 있습니다. 각 서비스 작업 클라이언트 메서드는 작업 응답 구조와 오류 인터페이스 유형을 반환합니다. 서비스 작업의 응답 구조에 액세스하기 전에 항상 `error` 유형을 확인하여 오류가 발생했는지 확인해야 합니다.

### 파라미터를 서비스 작업에 전달
<a name="passing-parameters-to-a-service-operation"></a>

 각 서비스 작업 메서드는 SDK에서 준수할 요청 기한을 설정하는 데 사용할 수 있는 [context.Context](https://golang.org/pkg/context/#Context) 값을 사용합니다. 또한 각 서비스 작업은 서비스의 해당 Go 패키지에 있는 `<OperationName>Input` 구조체를 사용합니다. 작업 입력 구조를 사용하여 API 입력 파라미터를 전달합니다.

 작업 입력 구조에는 표준 Go 숫자, 부울, 문자열, 맵 및 목록 유형과 같은 입력 파라미터가 있을 수 있습니다. 더 복잡한 API 작업에서는 서비스에 입력 파라미터 모델링이 더 복잡할 수 있습니다. 서비스별 구조 및 열거형 값과 같은 다른 유형은 서비스의 `types` Go 패키지에서 찾을 수 있습니다.

 또한 서비스는 Go 유형의 기본값과 사용자가 값을 설정했는지 여부를 구별할 수 있습니다. 이러한 경우 입력 파라미터를 사용하려면 해당 유형에 대한 포인터 참조를 전달해야 할 수 있습니다. 숫자, 부울 및 문자열과 같은 표준 Go 유형의 경우 이 변환을 용이하게 하기 위해 [aws](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws)에서 `<Type>` 및 `From<Type>` 편의 함수를 사용할 수 있습니다. 예를 들어 [aws.String](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#String)을 사용하여 `string`를 문자열에 대한 포인터가 필요한 입력 파라미터의 `*string` 유형으로 변환할 수 있습니다. 반대로 [aws.ToString](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#ToString)은 nil 포인터를 참조하지 않도록 보호하면서 `*string`을 `string`으로 변환하는 데 사용할 수 있습니다. `To<Type>` 함수는 서비스 응답을 처리할 때 유용합니다.

 Amazon S3 클라이언트를 사용하여 `GetObject` API를 직접 호출하고 `types` 패키지 및 `aws.<Type>` 헬퍼를 사용하여 입력을 구성하는 방법의 예를 살펴보겠습니다.

```
import "context"
    import "github.com/aws/aws-sdk-go-v2/config"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    import "github.com/aws/aws-sdk-go-v2/service/s3/types"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        panic(err)
    }
    
    client := s3.NewFromConfig(cfg)
    
    resp, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
        Bucket:       aws.String("amzn-s3-demo-bucket"),
        Key:          aws.String("keyName"),
        RequestPayer: types.RequestPayerRequester,
    })
```

### 작업 직접 호출을 위한 클라이언트 옵션 재정의
<a name="overriding-client-options"></a>

 기능 인수를 사용하여 클라이언트를 구성하는 동안 클라이언트 작업 옵션을 수정할 수 있는 방법과 마찬가지로, 서비스 작업 방법에 하나 이상의 기능 인수를 제공하여 작업 메서드를 직접 호출할 때 클라이언트 옵션을 수정할 수 있습니다. 이 작업은 동시성 면에서 안전하며 클라이언트의 다른 동시 작업에 영향을 주지 않습니다.

 예를 들어 클라이언트 리전을 ‘us-west-2’에서 ‘us-east-1’로 재정의하려면 다음을 수행합니다.

```
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-west-2"))
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := s3.NewFromConfig(cfg)
    
    params := &s3.GetObjectInput{
        // ...
    }
    
    resp, err := client.GetObject(context.TODO(), params, func(o *Options) {
        o.Region = "us-east-1"
    })
```

### 작업 응답 처리
<a name="handling-operation-responses"></a>

 각 서비스 작업에는 서비스의 작업 응답 멤버가 포함된 관련 출력 구조가 있습니다. 출력 구조는 다음 이름 지정 패턴 `<OperationName>Output`을 따릅니다. 일부 작업에는 작업 출력에 대해 정의된 멤버가 없을 수 있습니다. 서비스 작업을 직접 호출한 후에는 항상 반환 `error` 인수 유형을 확인하여 서비스 작업을 간접적으로 호출하는 동안 오류가 발생했는지 확인해야 합니다. 반환되는 오류는 클라이언트 측 입력 검증 오류부터 클라이언트에 반환되는 서비스 측 오류 응답까지 다양할 수 있습니다. 클라이언트가 nil이 아닌 오류를 반환하는 경우 작업의 출력 구조체에 액세스하면 안 됩니다.

 예를 들어 작업 오류를 로깅하고 직접 호출 함수에서 조기에 반환하려면 다음을 수행합니다.

```
response, err := client.GetObject(context.TODO())
    if err != nil {
        log.Printf("GetObject error: %v", err)
        return
    }
```

 특정 오류 유형을 검사하는 방법을 포함하여 오류 처리에 대한 자세한 내용은 TODO를 참조하세요.

#### `io.ReadCloser`를 사용한 응답
<a name="responses-with-ioreadcloser"></a>

 일부 API 작업은 `io.ReadCloser`인 출력 멤버가 포함된 응답 구조를 반환합니다. 이는 HTTP 응답 자체의 본문에 출력의 일부 요소를 노출하는 API 작업이 됩니다.

 예를 들어 Amazon S3 `GetObject` 작업은 `Body` 멤버가 객체 페이로드에 액세스하기 위한 `io.ReadCloser`인 응답을 반환합니다.

**주의**  
 콘텐츠를 사용했는지 여부에 관계없이 항상 모든 `io.ReadCloser` 출력 멤버를 `Close()`해야 합니다. 이렇게 하지 않으면 리소스가 유출되고 향후 직접 호출된 작업에 대한 응답 본문을 읽는 데 문제가 발생할 수 있습니다.

```
resp, err := s3svc.GetObject(context.TODO(), &s3.GetObjectInput{...})
    if err != nil {
        // handle error
        return
    }
    // Make sure to always close the response Body when finished
    defer resp.Body.Close()
    
    decoder := json.NewDecoder(resp.Body)
    if err := decoder.Decode(&myStruct); err != nil {
        // handle error
        return
    }
```

#### 응답 메타데이터
<a name="response-metadata"></a>

 모든 서비스 작업 출력 구조에는 [미들웨어.메타데이터](https://pkg.go.dev/github.com/aws/smithy-go/middleware#Metadata) 유형의 `ResultMetadata` 멤버가 포함됩니다. `middleware.Metadata`는 SDK 미들웨어에서 서비스에 의해 모델링되지 않은 서비스 응답의 추가 정보를 제공하는 데 사용됩니다. 여기에는 `RequestID`와 같은 메타데이터가 포함됩니다. 예를 들어, 서비스 응답과 연결된 `RequestID`를 검색하여 AWS Support가 요청 문제를 해결하는 데 도움이 되도록 하려면 다음을 수행합니다.

```
import "fmt"
    import "log"
    import "github.com/aws/aws-sdk-go-v2/aws/middleware"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ..
    
    resp, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
        // ...
    })
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    requestID, ok := middleware.GetRequestIDMetadata(resp.ResultMetadata)
    if !ok {
        fmt.Println("RequestID not included with request")
    }
    
    fmt.Printf("RequestID: %s\n", requestID)
```

## 서비스 클라이언트 동시 사용
<a name="concurrently-using-service-clients"></a>

 동일한 서비스 클라이언트를 동시에 사용하여 여러 요청을 보내는 고루틴을 만들 수 있습니다. 서비스 클라이언트를 원하는 수만큼의 고루틴과 함께 사용할 수 있습니다.

 다음 예제에서는 Amazon S3 서비스 클라이언트가 여러 고루틴에서 사용됩니다. 이 예제에서는 Amazon S3 버킷에 두 개의 객체를 동시에 업로드합니다.

```
import "context"
    import "log"
    import "strings"
    import "github.com/aws/aws-sdk-go-v2/config"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := s3.NewFromConfig(cfg)
    
    type result struct {
        Output *s3.PutObjectOutput
        Err    error
    }
    
    results := make(chan result, 2)
    
    var wg sync.WaitGroup
    wg.Add(2)
    
    go func() {
    defer wg.Done()
        output, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
            Bucket: aws.String("amzn-s3-demo-bucket"),
            Key:    aws.String("foo"),
            Body:   strings.NewReader("foo body content"),
        })
        results <- result{Output: output, Err: err}
    }()
    
    go func() {
        defer wg.Done()
        output, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
            Bucket: aws.String("amzn-s3-demo-bucket"),
            Key:    aws.String("bar"),
            Body:   strings.NewReader("bar body content"),
        })
        results <- result{Output: output, Err: err}
    }()
    
    wg.Wait()
    
    close(results)
    
    for result := range results {
        if result.Err != nil {
            log.Printf("error: %v", result.Err)
            continue
        }
        fmt.Printf("etag: %v", aws.ToString(result.Output.ETag))
    }
```

## 작업 페이지네이터 사용
<a name="using-operation-paginators"></a>

 일반적으로 항목 목록을 검색할 때 토큰 또는 마커의 출력 구조를 확인하여 AWS 서비스가 요청의 모든 결과를 반환했는지 확인해야 할 수 있습니다. 토큰 또는 마커가 있는 경우 이를 사용하여 결과의 다음 페이지를 요청합니다. 이러한 토큰 또는 마커를 관리하는 대신 서비스 패키지의 사용 가능한 페이지네이터 유형을 사용할 수 있습니다.

 페이지네이터 헬퍼는 지원되는 서비스 작업에 사용할 수 있으며 서비스 클라이언트의 Go 패키지에서 찾을 수 있습니다. 지원되는 작업에 대한 페이지네이터를 구성하려면 `New<OperationName>Paginator` 함수를 사용합니다. 페이지네이터 구성 함수는 서비스 `Client`, 작업의 `<OperationName>Input` 입력 파라미터 및 다른 선택적 페이지네이터 설정을 구성할 수 있는 선택적 기능 인수 세트를 사용합니다.

 반환된 작업 페이지네이터 유형은 마지막 페이지에 도달하거나 애플리케이션이 검색 중인 항목을 찾을 때까지 페이지가 지정된 작업을 반복할 수 있는 편리한 방법을 제공합니다. 페이지네이터 유형에는 `HasMorePages`와 `NextPage`의 두 가지 메서드가 있습니다. `HasMorePages`는 첫 번째 페이지를 검색하지 않았거나 작업을 사용하여 검색할 수 있는 추가 페이지가 있는 경우 `true`의 부울 값을 반환합니다. 작업의 첫 번째 또는 후속 페이지를 검색하려면 `NextPage` 작업을 직접 호출해야 합니다. `NextPage`는 `context.Context`를 가져오고 작업 출력과 해당 오류를 반환합니다. 클라이언트 작업 메서드 반환 파라미터와 마찬가지로 반환된 응답 구조를 사용하기 전에 항상 반환 오류를 확인해야 합니다. [작업 응답 처리](#handling-operation-responses)을(를) 참조하세요.

 다음 예제에서는 `ListObjectsV2` 페이지네이터를 사용하여 `ListObjectV2` 작업에서 최대 3페이지의 객체 키를 나열합니다. 각 페이지는 `Limit` 페이지네이터 옵션으로 정의되는 최대 10개의 키로 구성됩니다.

```
import "context"
    import "log"
    import "github.com/aws/aws-sdk-go-v2/config"
    import "github.com/aws/aws-sdk-go-v2/aws"
    import "github.com/aws/aws-sdk-go-v2/service/s3"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := s3.NewFromConfig(cfg)
    
    params := &s3.ListObjectsV2Input{
        Bucket: aws.String("amzn-s3-demo-bucket"),
    }
    
    paginator := s3.NewListObjectsV2Paginator(client, params, func(o *s3.ListObjectsV2PaginatorOptions) {
        o.Limit = 10
    })
    
    pageNum := 0
    for paginator.HasMorePages() && pageNum < 3 {
        output, err := paginator.NextPage(context.TODO())
        if err != nil {
            log.Printf("error: %v", err)
            return
        }
        for _, value := range output.Contents {
            fmt.Println(*value.Key)
        }
        pageNum++
    }
```

 클라이언트 작업 메서드와 마찬가지로 `NextPage`에 하나 이상의 기능적 인수를 제공하여 요청 리전과 같은 클라이언트 옵션을 수정할 수 있습니다. 작업을 직접 호출할 때 클라이언트 옵션을 재정의하는 방법에 대한 자세한 내용은 [작업 직접 호출을 위한 클라이언트 옵션 재정의](#overriding-client-options) 섹션을 참조하세요.

## 웨이터 사용
<a name="using-waiters"></a>

 비동기식 AWS API와 상호 작용하는 경우에는 특정 리소스를 사용할 수 있을 때까지 기다려야 추가 작업을 수행할 수 있습니다.

 예를 들어 Amazon DynamoDB `CreateTable` API는 CREATING의 TableStatus를 즉시 반환하며 테이블 상태가 `ACTIVE`로 전환될 때까지 읽기 또는 쓰기 작업을 간접 호출할 수 없습니다.

 테이블 상태를 지속적으로 폴링하는 로직을 작성하는 것은 번거로우며 오류가 발생하기 쉽습니다. 웨이터는 복잡성을 없애는 데 도움이 되며 폴링 작업을 처리하는 간단한 API입니다.

 예를 들어, 웨이터를 사용하여 DynamoDB 테이블이 생성되었고 쓰기 작업을 수행할 준비가 되었는지 폴링할 수 있습니다.

```
import "context"
    import "fmt"
    import "log"
    import "time"
    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/dynamodb"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := dynamodb.NewFromConfig(cfg)
    
    // we create a waiter instance by directly passing in a client
    // that satisfies the waiters client Interface. 
    waiter :=  dynamodb.NewTableExistsWaiter(client)
    
    // params is the input to api operation used by the waiter
    params := &dynamodb.DescribeTableInput {
        TableName: aws.String("test-table")
    }
    
    // maxWaitTime is the maximum wait time, the waiter will wait for 
    // the resource status.
    maxWaitTime := 5 * time.Minutes
    
    // Wait will poll until it gets the resource status, or max wait time 
    // expires.
    err := waiter.Wait(context.TODO(), params, maxWaitTime)  
    if err != nil {
        log.Printf("error: %v", err)
        return 
    }
    fmt.Println("Dynamodb table is now ready for write operations")
```

### 웨이터 구성 재정의
<a name="overriding-waiter-configuration"></a>

 기본적으로 SDK는 다양한 API에 대해 AWS 서비스에서 정의한 최적의 값으로 구성된 최소 지연 및 최대 지연 값을 사용합니다. 웨이터 구성 중에 또는 웨이터 작업을 간접 호출할 때 기능 옵션을 제공하여 웨이터 구성을 재정의할 수 있습니다.

 예를 들어, 웨이터 구성 중에 웨이터 구성을 재정의하려면 

```
import "context"
    import "fmt"
    import "log"
    import "time"
    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/dynamodb"
    
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := dynamodb.NewFromConfig(cfg)
    
    // we create a waiter instance by directly passing in a client
    // that satisfies the waiters client Interface. 
    waiter :=  dynamodb.NewTableExistsWaiter(client, func (o *dynamodb.TableExistsWaiterOptions) {
        
        // override minimum delay to 10 seconds
        o.MinDelay = 10 * time.Second
        
        // override maximum default delay to 300 seconds
        o.MaxDelay = 300 * time.Second
    })
```

각 웨이터의 `Wait` 함수는 기능 옵션도 사용합니다. 위 예제와 마찬가지로 `Wait` 요청당 웨이터 구성을 재정의할 수 있습니다.

```
// params is the input to api operation used by the waiter
    params := &dynamodb.DescribeTableInput {
        TableName: aws.String("test-table")
    }
    
    // maxWaitTime is the maximum wait time, the waiter will wait for 
    // the resource status.
    maxWaitTime := 5 * time.Minutes
    
    // Wait will poll until it gets the resource status, or max wait time 
    // expires.
    err := waiter.Wait(context.TODO(), params, maxWaitTime, func (o *dynamodb.TableExistsWaiterOptions) {
    
        // override minimum delay to 5 seconds
        o.MinDelay = 5 * time.Second
    
        // override maximum default delay to 120 seconds
        o.MaxDelay = 120 * time.Second
    })
    if err != nil {
        log.Printf("error: %v", err)
        return 
    }
    fmt.Println("Dynamodb table is now ready for write operations")
```

### 고급 웨이터 구성 재정의
<a name="advanced-waiter-configuration-overrides"></a>

 사용자 지정 재시도 가능 함수를 제공하여 웨이터 기본 동작을 추가로 사용자 지정할 수 있습니다. 웨이터별 옵션은 [작업 미들웨어를 사용자 지정](middleware.md#writing-a-custom-middleware)하기 위한 `APIOptions`도 제공합니다.

 예를 들어 고급 웨이터 재정의를 구성합니다.

```
import "context"
    import "fmt"
    import "log"
    import "time"
    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/dynamodb"
    import "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
    // ...
    
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Printf("error: %v", err)
        return
    }
    
    client := dynamodb.NewFromConfig(cfg)
    
    // custom retryable defines if a waiter state is retryable or a terminal state.
    // For example purposes, we will configure the waiter to not wait 
    // if table status is returned as `UPDATING`
    customRetryable := func(ctx context.Context, params *dynamodb.DescribeTableInput, 
        output *dynamodb.DescribeTableOutput, err error) (bool, error) {
        if output.Table != nil {
            if output.Table.TableStatus == types.TableStatusUpdating {
                // if table status is `UPDATING`, no need to wait
                return false, nil   
            }
        }
    }
    
    // we create a waiter instance by directly passing in a client
    // that satisfies the waiters client Interface. 
    waiter :=  dynamodb.NewTableExistsWaiter(client, func (o *dynamodb.TableExistsWaiterOptions) {
        
        // override the service defined waiter-behavior
        o.Retryable = customRetryable
    })
```

# AWS SDK for Go V2에서 오류 처리
<a name="handle-errors"></a>

 AWS SDK for Go는 Go `error` 인터페이스 유형을 충족하는 오류를 반환합니다. `Error()` 메서드를 사용하여 특별한 처리 없이 SDK 오류 메시지의 형식이 지정된 문자열을 가져올 수 있습니다. SDK에서 반환한 오류는 `Unwrap` 메서드를 구현할 수 있습니다. SDK는 이 `Unwrap` 메서드를 사용하여 오류에 대한 추가 컨텍스트 정보를 제공하는 동시에 기본 오류 또는 오류 체인에 대한 액세스를 제공합니다. 언래핑 오류 체인을 처리하려면 `Unwrap` 메서드를 [errors.As](https://golang.org/pkg/errors#As)와 함께 사용해야 합니다.

 애플리케이션이 `error` 인터페이스 유형을 반환할 수 있는 함수 또는 메서드를 간접 호출한 후 오류가 발생했는지 확인하는 것이 중요합니다. 오류 처리의 가장 기본적인 형태는 다음 예와 유사합니다.

```
if err != nil {
    // Handle error
    return
}
```

## 오류 로깅
<a name="logging-errors"></a>

 가장 간단한 형태의 오류 처리는 일반적으로 애플리케이션을 반환하거나 종료하기 전에 오류 메시지를 로깅하거나 인쇄하는 것입니다.

```
import "log"

// ...

if err != nil {
    log.Printf("error: %s", err.Error())
    return
}
```

## 서비스 클라이언트 오류
<a name="service-client-errors"></a>

 SDK는 서비스 클라이언트가 반환한 모든 오류를 [smithy.OperationError](https://pkg.go.dev/github.com/aws/smithy-go#OperationError) 오류 유형으로 래핑합니다. `OperationError`는 기본 오류와 연결된 서비스 이름 및 작업에 대한 컨텍스트 정보를 제공합니다. 이 정보는 중앙 집중식 오류 처리 메커니즘을 사용하여 하나 이상의 서비스에 대해 작업 배치를 수행하는 애플리케이션에 유용할 수 있습니다. 애플리케이션은 `errors.As`를 사용하여 이 `OperationError` 메타데이터에 액세스할 수 있습니다.

```
import "log"
import "github.com/aws/smithy-go"

// ...

if err != nil {
    var oe *smithy.OperationError
    if errors.As(err, &oe) {
        log.Printf("failed to call service: %s, operation: %s, error: %v", oe.Service(), oe.Operation(), oe.Unwrap())
    }
    return
}
```

### API 오류 응답
<a name="api-error-responses"></a>

 서비스 작업은 모델링된 오류 유형을 반환하여 특정 오류를 나타낼 수 있습니다. 이러한 모델링된 유형을 `errors.As`와 함께 사용하여 언래핑하고 작업 실패가 특정 오류로 인한 것인지 확인할 수 있습니다. 예를 들어 동일한 이름의 버킷이 이미 있는 경우 Amazon S3 `CreateBucket`에서 [BucketAlreadyExists](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#BucketAlreadyExists) 오류를 반환할 수 있습니다.

 예를 들어 `BucketAlreadyExists` 오류가 오류인지 확인하려면 다음을 수행합니다.

```
import "log"
import "github.com/aws/aws-sdk-go-v2/service/s3/types"

// ...

if err != nil {
    var bne *types.BucketAlreadyExists
    if errors.As(err, &bne) {
        log.Println("error:", bne)
    }
    return
}
```

 모든 서비스 API 응답 오류는 [smithy.APIError](https://pkg.go.dev/github.com/aws/smithy-go/#APIError) 인터페이스 유형을 구현합니다. 이 인터페이스는 모델링된 서비스 오류 응답과 모델링되지 않은 서비스 오류 응답을 모두 처리하는 데 사용할 수 있습니다. 이 유형은 서비스에서 반환한 오류 코드 및 메시지에 대한 액세스를 제공합니다. 또한 이 유형은 오류의 결함이 알려진 경우 클라이언트 또는 서버로 인한 것인지 여부를 나타냅니다.

```
import "log"
import "github.com/aws/smithy-go"

// ...

if err != nil {
    var ae smithy.APIError
    if errors.As(err, &ae) {
        log.Printf("code: %s, message: %s, fault: %s", ae.ErrorCode(), ae.ErrorMessage(), ae.ErrorFault().String())
    }
    return
}
```

## 요청 식별자 검색
<a name="retrieving-request-identifiers"></a>

 AWS Support에서 작업할 때 문제를 해결하려는 요청을 식별하는 요청 식별자를 제공하라는 메시지가 표시될 수 있습니다. [http.ResponseError](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/transport/http#ResponseError)를 사용하고 `ServiceRequestID()` 메서드를 사용하여 오류 응답과 연결된 요청 식별자를 검색할 수 있습니다.

```
import "log"
import awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"

// ...

if err != nil {
    var re *awshttp.ResponseError
    if errors.As(err, &re) {
        log.Printf("requestID: %s, error: %v", re.ServiceRequestID(), re.Unwrap());
    }
    return
}
```

### Amazon S3 요청 식별자
<a name="s3-request-identifiers"></a>

 Amazon S3 요청에는 AWS Support에서 요청 문제 해결을 지원하는 데 사용할 수 있는 추가 식별자가 포함되어 있습니다. [s3.ResponseError](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#ResponseError)를 사용하고 `ServiceRequestID()` 및 `ServiceHostID()`를 직접 호출하여 요청 ID와 호스트 ID를 검색할 수 있습니다.

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

// ...

if err != nil {
    var re s3.ResponseError
    if errors.As(err, &re) {
        log.Printf("requestID: %s, hostID: %s request failure", re.ServiceRequestID(), re.ServiceHostID());
    }
    return
}
```