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á.
Como usar o AWS SDK para Go
Aprenda maneiras comuns e recomendadas de programar com o AWS SDK para Go em suas aplicações.
Tópicos
Construir um cliente de serviço
Os clientes de serviço podem ser construídos usando as funções New ou NewFromConfig disponíveis no pacote Go do cliente de serviço. Cada função retornará um tipo de estrutura Client contendo os métodos para invocar as APIs de serviço. New e NewFromConfig fornecem o mesmo conjunto de opções configuráveis para construir um cliente de serviço, mas fornecem padrões de construção ligeiramente diferentes, que veremos nas seções a seguir.
NewFromConfig
A função NewFromConfig fornece uma interface consistente para construir clientes de serviço usando o aws.Configaws.Config pode ser carregado usando config.LoadDefaultConfigaws.Config em Configurar o SDK. O exemplo a seguir mostra como construir um cliente de serviço do Amazon S3 usando a função aws.Config e NewFromConfig:
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)
Substituição de configuração
NewFromConfig pode usar um ou mais argumentos funcionais que podem alterar a estrutura Options de configuração de um cliente. Isso permite fazer substituições específicas, como alterar a região ou modificar opções específicas do serviço, como a opção UseAccelerate do Amazon S3. Por exemplo:
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 })
As substituições no valor Options do cliente são determinadas pela ordem em que os argumentos funcionais são fornecidos para NewFromConfig.
Novo
nota
New é considerada uma forma mais avançada de construção de clientes. Recomendamos que você use NewFromConfig para a construção do cliente, já que assim é possível fazer a construção usando a estrutura aws.Config. Isso elimina a necessidade de construir uma instância de estrutura Options para cada cliente de serviço que a aplicação exige.
A função New é um construtor de cliente que fornece uma interface para construir clientes usando somente a estrutura Options de pacotes do cliente para definir as opções de configuração do cliente. Por exemplo, para construir um cliente do Amazon S3 usando New:
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, "")), })
Substituição de configuração
New pode usar um ou mais argumentos funcionais que podem alterar a estrutura Options de configuração de um cliente. Isso permite fazer substituições específicas, como alterar a região ou modificar opções específicas do serviço, como a opção UseAccelerate do Amazon S3. Por exemplo:
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 })
As substituições no valor Options do cliente são determinadas pela ordem em que os argumentos funcionais são fornecidos para New.
Como chamar operações de serviço
Depois de criar uma instância de cliente de serviço, você poderá usá-la para chamar operações de serviço. Por exemplo, para chamar a operação GetObject do Amazon S3:
response, err := client.GetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("obj-key"), })
Quando você chama uma operação de serviço, o SDK valida de forma síncrona a entrada, serializa a solicitação, a assina com suas credenciais, a envia para a AWS e, então, desserializa uma resposta ou um erro. Na maioria dos casos, você pode chamar operações de serviço diretamente. Cada método cliente da operação de serviço retornará uma estrutura de resposta da operação e um tipo de interface de erro. Você deve sempre verificar o tipo error para determinar se ocorreu um erro antes de tentar acessar a estrutura de resposta da operação de serviço.
Como passar parâmetros para uma operação de serviço
Cada método de operação de serviço usa um valor context.Context<OperationName>Input encontrada no respectivo pacote de Go do serviço. Você passa os parâmetros de entrada da API usando a estrutura de entrada da operação.
As estruturas de entrada de operação podem ter parâmetros de entrada, como os tipos padrão do Go de numéricos, boolianos, strings, mapas e listas. Em operações de API mais complexas, um serviço pode ter uma modelagem mais complexa dos parâmetros de entrada. Esses outros tipos, como estruturas específicas do serviço e valores de enumeração, são encontrados no pacote types de Go do serviço.
Além disso, os serviços podem distinguir entre o valor padrão de um tipo Go e se o valor foi definido ou não pelo usuário. Nesses casos, os parâmetros de entrada podem exigir que você passe uma referência de ponteiro para o tipo em questão. Para tipos padrão do Go, como numéricos, boolianos e strings, existem funções de conveniência <Type> e From<Type> disponíveis na AWSstring em *string para parâmetros de entrada que exigem um ponteiro para uma string. Inversamente, aws.ToString*string em string, oferecendo proteção contra a desreferência de um ponteiro nulo. As funções To<Type> são úteis ao lidar com as respostas de serviço.
Vamos ver um exemplo de como podemos usar um cliente do Amazon S3 para chamar a API GetObject e construir nossa entrada usando o pacote types e os auxiliares 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, })
Substituir as opções do cliente para a chamada de operação
Da mesma forma que as opções de operação do cliente podem ser modificadas durante a construção de um cliente usando argumentos funcionais, as opções do cliente podem ser modificadas no momento em que o método de operação é chamado, fornecendo um ou mais argumentos funcionais ao método de operação de serviço. Essa ação é segura para simultaneidade e não afeta outras operações simultâneas no cliente.
Por exemplo, para substituir a região “us-west-2” do cliente por “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" })
Como gerenciar respostas de operações
Cada operação de serviço tem uma estrutura de saída associada que contém os membros da resposta da operação do serviço. A estrutura de saída segue o seguinte padrão de nomenclatura <OperationName>Output. Algumas operações podem não ter membros definidos para a saída da operação. Depois de chamar uma operação de serviço, o tipo de argumento error de retorno deve sempre ser verificado para determinar se ocorreu um erro ao invocar a operação de serviço. Os erros retornados podem variar de erros de validação de entrada do lado do cliente até respostas de erro do lado do serviço retornadas ao cliente. A estrutura de saída da operação não deve ser acessada no caso de um erro diferente de nulo ser retornado pelo cliente.
Por exemplo, para registrar um erro de operação e retornar prematuramente da função de chamada:
response, err := client.GetObject(context.TODO()) if err != nil { log.Printf("GetObject error: %v", err) return }
Consulte mais informações sobre como lidar com erros, incluindo como inspecionar tipos de erro específicos em TODO
Respostas com io.ReadCloser
Algumas operações de API retornam uma estrutura de resposta que contém um membro de saída que é um io.ReadCloser. Esse é o caso das operações de API que expõem algum elemento de sua saída no corpo da própria resposta HTTP.
Por exemplo, a operação GetObject do Amazon S3 retorna uma resposta cujo membro Body é um io.ReadCloser para acessar a carga útil do objeto.
Atenção
Você DEVE SEMPRE Close() qualquer membro de saída io.ReadCloser, independentemente de ter consumido ou não seu conteúdo. A falha em fazer isso pode causar vazamento de recursos e gerar problemas ao ler corpos de resposta em operações que forem chamadas no futuro.
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 }
Metadados de resposta
Todas as estruturas de saída da operação de serviço incluem um membro ResultMetadata do tipo middleware.Metadatamiddleware.Metadata é usado pelo middleware do SDK para fornecer mais informações de uma resposta de serviço que não é modelada pelo serviço. Isso inclui metadados como RequestID. Por exemplo, para recuperar o RequestID associado a uma resposta de serviço para ajudar o AWS Support a solucionar uma solicitação:
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)
Usar clientes de serviço simultaneamente
Você pode criar goroutines que usam simultaneamente o mesmo cliente de serviço para enviar várias solicitações. É possível usar um cliente de serviço com quantas goroutines quiser.
No exemplo a seguir, um cliente de serviço do Amazon S3 é usado em várias goroutines. Esse exemplo faz upload simultaneamente de dois objetos em um bucket do 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)) }
Usar paginadores de operação
Normalmente, quando você recupera uma lista de itens, talvez seja necessário verificar a estrutura de saída em busca de um token ou marcador para confirmar se o serviço AWS retornou todos os resultados da solicitação. Caso o token ou marcador esteja presente, use-o para solicitar a próxima página de resultados. Em vez de gerenciar esses tokens ou marcadores, você pode usar os tipos de paginadores disponíveis no pacote de serviços.
Os auxiliares do paginador estão disponíveis para operações de serviço compatíveis e podem ser encontrados no pacote Go do cliente de serviço. Para construir um paginador para uma operação compatível, use a função New<OperationName>Paginator. As funções de construção do paginador usam o serviço Client, os parâmetros de entrada <OperationName>Input da operação e um conjunto opcional de argumentos funcionais, permitindo que você defina outras configurações opcionais do paginador.
O tipo de paginador de operação retornado fornece uma maneira conveniente de iterar sobre uma operação paginada até chegar à última página ou encontrar os itens que a aplicação estava procurando. Um tipo de paginador tem dois métodos: HasMorePages e NextPage. HasMorePages retornará um valor booliano de true se a primeira página não tiver sido recuperada ou se páginas adicionais estiverem disponíveis para recuperação usando a operação. Para recuperar a primeira página ou as páginas subsequentes da operação, a operação NextPage deve ser chamada. NextPage usa context.Context e retorna a saída da operação e qualquer erro correspondente. Assim como os parâmetros de retorno do método de operação do cliente, o erro de retorno sempre deve ser verificado antes de tentar usar a estrutura de resposta retornada. Consulte Como gerenciar respostas de operações.
O exemplo a seguir usa o paginador ListObjectsV2 para listar até três páginas de chaves de objeto da operação ListObjectV2. Cada página consiste em até 10 chaves, definidas pela opção Limit do paginador.
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++ }
Semelhante ao método de operação do cliente, as opções do cliente, como a região da solicitação, podem ser modificadas fornecendo um ou mais argumentos funcionais para NextPage. Consulte mais informações sobre como substituir as opções do cliente ao chamar uma operação em Substituir as opções do cliente para a chamada de operação.
Usar agentes de espera
Ao interagir com APIs assíncronas da AWS, muitas vezes você precisa esperar que determinado recurso esteja disponível para realizar outras ações nele.
Por exemplo, a API CreateTable do Amazon DynamoDB retorna imediatamente com um TableStatus de CREATING, e você não pode invocar operações de leitura ou gravação até que o status da tabela mude para ACTIVE.
Escrever uma lógica para pesquisar continuamente o status da tabela pode ser uma tarefa complicada e propensa a erros. Os waiters ajudam a eliminar a complexidade e são APIs simples que lidam com a tarefa de pesquisa para você.
Por exemplo, é possível usar waiters para pesquisar se uma tabela do DynamoDB foi criada e está pronta para uma operação de gravação.
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")
Substituir configuração do waiter
Por padrão, o SDK usa o atraso mínimo e o valor máximo de atraso configurados com valores ideais definidos pelos serviços da AWS para diferentes APIs. É possível substituir a configuração do waiter fornecendo opções funcionais durante a construção do waiter ou ao invocar uma operação de waiter.
Por exemplo, para substituir a configuração do waiter durante a construção do waiter
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 })
A função Wait em cada waiter também inclui opções funcionais. Assim como no exemplo acima, é possível substituir a configuração do waiter por solicitação 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")
Substituições avançadas da configuração do waiter
Além disso, é possível personalizar o comportamento padrão do waiter fornecendo uma função personalizada que pode ser repetida. As opções específicas do waiter também oferecem APIOptions personalizar middlewares da operação.
Por exemplo, para configurar substituições avançadas do waiter.
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 })