オントロジーの構築ファンクションオントロジーの編集関数から API を呼び出す

注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。

関数から API を呼び出す

TypeScript v1、TypeScript v2、Python の関数から外部ソースの API を呼び出すことができますが、追加の設定が必要です。この設定と外部ソースの使用方法について、以下で詳しく説明します。

ソースエイリアス

TypeScript v2 と Python の関数では、ソースエイリアスを介してソースを参照することを推奨します。ソースエイリアスは、特定のソースの代わりにソース識別子として使用できる、移植可能な名前付き参照です。Marketplace 製品を通じて関数を配布する場合、環境ごとにエイリアスを別のソースに再マッピングできるため、関数コードの移植性を保持できます。TypeScript v1 の関数は、生成されたソースシンボルを使用し、エイリアスをサポートしていません。

外部 API へのアクセスを設定する

デフォルトでは、関数から外部 API を呼び出すことは許可されていません。関数から外部システムを呼び出せるようにするには、Data Connection でソースを設定し、Foundry が外部システムに接続できるようにする必要があります。

関数がソースの外部システムに安全に接続するには、ソースでエクスポートを有効にし、ソースの Code Repositories へのインポートを許可する必要があります。どちらも、Data Connection でソースに移動し、接続設定セクションを開くことで設定できます。

TypeScript v1 の関数では、ソースのAPI名(接続設定のコードインポート設定タブで設定)が、コード内で参照する識別子になります。

ソースの証明書チェーンを完全に設定してください。

Webhook と関数のランタイム環境は同一ではありません。

Webhook が正しく動作していても、関数からの API 呼び出しで UNABLE_TO_GET_ISSUER_CERT エラーが発生することがあります。

証明書を検証するには、ソースターミナルの openssl コマンドに関するドキュメントを参照してください。

関数で外部ソースを使用する

関数から API を呼び出すには、まずリソースインポートサイドバーを使用して、ソースを関数リポジトリにインポートする必要があります。TypeScript v2 と Python の関数では、続いてソースエイリアスを作成し、そのエイリアスキーをソース識別子として使用することを推奨します。TypeScript v1 の関数は、インポートしたソースを直接参照します。その後、以下の例に示すように、関数がソースを使用することを宣言する必要があります。

以下に例を示します。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 import { ExternalSystems } from "@foundry/functions-api"; import { MySource } from "@foundry/external-systems/sources"; export class MyExternalFunctions { @ExternalSystems({ sources: [MySource] }) @Function() public async myExternalFunction(): Promise<string> { const { url } = MySource.getHttpsConnection(); const response = await MySource.fetch(url); return response.text(); } }
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { getSource, getHttpsConnection, getFetch } from "@palantir/functions-sources"; export const config = { sources: ["mySourceAlias"] } async function MyExternalFunction(): Promise<string> { const source = await getSource("mySourceAlias"); const { url } = getHttpsConnection(source); const fetch = await getFetch(source); const response = await fetch(url); return response.text(); }
Copied!
1 2 3 4 5 6 7 8 9 10 11 from functions.api import function from functions.sources import get_source @function(sources=["mySourceAlias"]) def my_external_function() -> str: source = get_source("mySourceAlias") url = source.get_https_connection().url client = source.get_https_connection().get_client() response = client.get(url) return response.text

ライブプレビューで関数をテストでき、公開後はその関数を使用して外部呼び出しを実行できます。

fetch 関数または HTTP エージェントをオーバーライドしない限り、サーバーレス実行やライブプレビューでは、サードパーティークライアントはまだサポートされていません。 すべての環境で API 呼び出しが正しく動作するようにするには、該当するライブラリのメソッドを使用し、適切な設定でリクエストを行う必要があります。外部ソースまたは Foundry 内部の URL への直接的な API 呼び出しは、すべての環境で動作するとは限りません。

ソースの属性と資格情報にアクセスする

各関数タイプに対応するライブラリが提供するソース属性にアクセスできます。

以下の例は、上記の例で使用したソースのベース URL を取得する方法を示しています。

Copied!
1 const { url } = MySource.getHttpsConnection();
Copied!
1 const { url } = getHttpsConnection(source);
Copied!
1 url = get_source("mySourceAlias").get_https_connection().url

以下の構文でシークレットにアクセスすることで、ソースに保存されている追加のシークレットや資格情報にもアクセスできます。

Copied!
1 const secret = MySource.getSecret("MySecret");
Copied!
1 const secret = source.secrets["MySecret"];
Copied!
1 secret = get_source("mySourceAlias").get_secret("MySecret")

設定済みのクライアントを使用する

