Lesson 16 of 20

Working with APIs

Async with asyncio

4 min read

Async programming lets you run multiple API calls concurrently. Instead of waiting for each call to complete, you can start several at once.

Why Async?

Synchronous (slow):
Call 1: |-------|
Call 2:         |-------|
Call 3:                 |-------|
Total: ~3 seconds

Asynchronous (fast):
Call 1: |-------|
Call 2: |-------|
Call 3: |-------|
Total: ~1 second

Basic Async Syntax

import asyncio

# Define an async function with 'async def'
async def fetch_data():
    print("Starting...")
    await asyncio.sleep(1)  # Non-blocking wait
    print("Done!")
    return "data"

# Run async function
result = asyncio.run(fetch_data())

Async HTTP with aiohttp

pip install aiohttp
import aiohttp
import asyncio

async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()

# Run it
data = asyncio.run(fetch_url("https://api.example.com/data"))

Making Concurrent API Calls

import aiohttp
import asyncio
import os

async def chat_completion(session, prompt):
    """Make a single chat completion request."""
    url = "https://api.openai.com/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}",
        "Content-Type": "application/json"
    }
    data = {
        "model": "gpt-4",
        "messages": [{"role": "user", "content": prompt}]
    }

    async with session.post(url, headers=headers, json=data) as response:
        result = await response.json()
        return result["choices"][0]["message"]["content"]

async def batch_completions(prompts):
    """Process multiple prompts concurrently."""
    async with aiohttp.ClientSession() as session:
        tasks = [chat_completion(session, p) for p in prompts]
        results = await asyncio.gather(*tasks)
        return results

# Process 5 prompts concurrently
prompts = [
    "What is Python?",
    "What is JavaScript?",
    "What is Rust?",
    "What is Go?",
    "What is Ruby?"
]

results = asyncio.run(batch_completions(prompts))
for prompt, result in zip(prompts, results):
    print(f"Q: {prompt}\nA: {result[:100]}...\n")

Key Concepts

Concept Description
async def Defines a coroutine function
await Pauses until the async operation completes
asyncio.run() Entry point to run async code
asyncio.gather() Run multiple coroutines concurrently
aiohttp Async HTTP client library

Error Handling in Async

async def safe_fetch(session, url):
    try:
        async with session.get(url, timeout=10) as response:
            response.raise_for_status()
            return await response.json()
    except asyncio.TimeoutError:
        print(f"Timeout: {url}")
        return None
    except aiohttp.ClientError as e:
        print(f"Error: {e}")
        return None

async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [safe_fetch(session, url) for url in urls]
        return await asyncio.gather(*tasks)

When to Use Async

Use Async Use Sync
Multiple API calls Single API call
I/O-bound tasks CPU-bound tasks
Web scraping Simple scripts
Real-time streaming Sequential processing

You've completed the Working with APIs module! Next, we'll learn about project structure. :::

Quiz

Module 4: Working with APIs

Take Quiz