# 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 Weather Buddy 3.0 - Multi-City Dashboard

Weather Buddy 3.0 - Multi-City Dashboard 🌍

``` ## Advanced GET Patterns ### 1. Request Signing Some APIs require signed requests: ```javascript // Example: AWS-style request signing import { createHash, createHmac } from 'crypto' function signRequest(secretKey, stringToSign) { return createHmac('sha256', secretKey) .update(stringToSign) .digest('hex') } const timestamp = new Date().toISOString() const signature = signRequest(SECRET_KEY, `GET\n/api/data\n${timestamp}`) const { data } = await tf.get('https://api.example.com/data', { headers: { 'X-Timestamp': timestamp, 'X-Signature': signature } }) ``` ### 2. GraphQL Queries via GET Yes, you can do GraphQL with GET: ```javascript const query = ` query GetUser($id: ID!) { user(id: $id) { name email posts { title } } } ` const { data } = await tf.get('https://api.example.com/graphql', { params: { query, variables: JSON.stringify({ id: '123' }) } }) ``` ### 3. Response Transformation Transform data as it arrives: ```javascript const api = createTypedFetch() // Add response transformer api.addResponseInterceptor(response => { // Convert snake_case to camelCase if (response.data) { response.data = snakeToCamel(response.data) } return response }) // Now all responses are automatically transformed const { data } = await api.get('/api/user_profile') console.log(data.firstName) // was first_name ``` ## Debugging GET Requests When things go wrong, TypedFetch helps you figure out why: ```javascript // Enable debug mode tf.enableDebug() // Make request await tf.get('https://api.example.com/data') // Console shows: // [TypedFetch] 🚀 GET https://api.example.com/data // [TypedFetch] 📋 Headers: { "Content-Type": "application/json" } // [TypedFetch] ⏱️ Response time: 234ms // [TypedFetch] ✅ Status: 200 OK // [TypedFetch] 💾 Cached for 5 minutes ``` ## Practice Time! 🏋️ ### Exercise 1: GitHub Repository Explorer Build a tool that searches GitHub repositories: ```javascript async function searchRepos(query, language = null, sort = 'stars') { // Your code here // Use: https://api.github.com/search/repositories // Params: q (query), language, sort, order } ``` ### Exercise 2: Paginated Data Fetcher Create a generic paginated fetcher: ```javascript async function* fetchAllPages(baseUrl, params = {}) { // Your code here // Should yield items one at a time // Should handle any paginated API } ``` ### Exercise 3: Smart Cache Manager Build a cache that respects cache headers: ```javascript class SmartCache { async get(url, options) { // Check cache-control headers // Respect max-age // Handle etags } } ``` ## Key Takeaways 🎯 1. **GET requests are for reading data** - No side effects 2. **Query parameters are your friends** - Use params option 3. **Headers control behavior** - Auth, versions, formats 4. **Pagination is everywhere** - Plan for it 5. **Parallel requests are faster** - Use Promise.all() 6. **Caching is automatic** - But you can control it 7. **Debug mode shows everything** - Use it when stuck ## Common Pitfalls to Avoid 🚨 1. **Building URLs manually** - Use params option instead 2. **Forgetting to encode values** - TypedFetch does it for you 3. **Sequential requests** - Parallelize when possible 4. **Ignoring pagination** - Always check for more pages 5. **Over-fetching data** - Request only needed fields 6. **Not handling errors** - Network requests fail ## What's Next? You've mastered reading data with GET requests. But what about creating, updating, and deleting? In Chapter 4, we'll explore the full CRUD (Create, Read, Update, Delete) operations with POST, PUT, and DELETE. We'll also evolve Weather Buddy to let users save favorite cities, customize their dashboard, and share their weather setup with friends. Ready to start changing data instead of just reading it? See you in Chapter 4! 🚀 --- ## Chapter Summary - GET requests are for reading data without side effects - Query parameters are handled automatically with the params option - Headers control authentication, API versions, and response formats - Pagination requires looping or generators for large datasets - Parallel requests with Promise.all() improve performance - TypedFetch automatically caches GET requests - Polling enables real-time updates with simple setInterval - Debug mode reveals everything about your requests - Weather Buddy now supports multiple cities with live updates and search **Next Chapter Preview**: POST, PUT, and DELETE - creating, updating, and deleting data. Learn to build full CRUD applications with TypedFetch.