Last active
April 6, 2025 09:18
-
-
Save mikeal/013dbb2ef3810cfe976cbe16ddb11c6f to your computer and use it in GitHub Desktop.
HTTP Client Comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const r2 = require('r2') | |
let doJsonThing = async (path, propname) => { | |
let res = await r2(`http://api.com${path}`).json | |
return res[propname] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const request = require('request') | |
let doJsonThing = (path, propname, cb) => { | |
request(`http://api.com${path}`, {json: true}, (err, resp, body) => { | |
if (err) return cb(err) | |
if (resp.statusCode < 200 || resp.statusCode > 299) { | |
return cb(new Error(`Status not 200, ${resp.statusCode}`)) | |
} | |
cb(null, body[propname]) | |
} | |
} |
@mikeal there's also response.ok
which maps to what you wrote. https://fetch.spec.whatwg.org/#ref-for-dom-response-ok①.
Wait I'm being an idiot, that was the old example. Ignore me.
Thanks for the detailed explanation, @mikeal -- interesting PoC
I want to believe you; I feel like there is something powerful I'm missing. But I don't understand your answer to @bluepnume and @bahmutov.
@jakearchibald: I'll take over the idiot badge ;)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So, I've been writing that 2xx checking boilerplate for the better part of 7 years in different projects. If there was an easy way to add it
request
, I would have done so a long time ago.Here's the problem, you have to signal to the API that you want JSON support (which adds accept headers). This also sets up the JSON decoding. However, a fair number of APIs return valid JSON bodies for their error conditions.
Because there's just a single handler (the callback) for socket errors, response errors, and success we can't add default status code checking for this case in request itself without blocking people from being able to handle their own http errors codes that have json bodies. It has been considered several times.
The reason you can do this w/ the promise API is that you have multiple entry points for the success condition. You can still support people checking their own 4xx errors by doing
await r2(url).response
but when doingawait r2(url).json
you can add some additional default semantics that make sense 99% of the time.The real power here isn't anything as simple as callbacks vs. promises. The real power is in the fact that errors throw, and that you can customize what is considered an error based on what property is accessed. This allows you to add all kinds of semantics for different usages that you just can't inspect when all you have is a callback to handle every class of error and success.
You don't need users to plug and propagate errors by hand, that's all language level now. And because you aren't passing in this future handler for the error you can create multiple entry points for the success conditions.