Prototype an API call before you write the client
Before writing a client for an API, I want answers: what does the response actually look like, what happens without a token, what are the limits? A scratch file gets those answers faster than reading the docs twice.
Our test subject: the GitHub REST API, which works without a token (with a low rate limit) and with one.
Step 1: the token comes from the environment
Never paste a token into code, even scratch code. It ends up in a screenshot, a gist or a commit.
const token = process.env.GITHUB_TOKEN;
In Node and Bun, process.env holds the environment the process started with. undefined here is a valid state, and the code should handle it.
Step 2: a request that fails properly
const res = await fetch("https://api.github.com/repos/oven-sh/bun", {
headers: {
Accept: "application/vnd.github+json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
signal: AbortSignal.timeout(5000),
});
if (!res.ok) {
throw new Error(`GitHub ${res.status}: ${await res.text()}`);
}
Three habits in there:
- Conditional header. The spread adds
Authorizationonly when there's a token. - A timeout.
fetchhas none by default.AbortSignal.timeout(5000)aborts after five seconds with aTimeoutError. res.okis your job.fetchonly rejects on network failure. A 404 or 403 resolves happily, so throw on it yourself, with the body: GitHub's error messages are good.
Step 3: type what you actually got
type Repo = {
full_name: string;
stargazers_count: number;
open_issues_count: number;
pushed_at: string;
};
const repo = (await res.json()) as Repo;
repo.full_name;
repo.stargazers_count;
Write the type from the real response, not from memory. And remember as is a promise to the compiler, not a check. For anything beyond a prototype, validate.
Step 4: read the limits
res.headers.get("x-ratelimit-limit");
res.headers.get("x-ratelimit-remaining");
Run it without a token and with one, and compare. That's the number your client's retry logic has to respect.
Doing it in a scratchpad
In a scratchpad I do this in JSLab, a JavaScript & TypeScript scratchpad for macOS, in a Bun tab:
- The token goes in Tools β Environment Variablesβ¦. Values are masked on screen, they're saved in a file only your user account can read, and every run sees them in
process.env. Or point the tab at your project's folder with Set Working Directory⦠and JSLab loads that folder's.env. - Top-level await just works, and Auto Log shows
repo.full_name, the star count and both headers beside their lines without a singleconsole.log. - A
Responseand itsHeadersare shown in their own form when logged, soreson its own line is worth a look too.
Need to hit an API that doesn't send CORS headers, from code that also touches the DOM? The Browser & Node APIs runtime has a fetch with no CORS restriction. The plain Browser runtime keeps real CORS, so you can check what a website would see.
JSLab launches Nov 15. Environment variables: https://js-lab.app/docs/environment-variables
Comments
No comments yet. Start the discussion.