JSTAcademy
0 XP
Dashboard
Crash Courses
Consuming APIs with fetch
10 min
Masters+175 XP
Crash Courses · Masters

Consuming APIs with fetch

Fetch, cache, and handle errors from external REST APIs in Next.js.
10 min read+175 XP on completionCert: REST APIs Crash Course
Tap any word in the text below to start reading from there.

Consuming APIs with fetch

fetch is the universal HTTP client. Typed wrappers give you consistency and type safety across all API calls.

Basic Fetch

// fetch rejects only on network error — always check res.ok
const res = await fetch('/api/courses')
if (!res.ok) {
  throw new Error(`HTTP ${res.status}: ${res.statusText}`)
}
const data = await res.json()

Typed API Client

// lib/api.ts
type ApiResponse<T> = { data: T; error?: never } | { data?: never; error: string }

async function apiFetch<T>(
  url: string,
  options?: RequestInit
): Promise<ApiResponse<T>> {
  try {
    const res = await fetch(url, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...options?.headers,
      },
    })

    const json = await res.json()

    if (!res.ok) {
      return { error: json.error ?? `HTTP ${res.status}` }
    }

    return { data: json.data ?? json }
  } catch (err) {
    return { error: 'Network error' }
  }
}

// Usage — fully typed
const { data: courses, error } = await apiFetch<Course[]>('/api/courses')
if (error) return <Error message={error} />
return <CourseList courses={courses} />

Fetch with Timeout

async function fetchWithTimeout<T>(url: string, ms = 5000): Promise<T> {
  const controller = new AbortController()
  const id = setTimeout(() => controller.abort(), ms)

  try {
    const res = await fetch(url, { signal: controller.signal })
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    return res.json()
  } finally {
    clearTimeout(id)
  }
}

Azure TTS API Call Pattern (used in this app)

const speechRes = await fetch(
  `https://${region}.tts.speech.microsoft.com/cognitiveservices/v1`,
  {
    method: 'POST',
    headers: {
      'Ocp-Apim-Subscription-Key': process.env.AZURE_SPEECH_KEY!,
      'Content-Type': 'application/ssml+xml',
      'X-Microsoft-OutputFormat': 'audio-48khz-192kbitrate-mono-mp3',
    },
    body: ssmlString,
  }
)

if (!speechRes.ok) {
  throw new Error(`Azure TTS error: ${speechRes.status}`)
}

const audioBuffer = await speechRes.arrayBuffer()
0%