Pythonおよび TypeScript 用の Microsoft Web IQ SDK を使用する

Python および TypeScript で入手できる、Microsoft Web IQ API の公式 SDK。 これらの SDK を使用すると、アプリケーションは Web 検索、ビデオ検索、参照、ニュース検索、画像検索にリアルタイムでアクセスできます。これは、正確で最新の情報に基づいて LLM の応答を裏付けるように設計されています。

Python TypeScript
パッケージ pip install webiq npm install @microsoft/webiq
ランタイム Python 3.11 以降 Node.js 22 以上
ライセンス MIT MIT

Installation

Python

pip install webiq

TypeScript

npm install @microsoft/webiq

クイック スタート

Python ガイド

import os
from webiq import WebIQClient
from webiq.types import BrowseContentFormat, ContentFormat

with WebIQClient(api_key=os.environ["WEBIQ_API_KEY"]) as client:
    # Web search
    web = client.web.search(
        "Python programming",
        max_results=5,
        content_format=ContentFormat.passage,
    )
    for r in web.webResults or []:
        print(r.title, r.url)

    # Videos search
    videos = client.videos.search("machine learning tutorial", max_results=5)
    for v in videos.videoResults or []:
        print(v.title, v.length)

    # Browse a URL
    page = client.browse.fetch("https://www.microsoft.com", content_format=BrowseContentFormat.markdown)
    print(page.content)

    # News search
    news = client.news.search("technology", max_results=5)
    for item in news.newsResults or []:
        print(item.title, "-", item.source)

    # Image search
    images = client.images.search("golden gate bridge", max_results=5)
    for img in images.imageResults or []:
        print(img.title, img.url)

TypeScript ガイド

import { WebIQClient, BrowseContentFormat, ContentFormat } from '@microsoft/webiq';

async function main() {
  const client = new WebIQClient({ apiKey: process.env.WEBIQ_API_KEY });

  // Web search
  const web = await client.web.search('TypeScript programming', {
    maxResults: 5,
    contentFormat: ContentFormat.PASSAGE,
  });
  for (const r of web.webResults ?? []) console.log(r.title, r.url);

  // Videos search
  const videos = await client.videos.search('machine learning tutorial');
  for (const v of videos.videoResults ?? []) console.log(v.title, v.length);

  // Browse a URL
  const page = await client.browse.fetch('https://www.microsoft.com', {
    contentFormat: BrowseContentFormat.MARKDOWN,
  });
  console.log(page.content);

  // News search
  const news = await client.news.search('technology', { maxResults: 5 });
  for (const item of news.newsResults ?? []) console.log(item.title, '-', item.source);

  // Image search
  const images = await client.images.search('golden gate bridge', { maxResults: 5 });
  for (const img of images.imageResults ?? []) console.log(img.title, img.url);

  await client.close();
}

main().catch(console.error);

Authentication

API キー

# Python
import os
from webiq import WebIQClient

client = WebIQClient(api_key=os.environ["WEBIQ_API_KEY"])
// TypeScript
import { WebIQClient } from '@microsoft/webiq';

const client = new WebIQClient({ apiKey: process.env.WEBIQ_API_KEY });

Microsoft Entra ID

任意のAzure Identity TokenCredentialを渡します。

# Python — uses `azure-identity`
from azure.identity import DefaultAzureCredential
from webiq import WebIQClient

client = WebIQClient(credential=DefaultAzureCredential())
// TypeScript — uses `@azure/identity`
import { DefaultAzureCredential } from '@azure/identity';
import { WebIQClient } from '@microsoft/webiq';

const client = new WebIQClient({
  credential: new DefaultAzureCredential(),
});

SDK のリソースとメソッド

クライアントは、 web、 videos、 browse、 news、 imagesの 5 つのリソース名前空間を公開します。

client.web.search() — Web を検索し、ページコンテンツを取得して根拠付けを行います。

response = client.web.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=10,                # 1–50 (default 10)
    language="en",                 # ISO 639-1 code
    region="US",                   # Country/region code
    location="lat:40.7;long:-74.0",  # Optional
    content_format=ContentFormat.passage,   # passage (default) | text | html | markdown (full-page content)
    max_length=3000,               # Max content chars (default 3000)
)
# response.webResults → list of { title, url, content, lastUpdatedAt, crawledAt, language, isAdult }

client.videos.search() — 必要に応じて再生リストをサポートする関連するビデオ コンテンツを検索します。

