All Products
Search
Document Center

OpenSearch:TypeScript request constructor example

Last Updated:Apr 01, 2026

Client.ts provides a reusable HTTP client for OpenSearch Industry Algorithm Edition. It handles request signing, credential management, retry logic, and error handling so you can focus on building search features.

Prerequisites

Before you begin, ensure that you have:

  • Node.js and npm installed

  • An Alibaba Cloud account with an AccessKey ID and AccessKey Secret

  • The OpenSearch Industry Algorithm Edition service endpoint for your instance

Install dependencies

Add the following packages to your package.json. Install them from npm.

dependencies — required at runtime:

PackagePurpose
@alicloud/credentialsManages Alibaba Cloud credentials, including AccessKey and STS token refresh
@alicloud/opensearch-utilGenerates request signatures and computes Content-MD5 for OpenSearch requests
@alicloud/tea-typescriptCore HTTP runtime: handles request execution, retries, and backoff
@alicloud/tea-utilUtility functions for serialization, header generation, and response parsing

devDependencies — required for TypeScript compilation:

PackagePurpose
typescriptTypeScript compiler
ts-nodeRun TypeScript files directly without a separate compilation step

Client.ts

Client.ts constructs and sends signed HTTP requests to OpenSearch. All requests go through the _request method, which:

  1. Retrieves credentials from the configured credential provider

  2. Sets required headers (Date, X-Opensearch-Nonce, Authorization, and optionally X-Opensearch-Security-Token)

  3. Computes Content-MD5 for request bodies

  4. Executes the request with configurable retry and backoff behavior

  5. Returns the parsed response body and headers, or throws on 4xx/5xx status codes

import OpenSearchUtil from '@alicloud/opensearch-util/dist/client';
import * as $tea from '@alicloud/tea-typescript';
import Util, * as $Util from '@alicloud/tea-util';
import Credential, * as $Credential from '@alicloud/credentials';
import Config from "./Config";

class Client {
  _endpoint: string;
  _protocol: string;
  _userAgent: string;
  _credential: Credential;

  constructor(config: Config) {
    if (Util.isUnset($tea.toMap(config))) {
      throw $tea.newError({
        name: "ParameterMissing",
        message: "'config' can not be unset",
      });
    }

    if (Util.empty(config.type)) {
      config.type = "access_key";
    }

    let credentialConfig = new $Credential.Config({
      accessKeyId: config.accessKeyId,       // AccessKey ID — load from environment variables, not hardcoded
      type: config.type,
      accessKeySecret: config.accessKeySecret, // AccessKey Secret — load from environment variables, not hardcoded
      securityToken: config.securityToken,   // STS security token (required for temporary credentials only)
    });
    this._credential = new Credential(credentialConfig);
    this._endpoint = config.endpoint;
    this._protocol = config.protocol;
    this._userAgent = config.userAgent;
  }

  async _request(method: string, pathname: string, query: {[key: string ]: any}, headers: {[key: string ]: string}, body: any, runtime: $Util.RuntimeOptions): Promise<{[key: string ]: any}> {
    let _runtime: { [key: string]: any } = {
      timeouted: "retry",
      readTimeout: runtime.readTimeout,
      connectTimeout: runtime.connectTimeout,
      httpProxy: runtime.httpProxy,
      httpsProxy: runtime.httpsProxy,
      noProxy: runtime.noProxy,
      maxIdleConns: runtime.maxIdleConns,
      retry: {
        retryable: runtime.autoretry,
        maxAttempts: Util.defaultNumber(runtime.maxAttempts, 3), // default: 3 attempts
      },
      backoff: {
        policy: Util.defaultString(runtime.backoffPolicy, "no"), // default: no backoff
        period: Util.defaultNumber(runtime.backoffPeriod, 1),
      },
      ignoreSSL: runtime.ignoreSSL,
    }

    let _lastRequest = null;
    let _now = Date.now();
    let _retryTimes = 0;
    while ($tea.allowRetry(_runtime['retry'], _retryTimes, _now)) {
      if (_retryTimes > 0) {
        let _backoffTime = $tea.getBackoffTime(_runtime['backoff'], _retryTimes);
        if (_backoffTime > 0) {
          await $tea.sleep(_backoffTime);
        }
      }

      _retryTimes = _retryTimes + 1;
      try {
        let request_ = new $tea.Request();
        let accesskeyId = await this._credential.getAccessKeyId();
        let accessKeySecret = await this._credential.getAccessKeySecret();
        let securityToken = await this._credential.getSecurityToken();
        request_.protocol = Util.defaultString(this._protocol, "HTTP");
        request_.method = method;
        request_.pathname = pathname;
        request_.headers = {
          'user-agent': Util.getUserAgent(this._userAgent),
          Date: OpenSearchUtil.getDate(),
          'Content-Type':'application/json',
          host: Util.defaultString(this._endpoint, `opensearch-cn-hangzhou.aliyuncs.com`),
          'X-Opensearch-Nonce': Util.getNonce(), // Unique nonce per request to prevent replay attacks
          ...headers,
        };
        if (!Util.isUnset(query)) {
          request_.query = Util.stringifyMapValue(query);
        }
        if (!Util.isUnset(securityToken) && securityToken!='') {
          request_.headers["X-Opensearch-Security-Token"] = securityToken; // Required for STS temporary credentials
        }

        if (!Util.isUnset(body)) {
          let reqBody = Util.toJSONString(body);
          request_.headers["Content-Type"] = "application/json";
          request_.headers["Content-MD5"] = OpenSearchUtil.getContentMD5(reqBody); // Integrity check for the request body
          request_.body = new $tea.BytesReadable(reqBody);
        }

        request_.headers["Authorization"] = OpenSearchUtil.getSignature(request_, accesskeyId, accessKeySecret); // HMAC signature for authentication
        _lastRequest = request_;
        let response_ = await $tea.doAction(request_, _runtime);

        let objStr = await Util.readAsString(response_.body);
        let obj = Util.parseJSON(objStr);
        let res = Util.assertAsMap(obj);
        if (Util.is4xx(response_.statusCode) || Util.is5xx(response_.statusCode)) {
          throw $tea.newError({
            message: response_.statusMessage,
            data: objStr,
            code: response_.statusCode,
          });
        }
        return {
          body: res,
          headers: response_.headers,
        };
      } catch (ex) {
        if ($tea.isRetryable(ex)) {
          continue;
        }
        throw ex;
      }
    }
    throw $tea.newUnretryableError(_lastRequest);
  }
}

export default Client;
Important

Never hardcode accessKeyId or accessKeySecret in your source code. Load credentials from environment variables or a secrets manager to avoid accidental exposure.

What's next

  • Implement Config.ts to define the configuration interface that Client expects

  • Use Client._request() to call OpenSearch APIs by passing the HTTP method, path, query parameters, and request body