개요
안녕하세요. 우리는 이전 포스팅인 [DynamoDB] 그거 알아요 ? DynamoDB는 HTTP로 통신한다는거 (RDB 운영 이슈, Transaction, Conflict)에서 DynamoDB는 HTTP로 통신한다는 사실을 알게 되었습니다. 오늘은 HTTP 통신을 직접 실행해보며 데이터가 어떻게 적재되고 일혀지는지에 대해서 알아보도록 하겠습니다.
Expression
오늘은 DynamoDB와 직접 통신하며 API를 테스트 해보고 사용하는 DynamoDB의 API의 주된 개념중 하나인 Expression에 대해서 알아보도록 하겠습니다.
테이블 및 환경 구축
오늘의 실습 환경은 Local Docker에서 테스트를 진행하며 이를 위해서 LocalStack DynamoDB을 사용하도록하겠습니다.
또한 테이블은 아래의 구조로 만들어 내겠습니다. 아래의 주요 내용을 해석하면 PK attribute와 SK attribute를 각각만들고 이에 대해서 Partition Key와 Sort Key로 지정합니다. 그리고 두 값 모두 String 타입을 기본으로 합니다.
awslocal dynamodb create-table \
--table-name user_order \
--key-schema \
AttributeName=PK,KeyType=HASH \
AttributeName=SK,KeyType=RANGE \
--attribute-definitions \
AttributeName=PK,AttributeType=S \
AttributeName=SK,AttributeType=S \
--billing-mode PAY_PER_REQUEST \
--region ap-south-1
DynamoDB는 Schema에서 Key로 사용되거나 Index로 사용되는 attribute 에 대해서만 db 명세에 기술해주면 됩니다. 아래는 위 스키마로 만들고 데이터를 적재했을 때의 item을 나타냅니다. title과 status는 별도의 스키마로는 정의되어있지 않습니다. 스키마리스한 부분으로 이해해주시면 됩니다.
기본
각 요청을 자세히 알아보기전에 먼저 공통된 구조에 대해서 먼저 알아보도록 하겠습니다. 리스트로 나타내면 공통된 구조는 아래와 같습니다.
- http method는 POST로 고정입니다.
- header에 Content-Type: application/x-amz-json-1.0가 들어옵니다.
- Authorization의 경우 아마존의 인증 토큰을 넣습니다.
- X-Amz-Target을 통해서 하고자하는 Action(생성, 조회 등)을 주입합니다.
- 각 Action의 구체적인 expression을 body에 추가합니다.
- 각 필드는 "{Key}" : { "{Type}" : "{Value}" } 의 형식을 가집니다.
아래는 해당 구조의 예시입니다.
curl --location 'http://localhost:4566' \
--header 'Content-Type: application/x-amz-json-1.0' \
--header 'Authorization: AWS_SIGNATURE' \
--header 'X-Amz-Target: DynamoDB_20120810.PutItem' \
--data '{
"TableName": "user_order",
"Item": {
"PK": {"S": "USER#123"},
"SK": {"S": "ORDER#2024-01-01"},
"title" : {"S" : "Coke 1L"},
"status" : {"S" : "DELIVERY"}
}
}'
생성과 수정, 그리고 삭제(Create & Update, Delete)
그렇다면 이제 먼저 실제로 생성과 수정에 대한 HTTP Request를 보내보고 결과를 확인해보도록 하겠습니다.
생성(Create)
생성하는 API는 아래의 구성을 가지고 있습니다.
- X-Amz-Target은
DynamoDB_20120810.PutItem
입니다. - Body에 Table의 이름과 넣고자하는 Item을 기술합니다.
- condition_expression을 통해서 key 충돌을 감지하여 override 되는것을 막을 수 있습니다.
아래는 DynamoDB에서 Item을 생성을 하는 HTTP Request입니다.
curl --location 'http://localhost:4566' \
--header 'Content-Type: application/x-amz-json-1.0' \
--header 'Authorization: AWS_SIGNATURE' \
--header 'X-Amz-Target: DynamoDB_20120810.PutItem' \
--data '{
"TableName": "user_order",
"Item": {
"PK": {"S": "USER#123"},
"SK": {"S": "ORDER#2024-01-01"},
"title" : {"S" : "Coke 1L"},
"status" : {"S" : "DELIVERY"}
}
}'
수정(Update) 과 ExpressionAttributeNames & ExpressionAttributeValues
업데이트하는 API는 아래의 구성을 가지고 있습니다.
- X-Amz-Target은
DynamoDB_20120810.UpdateItem
입니다. - Body에 Table의 이름을 기술합니다. (TableName)
- Update 하고자하는 Item의 Primary Key와 Update 어떤 데이터를 업데이트하고자하는지 기술합니다. (Key, UpdateExpression)
curl --location 'http://localhost:4566/' \
--header 'Content-Type: application/x-amz-json-1.0' \
--header 'Authorization: AWS_SIGNATURE' \
--header 'X-Amz-Target: DynamoDB_20120810.UpdateItem' \
--data '{
"TableName": "user_order",
"Key": {
"PK": {"S": "USER#123"},
"SK": {"S": "ORDER#2024-01-02"}
},
"UpdateExpression": "SET #status = :status",
"ExpressionAttributeNames": {
"#status": "status"
},
"ExpressionAttributeValues": {
":status": {"S": "DELIVERY"}
}
}'
before
after
추가로 UpdateExpression은 단순 Text를 통해서 표현됩니다. 따라서 오타 등이 발생할 가능성이 있습니다. 이를 사전에 방지하기 위해서 별도의 필드로 구분해서 사용하는 ExpressionAttributeNames과 ExpressionAttributeValues이 있습니다. 이를 활용하면 좋습니다. ExpressionAttributeNames는 attribute 이름을 치환할 때 사용하면 좋으며 ExpressionAttributeValues는 실제 value를 치환할 때 사용하면 좋다고 기술되어 있습니다.
삭제(Delete) & Condition Expression
Condition Expression은 조건식을 추가하는 Expression 입니다. 특정 조건일 경우에만 Write가 성공할 수 있도록 할 수 있습니다. 기본적으로 특정 ID가 있을 경우에만 해당 write를 실행하게 할 수 있습니다. 추가로적으로 이러한 기전은 DynamoDB의 경우 기본적으로 Optimistic Lock 조건으로 race condition을 해결하는데 Condition Expression은 이를 달성하는데 도움을 줄 수 있습니다. 아래는 PK와 SK 키가 존재해야하만 Item을 지우겠다는 의미로 ConditionExpression을 사용하였습니다.
- X-Amz-Target: DynamoDB_20120810.DeleteItem은 아이템을 삭제하고자할 때의 Header 입니다.
curl --location 'http://localhost:4566/' \
--header 'Content-Type: application/x-amz-json-1.0' \
--header 'Authorization: AWS_SIGNATURE' \
--header 'X-Amz-Target: DynamoDB_20120810.DeleteItem' \
--data '{
"TableName": "user_order",
"Key": {
"PK": {"S": "USER#123"},
"SK": {"S": "ORDER#2024-01-01"}
},
"ConditionExpression": "attribute_exists(PK) AND attribute_exists(SK)"
}'
마무리
오늘은 이렇게 DynamoDB의 API 중 Write와 관련된 내용에 대해서 알아보는 시간을 가져보았습니다.
다음 시간에는 Read와 관련된 이야기를 이어서 해보도록 하겠습니다.
감사합니다.
참고
[1] https://docs.localstack.cloud/references/coverage/coverage_dynamodb/
[2] https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html
'datasource > DyanmoDB' 카테고리의 다른 글
[DynamoDB] DynamoDB는 읽고 쓰는 만큼 비용을 냅니다 (0) | 2025.02.17 |
---|---|
[DynamoDB] DynamoDB에서 사용하는 용어 정리 (0) | 2025.02.13 |
[DynamoDB] 그거 알아요 ? DynamoDB는 HTTP로 통신한다는거 (RDB 운영 이슈, Transaction, Conflict) (0) | 2025.02.09 |
[DynamoDB] 왜 DynamoDB와 같은 Wide Columns DB는 RDB에 비해서 더 확장성(scalability)을 가지는가 ? (0) | 2025.02.04 |
댓글