response = client.videos.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=30,                # 1–30 (default 30)
    language="en",
    region="US",
    enable_playlist=True,          # Include playlist results
    freshness="month",             # week | month | year
)
# response.videoResults → list of { title, url, description, length, viewCount, moments[], thumbnailUrl, ... }
# response.playlists   → list of { title, videos[] }

ブラウズ

client.browse.fetch() — 任意の URL からコンテンツを抽出します。 ライブ クロールと JavaScript レンダリングをサポートします。

response = client.browse.fetch(
    url="https://www.microsoft.com",   # Required
    max_length=10000,                  # Max content chars, 1–500000
    live_crawl="fallback",             # "none" (cached only, default) | "fallback" (crawl if not cached) | "force" (always crawl, bypass cache)
    include_web_links=True,            # Include outbound hyperlinks
    include_image_links=True,          # Include image URLs
    render_dynamic_pages=False,        # JS rendering (requires live_crawl="fallback")
    content_format=BrowseContentFormat.markdown,   # text | html | markdown
)
# response → { url, title, content, isAdult, lastUpdatedAt, crawledAt, retryAfter, traceId }

client.news.search() — クエリに最も関連する抜粋を含む最新のニュース記事を入手します。

response = client.news.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=10,                # 1–20 (default 10)
    language="en",
    region="US",
    location="lat:40.7;long:-74.0",  # Optional
    content_format=ContentFormat.passage,
    max_length=3000,
)
# response.newsResults → list of { title, url, content, source, lastUpdatedAt, thumbnail, isAdult }

client.images.search() - 縦横比、サイズ、およびセーフサーチでフィルター処理を行う画像を検索します。

from webiq.types import ImageAspectRatio, ImageSize, SafeSearch

response = client.images.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=30,                # 1–30 (default 30)
    language="en",
    region="US",
    aspect_ratio=ImageAspectRatio.wide,   # square | wide | tall
    image_size=ImageSize.large,           # small | medium | large | extraLarge
    safe_search=SafeSearch.strict,        # off | strict
    watermark_free=True,
)
# response.imageResults → list of { title, url, hostPageUrl, caption, width, height, thumbnailUrl, ... }

Note

TypeScript メソッドでは、camelCase で同じパラメーターを使用します (例: maxResults、 contentFormat、 liveCrawl、 aspectRatio)。 呼び出し規則については、上記の TypeScript クイック スタートを参照してください。


非同期サポート

Python サポート

import asyncio
from webiq import WebIQAsyncClient

async def main():
    async with WebIQAsyncClient(api_key="your-api-key") as client:
        web, news = await asyncio.gather(
            client.web.search("async Python"),
            client.news.search("programming"),
        )
        for r in web.webResults or []:
            print(r.title)

asyncio.run(main())

TypeScript のサポート

TypeScript はネイティブで非同期に対応しています。 コンカレンシーには Promise.all を指定します。

const [web, news, videos] = await Promise.all([
  client.web.search('TypeScript'),
  client.news.search('programming'),
  client.videos.search('tutorial'),
]);

Configuration

タイムアウトと再試行

クライアントは、最上位のオプションとして timeout と retry を受け入れます。 各リソース メソッドでの呼び出しごとの timeout は、クライアント レベルの既定値をオーバーライドします。 SDK は、指数バックオフとジッターを使用して、408、500、502、503、504 を自動的に再試行します。応答 本文 に retryAfter フィールド("30s" など)が含まれている場合、SDK はバックオフ遅延の代わりにその指示に従って待機します。 429と430は決して自動再試行されず、RateLimitErrorとしてすぐに表面化するため、アプリケーションで独自のバックオフ ポリシーを適用できます。 クライアント側のタイムアウトも再試行されません ( APIConnectionErrorが発生します)。

# Python
from webiq import WebIQClient, RetryPolicy

client = WebIQClient(
    api_key="your-api-key",
    timeout=10.0,                  # seconds (default: 10.0)
    retry=RetryPolicy(
        max_retries=2,             # defaults shown
        base_delay_s=0.25,
        max_delay_s=4.0,
    ),
)

# Per-call override
response = client.web.search("query", language="de", region="DE", timeout=30.0)
// TypeScript
import { WebIQClient, RetryPolicy } from '@microsoft/webiq';

const client = new WebIQClient({
  apiKey: 'your-api-key',
  timeout: 10000, // milliseconds (default: 10000)
  retry: new RetryPolicy({
    maxRetries: 2, // defaults shown
    baseDelaySeconds: 0.25,
    maxDelaySeconds: 4.0,
  }),
});

