yunomuのブログ

趣味のこと

aws-sdk-go-v2でS3のNoSuchKeyを処理する

pkg.go.dev docs.aws.amazon.com

 これの捕捉。

 エラー関係の型はここ。

pkg.go.dev

 s3.GetObjectなどのAPIの戻り値のエラー型の定義は smithy パッケージの方にある。

pkg.go.dev

 smithy.OperationError がそれ。なので GetObject の場合のエラー処理はこういう感じになる。

import (
  "errors"
  "github.com/aws/smithy-go"
)

// (略)

out, err := s3Client.GetObject(ctx, input)
if err != nil {
  var opErr *smithy.OperationError
  var noSuchKey *types.NoSuchKey
  if errors.As(err, &opErr) && errors.As(opErr.Err, &noSuchKey) {
    // Keyが無い場合の処理
  } else {
    // その他のエラー処理
  }
}

 ここまではいい。

 キーの位置にオブジェクトが無い、つまりNoSuchKeyの場合だけを検出したい場合はGetObject.Output.Bodyが不要なので s3.HeadObject を使いたくなる。でも何故か s3.HeadObjectNoSuchKey エラーに対応していないのでちょっと面倒くさい。

 s3.HeadObjectでオブジェクトが無い事を検出するためにはHTTPのステータスコードを確認する必要がある。HTTPのステータスコードsmithy.OperationErrorErrフィールド、Errsmithy/transport/http.ResponseError型になっていて、その中のResponseフィールドがGo標準のnet/http.Response型になっているので、そこのStatusCodeフィールドを見る。つまりこう。

import (
  "errors"
  "github.com/aws/smithy-go"
  "github.com/aws/smithy-go/transport/http"
)

// (略)

out, err := s3Client.HeadObject(ctx, input)
if err != nil {
  var opErr *smithy.OperationError
  var httpErr *http.ResponseError
  if errors.As(err, &opErr) &&
     errors.As(opErr.Err, &httpError) &&
     httpError.Response.StatusCode == 404 {
    // Keyが無い場合の処理
  } else {
    // その他のエラー処理
  }
}

 ただし、s3.GetObjects3.HeadObjectも、バケットに対してs3:ListBucketの権限がついていない場合は NoSuchError (HTTP 404) ではなく InvalidObjectState (HTTP 403)が返るようになるので、このあたりはIAMの権限とセットで考えて設定する必要がある。

docs.aws.amazon.com