π¨ JavaScript Β· Topic 20 of 20
Fetch, JSON & Modules β JavaScript Questions with Answers
30 practice questions on Fetch, JSON & Modules, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
1 easy Β· 17 medium Β· 12 hard Β· Part of JavaScript: The language of the web - basics to advanced, 20 topics.
Medium questions (17)
Q3. medium
What does response.ok tell you?
- A true when the status is in the 200-299 range
- B That the network worked
- C That JSON parsed correctly
- D Nothing useful
Answer: A β true when the status is in the 200-299 range
A quick success test. response.status gives the exact code (404, 500...) for more specific handling.
response.okstatus
Q4. medium
How do you send a POST request with JSON?
- A fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) })
- B fetch(url, data)
- C fetch.post(url, data)
- D fetch(url, { post: data })
Answer: A β fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) })
Three parts matter: the method, the Content-Type header so the server parses it correctly, and a STRINGIFIED body (fetch cannot send a raw object).
POSTJSONHeaders
Q6. medium
What is JSON?
- A A text format for structured data, based on JavaScript object syntax but language-independent
- B A JavaScript library
- C A database
- D A type of function
Answer: A β A text format for structured data, based on JavaScript object syntax but language-independent
JavaScript Object Notation is the standard way APIs exchange data. It supports objects, arrays, strings, numbers, booleans and null - but not functions, undefined or comments.
JSONAPIs
Q7. medium
What is the difference between JSON.parse and JSON.stringify?
- A parse turns a JSON STRING into a JS value; stringify turns a JS value into a JSON string
- B They are the same
- C parse converts to a string
- D stringify validates JSON
Answer: A β parse turns a JSON STRING into a JS value; stringify turns a JS value into a JSON string
Mnemonic: parse comes IN (from text), stringify goes OUT (to text). Wrap JSON.parse of untrusted input in try/catch - malformed JSON throws a SyntaxError.
JSON.parseJSON.stringify
Q9. medium
How do you store an object in localStorage?
localStorage.setItem("user", JSON.stringify(user));
const user = JSON.parse(localStorage.getItem("user") ?? "null");
- A localStorage.setItem("key", JSON.stringify(obj)) then JSON.parse on read
- B localStorage.setItem("key", obj)
- C localStorage.obj = obj
- D Objects cannot be stored
Answer: A β localStorage.setItem("key", JSON.stringify(obj)) then JSON.parse on read
localStorage stores STRINGS only; saving an object directly gives "[object Object]". Always stringify on write and parse on read.
localStorageJSON
Q10. medium
What is the difference between localStorage and sessionStorage?
- A localStorage persists until cleared; sessionStorage is wiped when the tab closes
- B They are identical
- C sessionStorage is bigger
- D localStorage is per-tab
Answer: A β localStorage persists until cleared; sessionStorage is wiped when the tab closes
Both store strings per origin (roughly 5-10 MB). Choose sessionStorage for temporary per-tab state, localStorage for preferences that should survive restarts.
Web Storage
Q12. medium
How do you send an authorisation token with fetch?
fetch(url, { headers: { Authorization: `Bearer ${token}` } });
- A In the headers object: { Authorization: `Bearer ${token}` }
- B In the URL always
- C In the method
- D Tokens cannot be sent
Answer: A β In the headers object: { Authorization: `Bearer ${token}` }
Headers carry auth data. Avoid putting tokens in URLs, where they leak into logs and browser history.
HeadersAuthentication
Q14. medium
How do you read a plain-text response?
- A await response.text()
- B response.body
- C response.string()
- D response.data
Answer: A β await response.text()
Body readers: .json() for JSON, .text() for text/HTML, .blob() for binary (images, files), .formData() for form payloads.
Response methods
Q16. medium
What does export do in an ES module?
export const PI = 3.14;
export function area(r) { }
export default class Circle { }
- A Makes a value available for other modules to import
- B Sends data to the server
- C Saves a file
- D Deletes a variable
Answer: A β Makes a value available for other modules to import
Modules are private by default; export opens specific values to others. A file can have many NAMED exports and at most one DEFAULT export.
Modulesexport
Q17. medium
What is the difference between a named and a default export?
import { area, PI } from "./math.js";
import Circle from "./circle.js"; // any name works
import { area as calcArea } from "./math.js"; // rename
- A Named exports must be imported by their exact name in braces; a default export can be imported under any name
- B They are identical
- C Default exports are faster
- D You can have many defaults
Answer: A β Named exports must be imported by their exact name in braces; a default export can be imported under any name
Named imports use braces and exact names (better for autocomplete and refactoring); default imports pick their own name.
importexport
Q18. medium
How do you enable ES modules in a browser?
- A <script type="module" src="app.js"></script>
- B <script module>
- C Modules work automatically
- D <module src="app.js">
Answer: A β <script type="module" src="app.js"></script>
type="module" also implies defer and strict mode, and gives the file its own scope. Modules must be served over http(s), not opened via file://.
type=moduleScripts
Q20. medium
What scope do variables in a module have?
- A Module scope - private to that file unless exported
- B Global scope
- C Function scope only
- D No scope
Answer: A β Module scope - private to that file unless exported
This is a major advantage over classic scripts, where top-level var became global and could clash between files.
Module scope
Q22. medium
Are ES module imports hoisted?
- A Yes - imports are resolved before any module code runs, so import order in the file does not matter
- B No
- C Only default imports
- D Only in Node
Answer: A β Yes - imports are resolved before any module code runs, so import order in the file does not matter
The module graph is built first, then code executes. Convention is still to put imports at the top for readability.
HoistingModules
Q25. medium
How do you handle a fetch that might fail?
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
showError(err.message);
}
- A try/catch around await, plus a response.ok check inside
- B Only try/catch
- C Only response.ok
- D Fetch never fails
Answer: A β try/catch around await, plus a response.ok check inside
You need BOTH: catch handles network/CORS failures, while the ok check handles HTTP error statuses that resolve normally.
Error handlingfetch
Q26. medium
What does the async attribute do on a script tag?
- A Downloads in parallel and executes as soon as ready - order is NOT guaranteed
- B Same as defer
- C Delays the script
- D Makes functions async
Answer: A β Downloads in parallel and executes as soon as ready - order is NOT guaranteed
Use async for independent scripts like analytics. Use defer when scripts depend on the DOM or on each other, since defer preserves order and waits for parsing.
asyncdefer
Q28. medium
How do you send FORM data (including files) with fetch?
const fd = new FormData(form);
fetch(url, { method: "POST", body: fd });
- A Pass a FormData object as the body - and do NOT set Content-Type manually
- B JSON.stringify the form
- C Send it in the URL
- D Files cannot be sent
Answer: A β Pass a FormData object as the body - and do NOT set Content-Type manually
The browser sets the correct multipart Content-Type with its boundary automatically; setting it yourself breaks the upload.
FormDataFile upload
Q30. medium
What is the modern replacement for XMLHttpRequest?
- A fetch - promise-based and much cleaner
- B jQuery.ajax
- C WebSocket
- D There is none
Answer: A β fetch - promise-based and much cleaner
fetch is built in, returns promises and works naturally with async/await. XHR still appears in legacy code and for upload-progress events, which fetch handles less directly.
fetchXMLHttpRequest
Hard questions (12)
Q2. hard
Does fetch REJECT on a 404 or 500 response?
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
- A No - it only rejects on network failure; HTTP errors still resolve successfully
- B Yes, it rejects on any error status
- C Only on 500
- D It throws a SyntaxError
Answer: A β No - it only rejects on network failure; HTTP errors still resolve successfully
This surprises almost everyone. You must check response.ok (true for 200-299) and throw yourself, otherwise .catch() never sees server errors.
- The most common fetch bug in real projects.
response.okError handling
Q5. hard
Why must the body be JSON.stringify(data) rather than the object itself?
- A HTTP bodies are text/bytes - passing an object would send "[object Object]"
- B It is optional
- C To encrypt it
- D To compress it
Answer: A β HTTP bodies are text/bytes - passing an object would send "[object Object]"
The object must be serialised to a JSON string. On the server it is parsed back; in the browser, response.json() does the reverse.
JSON.stringifySerialization
Q8. hard
Which values are LOST by JSON.stringify?
JSON.stringify({ a: 1, f() {}, u: undefined }); // '{"a":1}'
- A Functions, undefined values and symbols are dropped; Dates become strings
- B Nothing is lost
- C Numbers are lost
- D Only arrays survive
Answer: A β Functions, undefined values and symbols are dropped; Dates become strings
JSON has no concept of functions or undefined, so those keys vanish. Dates serialise to ISO strings and do NOT come back as Date objects - a frequent source of bugs.
JSON limitations
Q11. hard
What is CORS?
- A A browser security rule requiring the server to permit cross-origin requests via response headers
- B A JavaScript library
- C A type of promise
- D An encoding format
Answer: A β A browser security rule requiring the server to permit cross-origin requests via response headers
By default a page cannot read responses from another origin. The SERVER must send Access-Control-Allow-Origin. CORS errors cannot be fixed from client-side JavaScript alone.
CORSSecurity
Q13. hard
How do you CANCEL an in-flight fetch request?
const ac = new AbortController();
fetch(url, { signal: ac.signal });
ac.abort();
- A With an AbortController and its signal
- B fetch.cancel()
- C clearTimeout(fetch)
- D You cannot cancel it
Answer: A β With an AbortController and its signal
Essential for search-as-you-type (cancel the previous request) and for cleanup when a component unmounts. The aborted promise rejects with an AbortError.
AbortController
Q15. hard
Why can a response body be read only ONCE?
- A It is a stream - after reading it is consumed; clone the response if you need it twice
- B A browser bug
- C For security
- D It can be read many times
Answer: A β It is a stream - after reading it is consumed; clone the response if you need it twice
Calling both .json() and .text() on the same response throws 'body stream already read'. Use response.clone() when you truly need two reads.
Streamsclone
Q19. hard
Why do ES modules require a server (not file://)?
- A Module loading is subject to CORS, which does not apply to the file protocol
- B Modules need a database
- C Browsers ban local files entirely
- D They do work with file://
Answer: A β Module loading is subject to CORS, which does not apply to the file protocol
Opening an HTML file directly gives a CORS error for module imports. Use a local server (VS Code Live Server, python -m http.server) during development.
CORSModules
Q21. hard
What is dynamic import()?
button.onclick = async () => {
const { Chart } = await import("./chart.js");
new Chart();
};
- A import("./mod.js") returns a PROMISE, letting you load a module on demand at runtime
- B A faster static import
- C Importing many files at once
- D A deprecated feature
Answer: A β import("./mod.js") returns a PROMISE, letting you load a module on demand at runtime
Static imports are hoisted and always loaded. Dynamic import enables code splitting and lazy loading - only fetching a heavy module when the user actually needs it.
Dynamic importCode splitting
Q23. hard
What is the difference between ES modules and CommonJS?
- A ESM uses import/export and is static/async; CommonJS uses require()/module.exports and is synchronous (Node's older system)
- B They are the same
- C CommonJS is browser-only
- D ESM is deprecated
Answer: A β ESM uses import/export and is static/async; CommonJS uses require()/module.exports and is synchronous (Node's older system)
Browsers support ESM natively; Node supports both (.mjs or "type": "module" for ESM). ESM's static structure enables tree-shaking during bundling.
CommonJSNode.js
Q24. hard
What is tree-shaking?
- A Bundlers removing exported code that is never imported, shrinking the final file
- B Sorting the DOM tree
- C Clearing the cache
- D A debugging technique
Answer: A β Bundlers removing exported code that is never imported, shrinking the final file
It works because ES module imports are static and analysable. Importing one function from a library can leave the rest out of your bundle.
BundlersOptimisation
Q27. hard
What does the URLSearchParams API help with?
const p = new URLSearchParams({ q: "js books", page: 2 });
fetch(`/search?${p}`); // /search?q=js+books&page=2
- A Building and reading query strings safely, with proper encoding
- B Parsing JSON
- C Creating modules
- D Storing cookies
Answer: A β Building and reading query strings safely, with proper encoding
Manual string concatenation breaks with spaces and special characters. URLSearchParams encodes values correctly.
URLSearchParamsQuery strings
Q29. hard
Why should API keys never be stored in front-end JavaScript?
- A All client code is visible to users - anyone can read the key from DevTools or the bundle
- B It makes the site slow
- C Browsers block them
- D It is fine to store them
Answer: A β All client code is visible to users - anyone can read the key from DevTools or the bundle
Minification is not security. Secret keys belong on a server that proxies the request; the browser calls YOUR endpoint instead.
SecurityAPI keys