カスタマイズされた HTTP クライアント (プロキシ、TLS、...)

HTTP の詳細設定 (プロキシ、カスタム TLS、接続プーリングなど) の場合。SDK は、呼び出し元が所有するクライアントを閉じません。

# Python — pass a pre-configured `httpx.Client` via `http_client`
import httpx
from webiq import WebIQClient, WebIQAsyncClient

# sync
http_client = httpx.Client(
  base_url="https://api.microsoft.ai/v3",
  proxy="http://proxy:8080",
)
client = WebIQClient(api_key="your-api-key", http_client=http_client)

# async
http_client = httpx.AsyncClient(
  base_url="https://api.microsoft.ai/v3",
  proxy="http://proxy:8080",
)
client = WebIQAsyncClient(api_key="your-api-key", http_client=http_client)
// TypeScript — pass a custom `fetchFn` that wraps the global `fetch`
import { ProxyAgent } from 'undici';
import { WebIQClient } from '@microsoft/webiq';

const proxyAgent = new ProxyAgent('http://my-proxy:8080');

const client = new WebIQClient({
  apiKey: 'your-api-key',
  // Spread `init` so headers, body, and the SDK's internal `AbortSignal` are preserved.
  fetchFn: (url, init) => fetch(url, { ...init, dispatcher: proxyAgent }),
});

キャンセル (TypeScript)

すべての TypeScript リソース メソッドは、AbortSignal経由でoptions.signalを受け入れます。 シグナルが abort されると、実行中の要求が取り消され、再試行が停止され、シグナルの reason は変更されずに再スローされます ( APIConnectionError ラップなし)。

// Apply a wall-clock budget that includes retries (the `timeout` option is per attempt only)
const result = await client.web.search('latest news', {
  signal: AbortSignal.timeout(5_000),
});

// Combine signals (e.g. an inbound request signal plus a wall-clock cap)
const result2 = await client.web.search('latest news', {
  signal: AbortSignal.any([req.signal, AbortSignal.timeout(5_000)]),
});

テレメトリフック

ログ記録、メトリック収集、デバッグのために、すべてのリクエスト/レスポンスを監視します。

# Python
from webiq import WebIQClient, TelemetryEvent

def on_request(event: TelemetryEvent):
    print(f"{event.method} {event.path} → {event.status_code} ({event.elapsed_ms}ms)")

client = WebIQClient(api_key="your-api-key", telemetry_hook=on_request)
// TypeScript
import { WebIQClient, TelemetryEvent } from '@microsoft/webiq';

const client = new WebIQClient({
  apiKey: 'your-api-key',
  telemetryHook: (event: TelemetryEvent) => {
    console.log(`${event.method} ${event.path} → ${event.statusCode} (${event.elapsedMs}ms)`);
  },
});

TelemetryEventフィールドは次のとおりです。

  • Python (snake_case): method、path、transport、attempt、status_code、request_id、trace_id、retry_after、elapsed_ms、error、error_body
  • TypeScript (camelCase): method、 path、 transport、 attempt、 statusCode、 requestId、 traceId、 retryAfter、 elapsedMs、 error、 errorBody

エラー処理

どちらの SDK でも、構造化エラー処理に対して型指定された例外が提供されます。 すべてのエラーは WebIQErrorから継承されます。

例外 HTTP の状態 トリガー
AuthenticationError 401 無効な API キーまたは不足している API キー
PermissionDeniedError 403 認証されたが、リソースに対して許可されていない
RateLimitError 429, 430 レート制限または同時リクエスト制限を超えました
APIStatusError 400, 404, 500, 503, 504, ... その他すべての HTTP エラー
APIConnectionError — ネットワークの問題、DNS エラー、タイムアウト
WebIQError — すべての SDK エラーの基本クラス

PermissionDeniedErrorとRateLimitErrorは両方ともAPIStatusErrorのサブクラスであるため、APIStatusErrorのより広範なハンドラはまだそれらをキャッチします。 SDK は429 / 430応答。サーバーのバックオフ ヒントは、アプリケーションで対応するためのerror.retry_after (Python) / error.retryAfter (TypeScript) で提供されます。

# Python
from webiq import (
    WebIQError,
    APIConnectionError,
    APIStatusError,
    AuthenticationError,
    PermissionDeniedError,
    RateLimitError,
)

try:
    response = client.web.search("test")
