ARISE AFRICA NETWORK VOCATIONAL COURSE (AAN)

Module 8 — Advanced JavaScript & APIs (Expanded)

Introduction & Learning Outcomes

This expanded module deepens your JavaScript knowledge and teaches you how to use web APIs to build interactive, data-driven applications. We focus on asynchronous programming, modern ES6+ features, consuming REST APIs, handling JSON, and building a practical Weather Dashboard that works offline using local sample data. By the end you will be comfortable architecting small API-driven front-end apps and handling common pitfalls like network errors and CORS.

Outcomes

Key Terms & Definitions

API
Application Programming Interface — a contract that allows software to interact with another software component.
Endpoint
A specific URL where an API exposes data or functionality.
REST
Representational State Transfer — architectural style for designing networked applications using HTTP verbs.
JSON
JavaScript Object Notation — lightweight data-interchange format, commonly used by APIs.
Promise
An object representing the eventual completion or failure of an asynchronous operation.
async/await
Syntactic sugar over promises that allows writing asynchronous code in a synchronous style.
CORS
Cross-Origin Resource Sharing — browser policy for allowing or blocking cross-origin requests.
Rate limit
Limit set by APIs on how many requests can be made in a given time window.
Fetch
Browser API to make network requests returning a promise.
HTTP methods
GET, POST, PUT, DELETE — verbs used to perform CRUD operations over HTTP.
Header
Metadata sent with requests and responses (e.g., Authorization, Content-Type).
Timeout
Limit after which a network request is considered failed.
Cache
Storing data temporarily to speed up future requests.
Debounce
A technique to delay execution to prevent excessive requests (useful for search APIs).
Throttling
Limiting how often a function can be called over time.

Detailed Theory (Advanced JavaScript Concepts)

ES6+ Syntax and Useful Patterns

Modern JavaScript (ES6 and later) introduces useful syntax and patterns that make code concise and expressive. Key features include:

The Event Loop, Callbacks & Promises

JavaScript is single-threaded; the event loop manages asynchronous operations. Callbacks were the earliest pattern; promises provide clearer handling:

// Promise example
new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
}).then(value => console.log(value)).catch(err => console.error(err));

Promises have states: pending, fulfilled, rejected. Chain them with .then() and handle errors with .catch() or final cleanup with .finally().

async/await

Async functions return promises and allow using await to pause until a promise resolves. Use try/catch to handle errors:

async function loadData(){
  try{
    const res = await fetch('data.json');
    const json = await res.json();
    return json;
  }catch(err){ console.error('Fetch failed', err); throw err; }
}

fetch() & handling responses

fetch() starts a request and returns a promise resolving to a Response object. Always check response.ok and parse JSON with response.json():

const r = await fetch('/api/items');
if(!r.ok) throw new Error('Network response was not ok');
const data = await r.json();

Error handling, timeouts & retries

Network requests can fail. Implement timeouts and retry strategies with exponential backoff to handle transient failures. Example minimal timeout wrapper:

function fetchWithTimeout(url, opts={}, timeout=7000){
  return Promise.race([
    fetch(url, opts),
    new Promise((_, rej) => setTimeout(() => rej(new Error('Timeout')), timeout))
  ]);
}

CORS & API keys

Browsers block cross-origin requests unless the server allows them via CORS headers. Never store secret API keys in client-side code for public apps; use a small backend proxy or serverless function to keep keys secret. For offline demos, use sample local JSON files to avoid needing real API keys.

Project — Weather Dashboard (Chosen demo)

The Weather Dashboard demonstrates fetching API data, parsing JSON, rendering to the DOM, error handling, caching, and saving user preferences. Because this course is offline-first, the dashboard will work with a local sample JSON file (sample-weather.json) and also show how to swap in a live API like OpenWeatherMap when a key is available.

What the dashboard teaches

Sample Data (sample-weather.json)

{
  "city": "Harare",
  "country": "ZW",
  "temp_c": 22.3,
  "condition": "Partly cloudy",
  "humidity": 60,
  "wind_kph": 12.3,
  "forecast": [
    {"day":"Today","high_c":25,"low_c":16},
    {"day":"Tomorrow","high_c":27,"low_c":17}
  ]
}

Live Playground — Weather Dashboard (Editable)

Edit the bundled HTML/JS on the left and press Run to preview. The preview fetches sample-weather.json embedded in the document (no network required).

Practical Labs — Step-by-step

Lab 1 — Simple API fetch and display

  1. Use the playground: press "Use Sample Data" and inspect the DOM update.
  2. Replace the sample fetch function with a real fetch to data.json when you host the JSON locally.

Lab 2 — Convert temperatures and persist preferences

  1. Add a toggle to switch between °C and °F. Save the preference to localStorage.
  2. On load, read preference and render accordingly.

Lab 3 — Implement retry logic and timeout

  1. Create fetchWithTimeout wrapper and implement exponential backoff for retries.
  2. Limit retries to a reasonable number (e.g., 3) and show informative user messages.

Lab 4 — Debounce search input

  1. Implement a debounce function so that typing a city name does not trigger too many searches.
  2. Use the debounce on input events and trigger the fetch only after user stops typing for 400ms.

Advanced Topics & Best Practices

Handling API keys securely

Never embed secret API keys in client-side code. Use a small server (Node/Express) or serverless function to store keys and forward requests. This also allows you to enforce rate limits and caching. For example, create an endpoint /api/weather?city=Harare that calls the external API with the secret key and returns sanitized JSON to the browser.

Pagination and large datasets

When APIs return large datasets, use pagination (page & limit) or cursor-based approaches. Request only necessary fields and use server-side filtering when possible.

Testing & Mocking APIs

For unit tests, mock fetch using libraries like fetch-mock or in browser use polyfills. For offline development use static JSON files or tools like JSON Server to simulate REST endpoints locally.

Faith Corner

"In all your getting, get understanding." — Proverbs 4:7. Be patient learning async patterns — understanding the event loop is key to mastery.

Knowledge Check — 20 Questions

  1. Q1. Which method starts an HTTP request in the browser and returns a Promise?


  2. Q2. What does response.ok indicate?


  3. Q3. Which keyword pauses execution until a promise resolves?


  4. Q4. What is CORS primarily for?


  5. Q5. Which is a safe place to store secret API keys?


  6. Q6. Which technique reduces the number of API calls while typing search input?


  7. Q7. What does JSON.parse() do?


  8. Q8. Which status codes indicate client error?


  9. Q9. What is a Promise.all used for?


  10. Q10. Which header is commonly used to pass an API token?


  11. Q11. Which is best to handle transient network errors?


  12. Q12. Which method returns the response body as JSON?


  13. Q13. What is the event loop responsible for?


  14. Q14. Which pattern avoids storing secrets in the client?


  15. Q15. What does the term 'rate limit' mean?


  16. Q16. Which approach helps when an API is slow?


  17. Q17. Which is a good practice when parsing unknown JSON?


  18. Q18. What does Promise.race do?


  19. Q19. Debouncing is most useful for:


  20. Q20. For offline-friendly apps, which is recommended?