Giter VIP home page Giter VIP logo

ky-universal's Introduction

ky-universal

Use Ky in both Node.js and browsers

As of Ky 1.0.0, it runs natively on Node.js. So this package is no longer needed.

Ky is made for browsers, but this package makes it possible to use it in Node.js too, by polyfilling most of the required browser APIs using node-fetch.

This package can be useful for:

  • Isomorphic code
  • Web apps (React, Vue.js, etc.) that use server-side rendering (SSR)
  • Testing browser libraries using a Node.js test runner

Note: Before opening an issue, make sure it's an issue with Ky and not its polyfills. Generally, if something works in the browser, but not in Node.js, it's an issue with node-fetch.

Keep in mind that Ky targets modern browsers when used in the browser. For older browsers, you will need to transpile and use a fetch polyfill.

Install

npm install ky ky-universal

Note that you also need to install ky.

Usage

import ky from 'ky-universal';

const parsed = await ky('https://httpbin.org/json').json();

// …

ReadableStream support

For ReadableStream support, also install web-streams-polyfill:

$ npm install web-streams-polyfill

You can then use it normally:

import ky from 'ky-universal';

const {body} = await ky('https://httpbin.org/bytes/16');
const {value} = await body.getReader().read();
const result = new TextDecoder('utf-8').decode(value);

// …

API

The API is exactly the same as the Ky API, including the named exports.

FAQ

How do I use this with a web app (React, Vue.js, etc.) that uses server-side rendering (SSR)?

Use it like you would use Ky:

import ky from 'ky-universal';

const parsed = await ky('https://httpbin.org/json').json();

// …

Webpack will ensure the polyfills are only included and used when the app is rendered on the server-side.

How do I test a browser library that uses Ky in AVA?

Put the following in package.json:

{
	"ava": {
		"require": [
			"ky-universal"
		]
	}
}

The library that uses Ky will now just work in AVA tests.

clone() hangs with a large response in Node - What should I do?

Streams in Node.js have a smaller internal buffer size (16 kB, aka highWaterMark) than browsers (>1 MB, not consistent across browsers). When using Ky, the default highWaterMark is set to 10 MB, so you shouldn't encounter many issues related to that.

However, you can specify a custom highWaterMark if needed:

import ky from 'ky-universal';

const response = await ky('https://example.com', {
	// 20 MB
	highWaterMark: 1000 * 1000 * 20
});

const data = await response.clone().buffer();

Related

  • ky - Tiny and elegant HTTP client based on the browser Fetch API
  • got - Simplified HTTP requests in Node.js

ky-universal's People

Contributors

arty-name avatar belgattitude avatar qix- avatar richienb avatar sakit0 avatar sholladay avatar sindresorhus avatar xxczaki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ky-universal's Issues

response.headers.get('') bug?

Hello, ive tried to migrate from axios (using nuxt), and start using '@nuxt/http' but when i was tryed to get header from the post response

import http from 'ky-universal'
const actions = {
  // Get Token
  async login(context, payload) {
    let data = null
    try {
      data = await http.post(
        process.env.apiUrl + '/api/content/create?type=User',
        {
          body: payload
        }
      )
    } catch (err) {}
    console.log(data.headers.get('Authorization'))
  },
}

console.log(data.headers.get('Authorization')) shows null, there is anyway to make it work?

in firefox network tab response header looks like:

HTTP/1.1 200 OK
Access-Control-Allow-Headers: Accept, Authorization, Content-Type
Access-Control-Allow-Origin: *
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhY2Nlc3MiOiJjb2xkQGNvbGQuY29sZCIsImF1ZCI6bnVsbCwiZXhwIjoxNTg0NTQyMzMwLCJpYXQiOm51bGwsImlzcyI6bnVsbCwianRpIjpudWxsLCJuYmYiOm51bGwsInN1YiI6bnVsbH0.SYAwu0h5xA6xNQQGqja9uItHq0Wbq-52I4CrT78N7U0
Cache-Control: max-age=2592000, public
Etag: MTU4MzkzNjUzMw==
Date: Wed, 11 Mar 2020 14:38:50 GMT
Content-Length: 0

next js - error: Cannot use import statement outside a module

I have a very simple fetcher that I'm setting up like so:

import ky from 'ky-universal';

const fetchFromApi = ky.extend({
  prefixUrl: process.env.BE_API_ROOT_DOMAIN,
});

export default fetchFromApi;

Which is giving the following error:

Screen Shot 2021-01-15 at 17 17 57

