adk-typescript
Version:
TypeScript port of Google's Agent Development Kit (ADK)
270 lines (269 loc) • 10.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.APIHubClient = void 0;
const axios_1 = __importDefault(require("axios"));
/**
* Client for interacting with the API Hub service
*/
class APIHubClient {
/**
* Initializes the APIHubClient.
*
* You must set either accessToken or serviceAccountJson. This
* credential is used for sending request to API Hub API.
*
* @param params Configuration parameters
* @param params.accessToken Google Access token. Generate with gcloud cli `gcloud auth print-access-token`. Useful for local testing.
* @param params.serviceAccountJson The service account configuration as a JSON string. Required if not using default service credential.
*/
constructor(params) {
this.rootUrl = 'https://apihub.googleapis.com/v1';
this.accessToken = null;
this.serviceAccount = null;
this.credentialCache = null;
if (params.accessToken) {
this.accessToken = params.accessToken;
}
else if (params.serviceAccountJson) {
this.serviceAccount = params.serviceAccountJson;
}
}
/**
* From a given path, get the first spec available in the API Hub.
*
* - If path includes /apis/apiname, get the first spec of that API
* - If path includes /apis/apiname/versions/versionname, get the first spec of that API Version
* - If path includes /apis/apiname/versions/versionname/specs/specname, return that spec
*
* Path can be resource name (projects/xxx/locations/us-central1/apis/apiname),
* and URL from the UI (https://console.cloud.google.com/apigee/api-hub/apis/apiname?project=xxx)
*
* @param path The path to the API, API Version, or API Spec.
* @returns The content of the first spec available in the API Hub.
*/
async getSpecContent(path) {
const [apiResourceName, apiVersionResourceName, apiSpecResourceName] = this.extractResourceName(path);
if (apiResourceName && !apiVersionResourceName) {
const api = await this.getApi(apiResourceName);
const versions = api.versions || [];
if (!versions.length) {
throw new Error(`No versions found in API Hub resource: ${apiResourceName}`);
}
const apiVersionResourceName = versions[0];
}
const localApiVersionResourceName = apiVersionResourceName;
let localApiSpecResourceName = apiSpecResourceName;
if (localApiVersionResourceName && !localApiSpecResourceName) {
const apiVersion = await this.getApiVersion(localApiVersionResourceName);
const specResourceNames = apiVersion.specs || [];
if (!specResourceNames.length) {
throw new Error(`No specs found in API Hub version: ${localApiVersionResourceName}`);
}
localApiSpecResourceName = specResourceNames[0];
}
if (localApiSpecResourceName) {
const specContent = await this.fetchSpec(localApiSpecResourceName);
return specContent;
}
throw new Error(`No API Hub resource found in path: ${path}`);
}
/**
* Lists all APIs in the specified project and location.
*
* @param project The Google Cloud project name.
* @param location The location of the API Hub resources (e.g., 'us-central1').
* @returns A list of API objects, or an empty list if an error occurs.
*/
async listApis(project, location) {
const url = `${this.rootUrl}/projects/${project}/locations/${location}/apis`;
const token = await this.getAccessToken();
const response = await axios_1.default.get(url, {
headers: {
'accept': 'application/json, text/plain, */*',
'Authorization': `Bearer ${token}`
}
});
return response.data.apis || [];
}
/**
* Get API detail by API name.
*
* @param apiResourceName Resource name of this API, like projects/xxx/locations/us-central1/apis/apiname
* @returns An API and details
*/
async getApi(apiResourceName) {
const url = `${this.rootUrl}/${apiResourceName}`;
const token = await this.getAccessToken();
const response = await axios_1.default.get(url, {
headers: {
'accept': 'application/json, text/plain, */*',
'Authorization': `Bearer ${token}`
}
});
return response.data;
}
/**
* Gets details of a specific API version.
*
* @param apiVersionName The resource name of the API version.
* @returns The API version details
*/
async getApiVersion(apiVersionName) {
const url = `${this.rootUrl}/${apiVersionName}`;
const token = await this.getAccessToken();
const response = await axios_1.default.get(url, {
headers: {
'accept': 'application/json, text/plain, */*',
'Authorization': `Bearer ${token}`
}
});
return response.data;
}
/**
* Retrieves the content of a specific API specification.
*
* @param apiSpecResourceName The resource name of the API spec.
* @returns The decoded content of the specification
* @private
*/
async fetchSpec(apiSpecResourceName) {
const url = `${this.rootUrl}/${apiSpecResourceName}:contents`;
const token = await this.getAccessToken();
const response = await axios_1.default.get(url, {
headers: {
'accept': 'application/json, text/plain, */*',
'Authorization': `Bearer ${token}`
}
});
const contentBase64 = response.data.contents || '';
if (contentBase64) {
// In Node.js
if (typeof Buffer !== 'undefined') {
return Buffer.from(contentBase64, 'base64').toString('utf-8');
}
// In browser
return atob(contentBase64);
}
else {
return '';
}
}
/**
* Extracts the resource names of an API, API Version, and API Spec from a given URL or path.
*
* @param urlOrPath The URL (UI or resource) or path string.
* @returns A tuple containing the API resource name, API version resource name, and API spec resource name.
* @private
*/
extractResourceName(urlOrPath) {
let queryParams = null;
let path;
try {
const parsedUrl = new URL(urlOrPath);
path = parsedUrl.pathname;
queryParams = {};
// Parse the query string
for (const [key, value] of parsedUrl.searchParams.entries()) {
if (!queryParams[key]) {
queryParams[key] = [];
}
queryParams[key].push(value);
}
// This is a path from UI. Remove unnecessary prefix.
if (path.includes('api-hub/')) {
path = path.split('api-hub')[1];
}
}
catch (e) {
path = urlOrPath;
}
const pathSegments = path.split('/').filter(segment => segment);
let project = null;
let location = null;
let apiId = null;
let versionId = null;
let specId = null;
if (pathSegments.includes('projects')) {
const projectIndex = pathSegments.indexOf('projects');
if (projectIndex + 1 < pathSegments.length) {
project = pathSegments[projectIndex + 1];
}
}
else if (queryParams && queryParams['project']) {
project = queryParams['project'][0];
}
if (!project) {
throw new Error(`Project ID not found in URL or path in APIHubClient. Input path is '${urlOrPath}'. ` +
`Please make sure there is either '/projects/PROJECT_ID' in the path or 'project=PROJECT_ID' query param in the input.`);
}
if (pathSegments.includes('locations')) {
const locationIndex = pathSegments.indexOf('locations');
if (locationIndex + 1 < pathSegments.length) {
location = pathSegments[locationIndex + 1];
}
}
if (!location) {
throw new Error(`Location not found in URL or path in APIHubClient. Input path is '${urlOrPath}'. ` +
`Please make sure there is either '/location/LOCATION_ID' in the path.`);
}
if (pathSegments.includes('apis')) {
const apiIndex = pathSegments.indexOf('apis');
if (apiIndex + 1 < pathSegments.length) {
apiId = pathSegments[apiIndex + 1];
}
}
if (!apiId) {
throw new Error(`API id not found in URL or path in APIHubClient. Input path is '${urlOrPath}'. ` +
`Please make sure there is either '/apis/API_ID' in the path.`);
}
if (pathSegments.includes('versions')) {
const versionIndex = pathSegments.indexOf('versions');
if (versionIndex + 1 < pathSegments.length) {
versionId = pathSegments[versionIndex + 1];
}
}
if (pathSegments.includes('specs')) {
const specIndex = pathSegments.indexOf('specs');
if (specIndex + 1 < pathSegments.length) {
specId = pathSegments[specIndex + 1];
}
}
const apiResourceName = `projects/${project}/locations/${location}/apis/${apiId}`;
const apiVersionResourceName = versionId ? `${apiResourceName}/versions/${versionId}` : null;
const apiSpecResourceName = (versionId && specId) ? `${apiVersionResourceName}/specs/${specId}` : null;
return [
apiResourceName,
apiVersionResourceName,
apiSpecResourceName,
];
}
/**
* Gets the access token for service account authentication
*
* @returns The access token
* @private
*/
async getAccessToken() {
if (this.accessToken) {
return this.accessToken;
}
if (this.credentialCache && !this.isCredentialExpired(this.credentialCache)) {
return this.credentialCache.token;
}
throw new Error('Authentication not implemented: please provide an access token to the API Hub client');
}
/**
* Checks if the credential is expired
*
* @param credential The credential to check
* @returns True if expired, false otherwise
* @private
*/
isCredentialExpired(credential) {
return credential.expired || false;
}
}
exports.APIHubClient = APIHubClient;