Работа с DocumentDB
В этом примере мы рассмотрим, как использовать Yandex DocumentDB (совместимый с DynamoDB) в функции на TypeScript. DocumentDB - это полностью управляемая документоориентированная база данных, которая позволяет хранить и запрашивать данные в формате JSON.
Архитектура примера
Функция обрабатывает HTTP-запросы и взаимодействует с DocumentDB:
- При GET-запросе функция извлекает данные из базы по указанному ID
- При POST-запросе функция сохраняет данные в базу
Код функции
import {Http} from '@yandex-cloud/function-types/dist/src/http';
import {DynamoDBClient} from "@aws-sdk/client-dynamodb";
import {DynamoDBDocumentClient, PutCommand, QueryCommand} from "@aws-sdk/lib-dynamodb";
const ENDPOINT = process.env.ENDPOINT;
// The handler function is an asynchronous function that handles HTTP events.
// It takes a Http.Event object as a parameter and returns a Promise that resolves to a Http.Result object.
export async function handler(event: Http.Event): Promise<Http.Result> {
const client = new DynamoDBClient({
endpoint: ENDPOINT,
region: 'ru-central1',
});
const docClient = DynamoDBDocumentClient.from(client);
switch (event.httpMethod) {
case 'GET': {
const command = new QueryCommand({
TableName: 'demo',
KeyConditionExpression: 'id = :id',
ExpressionAttributeValues: {
':id': parseInt(event.queryStringParameters.id, 10)
}
});
// Return a Http.Result object with a status code of 200, custom headers, and a body.
const response = await docClient.send(command);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(response.Items)
};
}
case 'POST': {
const body = JSON.parse(event.body);
const command = new PutCommand({
TableName: 'demo',
Item: {
id: body.id,
key: body.key,
value: body.value
}
});
await docClient.send(command);
return {
statusCode: 200,
body: 'OK'
};
}
default:
return {
statusCode: 405,
headers: {},
body: 'Method Not Allowed'
};
}
}
Функция использует AWS SDK для DynamoDB, который совместим с Yandex DocumentDB. Обратите внимание на следующие моменты:
- Создание клиента DynamoDB с указанием конечной точки DocumentDB:
const client = new DynamoDBClient({
endpoint: ENDPOINT,
region: 'ru-central1',
});
- Использование DynamoDBDocumentClient для более удобной работы с данными:
const docClient = DynamoDBDocumentClient.from(client);
- Выполнение запросов к базе данных с помощью команд QueryCommand и PutCommand.
Развертывание
Функция
Для развертывания функции в Yandex Cloud используется Terraform. Сначала компилируем TypeScript-код в JavaScript:
resource "null_resource" "build_typescript" {
provisioner "local-exec" {
command = "cd ../function && npm run build"
}
triggers = {
always_run = timestamp()
}
}
Затем создаем архив с функцией:
data "archive_file" "function_files" {
output_path = "./function.zip"
source_dir = "../dist"
type = "zip"
depends_on = [
null_resource.build_typescript
]
}
И создаем саму функцию в Yandex Cloud:
resource "yandex_function" "document-db-function" {
name = "document-db"
user_hash = data.archive_file.function_files.output_sha256
runtime = "nodejs18"
entrypoint = "main.handler"
memory = "128"
execution_timeout = "10"
content {
zip_filename = data.archive_file.function_files.output_path
}
secrets {
id = yandex_lockbox_secret.db-keys.id
version_id = yandex_lockbox_secret_version.db-keys.id
key = "AWS_ACCESS_KEY_ID"
environment_variable = "AWS_ACCESS_KEY_ID"
}
secrets {
id = yandex_lockbox_secret.db-keys.id
version_id = yandex_lockbox_secret_version.db-keys.id
key = "AWS_SECRET_ACCESS_KEY"
environment_variable = "AWS_SECRET_ACCESS_KEY"
}
environment = {
ENDPOINT = yandex_ydb_database_serverless.db.document_api_endpoint
}
service_account_id = yandex_iam_service_account.lockbox_reader.id
depends_on = [
yandex_lockbox_secret.db-keys,
yandex_lockbox_secret_version.db-keys,
yandex_ydb_database_serverless.db,
yandex_iam_service_account.lockbox_reader
]
}
Чтобы сделать функцию доступной из интернета, создаем IAM-привязку:
// IAM binding for making function public
resource "yandex_function_iam_binding" "test_function_binding" {
function_id = yandex_function.document-db-function.id
role = "functions.functionInvoker"
members = ["system:allUsers"]
}
База данных
Для создания базы данных DocumentDB и таблицы используется следующая конфигурация:
resource "yandex_ydb_database_serverless" "db" {
name = "test-ydb-serverless"
folder_id = var.folder_id
location_id = "ru-central1"
}
resource "aws_dynamodb_table" "test" {
depends_on = [
yandex_resourcemanager_folder_iam_binding.db_admin,
yandex_iam_service_account_static_access_key.db_admin,
yandex_ydb_database_serverless.db
]
name = "demo"
billing_mode = "PAY_PER_REQUEST" # только такой billing_mode поддерживается у нас и его нужно явно указывать.
hash_key = "id"
range_key = "key"
attribute {
name = "id"
type = "N"
}
attribute {
name = "key"
type = "S"
}
}
Обратите внимание, что:
- Создается serverless-база данных YDB
- Таблица создается с использованием AWS-совместимого провайдера
- Таблица имеет hash key
id
типа Number и range keykey
типа String - Используется режим биллинга PAY_PER_REQUEST
Использование
После развертывания инфраструктуры вы можете взаимодействовать с функцией следующим образом:
Сохранение данных
FUNCTION_ID=$(terraform -chdir=./tf output -raw function_id)
curl "https://functions.yandexcloud.net/$FUNCTION_ID?name=test" \
-XPOST \
-H'Content-type: application/json' \
-d'{"id":1, "key":"foo", "value":"bar"}'
Ответ должен быть:
OK
Получение данных
FUNCTION_ID=$(terraform -chdir=./tf output -raw function_id)
curl "https://functions.yandexcloud.net/$FUNCTION_ID?id=1" \
-H'Content-type: application/json'
Ответ будет содержать данные из базы в формате JSON.
Заключение
Этот пример демонстрирует, как легко интегрировать Yandex DocumentDB с функциями на TypeScript. Используя AWS SDK для DynamoDB, вы можете взаимодействовать с DocumentDB так же, как с DynamoDB, что упрощает миграцию существующих приложений.