Mobile Step 3: API Client

Connect your chat app to the Flask backend using fetch().

What You'll Learn

  • Making HTTP requests with fetch()
  • Async/await for asynchronous code
  • Handling JSON responses
  • Error handling for network requests

Step 1: Set the API Base URL

const API_BASE_URL = "http://10.0.2.2:5000";

Which URL to use: | Environment | URL | |---|---| | Android emulator | http://10.0.2.2:5000 | | iOS simulator | http://localhost:5000 | | Physical device | http://YOUR_COMPUTER_IP:5000 | | Expo web | http://localhost:5000 |

Find your computer's IP:

# macOS/Linux
ip addr show | grep inet

# Windows
ipconfig

Step 2: Fetch Messages on App Load

import { useEffect } from "react";

useEffect(() => {
  fetchMessages();
}, []);

const fetchMessages = async () => {
  try {
    const response = await fetch(`${API_BASE_URL}/api/messages`);
    const data: Message[] = await response.json();
    setMessages(data);
  } catch (err) {
    console.error("Failed to fetch messages:", err);
  }
};
  • useEffect runs once when the app loads (the [] dependency array means "run once")
  • fetch() sends a GET request to the backend
  • response.json() parses the JSON response body

Step 3: Send a Message

Replace the placeholder handleSend from step 2:

const handleSend = async () => {
  const text = input.trim();
  if (!text) return;

  setInput("");  // Clear input immediately
  setError(null);

  // Add user message to the list immediately (optimistic UI)
  const tempUser: Message = {
    id: Date.now(),
    content: text,
    sender: "user",
  };
  setMessages((prev) => [...prev, tempUser]);

  try {
    const response = await fetch(`${API_BASE_URL}/api/chat`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: text }),
    });

    if (!response.ok) {
      const errData = await response.json();
      throw new Error(errData.error || "Request failed");
    }

    const data = await response.json();

    // Replace temp message with server-confirmed message, add AI reply
    setMessages((prev) =>
      prev.map((m) =>
        m.id === tempUser.id ? data.user_message : m
      ).concat(data.ai_message)
    );
  } catch (err: any) {
    setError(err.message || "Failed to send message");
    // Mark the failed message
    setMessages((prev) =>
      prev.map((m) =>
        m.id === tempUser.id
          ? { ...m, content: `${m.content} (failed)` }
          : m
      )
    );
  }
};

Step 4: Understanding fetch()

const response = await fetch(url, {
  method: "POST",                    // HTTP method
  headers: {
    "Content-Type": "application/json",  // Tell server we're sending JSON
  },
  body: JSON.stringify({ message: text }),  // Convert object to JSON string
});

The await keyword pauses execution until the response comes back. Without it, the code would continue before the request finishes.

Step 5: Error Handling

try {
  // Network request
} catch (err) {
  // Something went wrong — no response at all (network error)
}

Two types of errors: 1. Network error — can't reach the server (caught by catch) 2. HTTP error — server responded with an error status (check response.ok)

Step 6: Test the Connection

  1. Start the backend: python app/__init__.py (from backend/)
  2. Start the mobile app: npx expo start (from mobile/)
  3. Type a message and tap Send
  4. The message appears, and the AI should respond (if you configured OpenAI)
  5. If the AI doesn't respond: check the error banner

Common Issues

"Network request failed" — The app can't reach the backend: - Is the backend running? - Is the URL correct for your platform (emulator vs physical device)? - Are both devices on the same network?

JSON parse error — The response isn't valid JSON: - Check the backend terminal for errors - Test with curl to confirm the API works