[Документация Yandex Cloud](../../index.md) > [Yandex Cloud Functions](../index.md) > [Практические руководства](index.md) > Бэкенд на Serverless > Разработка пользовательской интеграции

# Разработка пользовательской интеграции в API Gateway


{% note warning %}

Часть ресурсов, необходимых для прохождения практического руководства, доступны только в [регионе Россия](../../overview/concepts/region.md).

{% endnote %}


С помощью serverless-технологий можно создать собственную интеграцию с сервисами Yandex Cloud.

Пользовательская интеграция представляет собой [функцию](../concepts/function.md) Yandex Cloud Functions или [контейнер](../../serverless-containers/concepts/container.md) Yandex Serverless Containers, которые предназначены для решения типовой задачи.

Функция или контейнер могут быть сконфигурированы в спецификации [API-шлюза](../../api-gateway/concepts/index.md) API Gateway по стандарту [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification) для выполнения определенных HTTP-запросов.

Разработайте функцию-интеграцию с Yandex Managed Service for YDB для работы с [СУБД YDB](../../ydb/concepts/index.md#ydb). Функция будет взаимодействовать с Managed Service for YDB и обрабатывать внешние HTTP-запросы через API-шлюз с использованием [HTTP API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html), совместимого с [Amazon DynamoDB](https://aws.amazon.com/ru/dynamodb/). Язык кода функции — TypeScript, среда выполнения — Node.js 16.

Интеграция будет применена для реализации [CRUD](https://ru.wikipedia.org/wiki/CRUD) API для работы с базой данных фильмов, развернутой в Managed Service for YDB.

Чтобы развернуть проект:
1. [Настройте окружение](#setup-environment).
1. [Скачайте проект с интеграцией](#download-project).
1. [Скомпилируйте функцию](#compile-function).
1. [Загрузите файл функции в бакет](#upload-to-bucket).
1. [Подготовьте конфигурацию ресурсов для интеграции](#prepare-configuration).
1. [Разверните ресурсы для интеграции](#deploy-resources).
1. [Проверьте работу созданного CRUD API](#test-api).

Если созданные ресурсы больше не нужны, [удалите](#clear-out) их.

## Перед началом работы {#before-you-begin}

Зарегистрируйтесь в Yandex Cloud и создайте [платежный аккаунт](../../billing/concepts/billing-account.md):
1. Перейдите в [консоль управления](https://console.yandex.cloud), затем войдите в Yandex Cloud или зарегистрируйтесь.
1. На странице **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** убедитесь, что у вас подключен платежный аккаунт, и он находится в [статусе](../../billing/concepts/billing-account-statuses.md) `ACTIVE` или `TRIAL_ACTIVE`. Если платежного аккаунта нет, [создайте его](../../billing/quickstart/index.md) и [привяжите](../../billing/operations/pin-cloud.md) к нему облако.

Если у вас есть активный платежный аккаунт, вы можете создать или выбрать [каталог](../../resource-manager/concepts/resources-hierarchy.md#folder), в котором будет работать ваша инфраструктура, на [странице облака](https://console.yandex.cloud/cloud).

[Подробнее об облаках и каталогах](../../resource-manager/concepts/resources-hierarchy.md).

### Необходимые платные ресурсы {#paid-resources}

В стоимость ресурсов для интеграции входят:
* Плата за объем хранилища, занятый данными, количество операций с данными и исходящий трафик ([тарифы Yandex Object Storage](../../storage/pricing.md)).
* Плата за операции с YDB и хранение данных ([тарифы Managed Service for YDB в бессерверном режиме](../../ydb/pricing/serverless.md)).
* Плата за количество вызовов функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик ([тарифы Cloud Functions](../pricing.md)).
* Плата за количество запросов к API-шлюзу и исходящий трафик ([тарифы API Gateway](../../api-gateway/pricing.md)).

## Настройте окружение {#setup-environment}

{% list tabs group=operating_system %}

- Windows {#windows}

  1. [Установите утилиту WSL](https://docs.microsoft.com/ru-ru/windows/wsl/install) для использования окружения Linux.
  1. Запустите подсистему Linux (по умолчанию — Ubuntu).
  1. Настройте окружение так, как описано в инструкции для операционной системы Linux.

- Linux {#linux}

  {% note info %}

  Если вы используете дистрибутив, отличный от Ubuntu, установите указанные утилиты с помощью команд вашего пакетного менеджера.

  {% endnote %}

  1. Последовательно установите следующие утилиты с помощью команд в терминале:
     * [Curl](https://curl.se/) и [Git](https://git-scm.com/):

       ```bash
       sudo apt-get install curl git -y
       ```

     * [WebStorm](https://www.jetbrains.com/ru-ru/webstorm/) или другая [среда разработки с поддержкой TypeScript](https://ru.wikipedia.org/wiki/TypeScript#IDE_и_поддержка_редакторов):

       ```bash
       sudo snap install webstorm --classic
       ```

     * [Node.js](https://nodejs.org/ru/) не ниже версии `16.9.1`:

       ```bash
       curl --silent --location https://deb.nodesource.com/setup_16.x | sudo -E bash
       sudo apt-get install nodejs
       node -v
       npm -v
       ```

     * [TypeScript](https://www.typescriptlang.org/):

       ```bash
       sudo npm install -g typescript
       ```

     * [Yandex Cloud CLI](../../cli/quickstart.md):

       ```bash
       curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash
       exec -l $SHELL
       yc version
       ```

     * [AWS CLI](https://aws.amazon.com/ru/cli/):

       ```bash
       curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" --output "awscliv2.zip"
       unzip awscliv2.zip
       sudo ./aws/install
       ```

     
     * [Terraform](https://www.terraform.io/) не ниже версии `1.0.8`:

       ```bash
       sudo apt-get update && sudo apt-get install -y gnupg software-properties-common curl
       curl --fail --silent --show-error --location https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
       sudo apt-add-repository "deb [arch=$(dpkg --print-architecture)] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
       sudo apt-get update && sudo apt-get install terraform -y
       terraform version
       ```



  1. [Создайте](../../cli/operations/profile/profile-create.md#interactive-create) профиль Yandex Cloud CLI с базовыми параметрами.
  1. [Настройте](../../ydb/docapi/tools/aws-setup.md) AWS CLI.

- macOS {#macos}

  1. Последовательно установите следующие утилиты с помощью команд в терминале:
     * [Homebrew](https://brew.sh):

       ```bash
       /bin/bash -c "$(curl --fail --silent --show-error --location https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
       ```

     * [Curl](https://curl.se/) и [Git](https://git-scm.com/):

       ```bash
       brew install curl git
       ```

     * [WebStorm](https://www.jetbrains.com/ru-ru/webstorm/) или другая [среда разработки с поддержкой TypeScript](https://ru.wikipedia.org/wiki/TypeScript#IDE_и_поддержка_редакторов):

       ```bash
       brew install --cask webstorm
       ```

     * [Node.js](https://nodejs.org/ru/) не ниже версии `16.9.1`:

       ```bash
       brew install node
       node -v
       npm -v
       ```

     * [TypeScript](https://www.typescriptlang.org/):

       ```bash
       npm install -g typescript
       ```

     * [Yandex Cloud CLI](../../cli/quickstart.md):

       ```bash
       curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash
       exec -l $SHELL
       yc version
       ```

     * [AWS CLI](https://aws.amazon.com/ru/cli/):

       ```bash
       curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" --output "AWSCLIV2.pkg"
       sudo installer -pkg AWSCLIV2.pkg -target /
       ```

     
     * [Terraform](https://www.terraform.io/) не ниже версии `1.0.8`:

       ```bash
       brew tap hashicorp/tap
       brew install hashicorp/tap/terraform
       terraform version
       ```



  1. [Создайте](../../cli/operations/profile/profile-create.md#interactive-create) профиль с базовыми параметрами.
  1. [Настройте](../../ydb/docapi/tools/aws-setup.md) AWS CLI.

{% endlist %}

## Скачайте проект с интеграцией {#download-project}

Склонируйте репозиторий с проектом для интеграции:

```bash
git clone https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector.git
```

В директории `src` находятся исходные файлы для создания функции:
* [event.ts](https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector/blob/main/src/event.ts) — код интерфейса `Event`, описывающий [структуру запроса](../../api-gateway/concepts/extensions/cloud-functions.md#request_v1), и интерфейса `RequestContext`, описывающий контекст запроса.
* [dynamodb.ts](https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector/blob/main/src/dynamodb.ts) — код обработки вызова функции и основных команд.
* [iam.ts](https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector/blob/main/src/iam.ts) — код получения [IAM-токенов](../../iam/concepts/authorization/iam-token.md), необходимых для авторизации при запросах к YDB.

При вызове функции в файле [dynamodb.ts](https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector/blob/main/src/dynamodb.ts) в поле `requestContext.apiGateway.operationContext` объекта `event` передается контекст операции.

Контекст операции определяется в параметре [`context`](../../api-gateway/concepts/extensions/cloud-functions.md#parameters) в спецификации [API-шлюза](../../api-gateway/concepts/index.md), вызывающего функцию-интеграцию.

{% note info %}

При интеграции с помощью [контейнера](../../serverless-containers/concepts/container.md) контекст операции передается через специальный заголовок [`X-Yc-ApiGateway-Operation-Context`](../../api-gateway/concepts/extensions/containers.md#parameters).

{% endnote %}

В файле [event.ts](https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector/blob/main/src/event.ts) определены интерфейсы для основных команд Amazon DynamoDB и их параметров, которые будут реализованы в данной интеграции. Это нужно для спецификации формата контекста операции и работы с ним внутри функции.

## Скомпилируйте функцию {#compile-function}

1. Откройте терминал и перейдите в корневую директорию проекта:

   ```bash
   cd <путь_к_корневой_директории_проекта>
   ```

1. Установите необходимые проекту зависимости:

   ```bash
   npm ci
   ```

1. Выполните компиляцию и сборку кода функции:

   ```bash
   npm run build
   ```

1. Упакуйте собранный код функции в ZIP-архив:
  
   ```bash
   npm run package
   ```

## Загрузите файл функции в бакет {#upload-to-bucket}

1. [Создайте](../../storage/operations/buckets/create.md) бакет с публичным доступом. Сохраните имя бакета, оно потребуется в дальнейшем.
1. [Загрузите](../../storage/operations/objects/upload.md) в бакет ZIP-архив `apigw-dynamodb-connector-0.0.1.zip` с кодом функции из директории `build`.

## Подготовьте конфигурацию ресурсов для интеграции {#prepare-configuration}

Для развертывания CRUD API с помощью функции-интеграции будет использоваться инструмент [Terraform](https://www.terraform.io).

Специальный [Terraform-модуль](https://github.com/yandex-cloud-examples/yc-serverless-ydb-api), разработанный для этого примера интеграции, упрощает процесс конфигурации ресурсов Yandex Cloud. Создаваемые Terraform ресурсы:
* Бессерверная база данных YDB.
* Функция-интеграция.
* Сервисный аккаунт для доступа функции к базе данных.
* API-шлюз.

Чтобы подготовить конфигурационные файлы для Terraform:
1. Узнайте имя активного профиля (`ACTIVE`) интерфейса командной строки Yandex Cloud CLI. В терминале выполните команду:

   ```bash
   yc config profile list
   ```

1. Получите параметры активного профиля:

   ```bash
   yc config profile get <имя_профиля>
   ```

   Сохраните полученные параметры:
   * `cloud-id` — идентификатор [облака](../../resource-manager/concepts/resources-hierarchy.md#cloud).
   * `folder-id` — идентификатор [каталога](../../resource-manager/concepts/resources-hierarchy.md#folder).

1. Получите [IAM-токен](../../iam/concepts/authorization/iam-token.md) или [авторизованный ключ](../../iam/concepts/authorization/key.md).
1. Создайте директорию `crud-api` и перейдите в нее:

   ```bash
   mkdir crud-api
   cd crud-api
   ```

   В дальнейшем все команды Terraform выполняйте в директории `crud-api`.
1. Создайте файл `main.tf` и скопируйте в него конфигурацию Terraform-модуля. Укажите параметры создаваемых ресурсов:
   * `cloud_id` — идентификатор облака.
   * `folder_id` — идентификатор каталога.
   * `database_connector_bucket` — имя бакета с функцией-интеграцией.

   ```hcl
   locals {
     cloud_id    = "<идентификатор_облака>"
     folder_id   = "<идентификатор_каталога>"
     zone        = "kz1-d"
   }

   module "crud-api" {
     source = "github.com/yandex-cloud-examples/yc-serverless-ydb-api"

     folder_id                 = local.folder_id
     api_name                  = "movies-api"
     database_name             = "movies-db"
     service_account_name      = "movies-api-service-account"
     region                    = "region-id"
     openapi_spec              = "api.yaml"
     table_specs               = ["file://table.json"]
     database_connector_bucket = "<имя_бакета_с_функцией-интеграцией>"
     database_connector_object = "apigw-dynamodb-connector-0.0.1.zip"
   }

   terraform {
     required_providers {
       yandex = {
         source = "yandex-cloud/yandex"
       }
       null   = {
         source = "registry.terraform.io/hashicorp/null"
       }
     }
     required_version = ">= 0.13"
   }

   provider "yandex" {
     cloud_id  = local.cloud_id
     folder_id = local.folder_id
     zone      = local.zone
   }

   output "crud_api_domain" {
     value = module.crud-api.api_gateway_domain
   }
   ```

1. Создайте файл `table.json` и скопируйте в него спецификацию схемы таблицы создаваемой YDB:

   ```json
   {
     "TableName": "movie",
     "KeySchema": [
       {
         "AttributeName": "id",
         "KeyType": "HASH"
       }
     ],
     "AttributeDefinitions": [
       {
         "AttributeName": "id",
         "AttributeType": "S"
       },
       {
         "AttributeName": "title",
         "AttributeType": "S"
       },
       {
         "AttributeName": "year",
         "AttributeType": "N"
       }
     ]
   }
   ```

1. Создайте файл `api.yaml` и скопируйте в него OpenAPI-спецификацию создаваемого API-шлюза:

   ```yaml
   openapi: "3.0.0"
   info:
     version: 1.0.0
     title: Movies API
   x-yc-apigateway:
     service_account_id: ${SERVICE_ACCOUNT_ID}

   paths:
     /movies:
       post:
         description: Create movie
         operationId: createMovie
         requestBody:
           description: Movie to create
           required: true
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/Movie'
         responses:
           '200':
             description: Created or updated movie
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Movie'
           default:
             description: error
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Error'
         x-yc-apigateway-integration:
           type: cloud_functions
           function_id: ${FUNCTION_ID}
           context:
             command: PutItem
             endpoint: ${DATABASE_ENDPOINT}
             tableName: movie
       get:
         description: Get movies
         operationId: getMovies
         parameters:
           - name: from
             in: query
             description: Identifier from which will be queried movies in ascending order
             required: true
             schema:
               type: string
           - name: limit
             in: query
             description: Maximum number of movies in response
             required: false
             schema:
               type: number
               default: 10
         responses:
           '200':
            description: Movies
             content:
               application/json:
                 schema:
                   type: array
                   items:
                     $ref: '#/components/schemas/Movie'
           default:
             description: error
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Error'
         x-yc-apigateway-integration:
           type: cloud_functions
           function_id: ${FUNCTION_ID}
           context:
             command: Scan
             endpoint: ${DATABASE_ENDPOINT}
             tableName: movie
             limit: '{limit}'
             exclusiveStartKey: '{"id": "{from}"}'
     /movies/{movieId}:
       parameters:
         - name: movieId
           in: path
           description: Identifier of movie
           required: true
           schema:
             type: string
       get:
         description: Get movie by id
         operationId: getMovieById
         responses:
           '200':
             description: Movie
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Movie'
           default:
             description: error
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Error'
         x-yc-apigateway-integration:
           type: cloud_functions
           function_id: ${FUNCTION_ID}
           context:
             command: GetItem
             endpoint: ${DATABASE_ENDPOINT}
             tableName: movie
             key: '{"id": "{movieId}"}'
       put:
         description: Update movie by id
         operationId: updateMovieById
         requestBody:
           description: Movie or attributes to update
           required: true
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/Movie'
         responses:
           '200':
             description: Updated movie
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Movie'
           default:
             description: error
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Error'
         x-yc-apigateway-integration:
           type: cloud_functions
           function_id: ${FUNCTION_ID}
           context:
             command: UpdateItem
             endpoint: ${DATABASE_ENDPOINT}
             tableName: movie
             key: '{"id": "{movieId}"}'
       delete:
         description: Delete movie by id
         operationId: deleteMovieById
         responses:
           '200':
             description: Deleted movie
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Movie'
           default:
             description: error
             content:
               application/json:
                 schema:
                   $ref: '#/components/schemas/Error'
         x-yc-apigateway-integration:
           type: cloud_functions
           function_id: ${FUNCTION_ID}
           context:
             command: DeleteItem
             endpoint: ${DATABASE_ENDPOINT}
             tableName: movie
             key: '{"id": "{movieId}"}'
   components:
     schemas:
       Movie:
         type: object
         required:
           - id
           - title
           - year
         properties:
           id:
             type: string
           title:
             type: string
           year:
             type: integer

       Error:
         type: object
         required:
           - message
         properties:
           message:
             type: string
   ```

## Разверните ресурсы для интеграции {#deploy-resources}

1. Инициализируйте Terraform. В терминале выполните команду:

   ```bash
   terraform init
   ```

1. Разверните облачные ресурсы:

   ```bash
   terraform apply
   ```

1. Подтвердите создание ресурсов: введите в терминале `yes` и нажмите **Enter**.

   В выводе команды в переменной `crud_api_domain` будет указан доменный адрес созданного CRUD API. Сохраните этот адрес, он потребуется в дальнейшем.

   Проверить созданные ресурсы можно в [консоли управления](https://console.yandex.cloud).

## Проверьте работу созданного CRUD API {#test-api}

Для проверки работы созданного CRUD API выполните следующие HTTP-запросы:
1. Добавьте информацию о фильме. В терминале выполните команду:

   ```bash
   curl \
     --location \
     --request POST 'https://<доменный_адрес_CRUD_API>/movies' \
     --header 'Content-Type: application/json' \
     --data-raw '{
       "id": "301",
       "title": "The Matrix",
       "year": 1999
     }'
   ```

1. Получите информацию о фильме:

   ```bash
   curl \
     --location \
     --request GET 'https://<доменный_адрес_CRUD_API>/movies/301'
   ```

1. Измените информацию о фильме:

   ```bash
   curl \
     --location \
     --request PUT 'https://<доменный_адрес_CRUD_API>/movies/301' \
     --header 'Content-Type: application/json' \
     --data-raw '{
       "title": "Матрица"
     }'
   ```

1. Добавьте информацию о другом фильме:

   ```bash
   curl \
     --location \
     --request POST 'https://<доменный_адрес_CRUD_API>/movies' \
     --header 'Content-Type: application/json' \
     --data-raw '{
       "id": "299",
       "title": "The Matrix Reloaded",
       "year": 2003
     }'
   ```

1. Получите список фильмов:

   ```bash
   curl \
     --location \
     --request GET 'https://<доменный_адрес_CRUD_API>/movies?from=1&limit=5'
   ```

1. Удалите информацию об одном из фильмов:

   ```bash
   curl \
     --location \
     --request DELETE 'https://<доменный_адрес_CRUD_API>/movies/301' \
     --data-raw ''
   ```

## Как удалить созданные ресурсы {#clear-out}

Чтобы перестать платить за созданные ресурсы:
* Удалите ресурсы, созданные с помощью Terraform. В терминале выполните команду:

  ```bash
  terraform destroy
  ```

  Подтвердите удаление ресурсов: введите в терминале `yes` и нажмите **Enter**.
* [Удалите](../../storage/operations/buckets/delete.md) бакет с файлом функции.