REST API を提供するソースでは、ソースオブジェクトからクライアントを取得できます。このクライアントには、ソースで指定されたサーバー証明書とクライアント証明書があらかじめ設定されています。また、関数が実行される環境からの外向き通信を可能にする追加のプロキシ設定も含まれています。すべての環境から関数がソースに外向き通信できることを保証するため、可能な限り、このクライアントを常に使用してください。

Copied!
1 const fetch = MySource.fetch;
Copied!
1 const fetch = await getFetch(source);
Copied!
1 client = source.get_https_connection().get_client()

または、独自のクライアントや、外部リクエストを行うサードパーティーライブラリを使用し、ソースオブジェクトから属性と資格情報を取得することもできます。

TypeScript v2 の関数は、カスタム HTTP エージェントを受け入れるサードパーティーライブラリと連携するための追加の統合ポイントとして、設定済みの HTTP エージェントを提供します。

以下の例は、このエージェントを取得し、axios ↗ とともに使用する方法を示しています。

Copied!
1 2 3 4 5 6 7 8 9 import { getHttpAgent, getHttpsConnection } from "@palantir/functions-sources"; import axios from 'axios'; const agent = await getHttpAgent(source); const { url } = getHttpsConnection(source); const response = await axios.get(url, { httpsAgent: agent, });

現在、ソースが HTTPS クライアントを提供していない限り、資格情報ではないソース属性にアクセスすることはできません。たとえば、PostgreSQL ソースの hostname や、シークレットではないほかの属性にはアクセスできません。

アウトバウンドアプリケーションで OAuth 2.0 を使用する

外部 API が OAuth 2.0 認可を必要とする場合は、Control Panel でアウトバウンドアプリケーションを設定し、REST API ソースの認証方法として使用できます。関数の実行時に、ソースは呼び出したユーザーの OAuth アクセストークンをセッション資格情報として公開します。関数はそのトークンを使用して、ユーザーに代わって外部 API を呼び出せます。

このパターンは、Python および TypeScript v2 関数でサポートされています。コード例については、後述のソースの事前設定済みクライアントを使用するを参照してください。

制限事項

  • TypeScript v1: TypeScript v1 関数は、ソースから OAuth トークンを直接取得できません。TypeScript v1 関数から OAuth 2.0 API に対して認証するには、アウトバウンドアプリケーションが設定された REST API ソース上の Webhook で呼び出しをラップします。トークンに直接アクセスするには、TypeScript v2 への移行を検討してください。
  • デプロイモード:関数がデプロイモードで実行されている場合、OAuth トークンの更新は利用できません。実行中に呼び出したユーザーのアクセストークンが期限切れになっても、関数は自動的に更新できません。OAuth ベースのアウトバウンドアプリケーションを使用するには、サーバーレスモードで関数を実行します。
  • Workshop での関数の直接使用:関数ベースの変数やウィジェットのコンテンツを設定する関数など、Workshop モジュール内で直接使用される関数は、OAuth 2.0 の対話型認可プロンプトを表示できません。ユーザーがアウトバウンドアプリケーションをまだ認可していない場合、関数はプロンプトを表示せず、実行に失敗します。Workshop から OAuth ベースの関数を使用するには、関数ベースのアクションでラップします。または、Workshop で関数が直接呼び出される前に、ユーザーが別の対話型インターフェース(同じアウトバウンドアプリケーションに対する関数ベースのアクションなど)で認可フローを完了していることを確認してください。

ソースの事前設定済みクライアントを使用する

最も簡単な方法は、ソースが提供する HTTP クライアントを使用することです。Authorization ヘッダーは自動的に挿入されます。

Copied!
1 2 3 4 5 6 7 8 9 10 11 from functions.api import function from functions.sources import get_source @function(sources=["myOAuthSourceAlias"]) def call_external_api() -> str: source = get_source("myOAuthSourceAlias") url = source.get_https_connection().url client = source.get_https_connection().get_client() response = client.get(url + "/api/v1/resource", timeout=10) return response.text
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { getSource, getHttpsConnection, getFetch } from "@palantir/functions-sources"; export const config = { sources: ["myOAuthSourceAlias"] }; export default async function callExternalApi(): Promise<string> { const source = await getSource("myOAuthSourceAlias"); const { url } = getHttpsConnection(source); const fetch = await getFetch(source); const response = await fetch(url + "/api/v1/resource"); return response.text(); }

トークンを手動で挿入してネイティブ HTTP クライアントを使用する

