🔧output-error-http-client
- プラグイン
- outputai
- ソース
- GitHub で見る ↗
説明
HTTPクライアントのOutput SDKステップにおける誤用を修正します。 次のような場合に使用: - トレースされていないリクエストが発生している - エラーの詳細が欠落している - axiosに関連するエラーが発生している - HTTPコールが適切にログ記録・リトライされていない
原文を表示
Fix HTTP client misuse in Output SDK steps. Use when seeing untraced requests, missing error details, axios-related errors, or when HTTP calls aren't being properly logged and retried.
ユースケース
- ✓トレースされていないリクエストを修正する
- ✓エラーの詳細が欠落しているときに対応する
- ✓axiosに関連するエラーを解決する
- ✓HTTPコールのログ記録・リトライを修正する
本文(日本語訳)
HTTP クライアントの誤用を修正する
概要
このスキルは、Output SDK の @outputai/http が提供する httpClient を使わずに、axios・fetch・その他の HTTP クライアントを直接使用している場合の問題を診断・修正するために役立ちます。
Output SDK のクライアントは、トレーシング・自動リトライ・より優れたエラーハンドリングを提供します。
このスキルを使用するタイミング
次のような場合に使用:
- HTTP リクエストがトレースされていない(ワークフローのトレースに表示されない)
- 失敗したリクエストのエラー詳細が欠落している
- axios 関連のエラーやインポートの問題が発生している
- HTTP 失敗時のリトライが機能していない
- タイムアウトの動作が一貫していない
根本原因
axios・fetch・その他の HTTP クライアントを直接使用すると、Output SDK の以下の機能がバイパスされます:
- リクエスト/レスポンスのトレーシング: ワークフローのトレースにコールが記録されない
- 自動リトライ: 失敗したリクエストが再試行されない
- エラーの標準化: エラーフォーマットが一貫しない場合がある
- タイムアウトの制御: タイムアウトがステップのタイムアウトと連携しない場合がある
症状
axios を直接使用している場合
// 誤り: axios を使用
import axios from 'axios';
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const response = await axios.get( 'https://api.example.com/data' );
return response.data;
}
} );
fetch を直接使用している場合
// 誤り: fetch を使用
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const response = await fetch( 'https://api.example.com/data' );
return response.json();
}
} );
解決策
@outputai/http の httpClient を使用してください:
基本的な使い方
import { z, step } from '@outputai/core';
import { httpClient } from '@outputai/http';
export const fetchData = step( {
name: 'fetchData',
inputSchema: z.object( {
endpoint: z.string()
} ),
outputSchema: z.object( {
data: z.unknown()
} ),
fn: async input => {
const client = httpClient( {
prefixUrl: 'https://api.example.com'
} );
const data = await client.get( input.endpoint ).json();
return { data };
}
} );
詳細な設定を指定する場合
import { httpClient } from '@outputai/http';
const client = httpClient( {
prefixUrl: 'https://api.example.com',
timeout: 30000, // 30 秒タイムアウト
retry: {
limit: 3, // 最大 3 回リトライ
methods: [ 'GET', 'POST' ], // リトライ対象のメソッド
statusCodes: [ 408, 500, 502, 503, 504 ] // リトライを発動するステータスコード
},
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
} );
HTTP メソッド
GET リクエスト
const data = await client.get( 'users/123' ).json();
POST リクエスト
const result = await client.post( 'users', {
json: {
name: 'John',
email: 'john@example.com'
}
} ).json();
PUT リクエスト
const updated = await client.put( 'users/123', {
json: {
name: 'John Updated'
}
} ).json();
DELETE リクエスト
await client.delete( 'users/123' );
クエリパラメータを指定する場合
const data = await client.get( 'search', {
searchParams: {
q: 'query',
limit: 10
}
} ).json();
移行の完全な例
移行前(誤り — axios を使用)
import axios from 'axios';
import { step } from '@outputai/core';
export const createUser = step( {
name: 'createUser',
fn: async input => {
try {
const response = await axios.post(
'https://api.example.com/users',
{ name: input.name, email: input.email },
{
headers: { 'Authorization': `Bearer ${process.env.API_KEY}` },
timeout: 30000
}
);
return response.data;
} catch ( error ) {
if ( axios.isAxiosError( error ) ) {
throw new Error( `API Error: ${error.response?.data?.message}` );
}
throw error;
}
}
} );
移行後(正しい — httpClient を使用)
import { z, step } from '@outputai/core';
import { httpClient } from '@outputai/http';
export const createUser = step( {
name: 'createUser',
inputSchema: z.object( {
name: z.string(),
email: z.string().email()
} ),
outputSchema: z.object( {
id: z.string(),
name: z.string(),
email: z.string()
} ),
fn: async input => {
const client = httpClient( {
prefixUrl: 'https://api.example.com',
timeout: 30000,
retry: { limit: 3 },
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`
}
} );
const user = await client.post( 'users', {
json: {
name: input.name,
email: input.email
}
} ).json();
return user;
}
} );
エラーハンドリング
httpClient は構造化されたエラーハンドリングを提供します:
import { httpClient, HTTPError } from '@outputai/http';
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const client = httpClient( { prefixUrl: 'https://api.example.com' } );
try {
return await client.get( 'data' ).json();
} catch ( error ) {
if ( error instanceof HTTPError ) {
// レスポンスの詳細にアクセス
const status = error.response.status;
const body = await error.response.json();
throw new Error( `API returned ${status}: ${body.message}` );
}
throw error;
}
}
} );
axios / fetch の使用箇所を探す
コードベースを検索してください:
# axios のインポートを検索
grep -rn "from 'axios'\|from \"axios\"" src/
# fetch の呼び出しを検索
grep -rn "await fetch(" src/
# その他の HTTP ライブラリを検索
grep -rn "got\|node-fetch\|request\|superagent" src/
httpClient のメリット
- トレーシング: リクエストがタイミング情報付きでワークフローのトレースに表示される
- 自動リトライ: 一時的な障害に対して設定可能なリトライロジックを提供
- 一貫したエラー: すべてのリクエストにわたって標準化されたエラーフォーマット
- タイムアウトの統合: ステップおよびワークフローのタイムアウトと連携して動作
- 型安全性: TypeScript の完全なサポート
設定オプション
| オプション | 説明 | デフォルト |
|---|---|---|
prefixUrl |
すべてのリクエストのベース URL | (必須) |
timeout |
リクエストタイムアウト(ミリ秒) | 10000 |
retry.limit |
最大リトライ回数 | 2 |
retry.methods |
リトライ対象の HTTP メソッド | ['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE'] |
retry.statusCodes |
リトライを発動するステータスコード | [408, 413, 429, 500, 502, 503, 504] |
headers |
デフォルトヘッダー | {} |
確認手順
httpClient への移行後:
- ワークフローを実行する:
npx output workflow run <name> '<input>' - トレースを確認する:
npx output workflow debug <id> --json - トレーシングを検証する: HTTP リクエストがステップのトレースに表示されていることを確認
- リトライをテストする: 障害をシミュレートしてリトライの動作を検証
関連する問題
- ワークフロー関数における I/O については
output-error-direct-ioを参照 - 接続の問題については
output-services-checkを参照 - 暗号化されたシークレットの管理については
output-dev-credentialsを参照
原文(English)を表示
Fix HTTP Client Misuse
Overview
This skill helps diagnose and fix issues caused by using axios, fetch, or other HTTP clients directly instead of Output SDK's httpClient from @outputai/http. The Output SDK client provides tracing, automatic retries, and better error handling.
When to Use This Skill
You're seeing:
- Untraced HTTP requests (not appearing in workflow traces)
- Missing error details for failed requests
- axios-related errors or import issues
- Retries not working for HTTP failures
- Inconsistent timeout behavior
Root Cause
Using axios, fetch, or other HTTP clients directly bypasses Output SDK's:
- Request/response tracing: Calls aren't logged in workflow traces
- Automatic retries: Failed requests aren't retried
- Error standardization: Error formats may be inconsistent
- Timeout handling: Timeouts may not integrate with step timeouts
Symptoms
Using axios Directly
// WRONG: Using axios
import axios from 'axios';
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const response = await axios.get( 'https://api.example.com/data' );
return response.data;
}
} );
Using fetch Directly
// WRONG: Using fetch
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const response = await fetch( 'https://api.example.com/data' );
return response.json();
}
} );
Solution
Use httpClient from @outputai/http:
Basic Usage
import { z, step } from '@outputai/core';
import { httpClient } from '@outputai/http';
export const fetchData = step( {
name: 'fetchData',
inputSchema: z.object( {
endpoint: z.string()
} ),
outputSchema: z.object( {
data: z.unknown()
} ),
fn: async input => {
const client = httpClient( {
prefixUrl: 'https://api.example.com'
} );
const data = await client.get( input.endpoint ).json();
return { data };
}
} );
With Full Configuration
import { httpClient } from '@outputai/http';
const client = httpClient( {
prefixUrl: 'https://api.example.com',
timeout: 30000, // 30 second timeout
retry: {
limit: 3, // Retry up to 3 times
methods: [ 'GET', 'POST' ], // Which methods to retry
statusCodes: [ 408, 500, 502, 503, 504 ] // Which status codes trigger retry
},
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
} );
HTTP Methods
GET Request
const data = await client.get( 'users/123' ).json();
POST Request
const result = await client.post( 'users', {
json: {
name: 'John',
email: 'john@example.com'
}
} ).json();
PUT Request
const updated = await client.put( 'users/123', {
json: {
name: 'John Updated'
}
} ).json();
DELETE Request
await client.delete( 'users/123' );
With Query Parameters
const data = await client.get( 'search', {
searchParams: {
q: 'query',
limit: 10
}
} ).json();
Complete Migration Example
Before (Wrong - using axios)
import axios from 'axios';
import { step } from '@outputai/core';
export const createUser = step( {
name: 'createUser',
fn: async input => {
try {
const response = await axios.post(
'https://api.example.com/users',
{ name: input.name, email: input.email },
{
headers: { 'Authorization': `Bearer ${process.env.API_KEY}` },
timeout: 30000
}
);
return response.data;
} catch ( error ) {
if ( axios.isAxiosError( error ) ) {
throw new Error( `API Error: ${error.response?.data?.message}` );
}
throw error;
}
}
} );
After (Correct - using httpClient)
import { z, step } from '@outputai/core';
import { httpClient } from '@outputai/http';
export const createUser = step( {
name: 'createUser',
inputSchema: z.object( {
name: z.string(),
email: z.string().email()
} ),
outputSchema: z.object( {
id: z.string(),
name: z.string(),
email: z.string()
} ),
fn: async input => {
const client = httpClient( {
prefixUrl: 'https://api.example.com',
timeout: 30000,
retry: { limit: 3 },
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`
}
} );
const user = await client.post( 'users', {
json: {
name: input.name,
email: input.email
}
} ).json();
return user;
}
} );
Error Handling
The httpClient provides structured error handling:
import { httpClient, HTTPError } from '@outputai/http';
export const fetchData = step( {
name: 'fetchData',
fn: async input => {
const client = httpClient( { prefixUrl: 'https://api.example.com' } );
try {
return await client.get( 'data' ).json();
} catch ( error ) {
if ( error instanceof HTTPError ) {
// Access response details
const status = error.response.status;
const body = await error.response.json();
throw new Error( `API returned ${status}: ${body.message}` );
}
throw error;
}
}
} );
Finding axios/fetch Usage
Search your codebase:
# Find axios imports
grep -rn "from 'axios'\|from \"axios\"" src/
# Find fetch calls
grep -rn "await fetch(" src/
# Find other HTTP libraries
grep -rn "got\|node-fetch\|request\|superagent" src/
Benefits of httpClient
- Tracing: Requests appear in workflow traces with timing
- Automatic Retries: Configurable retry logic for transient failures
- Consistent Errors: Standardized error format across all requests
- Timeout Integration: Works with step and workflow timeouts
- Type Safety: Full TypeScript support
Configuration Options
| Option | Description | Default |
|---|---|---|
prefixUrl |
Base URL for all requests | (required) |
timeout |
Request timeout in ms | 10000 |
retry.limit |
Max retry attempts | 2 |
retry.methods |
HTTP methods to retry | ['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE'] |
retry.statusCodes |
Status codes to retry | [408, 413, 429, 500, 502, 503, 504] |
headers |
Default headers | {} |
Verification
After migrating to httpClient:
- Run the workflow:
npx output workflow run <name> '<input>' - Check the trace:
npx output workflow debug <id> --json - Verify tracing: HTTP requests should appear in the step trace
- Test retries: Simulate failures to verify retry behavior
Related Issues
- For I/O in workflow functions, see
output-error-direct-io - For connection issues, see
output-services-check - For encrypted secrets management, see
output-dev-credentials
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。