Перейти к основному содержимому

Работа с 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. Обратите внимание на следующие моменты:

  1. Создание клиента DynamoDB с указанием конечной точки DocumentDB:
const client = new DynamoDBClient({
endpoint: ENDPOINT,
region: 'ru-central1',
});
  1. Использование DynamoDBDocumentClient для более удобной работы с данными:
const docClient = DynamoDBDocumentClient.from(client);
  1. Выполнение запросов к базе данных с помощью команд 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 key key типа 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, что упрощает миграцию существующих приложений.