ソースが提供する HTTP クライアントではなく、独自の HTTP クライアントを使用する必要がある場合は、セッション資格情報から OAuth トークンを取得し、Authorization ヘッダーを手動で設定します。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import requests from functions.api import function from functions.sources import get_source from external_systems.sources import OauthCredentials, Refreshable, SourceCredentials @function(sources=["myOAuthSourceAlias"]) def call_external_api() -> str: source = get_source("myOAuthSourceAlias") url = source.get_https_connection().url refreshable_credentials: Refreshable[SourceCredentials] = source.get_session_credentials() session_credentials: SourceCredentials = refreshable_credentials.get() if not isinstance(session_credentials, OauthCredentials): raise ValueError("Expected OAuth credentials") access_token: str = session_credentials.access_token response = requests.get( url + "/api/v1/resource", headers={"Authorization": f"Bearer {access_token}"}, timeout=10, ) return response.text
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { getSource, getHttpsConnection } from "@palantir/functions-sources"; export const config = { sources: ["myOAuthSourceAlias"] }; export default async function callExternalApi(): Promise<string> { const source = await getSource("myOAuthSourceAlias"); const credentials = await source.sessionCredentials?.get(); if (!credentials || credentials.type !== "oauth") { throw new Error("Expected OAuth credentials"); } const accessToken: string = credentials.accessToken; const { url } = getHttpsConnection(source); const response = await fetch(url + "/api/v1/resource", { headers: { Authorization: `Bearer ${accessToken}` }, }); return response.text(); }

アクションで OAuth ベースの関数を使用する

よく使われるパターンは、OAuth ベースの外部 API を呼び出し、その結果をオントロジー編集に渡す方法です。その関数を関数ベースのアクションとして公開できます。ユーザーが Workshop または AIP Studio からアクションを実行すると、そのユーザーの OAuth トークンを使用して API が呼び出され、結果として行われるオブジェクトの編集は、そのユーザーによるものとして記録されます。

たとえば、以下の関数は OAuth トークンを使用して、呼び出したユーザーのプロフィールをサードパーティーの属性サービスから取得します。その後、その情報を使って新しいオントロジーオブジェクトを作成します。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from functions.api import function, OntologyEdit from functions.sources import get_source from ontology_sdk import FoundryClient from ontology_sdk.ontology.objects import UserProfile @function(sources=["myOAuthSourceAlias"], edits=[UserProfile]) def link_user_profile() -> list[OntologyEdit]: source = get_source("myOAuthSourceAlias") url = source.get_https_connection().url client = source.get_https_connection().get_client() response = client.get(url + "/v1/me", timeout=10) response.raise_for_status() profile = response.json() ontology_edits = FoundryClient().ontology.edits() ontology_edits.objects.UserProfile.create( profile["id"], display_name=profile["display_name"], ) return ontology_edits.get_edits()
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import { getSource, getHttpsConnection, getFetch } from "@palantir/functions-sources"; import { UserProfile } from "@ontology/sdk"; import { Client } from "@osdk/client"; import { createEditBatch, Edits } from "@osdk/functions"; type OntologyEdit = Edits.Object<UserProfile>; export const config = { sources: ["myOAuthSourceAlias"], edits: [UserProfile], }; export default async function linkUserProfile(client: Client): Promise<OntologyEdit[]> { const source = await getSource("myOAuthSourceAlias"); const { url } = getHttpsConnection(source); const fetch = await getFetch(source); const response = await fetch(url + "/v1/me"); if (!response.ok) { throw new Error(`Failed to fetch profile: ${response.status}`); } const profile = await response.json(); const batch = createEditBatch<OntologyEdit>(client); batch.create(UserProfile, { userProfileId: profile.id, displayName: profile.display_name, }); return batch.getEdits(); }

よくあるエラーをトラブルシューティングする

HTTP 401: Unauthorized、Credentials expired and no refresh handler provided、Resolved source credentials are not present on the Source などの OAuth 認可エラーについては、Data Connection のトラブルシューティングリファレンスの OAuth とアウトバウンドアプリケーションを参照してください。

HTTP 407: プロキシ認証が必要

関数のネットワークリクエストは、ソースのエグレスポリシーで許可されている必要があります。宛先ホスト名が許可されたポリシーと一致しない場合、リクエストが HTTP 407: Proxy Authentication Required を返すことがあります。

エグレスポリシーに問題がないように見える場合は、リクエスト URL の組み立て方を確認します。getHttpsConnection() から取得した URL には末尾のスラッシュがないため、先頭の / を省略したパスを追加すると、ホスト名と結合されます。

Copied!
1 2 "https://example.com" + "api/v1" → "https://example.comapi/v1"

結果として生成されるホスト名(example.comapi)は、どのエグレスポリシーでも許可されていないため、リクエストは拒否されます。パスの先頭に / を付けます(例:url + "/api/v1")。