except PermissionDeniedError as e:
    # 403 — authenticated, but not allowed to call this resource
    print(f"Forbidden (HTTP {e.status_code}): {e}")
except AuthenticationError as e:
    # 401 — invalid or missing API key
    print(f"Auth failed (HTTP {e.status_code}): {e}")
except RateLimitError as e:
    # 429 or 430 — rate limit / concurrent-request limit (never auto-retried)
    print(f"Rate limited. Retry after: {e.retry_after}")
except APIStatusError as e:
    print(f"API error (HTTP {e.status_code}): {e}")
except APIConnectionError as e:
    print(f"Connection failed: {e}")
except WebIQError as e:
    print(f"SDK error: {e}")
// TypeScript
import {
  WebIQError,
  APIConnectionError,
  APIStatusError,
  AuthenticationError,
  PermissionDeniedError,
  RateLimitError,
} from '@microsoft/webiq';

try {
  const results = await client.web.search('test');
} catch (error) {
  if (error instanceof PermissionDeniedError) {
    // 403 — authenticated, but not allowed to call this resource
    console.error(`Forbidden (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof AuthenticationError) {
    // 401 — invalid or missing API key
    console.error(`Auth failed (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof RateLimitError) {
    // 429 or 430 — rate limit / concurrent-request limit (never auto-retried)
    console.error(`Rate limited. Retry after: ${error.retryAfter}`);
  } else if (error instanceof APIStatusError) {
    console.error(`API error (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof APIConnectionError) {
    console.error('Connection failed:', error.message);
  }
}

エラーの詳細を確認しています

すべての APIStatusError インスタンス ( PermissionDeniedError と RateLimitErrorを含む) は、完全なエラー応答本文を公開します。 Python SDK のほとんどの入力検証の問題 (例: max_results範囲外、空のquery) は、Pydantic によってクライアント側でキャッチされ、要求が送信される前にpydantic.ValidationErrorが発生します。次のパターンはサーバーが要求を拒否したときに適用されます。 browse.fetch は、欠落している URL やフィルタリングされた URL が構造化エラーとして表示されるものをトリガーする便利な方法です。

# Python
from webiq import WebIQClient
from webiq.errors import APIStatusError

client = WebIQClient(api_key="your-api-key")

try:
    response = client.browse.fetch("https://www.not-microsoft.com")
except APIStatusError as e:
    print(f"Status: {e.status_code}")                          # e.g. 404
    print(f"Message: {e}")                                      # e.g. "No result is found"
    if isinstance(e.body, dict):
        print(f"Error code: {e.body.get('errorCode')}")        # e.g. "BrowseApiDocNotFound"
        print(f"Category: {e.body.get('errorCategory')}")      # e.g. "UserError"
        print(f"Details: {e.body.get('technicalDetails')}")    # e.g. "NotFound"
        print(f"Trace ID: {e.body.get('traceId')}")
        print(f"Retry after: {e.body.get('retryAfter')}")
// TypeScript
import { WebIQClient, APIStatusError } from '@microsoft/webiq';

async function main() {
  const client = new WebIQClient({ apiKey: 'your-api-key' });

  try {
    await client.browse.fetch('https://www.not-microsoft.com');
  } catch (error) {
    if (error instanceof APIStatusError) {
      console.error(`Status: ${error.statusCode}`); // e.g. 404
      console.error(`Message: ${error.message}`); // e.g. "No result is found"

      // Full error body from the API response
      if (error.body && typeof error.body === 'object') {
        const body = error.body as Record<string, unknown>;
        console.error(`Error code: ${body.errorCode}`); // e.g. "BrowseApiDocNotFound"
        console.error(`Category: ${body.errorCategory}`); // e.g. "UserError"
        console.error(`Details: ${body.technicalDetails}`); // e.g. "NotFound"
        console.error(`Trace ID: ${body.traceId}`); // for debugging with support
        console.error(`Retry after: ${body.retryAfter}`); // for retryable errors
      }
    }
  }
}

main().catch(console.error);

デバッグのヒント

  • traceId — すべての応答には、エンドツーエンドデバッグ用の traceId フィールドが含まれています。 サポートにお問い合わせの際は、それを含めてください。
  • テレメトリ フック — 要求の試行、状態コード、タイミングをログに記録するコールバックをアタッチします。
  • エラー本文 — APIStatusError.body には、errorCode、errorCategory、technicalDetails、traceId を含む完全なサーバー応答が含まれます。