# Chapter 3: The Magic of GET Requests *"Reading is fundamental - especially when reading data from APIs."* --- ## The Read-Only Superpower Sarah had been using TypedFetch for a week now, and her Weather Buddy app was getting popular at the office. But her colleague Marcus had a challenge: "Can you make it show weather for multiple cities at once? And add search suggestions as I type?" "That's going to need a lot of GET requests," Sarah said. Marcus grinned. "Good thing GET requests are TypedFetch's specialty." ## GET Requests: The Workhorses of the Web If APIs were a library, GET requests would be checking out books. You're not changing anything - just reading information. And it turns out, 80% of API calls you'll ever make are GET requests. With TypedFetch, GET requests aren't just simple - they're powerful. Let's explore. ## Query Parameters: Asking Specific Questions Remember our restaurant metaphor? Query parameters are like asking your waiter for modifications: "Can I get the burger without pickles? Extra fries? Medium-rare?" ### The Manual Way (Ugh): ```javascript // Building URLs by hand is error-prone const city = 'San Francisco' const units = 'metric' const url = `https://api.weather.com/data?city=${encodeURIComponent(city)}&units=${units}` ``` ### The TypedFetch Way: ```javascript const { data } = await tf.get('https://api.weather.com/data', { params: { city: 'San Francisco', // Automatically encoded! units: 'metric' } }) ``` TypedFetch handles all the encoding for you. Spaces, special characters, Unicode - all taken care of. ## Real Example: Building a Smart City Search Let's build a city search with auto-complete: ```javascript async function searchCities(query) { const { data } = await tf.get('https://api.teleport.org/api/cities/', { params: { search: query, limit: 5 } }) return data._embedded['city:search-results'].map(city => ({ name: city.matching_full_name, population: city.population, country: city._links['city:country'].name })) } // Usage const cities = await searchCities('New') // Returns: New York, New Orleans, New Delhi, etc. ``` ## Headers: Your API Passport Headers are like showing your ID at a club. They tell the API who you are and what you want. ```javascript // Common headers you'll need const { data } = await tf.get('https://api.github.com/user/repos', { headers: { 'Authorization': 'Bearer ghp_yourtoken123', // Authentication 'Accept': 'application/vnd.github.v3+json', // API version 'X-GitHub-Api-Version': '2022-11-28' // Specific version } }) ``` ### Pro Tip: Setting Default Headers If you're always sending the same headers, set them once: ```javascript // Create a custom instance import { createTypedFetch } from 'typedfetch' const github = createTypedFetch() // Add auth to every request github.addRequestInterceptor(config => ({ ...config, headers: { ...config.headers, 'Authorization': 'Bearer ghp_yourtoken123' } })) // Now all requests include auth const { data: repos } = await github.get('https://api.github.com/user/repos') const { data: gists } = await github.get('https://api.github.com/gists') ``` ## Pagination: Getting Data in Chunks Most APIs don't dump thousands of records on you at once. They paginate - giving you data in bite-sized chunks. ```javascript async function getAllUsers() { const users = [] let page = 1 let hasMore = true while (hasMore) { const { data } = await tf.get('https://api.example.com/users', { params: { page, limit: 100 } }) users.push(...data.users) hasMore = data.hasNextPage page++ } return users } ``` ### Smarter Pagination with Generators For large datasets, loading everything into memory isn't smart. Use generators: ```javascript async function* paginatedUsers() { let page = 1 let hasMore = true while (hasMore) { const { data } = await tf.get('https://api.example.com/users', { params: { page, limit: 100 } }) // Yield each user one at a time for (const user of data.users) { yield user } hasMore = data.hasNextPage page++ } } // Process users without loading all into memory for await (const user of paginatedUsers()) { console.log(user.name) // Process one user at a time } ``` ## Real-Time Updates: Polling Done Right Want live data? The simplest approach is polling - repeatedly checking for updates: ```javascript function pollWeather(city, callback, interval = 60000) { // Immediately fetch updateWeather() // Then poll every interval const timer = setInterval(updateWeather, interval) async function updateWeather() { try { const { data } = await tf.get('https://wttr.in/v2', { params: { location: city, format: 'j1' } }) callback(data) } catch (error) { console.error('Weather update failed:', error.message) // Don't stop polling on error } } // Return cleanup function return () => clearInterval(timer) } // Usage const stopPolling = pollWeather('Tokyo', weather => { console.log(`Tokyo is ${weather.current_condition[0].temp_C}°C`) }) // Stop when done // stopPolling() ``` ## Performance Tricks: Making GET Requests Fly ### 1. Parallel Requests When you need data from multiple endpoints, don't wait: ```javascript // ❌ Slow - Sequential const user = await tf.get('/api/user/123') const posts = await tf.get('/api/user/123/posts') const comments = await tf.get('/api/user/123/comments') // ✅ Fast - Parallel const [user, posts, comments] = await Promise.all([ tf.get('/api/user/123'), tf.get('/api/user/123/posts'), tf.get('/api/user/123/comments') ]) ``` ### 2. Conditional Requests Only fetch if data changed: ```javascript // Using ETags const { data, response } = await tf.get('/api/resource') const etag = response.headers.get('etag') // Later, only get if changed const { data: newData, response: newResponse } = await tf.get('/api/resource', { headers: { 'If-None-Match': etag } }) if (newResponse.status === 304) { console.log('Data hasn't changed!') } ``` ### 3. Selective Fields Many APIs let you choose what data to return: ```javascript // Get only what you need const { data } = await tf.get('https://api.github.com/users/torvalds', { params: { fields: 'login,name,avatar_url,public_repos' } }) ``` ## Let's Build: Weather Buddy 3.0 - Multi-City Dashboard Time to put it all together: ```html