Indie Kit DocsIndie Kit Docs
Tutorials

Making API Calls

Learn how to make API calls with and without authentication in Indie Kit using SWR and fetch

Making API Calls 🔌

Let's explore how to make API calls in Indie Kit. We'll cover both authenticated and public endpoints using SWR and fetch. 🚀

Public API Calls 🌐

These endpoints don't require authentication. Perfect for public data like blog posts or product listings.

Backend Implementation

// src/app/api/products/route.ts
import { NextResponse } from 'next/server'
 
export async function GET() {
  const products = [
    { id: 1, name: 'Product 1' },
    { id: 2, name: 'Product 2' },
  ]
  
  return NextResponse.json(products)
}

Frontend Implementation

// src/components/products/product-list.tsx
'use client'
 
import useSWR from 'swr'
 
export function ProductList() {
  const { data, error, isLoading } = useSWR('/api/products')
 
  if (error) return <div>Failed to load products</div>
  if (isLoading) return <div>Loading...</div>
 
  return (
    <ul>
      {data.map((product) => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  )
}

Protected API Calls 🔒

These endpoints require authentication. Perfect for user-specific data or admin actions.

Backend Implementation

// src/app/api/app/user-settings/route.ts
import { withAuthRequired } from '@/lib/auth/withAuthRequired'
import { NextResponse } from 'next/server'
 
export const GET = withAuthRequired(async (req, context) => {
  const { session } = context
  
  const settings = {
    userId: session.user.id,
    theme: 'light',
    notifications: true,
  }
  
  return NextResponse.json(settings)
})
 
export const POST = withAuthRequired(async (req, context) => {
  const { session } = context
  const body = await req.json()
  
  // Update settings logic here...
  
  return NextResponse.json({ success: true })
})

Frontend Implementation

// src/components/settings/user-settings.tsx
'use client'
 
import useSWR, { mutate } from 'swr'
 
export function UserSettings() {
  const { data, error, isLoading } = useSWR('/api/app/user-settings')
 
  const updateSettings = async (newSettings) => {
    try {
      const response = await fetch('/api/app/user-settings', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(newSettings),
      })
 
      if (!response.ok) throw new Error('Failed to update settings')
 
      // Update the local data immediately
      mutate('/api/app/user-settings', { ...data, ...newSettings }, false)
 
      // Show success message
      toast.success('Settings updated!')
    } catch (error) {
      toast.error('Failed to update settings')
    }
  }
 
  if (error) return <div>Failed to load settings</div>
  if (isLoading) return <div>Loading...</div>
 
  return (
    <div>
      <h2>User Settings</h2>
      <button
        onClick={() => updateSettings({ theme: 'dark' })}
      >
        Switch to Dark Theme
      </button>
    </div>
  )
}

Using SWR Effectively 🎯

SWR (Stale-While-Revalidate) is already configured in Indie Kit. Here's how to use it:

  1. Basic Fetching

    const { data, error, isLoading } = useSWR('/api/endpoint')
  2. With Mutation

    // Update local data and revalidate
    mutate('/api/endpoint', newData)
     
    // Update local data without revalidation
    mutate('/api/endpoint', newData, false)
  3. Conditional Fetching

    // Only fetch when user is defined
    const { data } = useSWR(user ? `/api/users/${user.id}` : null)

💡 Pro Tip Read more about SWR features in the official documentation.

Best Practices 💫

  1. Error Handling 🚨

    if (error) {
      if (error.status === 401) {
        // Handle unauthorized
        return <div>Please log in</div>
      }
      // Handle other errors
      return <div>Error: {error.message}</div>
    }
  2. Loading States

    if (isLoading) {
      return <LoadingSpinner />
    }
  3. Optimistic Updates

    // Update UI immediately, then revalidate
    mutate('/api/endpoint', { ...data, ...newData }, false)
  4. Type Safety 🛡️

    interface Settings {
      theme: 'light' | 'dark'
      notifications: boolean
    }
     
    const { data } = useSWR<Settings>('/api/app/user-settings')

Security Tips 🔐

  1. Always use withAuthRequired for protected routes
  2. Validate request bodies server-side
  3. Use proper HTTP methods (GET for fetching, POST for creating, etc.)
  4. Handle errors gracefully on both client and server

Now you're ready to build powerful features with API calls in Indie Kit! 🚀

On this page