The tutorial and guides
The Norway Data API's tutorial and how-to guides live in this repo, in the /samples section, not in the API repo. The API reference explains how the API works, and the guides explain how to get things done with it. This page covers how the guides connect to the API, and what to check when the API changes.
Quick reference
- The guides are in
samples/norway-data-api-guides/, under the Norway Data API Guides category insidebarsSamples.js, and listed onsamples/index.mdx. - Unlike the other samples, they aren't genericized: their code runs against the live API. Don't add the samples disclaimer to them.
- The spec links to the tutorial from its Quick start section and from
externalDocs. If the tutorial's URL changes, update both in the API repo. - The guides link to sections of the reference by anchor, such as
#description/errors. If a heading in the spec is renamed, those links break, and the build can't catch it. - Every guide ends with a Feedback section: the
GuideFeedbackcomponent links to the API repo's Docs feedback issue form (.github/ISSUE_TEMPLATE/docs.yml), with the page's URL filled in. Add it to new guides too. - The fact of the day guide shows a live demo, the
FactOfTheDaycomponent. Its logic is a copy of the page's code. If you change one, change the other. - Nothing tests the guides' code automatically. When the API changes, check the guides it affects (see What the guides depend on) and re-run their code (see Test the guides).
The pages
| Page | Type | What it covers |
|---|---|---|
| Show a random fact with its places | Tutorial | A first program: get a random fact, then each place in its placeIds. Built up step by step, with prerequisites and troubleshooting. |
| Explore the API in Postman | How-to | Import the Postman collection from the API repo, what's in it, its variables, and running its tests in Postman or with Newman. |
| Get every item in a collection | How-to | Follow pagination.links.next until it's null. |
| Handle errors and retries | How-to | Which errors to retry and how long to wait. Retry decisions use the status code, because some 429s have no body and no type. Everything else uses type. |
| Cache responses with ETags | How-to | max-age, If-None-Match, and 304 for server-side code. Browsers do this on their own. |
| Call the API from a browser | How-to | What a page can send and read across origins, why requests fail with "Failed to fetch", and Content Security Policy. |
| Build a fact of the day page | Sample app | A complete web page that picks a fact from the date, with a live demo on the page. |
Conventions
- Every program runs as copied. Each page has the complete code, not fragments that only work together.
- JavaScript and Python in tabs. The tabs use
groupId="language", so a reader's choice carries across the page and the other guides. - Few requirements. JavaScript needs Node.js 18 or later and uses
.mjsfiles. Python uses only the standard library. - Output shown is real output. Any output on a page comes from running that page's code against the live API.
- Absolute links to the reference. Links to a section of the reference use the full URL, such as
https://www.marlasowards.com/api-reference#description/errors. Scalar creates those anchors in the browser, so the build's link checker would report a relative link as a broken anchor.
What the guides depend on
| If this changes in the API | Check |
|---|---|
| Fields in facts, places, or pagination | Every guide |
| A heading in the spec's introduction | Anchor links in every guide |
| The Postman collection's requests, folders, variables, or test counts | Explore the API in Postman, including the Newman summary |
Error types, the problem details format, or Retry-After | Handle errors and retries |
Pagination, or the maximum limit (50) | Get every item in a collection, Build a fact of the day page |
Cache-Control, ETag, or 304 behavior | Cache responses with ETags, Call the API from a browser |
| CORS headers, or the headers a preflight allows | Call the API from a browser, Build a fact of the day page |
| The rate limit (60 requests per 60 seconds) | The tutorial's troubleshooting, Handle errors and retries, Call the API from a browser |
| The data, such as the number of facts or fact 14 | The tutorial's sample output, Get every item in a collection |
A known limitation: the browser guide warns against sending If-None-Match from browser code, because 304s from the CDN have no CORS headers (see Design decisions). If that's ever fixed, remove the warning.
Test the guides
Copy each program from the page into a file and run it. Then compare its output with the page.
- JavaScript:
node <file>.mjs - Python:
python <file>.py. On Windows, usepython -X utf8 <file>.py, or Norwegian letters such asácan print wrong.
Some guides need more than running the code:
-
The tutorial: its output is random. To get the exact output at the top of the page, temporarily change
/random-factto/facts/14. -
Get every item: at the default page size, every collection fits on one page, so the loop runs only once. Change
limitto4so it follows several pages, and check that the counts match each collection'spagination.total. -
Handle errors and retries: the API can't return a
500on demand. Replacefetch(or Python'surlopen) with a fake that returns a set sequence of responses, and replace the timer (setTimeoutortime.sleep) with one that records each wait instead of waiting. Check these cases:- a
500then success - a
500every time (three retries, then an error) - a
429withRetry-After - a
429with an empty body and no header (a 60-second wait) - a
400and a404(not retried) - a
502with an HTML body (retried)
To test against a real
429, send about 70 requests to/random-fact, which is never cached. This uses up your IP address's limit for a minute. - a
-
Call the API from a browser: only a browser enforces CORS, so
curlcan't test this guide. Serve the pages from another origin, such aspython -m http.server 8000, and load them in headless Chrome with a throwaway profile:chrome --headless=new --user-data-dir=<temp-folder> --virtual-time-budget=20000 --dump-dom http://localhost:8000/page.htmlA test page can write each result into the page, and
--dump-domprints it. Also open the guide's page from afile://URL. -
Build a fact of the day page: load the page with
--dump-domas above, and check the fact against the rule: the day number (Date.UTCof today divided by 86,400,000) modulo the number of facts, plus one, is the fact's ID while IDs have no gaps. Also check a date whose fact has places, by temporarily changingnew Date()to a fixed date, and an error, by temporarily pointingBASE_URLat a path that doesn't exist. Then check the live demo on the built site withnpm run buildandnpm run serve.