Developing a custom integration in API Gateway
Using serverless technologies, you can create your own integration with Yandex Cloud services.
User integration is a Yandex Cloud Functions-enabled function or Yandex Serverless Containers-enabled container designed to perform common tasks.
You can configure a function or container in the API Gateway specification under OpenAPI 3.0
Develop an integration function with Yandex Managed Service for YDB for YDB. The function will interact with Managed Service for YDB and processes external HTTP requests over the API gateway using the Amazon DynamoDB
The integration will be applied to implement the CRUD
To deploy a project:
- Set up your environment.
- Download a project with integration.
- Compile a function.
- Upload the function file to the bucket.
- Prepare a resource configuration for the integration.
- Deploy resources for the integration.
- Test the new CRUD API.
If you no longer need the resources you created, delete them.
Getting started
Sign up in Yandex Cloud and create a billing account:
- Navigate to the management console
and log in to Yandex Cloud or register a new account. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVE
orTRIAL_ACTIVE
status. If you do not have a billing account, create one and link a cloud to it.
If you have an active billing account, you can navigate to the cloud page
Learn more about clouds and folders.
Required paid resources
The cost of integration resources includes:
- Fee for the occupied data storage volume, number of data operations, and outbound traffic (see Yandex Object Storage pricing).
- Fee for YDB operations and data storage (see Managed Service for YDB pricing for serverless mode).
- Fee for the number of function calls, computing resources allocated to a function, and outbound traffic (see Cloud Functions pricing).
- Fee for the number of requests to the API gateway and outbound traffic (see API Gateway pricing).
Set up your environment
- Install the WSL utility
to run a Linux environment. - Run the subsystem (by default, Ubuntu).
- Configure the environment as described in the Linux manual.
Note
If you use a distribution other than Ubuntu, install the specified utilities using your package manager commands.
-
Install these utilities in the specified order using commands in the terminal:
-
sudo apt-get install curl git -y
-
WebStorm
or any other development environment that supports TypeScript :sudo snap install webstorm --classic
-
Node.js
16.9.1
or higher:curl --silent --location https://deb.nodesource.com/setup_16.x | sudo -E bash sudo apt-get install nodejs node -v npm -v
-
sudo npm install -g typescript
-
curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash exec -l $SHELL yc version
-
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" --output "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
-
Terraform
1.0.8
or higher: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
-
-
Create a Yandex Cloud CLI profile with basic settings.
-
Set up the AWS CLI.
-
Install these utilities in the specified order using commands in the terminal:
-
/bin/bash -c "$(curl --fail --silent --show-error --location https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
brew install curl git
-
WebStorm
or any other development environment that supports TypeScript :brew install --cask webstorm
-
Node.js
16.9.1
or higher:brew install node node -v npm -v
-
npm install -g typescript
-
curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash exec -l $SHELL yc version
-
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" --output "AWSCLIV2.pkg" sudo installer -pkg AWSCLIV2.pkg -target /
-
Terraform
1.0.8
or higher:brew tap hashicorp/tap brew install hashicorp/tap/terraform terraform version
-
-
Create a profile with basic settings.
-
Set up the AWS CLI.
Download a project with integration
Clone the integration project repository:
git clone https://github.com/yandex-cloud-examples/yc-serverless-apigw-dynamodb-connector.git
The src
folder contains source files for creating the function:
- event.ts
:Event
code describing the request structure andRequestContext
code. - dynamodb.ts
: Code to process function calls and basic commands. - iam.ts
: Code to retrieve IAM tokens for authorization when executing requests to YDB.
When a function is called, the operation context is provided in the dynamodb.tsrequestContext.apiGateway.operationContext
field of the event
object.
The operation context is defined in the context
parameter in the specification of the API gateway invoking the integration function.
Note
In case of container-based integration, the operation context is provided in a special header: X-Yc-ApiGateway-Operation-Context
.
The event.ts
Compile a function
-
Open the terminal and navigate to the project root folder:
cd <path_to_project_root_directory>
-
Set the dependencies required for the project:
npm ci
-
Compile and build the function code:
npm run build
-
Add the function code you built to a ZIP archive:
npm run package
Upload the function file to the bucket
- Create a bucket with public access. Save the bucket name. You will need it later.
- Upload the
apigw-dynamodb-connector-0.0.1.zip
archive with the function code from thebuild
directory to the bucket.
Set up a resource configuration for the integration
To deploy the CRUD API using the integration function, you will need Terraform
A special Terraform module
- Serverless YDB database.
- Integration function.
- Service account for the function to access the database.
- API gateway.
To get configuration files for Terraform ready:
-
Find out the name of the
ACTIVE
profile of the Yandex Cloud CLI command line interface. In the terminal, run this command:yc config profile list
-
Get the active profile properties:
yc config profile get <profile_name>
Save the properties:
token
: OAuth tokencloud-id
: Cloud IDfolder-id
: Folder ID
-
Create a
crud-api
directory and navigate to it:mkdir crud-api cd crud-api
Run all subsequent Terraform commands in the
crud-api
folder. -
Create a file named
main.tf
and copy into it the Terraform module configuration. Configure the resources being created:cloud_id
: Cloud ID.folder_id
: Folder ID.oauth_token
: OAuth token.database_connector_bucket
: Name of the bucket with the integration function.
locals { cloud_id = "<cloud_ID>" folder_id = "<folder_ID>" oauth_token = "<OAuth_token>" zone = "ru-central1-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 = "<name_of_bucket_with_integration_function>" 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" { token = local.oauth_token cloud_id = local.cloud_id folder_id = local.folder_id zone = local.zone } output "crud_api_domain" { value = module.crud-api.api_gateway_domain }
-
Create a file named
table.json
and copy into it the specification of the table schema created by YDB:{ "TableName": "movie", "KeySchema": [ { "AttributeName": "id", "KeyType": "HASH" } ], "AttributeDefinitions": [ { "AttributeName": "id", "AttributeType": "S" }, { "AttributeName": "title", "AttributeType": "S" }, { "AttributeName": "year", "AttributeType": "N" } ] }
-
Create a file named
api.yaml
and copy into it the OpenAPI specification of the new API gateway: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 for the integration
-
Initiate Terraform. In the terminal, run this command:
terraform init
-
Deploy cloud resources:
terraform apply
-
Confirm creating the resources: type
yes
in the terminal and press Enter.In the command output, the
crud_api_domain
variable will show the domain address of the new CRUD API. Save the address. You will need it later.You can use the management console
to check the created resources.
Test the new CRUD API
To test the new CRUD API, send the following HTTP requests:
-
Add movie details. In the terminal, run this command:
curl \ --location \ --request POST 'https://<domain_address_of_CRUD_API>/movies' \ --header 'Content-Type: application/json' \ --data-raw '{ "id": "301", "title": "The Matrix", "year": 1999 }'
-
Retrieve movie details:
curl \ --location \ --request GET 'https://<domain_address_of_CRUD_API>/movies/301'
-
Modify movie details:
curl \ --location \ --request PUT 'https://<domain_address_of_CRUD_API>/movies/301' \ --header 'Content-Type: application/json' \ --data-raw '{ "title": "The Matrix" }'
-
Add details for another movie:
curl \ --location \ --request POST 'https://<domain_address_of_CRUD_API>/movies' \ --header 'Content-Type: application/json' \ --data-raw '{ "id": "299", "title": "The Matrix Reloaded", "year": 2003 }'
-
Retrieve a movie list:
curl \ --location \ --request GET 'https://<domain_address_of_CRUD_API>/movies?from=1&limit=5'
-
Delete the details of one of the movies:
curl \ --location \ --request DELETE 'https://<domain_address_of_CRUD_API>/movies/301' \ --data-raw ''
How to delete the resources you created
To stop paying for the resources you created:
-
Delete the resources you created with Terraform. In the terminal, run this command:
terraform destroy
Confirm the resource deletion: type
yes
in the terminal and press Enter. -
Delete the bucket with the function file.