AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Defensive Api Handling

skill-bradtaylorsf-alphaagent-team-defensive-api-handling · by bradtaylorsf

Safely handles API responses to prevent crashes from malformed JSON, HTML error pages, or unexpected response types. Use any time calling API endpoints.

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-bradtaylorsf-alphaagent-team-defensive-api-handling

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-bradtaylorsf-alphaagent-team-defensive-api-handling)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
6mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Defensive Api Handling? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Defensive API Handling

Purpose: Safely handle API responses to prevent crashes

When to Use: Any time you call an API endpoint (in tests or production code)


Never Assume API Returns JSON

APIs can return:

  • JSON (expected)
  • HTML error pages
  • Empty responses
  • Malformed JSON
  • Non-200 status codes

Your code must handle ALL of these safely.


Pattern 1: Safe JSON Parsing

async function safeJsonParse(response: Response): Promise {
  // 1. Check status code
  if (!response.ok) {
    console.warn(`API returned ${response.status} ${response.statusText}`);
    return null;
  }

  // 2. Check content type
  const contentType = response.headers.get('content-type');
  if (!contentType?.includes('application/json')) {
    console.warn(`Expected JSON, got ${contentType}`);
    const text = await response.text();
    console.warn(`Response body: ${text.slice(0, 200)}`);
    return null;
  }

  // 3. Try to parse
  try {
    return await response.json();
  } catch (error) {
    console.warn('Failed to parse JSON:', error.message);
    return null;
  }
}

Pattern 2: Fetch with Timeout

async function fetchWithTimeout(
  url: string,
  options: RequestInit = {},
  timeoutMs: number = 10000
): Promise {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal
    });
    return response;
  } finally {
    clearTimeout(timeout);
  }
}

Pattern 3: Retry Logic

async function fetchWithRetry(
  url: string,
  options: RequestInit = {},
  maxRetries: number = 3,
  delayMs: number = 1000
): Promise {
  for (let attempt = 1; attempt = 500 && attempt  setTimeout(resolve, delayMs * attempt));
        continue;
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries) {
        console.error(`All ${maxRetries} attempts failed:`, error.message);
        return null;
      }
      await new Promise(resolve => setTimeout(resolve, delayMs * attempt));
    }
  }
  return null;
}

Pattern 4: Type-Safe API Responses

// Define expected response types
interface ApiResponse {
  data?: T;
  error?: string;
}

// Type guard function
function isApiResponse(
  value: unknown,
  dataGuard: (v: unknown) => v is T
): value is ApiResponse {
  if (typeof value !== 'object' || value === null) return false;
  const obj = value as Record;

  if ('error' in obj && typeof obj.error !== 'string') return false;
  if ('data' in obj && !dataGuard(obj.data)) return false;

  return true;
}

// Safe API call with type checking
async function safeApiCall(
  url: string,
  dataGuard: (v: unknown) => v is T
): Promise {
  const response = await fetchWithRetry(url);
  if (!response) return null;

  const json = await safeJsonParse(response);
  if (!json) return null;

  if (!isApiResponse(json, dataGuard)) {
    console.warn('Unexpected response structure:', json);
    return null;
  }

  if (json.error) {
    console.warn('API returned error:', json.error);
    return null;
  }

  return json.data ?? null;
}

Pattern 5: Error Boundary for API Calls

async function withApiErrorBoundary(
  operation: () => Promise,
  context: string,
  fallback: T
): Promise {
  try {
    return await operation();
  } catch (error) {
    console.error(`[${context}] API error:`, error.message);

    // Log additional context
    if (error instanceof TypeError && error.message.includes('fetch')) {
      console.error(`Network error - check connectivity`);
    }

    return fallback;
  }
}

// Usage
const users = await withApiErrorBoundary(
  () => fetchUsers(),
  'fetchUsers',
  [] // fallback to empty array
);

Anti-Patterns to Avoid

// ❌ BAD: Assumes JSON, no error handling
const data = await fetch('/api/users').then(r => r.json());

// ❌ BAD: No timeout
const response = await fetch('/api/slow-endpoint');

// ❌ BAD: Trusts response structure
const users = data.users.map(u => u.name);

// ❌ BAD: Silent failures
try {
  return await fetch('/api/users').then(r => r.json());
} catch {
  return [];  // Caller doesn't know it failed
}

Success Criteria

  • Zero SyntaxError: Unexpected token '<' errors
  • Zero Cannot read property of undefined errors
  • Cleanup hooks never cause test suite to crash
  • Tests skip gracefully when API unavailable
  • All API calls have timeouts
  • Errors are logged with context

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.