Scala DynamoDBを利用する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

PlayframeworkからAWS SDK for Java 2.0を使用して、DynamoDBを利用したので記録しておきます。

といってもJavaのAWS SDKを使用するだけなので、Scalaはあまり関係ないかも(^_^;)

依存ライブラリ

build.sbt

libraryDependencies += "software.amazon.awssdk" % "aws-sdk-java" % "2.13.27"


DynamoDBに接続する

ダメなケース

以下のようにDynamoDbClientにクレデンシャルを渡して接続すればうまく行くように思ったんだけど、これではダメ。

import software.amazon.awssdk.regions.Region
import java.util.HashMap
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
import software.amazon.awssdk.services.dynamodb.model.{AttributeValue, GetItemRequest}
import software.amazon.awssdk.auth.credentials.{AwsSessionCredentials, StaticCredentialsProvider}

val dynamodb = DynamoDbClient.builder()
  .region(Region.AP_NORTHEAST_1)
  .credentialsProvider(
    StaticCredentialsProvider.create(
      AwsSessionCredentials.create(accessKey, secretKey, "")
    )
  ).build()


Execution exception[[DynamoDbException: The security token included in the request is invalid (Service: DynamoDb, Status Code: 400, Request ID: ..., Extended Request ID: null)]]

のようにrequestに無効な認証トークンが含まれるとエラーで伝えられる。


クレデンシャルの正しい指定方法

結論からいうと、AwsSessionCredentialsがダメで代わりにAwsBasicCredentialsでクレデンシャルを指定する。

import software.amazon.awssdk.auth.credentials.{AwsBasicCredentials, StaticCredentialsProvider}

val dynamodb = DynamoDbClient.builder()
  .region(Region.AP_NORTHEAST_1)
  .credentialsProvider(
    StaticCredentialsProvider.create(
      AwsBasicCredentials.create(accessKey, secretKey)
     )
  ).build()

とすることで、DynamoDBのハンドルが取れる。

参考にしたページ

AWS DynamoDB • Alpakka Documentation

公式のドキュメントではAwsBasicCredentialsについては触れられておらず、ハマってしまった(^_^;)

AWS 認証情報の提供と取得 - AWS SDK for Java バージョン 2

DynamoDBのテーブル、Itemにアクセスする

例として、プライマリキーid:Intuserテーブルにアクセスします。


取得する条件の定義

id:25のItemを取得するには、

val keyToGet = new HashMap[String,AttributeValue]()
keyToGet.put("id", AttributeValue.builder().n("25").build())

とJavaのHashMapを作成します。

nメソッドはDynamoDBのnumber型に値を指定するメソッド(何故か引数の型はString...(^_^;))、string型への問い合わせはs(String)を使用します。


問い合わせリクエストの作成

上記で作成したHashMapを元に、リクエストを作成します。問い合わせ先のテーブルを指定します。

val request = GetItemRequest.builder().key(keyToGet).tableName("user").build()


DynamoDBへ問い合わせ & 結果の取得
val keyToGet = new HashMap[String,AttributeValue]()
keyToGet.put("id", AttributeValue.builder().n("25").build())
val request = GetItemRequest.builder().key(keyToGet).tableName("user").build()
val returnedItem = dynamodb.getItem(request)
println(returnedItem)


各要素へアクセスするには、

println(returnedItem.item().get("email").s())

のように記述出来ます。


その他の操作は以下を見ながら進めていこうと思う。まだ試してないので、試して記録できそうなら、追記します。

DynamoDB の項目の使用 - AWS SDK for Java バージョン 2


セカンダリインデックスでのSearch & Fetch

セカンダリインデックスを使用したQueryの例。

セカンダリインデックスではなくプライマリキーを指定する場合は、indexNameの指定をせず、keyConditionExpressionにプライマリキーの検索条件を記述すればよい。

val dynamodb = DynamoDbClient.builder().region(Region.AP_NORTHEAST_1).build()
val cond = new HashMap[String, AttributeValue]()
cond.put(":val", AttributeValue.builder().n("0").build())

val q = QueryRequest.builder()
  .tableName("yourTableName")
  .indexName("makedIndexName")
  .keyConditionExpression( "indexKey = :val")
  .expressionAttributeValues( cond )
  .build()
  val ret = dynamodb.query(q)
  println(ret)

※これ演算子が=以外だとエラーになるんだけどどうやって指定するんだろう...

追記:

QueryRequest.Builder (AWS SDK for Java - 2.13.32)

これ読む限り、

The partition key equality test is required, and must be specified in the following format:
partitionKeyName = :partitionkeyval

ソートキーしか演算子いじっちゃダメらしい。


OSに設定済みの環境変数をクレデンシャルとして透過的に使用する。


default profileまたはexport済みのAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWSを使用する

credentialsProviderを渡さなければdefaultのprofileまたはexport済みの環境変数を参照する。

val dynamodb = DynamoDbClient.builder().region(Region.AP_NORTHEAST_1).build()


OSに定義してあるaws profileを指定して認証する
val dynamodb = DynamoDbClient.builder()
  .region(Region.AP_NORTHEAST_1)
  .credentialsProvider(
    ProfileCredentialsProvider.create("selectedProfileName")
  ).build()

この2つが認証取れるのに同じアクセスキーで何故、AwsSessionCredentialsじゃ認証取れないの(^_^;)と無駄にハマってしまいました。