Fetch API has landed into Node.js
github.com
github.com
This is still experimental and we'd love to hear from the community what you'd like to see.
It's still very common to see Node modules that use require(), for example, but would otherwise work flawlessly in a browser where there is no require() support (without using shims and other libraries).
Node has supported ESModules (`import`) for a while and you can use it (either by naming your files `.mjs` or setting `type: module` in your package.json.
There is a solid interop story between require/import and you can mix if you want.
`require` is going to be supported "forever" so code doesn't break and both module systems work.
As for the general question: Node is committed to supporting modern JavaScript and to not allow such a gap to be created. If you see a place Node doesn't do a great job at that please tell us!
For example to use `require` inside ESModules you would do:
```mjs import { createRequire } from 'module'; const require = createRequire(import.meta.url); require('./whatever-in-cjs'); ```
There is a reason this isn't "by default" though since ESM doesn't "silently" interop with CJS to not make writing universal code harder.
https://github.com/arcanis/clipanion/blob/master/rollup.conf...
"Seemingly increasing gap" - how did you come to that conclusion? If anything the gap has reduced since the availability of ES modules. I see more and more libraries preferring ES modules, but ultimately that's up to the library developers.
The person who took it through the finish line (and deserves the most props here IMO) is Michael https://github.com/targos
The people who worked most on Undici are Matteo https://github.com/mcollina and Robert https://github.com/ronag
The person to work most on fetch in Undici is Ethan https://github.com/Ethan-Arrowood
Also worth calling our James whose work on web streams in Node as well as events/cancellation helped drive a bunch of this.
I can name maybe 50 people who worked on this effort overall at some capacity (I am one of them - spending maybe 40 years on APIs to help enable this).
Note the job isn't entirely done and help is very much appreciated!
I hope you realize no disrespect, this will greatly improve the daily work for me since I use node at work every day.
> I just wonder how come features like this that kind of seems obvious to include in the ecosystem takes quite some time to land?
I answered that below (check it out) but note how expensive adding a bad API is vs. asking people for one more `npm install` :) There is more discussion in https://github.com/nodejs/node/issues/19393 and in https://docs.google.com/document/d/1tn_-0S_FG_sla81wFohi8Sc8... a discussion from 2018 we had on it
Last question I have is will this be included in the next version of the LTS version or how do experimental features usually progress for someone who are unfamiliar?
Can't wait until I can use fetch in my codebase without any additional dependencies!
They could have built a fetch interface on top of http, but they probably saw an opportunity to make more drastic improvements.
Node uses undici JS library. Undici includes a C HTTP parser that is used via webassembly. The parser is generated from rules that are implemented in JS/TS using llparse framework.
A native C binary there in the middle is quite surprising.
And with every public API: Once you add it, you can't really hope to ever change it and even bug-fixes could be breaking some user's code (because they relied on the bug), so you have to be very careful to ship your public API as bug-free as possible.
But I can't help to feel like Node is progressing kind of slow compared to other languages / tools. This is just a personal impression from a bystander who is not really into the actual progression though. I have a feeling that node used to push new features all the time but in last couple of years have stagnated somewhat. Stuff like imports etc is still not really here.
I understand that developing an api that has such huge userbase as node is a massive undertaking that probably has issues that I can't imagine but it doesn't really help me in my day-to-day experience with it.
Node also isn’t actually a language, so there’s a lot of stuff that Node developers get in new version, but it’s actually being done in the V8 project.
And this is no obscure corner case, ts-node is huge
This was a huge pain for us. We develop an SDK that needs to work on Node, browsers and React Native.
I am super happy to hear about this :)
Deno decided to break spec [1][2] so the following code works fine:
fetch('https://httpbin.org/status/302', {redirect: 'manual'})
.then(res => console.log(res.status, res.headers))
In undici this will succeed but with res.status 0 and no headers, as per spec. You aren't allowed to see the content of a redirect, like in a browser.[0] https://github.com/nodejs/undici/issues/1072 [1] https://github.com/denoland/deno/pull/8353 [2] https://github.com/denoland/deno/issues/4389
Right now most developers either write their own library to do these things on top of fetch or another HTTP client or use a third party library from npm.
A new standard would allow us to make http requests out of the box comparable to high level HTTP clients like superagent, axios etc. that have been in use for the last decade, since before fetch was conceived, with whatever benefits fetch provides (I think it's cancellable now?).
The level of collaboration and good-faith we've been getting from spec bodies like WHATWG is very high as it is and we really don't want to push or abuse it.
The rest of your "improvements" aren't that. They're opinions, opinions laser focused on a JSON centric api.
I'm sorry to say this, but not all of the web is one big JSON blob.
Some of us have to talk to SOAP (xml) services.
Sometimes it's weird rpc stuff with protobuf.
Or even just pulling down raw binary data and feeding that through an API/library that wasn't built for web streams.
Honestly, the amount of code you need to add over the top of a primitive like the Fetch API to get what you wanted (bar the redirect change) is trivial and minimal.
I don’t know if chrome apps are still in existence, but if they are the “server side” fetch spec could apply to them too.
All the existing HTTP clients discussed in the previous post also run in the browser.
In case you disagree, you may want to reply why instead of down voting.
Edit: also, you are being downvoted because the etiquette on HN are that you don't ask "why was X downvoted".
We could have stuck with ‘if index is not equal to minus one’ but we have array includes now for the same reason.
> set JSON as the default request content type
or something similarly subjective.
Downvoting is going a bit too far, but bundling a few individual opinions on defaults alongside broadly accepted (implemented in both Node & Deno after much discussion) features seems... presumptuous.
Here is discussion about it in Node with some (pretty old) discussion https://docs.google.com/document/d/1tn_-0S_FG_sla81wFohi8Sc8...
I thought it was a Node popular library.
It's promise based (thus easier to integrate into code than older callback styles), and designed to give some better options around CORS and handling responses.
> Why it should be in node?
There is a push to adopt some certain "web apis" (APIs that emerged in web browsers) to increase compatibility, reusability and reduce cognitive load when working with both backend and frontend javascript.
Having a common low level call like fetch() means that libraries that are built atop it (SDKs to talk to services, or apply common middleware like JSON:API, oAuth etc) can be shared between node/deno and browsers.
The question is totally legitimate but please assume core doesn't make "load random binary" level kind of goofs :)
Its unverified binaries are just as good as random binaries, and silently replacing any pre-existing yarn/pnpm/whathaveyou without checking if it was perhaps a custom build is not exactly predictable either.
Other than Corepack, though, I think you people are doing an amazing job!
Curious to check but quick question: does it support upload progress? If not, is it considered?
If you upload a string for example you would have to take an extra step to get upload progress (make it into a stream and monitor that).
There is additional (unrelated) talk in the fetch standard itself to provide this sort of functionality as part of `fetch` which would save the middle step.
> ...we'd love to hear from the community what you'd like to see.
In our tests, fetch on Deno was wayy faster than undici fetch that now has been merged into nodejs.
I couldn't figure out why that was case, but forwarding requests over node's http2 client (instead of undici fetch) then had comparable (but not as fast) performance as Deno (presumably because our hand rolled impl lacked connection pooling).
I am confident that Node's implementation will _eventually_ have comparable performance.
That said: please do open an issue in the undici repo at https://nodejs.org/node/undici so this gets tracked.
The Web Platform APIs aren't perfect, but they are better, and more thoroughly thought out than Node's.
Node has been talking about Fetch since at least 2018 _before_ Ryan even announced Deno. This is true for promises, ESModules etc. Ryan _attended those meetings_ in the Node collaborator summit.
Don't get me wrong I am thankful for Deno (and a contributor!) but:
- It's a lot easier to make changes when the project is new and you don't have a lot of users (which is great for Deno) whereas Node has a whole (huge) ecosystem to consider on every change. - It's a lot easier to make changes with venture capital and funding to hire a bunch of people to work on it full time vs. a project with a "regular" MIT license where the code is owned by the community and not a company.
Those are not complaints about Deno, I like Deno (and not just Ryan, Lucas, Kit, Ben and the other people are nice and helpful and the project is really nice).
It's just to explain very little of Node's innovation is (at the moment) driven by Deno.
I'm not a web developer so I had a very hard time understanding why there are so many different type of imports in JavaScript like require, import, umd, amd, etc and which one works in browser and which one works in node?
Also why do so many libraries have this strange 5 line header code for this umd, amd, business. Is that to make their packages work with nodejs?
Does anyone who knows enough JavaScript point me in the right direction about it. I find all this very confusing.
You need to tell Node to use the format by either naming your file `.mjs` or setting `"type": "module"` in your `package.json` file.
> Also why do so many libraries have this strange 5 line header code for this umd, amd, business. Is that to make their packages work with nodejs?
That's just old for "adapt the module system" from the old days and libraries just didn't bother updating.
I still use amd in my job at Microsoft though for some things so I guess it's not useless :)
But why? This makes it much harder to ensure that identical code works in browser and nodejs, to the point where I sometimes just can't use nodejs. And I don't use package.json, so having to name files ".mjs" is a really painfull restriction.
it sounds like you're looking to have a problem with javascript tbh. don't use it, whatever
Example: RewriteRule "(.*).js$" "$1.mjs" [R=301 NC]
Reference documentation: https://httpd.apache.org/docs/2.4/rewrite/intro.html
It's a pain in the ass.
It works pretty well, and then you need to use something like Azure Functions and then suddenly it doesn’t. For various reasons.
My most recent example was using lodash, which works perfectly fine with import with typescript targeting esnext in node16, but then needs to be setup with require when you target an azure function and commonjs. I mean, maaaybe you could avoid it by using mjs, which is currently sort of needed to move into the node16 functionality in azure functions, even though they sort of run node16 just fine in part of them without it, and you sort of don’t want to use mjs files and so on.
I’m sure it’ll get there in a few years, but it is no doubt annoying to have to fight the toolset ever so often. Over something that feels like it should just be working.
That last part isn’t really exclusive to node these days though, is it?
Some people tried to force ESM adoption by making popular modules ESM-only for no technical reason, but tools are not there yet, and it only annoyed (predictably) half of the internet. Because even if you are pro-ESM or indifferent to it, you can’t do much to migrate your projects’ build pipelines. If you see typescript and webpack, you wouldn’t see “ESM” in there. It either doesn’t work or is too fragile for production.
People who claim it’s done say so because they are using particularly unaffected stacks (including no stack). Idk which way to promote ESM would be the most correct, but this one is too deceptive.
Being the standard for the lsat 7 years strikes me as a good reason.
If I remember my history correctly, it's because when Node first came out, there was no import system in JS, let alone a standardized one; there was no sense of scoping (everything global), nothing about dynamic or lazy loading of dependencies, no tree shaking / removing unused code, and even going to the definition of something in an editor was difficult.
NodeJS adopted CommonJS (I don't recall if they invented it), which is a module and dependency system based on require() and exports. It was only a few years later when the JS standards body settled on import; by then, the JS (dependency / module management) world was already very divided.
There isn't a straight forward solution, but the closest for me is the combination of using a transpiler (Babel), and a bundler (Webpack).
A common criticism on node/javascript projects is the boiler plate setup required. As far as I know, there isn't an IDE that takes care of doing this part for you, where your experience developing outside of the web might (I like to think it akin to starting a project from scratch with C++, gcc, and make).
Some larger projects, do have scripts that do a lot of boiler plate for you, such as Create-React-App. https://github.com/facebook/create-react-app but that is for a specific use case.
there isn't an IDE that takes care of doing this part for you
Did you try WebStorm? Any setup specifics that it doesn't support for you?At the time, I was using sublime, and now I use AWS Cloud9 exclusively.
I took a look through the source of this new fetch API, and it seems to have inherited that wart: https://github.com/nodejs/undici/blob/2dd3437e20c5a3cc466226...
I've argued with the authors of the fetch spec about this before, and ultimately settled on using https://www.npmjs.com/package/set-cookie-parser#user-content... to work around this flaw. (For clarity, I published the package, but chrusart wrote that method - https://github.com/nfriedly/set-cookie-parser/pull/19)
https://www.npmjs.com/package/undici
However the fetch implementation itself is documented as unstable and only supports Node 16.x. I believe this is because it is not quite spec compliant yet, so there is latitude for breaking changes that make it more spec compliant.
It's nice to see the really popular ones make it in though, makes for fewer dependencies when doing browser compatible projects and also allows one to be lazy and not learn the Node way of doing it. Maybe we'll see websocket go into core some day too.
The "all over the place"-ness tends to come more from people who act like changing to a newer library is the only way to code something new not from the lack of JS forcing a single API be used across every app regardless of type.
I'm curious to know what position you occupy in our industry?
Calling an external API from a backend that integrates directly with an client app has been rare for me. Payment processing is all that comes to mind, and that was usually through an imported API package. I've made data scraping tools, but they were unique projects, not part of an app backend. I am a senior full-stack webdev.
Which brings us back to the original question you responded to above. Contrary to your odd views of how software is architected, issuing HTTP requests from the backend is both normal and common enough to be banal. Node adopting the fetch API is generally a good thing as it allows JS developers to code against the same interface whether they are working from the frontend or the backend.
For `fetch` it will take us around a year or two probably.
I wrote more details on the PR itself but I (and others) basically feel strongly that it should be as close to compliant as possible (Deno have a nice list which they happily shared with us of how they diverge and that seems reasonable).
Basically there is a bunch of stuff that should happen first:
- We need to run (and pass) the web platform tests.
- We want to go over the spec (again) and check compliance and add more tests and fix bugs.
- We want community feedback on the implementation and to improve the DX to be better (while not sacrificing spec compliance).
- We want better support for stuff like `File` in core.
- Web streams need to go out of experimental first.
This was a _long_ road that had many stepping stones (like EventTarget, AbortController, Blob, ReadableStream etc). It's important to get it right.
Worth mentioning the fact it's experimental doesn't mean it's not safe to use in simple code in this case - it just means if you make your code behave in a way that diverges from the specification we may change our implementation to match the specification and break your code.
Anything like `await fetch('./someUrl').then(x => x.text())` should be fine.
https://developer.mozilla.org/en-US/docs/Web/API/Request/for... https://developer.mozilla.org/en-US/docs/Web/API/FormData
Yes.
> FormData
Yes, but not in that PR since `FormData` needs to behave differently as part of the platform but there is intent to support it before moving from experimental.
However, I feel the fetch API is completely botched because it lacks timeout support. I have cobbled some together for https://github.com/Backblaze/gists/pull/8 but gosh. I really hope all that is actually not necessary :/
Also, keep in mind that the linked solution does not abort the web request. It only aborts waiting for the response in the JS code. The browser does not close the connection.
node server.js --experimental-fetch
Got 'fetch is not defined' reference error.
This _just landed today_. You can get it by building from master:
```
# there is more details in building.md
git clone https://github.com/nodejs/node
cd node
# may need to pass --openssl-no-asm
./configure
make -j12
./out/Release/node --experimental-fetch
```
Otherwise - wait a bit for the next v17 release to land per the normal release cycle :)
node server.js --experimental-fetch
“I'm curious why Node core has decided to make this an official part of Node?”
The standard describes many functions and classes. What makes fetch more land-able than e.g. the event system, of which node has incompatible implementation? Or feature detection via navigator. Why it? What were the main point(s) of adding fetch specifically?
If something is standard, and it makes sense in the context of a backend, then it's convenient to just use the same API on both ends. Navigator makes almost no sense on the backend unless maybe it worked as a dummy polyfill object.
I don't think it is so strange for node to incorporate it as part of their standard lib as well.
1. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
As someone who has been working almost exclusively on Node.js applications for years now, this is big.
Front-end developers have, for years, enjoyed this wrapper around the clunky XHR API. It is simple, intuitive, and it comes _free_ in the browser environment (and was easily shimmable before it was standard). Additionally, the depreciation of the popular request[0] a while ago, there has been a gap in The Right Way to do http requests without going into the low-level API that ‘http(s)’ provides. Fetch is promised-based (enabling seamless async/await) and, most importantly, standardized.
Basically, fetch provides a meaningful abstraction atop each platforms’ implementation of http-request-doing further unifying server-side and client-side patterns and idioms.
"With fetch available in node, we have a single, standardised, promise-based HTTP client Interface available on all (more or less common) JavaScript platforms.
This is great news for an ecosystem traditionally extremely fragmented and may lead the way to more consolidation in the JS library space. "
Then it took a while to get consensus it's fine to do even if we can't implement the standard fully and diverge from it on stuff like CORS (like Deno does).
Then there were a bunch of work adding APIs like `EventTarget` and `AbortSignal` to Node.js which are quirky'ish web APIs.
As a side note just to show positive collaboration: that work made me make maybe 10 PRs fixing things in EventTarget in Deno - and Deno helped Node a bunch now when landing fetch.
Then web streams and blobs and a few other things as well as the undici work in the background.
Then undici-fetch by Ethan, merge into Undici and then the PR by Michael - and it's still not done :)
Finally
Some people argued users would still like it and there was an attempt[1] by Myles but at the end of the day - the changes were pretty big.
For example: a response body in fetch is a web stream (a whole new stream type) and to cancel you use an AbortController (web type) which is an EventTarget (another web type). `node-fetch` uses Node streams instead which is very reasonable but not something a platform can "get away" with while still calling it fetch.
Here is a comment I wrote about it in the tracker during the PR review process https://github.com/nodejs/node/pull/41749#issuecomment-10257...
I think the only benefit it that it makes it easier to share code between front end and back end.
This is great news for an ecosystem traditionally extremely fragmented and may lead the way to more consolidation in the JS library space.
It's a great news for people doing both front end and backend I guess, but for people doing NodeJS développement it's just one more option to do http request (which I guess is going to be very similar to the module node-fetch that have existed for a while, without special consolidation effect)
...and that's part of why this is great news. Node APIs are the avocado colored appliances of the JS ecosystem.
software, why do you suck now?
e.g., here's your "trivial" API's spec. Then there are the intentional deviations for CORS, e.g., which there is no spec for.
Not to mention the Fetch API isn't available on every other platform... maybe you're thinking of the general ability to make HTTP requests, but nodejs had that from the start.
The issue in the JavaScript ecosystem for this kind of stuff is that it runs on two very different environments and they need time to find solutions that work for all the parties involved.