Lesson 5 of 6 · 12 min · 2 hands-on steps
Calling AI Models from Your Own App
How AI APIs work, how to structure a conversation, and how to handle the response safely.
How AI APIs work
You send a request with a model name, instructions (a system prompt), and the conversation so far. You get back a response with the model's reply. Most providers work like this; here's the shape used by Anthropic's Claude API:
const request = {
model: "claude-haiku-4-5",
max_tokens: 1024,
system: "You are a friendly coding tutor. Give hints, not answers.",
messages: [
{ role: "user", content: "Why does my loop never stop?" },
],
};
console.log(JSON.stringify(request, null, 2));The API is stateless: it doesn't remember previous calls, so you send the conversation history every time.
Responses are blocks
The reply comes back as a list of content blocks. Usually text, but models can also return other block types (like tool calls), and they can refuse unsafe requests. Never assume content[0].text exists; check the block types and the stop_reason.
Production rules
- Keep API keys on the server. Call the AI from your back end, never from browser code where anyone can steal the key.
- Control cost: limit history length and
max_tokens, cap messages per user per day, and set a spending limit with your provider. - Stream long responses so users see text appear immediately.
- Handle errors: rate limits (429), timeouts and outages happen. Show a friendly message and retry later.
- Don't trust the output blindly: validate anything the model returns before acting on it.
Production AI features use exactly these patterns: history trimming, a system prompt, daily caps, streaming, and refusal handling.
🧪 Practice: 2 steps
0 / 2 doneStep 1 of 2 · Build the request
AI chat APIs take a list of messages with roles. Write buildRequest(history, userText) that returns:
{
model: "claude-haiku-4-5",
max_tokens: 1024,
system: "You are a friendly coding tutor.",
messages: [...history, { role: "user", content: userText }]
}
Keep only the last 10 messages of history (to control cost), and trim userText. Throw an Error if userText is empty after trimming.
function buildRequest(history, userText) {
return {};
}
Output appears here. Press Run or Ctrl/⌘ + Enter.
Step 2 of 2 · Read the response safely
Responses contain a content array of blocks; text blocks look like { type: "text", text: "…" }, but other types exist. Write extractText(response) that joins the text of all text blocks.
If response.stop_reason is "refusal", return "Sorry, I can't help with that.". If there are no text blocks, return "".
function extractText(response) {
return response.content[0].text;
}
Output appears here. Press Run or Ctrl/⌘ + Enter.
✅ Check your understanding
Where should your AI provider API key live?
Why limit how many past messages you send each time?
Create a free account to track your progress.