Can't put my finger on it... Any ideas?

HighWatermark FAQ clarification

Hi hopefully this is an easy / quick answer

In the FAQ here: https://github.com/sindresorhus/ky-universal#clone-hangs-with-a-large-response-in-node---what-should-i-do
It's stated that Ky is used under the hood and has a default highWatermark of 10mb.

However when using ky-universal I run into issues with cloning at 20kb and looking through https://github.com/sindresorhus/ky I (perhaps naively) don't think a highWatermark default is being set.

Perhaps I'm just missing it, but would be great to get clarification on this.

Thanks in advance.

Module not found error

Hi, I'm using ky-universal in a nuxtjs project and at the build there is an error:

Module not found: Error: Can't resolve 'web-streams-polyfill/ponyfill/es2018'```

What can I do to solve this Issue?

Thanks

globalThis.Request is not a constructor

In node v16.16.0 with

"ky": "^0.31.3",
"ky-universal": "^0.10.1"

my script throws

node_modules/ky/distribution/core/constants.js:6
        hasContentType = new globalThis.Request('https://a.com', {
                         ^

TypeError: globalThis.Request is not a constructor

This appears to have been introduced at ky 0.31.2

await is only valid in async functions and the top level bodies of modules

After updating to 0.9.1 I'm getting:

    \node_modules\ky-universal\index.js:58
        globalThis.ReadableStream = await Promise.resolve().then(function () {
                                    ^^^^^

    SyntaxError: await is only valid in async functions and the top level bodies of modules

    > 1 | import ky from 'ky-universal';
        | ^

I'm using node v15.6.0.

I'm not quite sure how I'm supposed to fix this. Any help would be greatly appreciated.

web-streams-polyfill is not really optional

The way web-streams-polyfill is called makes it a non optional dependancy as it is declared in package.json

if (!global.ReadableStream) {
	try {
		global.ReadableStream = require('web-streams-polyfill/ponyfill/es2018');
	} catch (_) {}
}

Therefore if the environment simply does not have ReadableStreams the dependancy is called. If a developer is not using readable streams they still have to install it. Thus the dependancy is not optional.

clone() hangs with large response in Node

Issuehunt badges

I hit this bug today, it was caused by node-fetch/node-fetch#386

The bug makes ky-universal not useable at all in node. (You don't know when the code will hang as you don't know the response size ahead of time)

Is there a way to remove clone() from the source code?


IssueHunt Summary

xxczaki xxczaki has been rewarded.

Backers (Total: $80.00)

Submitted pull Requests


Tips

Ky requires DOM types

Hi,

When using ky-universal with Typescript it requires DOM types ("lib": ["dom"]) to be included in tsconfig, because of it's dependency on ky. i. e. without it the build fails with:

node_modules/ky/index.d.ts:426:11 - error TS2304: Cannot find name 'Request'.

This is a bit inconvenient when using ky-universal in a node.js service since it doesn't make sense to add DOM types to a backend project.

Are there any workarounds for this that you are aware of?

Thanks!

afterResponse hook stops response from resolving

Repro — https://github.com/paambaati/ky-body-timeout-repro

I use ky and ky-universal in a Next.js app and I noticed responses failing with a body-timeout error on the Node.js side only for responses above roughly 50KB in size. I've tried tweaking the highWatermark and size options, but it doesn't seem to have an effect.

I have an afterResponse hook that does some additional stuff like logging the responses, redirecting to my login page if the response is a 401, etc.

If I remove the hook, it works. This is illustrated in my repro where I've added a hook with just one console.log statement, and you can see the issue occurring. Returning the res has no effect. If the hook is completely removed on the repro, it works.

CC: @sindresorhus, @sholladay, @szmarczak

fetch and electron renderer fail

In a electron renderer thread if you don't bundle (nodeIntegration===true) you get whatever main prop a package points to, in this case we get the node version of ky.

But if we look at these lines https://github.com/sindresorhus/ky-universal/blob/master/index.js#L14-L16 we will get into troubles because the if clause tests if global.fetch exists and in electron renderer that will be true because native web fetch is available.

So instead of using node-fetch we use native fetch, but when another package using ky uses https://github.com/form-data/form-data with fetch it fails because form-data only works with node-fetch.

To fix this either we detect the environment for this specific case and workaround it or we remove the if clauses since ky already allows for lazy resolution of globals.

I'm happy to PR a fix, but would like some feedback on this first.

.json() maximum size/length?

I recently encounter a very strange situation. My ky.get().json() hangs without any response.

The project sends API query to Contentful and gets response. I tried multiple times and finally figure out that, there seems to be limit of the response size/length?

In Postman, I can see that my limit is around 3.3 KB. Any of you encounter similar situation?

Loading ky-universal from node loads browser.js instead of index.js

Versions information

Node 14
[email protected]
[email protected]

Description

This is a sample project demonstrating the problem. Inside the package.json file we specify that the .js files are treated as esm modules.

However running the simple test.js sample:

import ky from 'ky-universal'

const parsed = await ky('https://httpbin.org/json').json()
console.log(parsed)

Fails i.e:

Screenshot 2021-01-13 at 13 49 51

The issue seems that it seems to be loading the browser.js variant instead of the index.js which polyfills for the node environment.

E.g. if we explictely import the index.js variant that does the polyfill'ing it works as intended:

import ky from './node_modules/ky-universal/index.js'

const parsed = await ky('https://httpbin.org/json').json()
console.log(parsed)

Screenshot 2021-01-13 at 13 53 03

The problem seem to be related to the changes done in the latest version.
Since the test samples will work perfectly fine with the previous versions of ky and ky-universal.

Checking out the branch previous-versions that use [email protected] and [email protected]
Screenshot 2021-01-13 at 13 55 54

Using Ky breaks Vuex

I am writing an app for web and electron using Quasar. I wanted to move from axios to Ky but as soon as I replace it Vuex store refuses to accept changes to it's state. store.commit works and I am able to log payload data and current store values but no mutations are accepted by store without any errors or warnings. This is very interesting and I can't pin where it fails. Any help would be appreciated.

Headers is not a constructor

We are working on a KY / Fetch-based universal HTTP layer for Nuxt. The problem is that Nuxt already polyfills global.fetch, this is breaking ky-universal as if (!global.fetch) prevents filling other globals that ky internally depends on them.

Update: Issue still exists by removing if condition. Maybe a jest / webpack global issue. Closing issue for now.

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module

In Node.js v14, I got this error.

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/salty/Documents/src/youtu-bu/node_modules/ky-universal/index.js
require() of ES modules is not supported.
require() of /Users/salty/Documents/src/youtu-bu/node_modules/ky-universal/index.js from /Users/salty/Documents/src/youtu-bu/packages/youtu-bu-sakagura/.next/server/pages/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /Users/salty/Documents/src/youtu-bu/node_modules/ky-universal/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/salty/Documents/src/youtu-bu/node_modules/ky-universal/package.json.

Could you tell me why do you use "type": "module" in package.json?

Reference Error : Buffer is not defined.

Hello, I am using a package which uses ky-universal as a dependency.
I am getting an error while executing on the ky-universal package that


    /home/kush/Code/solid-stream-aggregator/node_modules/ky-universal/node_modules/node-fetch/src/utils/form-data.js:1
    ReferenceError: Buffer is not defined

      at Object.<anonymous> (node_modules/ky-universal/node_modules/node-fetch/src/utils/form-data.js:7:24)

Tests fail after upgrading ky-universal from 0.9.1 to 0.10.x (underlying error: TextDecoder is not defined)

I use ky in a React app.
For tests (jest on node) I inject ky-universal instead.
(with beforeRequest hook set to return canned responses - also useful for mocks during developments! 😁)

Recently upgraded from 0.9.1 to 0.10.x and all tests relying on ky failed.
Since the diff is mostly a node-fetch minor bump and everything else being equal, obviously it's NOT an issue with ky-universal, but with a dependency.

Took me a while, but I was able to find the underlying error: ReferenceError: TextDecoder is not defined
(thrown by this line: https://github.com/node-fetch/node-fetch/blob/main/src/body.js#L159)

From there, the way to a workaround was shorter. In my setupTests file, I just added:

import {TextDecoder} from 'util'
global.TextDecoder = TextDecoder

(I you use TS, you can easily appease its complaint with: global.TextDecoder = TextDecoder as typeof global.TextDecoder)

And although I still don't understand how such a built-in api became undefined, at least I was back to green ✅

I know ky-universal is not as popular as ky, but if a search engine brings even a single soul to this text and they find it helpful, I'll be happy.

LLAP! 🖖

TypeError: Headers is not a constructor

I've had a somewhat frustrating start to ky, not sure what I'm doing wrong

(node:29176) UnhandledPromiseRejectionWarning: TypeError: Headers is not a constructor
    at new Ky (/Volumes/Repositories/Private/apitests/testProj1/node_modules/ky/umd.js:211:20)
    at Function.ky.(anonymous function) [as get] (/Volumes/Repositories/Private/apitests/testProj1/node_modules/ky/umd.js:389:37)
    at getParentChildEndpoint (/Volumes/Repositories/Private/apitests/testProj1/src/api/util/getParentChildEndpoint.js:14:16)
    at Object.getStatus (/Volumes/Repositories/Private/apitests/testProj1/src/api/instanceApi.js:49:22)

Rerproduced like this:

const ky = require('ky-universal').default;

const prefix = 'http://aa9da6ff.ngrok.io/api/instances/gub6r';
const instanceApi = ky.create({ prefixUrl: prefix, throwHttpErrors: false });
const result = await instanceApi.get('status').json();

This seems to be line 211 in umd.js:
Screenshot 2019-06-17 at 11 15 57

I have both KY and Ky-universal installed. What am I doing wrong or missing?

If I try to catch this, the error is the same as that shown in the stack trace. I'd expect a HTTP error (like 404), not a stack trace like this. Thanks!

I changed how to add proxy in KY

I currently need to use KY on a machine with high confidentiality. This machine only has an intranet. I checked many online tutorials, but I didn't find the way to add an agent. Can you give me an example?

Workaround for ky-universal not being able to be used with Jest

This is not a bug report or an issue with ky-universal.
I'm sharing a solution to a problem I had, hoping it would be visible to people having the same problem if I put it here.
I'd be glad to move it to somewhere else if this is not the best place to share this.

TLDR;

I wasn't able to import ky-universal in a Jest test file.
I worked around this by creating the following file:
jest.setup.js:

const fetch = require('node-fetch');

globalThis.fetch = fetch;
globalThis.Request = fetch.Request;
globalThis.Headers = fetch.Headers;

And adding this to jest.config.js:

module.exports = {
   ...
   setupFiles: ["./jest.setup.js"],
   ...
}

More details

ky-universal is an ES6 module.
No matter how hard I tried, I was not able to make Jest load an ES6 module.
It got transformed to something like this, probably by Babel:

 ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import ky from "ky";

And imports can't be anywhere except at the top level in ES6 Modules.

With ky, I was able to get it transformed to cjs by installing esbuild:
yarn add -D esbuild esbuild-jest
and adding this in my jest.config.js:

module.exports = {
   ...
   transform: {
     "^.+\\.(t|j)sx?$": [
       "esbuild-jest",
       {}
     ],
   },
   transformIgnorePatterns: [
     '/node_modules/(?!ky)'
   ]
   ...
}

But ky-universal is doing top-level await inside it, and neither esbuild-jest nor ts-jest was able to process top level await.

I tried so hard to make this work with just ES6 support and not using a bundler like esbuild. But I had to conclude this is pretty much impossible after two days of digging.

So I tried to start with just ky, which works fine when converted into cjs by esbuild, and started putting stuff into globalThis, one by one, by looking at the errors that came up.

For my code, errors stopped appearing after I assigned the above three things, but there could be more.
If it happens just check the error to see what's missing and add it to globalThis.

Create-React-App testing fails with ReferenceError: Buffer is not defined

Hi there,

Running a simple test fails saying that Buffer is not defined. I tried npm i buffer --save but that didn't work.

Here's the test:

describe("App", () => {
    it("render", () => {
        render(App);
    });
});

And here's the log:

  ● Test suite failed to run

    /Users/danielbakas/Documents/Profesional/Semantyk/Projects/Semantyk/client/node_modules/ky-universal/node_modules/node-fetch/src/utils/form-data.js:1
    ReferenceError: Buffer is not defined

      at Object.<anonymous> (node_modules/ky-universal/node_modules/node-fetch/src/utils/form-data.js:7:24)

Any idea on how to fix this?

Thanks 😋

Error classes are not exposed

The error classes HTTPError and TimeoutError seem to be inaccessible through ky-universal. It only re-exports the default export of ky/umd, not these classes. Following workaround can only be found by inspecting the source code:

const { HTTPError, TimeoutError } = require('ky/umd')

I think it is reasonable to expect following to work:

const { HTTPError, TimeoutError } = require('ky-universal')

Would you accept a PR implementing this?

Can ky clients also be isomorphic?

I have the following use case:

  • A custom Client class that returns a singleton of a ky instance to be used in both client and server (I’m using Astro for both)
  • The class have a internal instance to be used in all requests, and a extend method that mutates this internal instance by calling ky.extend and setting the value
  • The server extends the Client instance to add custom headers
  • The headers are available automatically when using on the client side

Is this setup possible? If not, what would be an alternative?

Does ky-universal have the same API methods as ky?

We are definitely sending a non 2xx response to the ky.post (using ky-universal), and no error is thrown. We assumed that both ky and ky-universal have the same methods, but upon reading the read.me for ky-universal it is not explicitly stated that it does (or doesn't for that matter).

Would you mind updating the read.me to be more explicit regarding how ky-universal can be used?

Many thanks!

Must use import to load ES Module

When trying to use ky/ky-universal with the newly created Next.js app receive such error:
Error: Must use import to load ES Module: /Users/---/node_modules/ky-universal/index.js
require() of ES modules is not supported.
require() of /---/node_modules/ky-universal/index.js from /---/.next/server/pages/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /---/node_modules/ky-universal/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /---/node_modules/ky-universal/package.json.

Packages version:
Node 14.15.4,
"dependencies": {
"ky": "^0.26.0",
"ky-universal": "^0.9.1",
"next": "10.0.5",
"react": "17.0.1",
"react-dom": "17.0.1"
}

Code extract

import ky from "ky-universal";

export default function Home() {
  const fetchData = async () => {
    const res = await ky
      .get("https://jsonplaceholder.typicode.com/todos/1")
      .json();
    setData(res);
    console.log(res);
  };

body.getReader() method missing (node 14.x)

There seems to be a problem using web-streams-polyfill on nodejs 14.x

I ran into the issue where, given some code like described in the documentation:

const ky = require('ky-universal');

(async () => {
	const {body} = await ky('https://httpbin.org/bytes/16');
	const {value} = await body.getReader().read();
	const result = new TextDecoder('utf-8').decode(value);

	// …
})();

I would get a runtime error:

TypeError: _a.getReader is not a function

at the 'body.getReader() call.

I read the docs to install web-streams-polyfill which I did (3.0.0) but still get the error.

I took stepped through the ky-universal code and see

//index.js
if (!global.ReadableStream) {
	try {
		global.ReadableStream = require('web-streams-polyfill/ponyfill/es2018');
	} catch (_) {}
}

This seems to be a problem because the require('web-streams-polyfill/ponyfill/es2018') returns an object, so the following fails:

//ky/umd.js
const supportsStreams = typeof globals.ReadableStream === 'function';

so.... clever me, I thought I would pre-shim the globals.ReadableStream to hot-patch the problem by adding this to my app code:

if ( !global.ReadableStream ) {
  global.ReadableStream = require( 'web-streams-polyfill/ponyfill/es2018' ).ReadableStream
}

but still, the body.getReader() function doesn't exist. Unfortunately the ky code is too fancy for me to follow, so here I am, filing this issue!

fyi, I also tried [email protected] but same error.

.json() shorthand doesn't resolve in nodejs env

Broken:

import ky from "ky-universal";

const result = await ky
  .post(process.env.BE_ENDPOINT!, {
    json: jsonBody,
  })
  .json();

// we never reach here, await never resolves

Works:

import ky from "ky-universal";

const response = await ky
  .post(process.env.BE_ENDPOINT!, {
    json: jsonBody,
  });

const result = await response.json(); // result is here, yay

deps:

"node": "16.17.1"

"ky": "0.33.2",
"ky-universal": "0.11.0",
"web-streams-polyfill": "3.2.1"

ky-universal#[email protected]

NOTE - Seems to depend on the response body somehow (size?), as it doesn't happen for all requests, but it is consistent within the context of a single request (ie. a broken request/response pair stays broken, a valid request/response pair works).

Import in typescript

Hi all,

Don't working default import in ts, like import ky from 'ky-universal' is undefiend
but:

const ky = require('ky-universal')

is working

Prefer own version of node-fetch or allow users to specify it

I just reported an issue on the Next.js issue tracker that concerns ky-universalvercel/next.js#13549

tl;dr

The body timeout issue on parsing large JSON responses still happens with v0.7.0 when using Next.js.

A contributor pointed out (see vercel/next.js#13549 (comment)) that this is happening because ky-universal is preferring global fetch over the latest beta version (own dependency). How do you propose we solve this?

One option I can think of is letting users inject their version of node-fetch. Another way to solve this would be expose a flag to force-use the bundled version of node-fetch.

Are there better solutions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.