sindresorhus / ky Goto Github PK
View Code? Open in Web Editor NEW๐ณ Tiny & elegant JavaScript HTTP client based on the browser Fetch API
License: MIT License
๐ณ Tiny & elegant JavaScript HTTP client based on the browser Fetch API
License: MIT License
I tested fetch() a time ago and requests to PHP backend not populated $_GET / $_POST variables.
Is that populated with ky requests?
I've got this code:
fetchHomeCards = async () => {
this.setState({ loading: true });
const response = await ky("/api/cards/");
if (response.ok) {
...
it used to work just fine in 0.4.1, but busted now.
In Firefox I get TypeError: /api/cards/ is not a valid URL.
on this line:
var url = new _globalThis.URL(this._options.prefixUrl + this._input);
In Chrome I get a lot more helpful error:
index.js:181 Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL
at new Ky (index.js:181)
at ky (index.js:518)
at CardsContainer._callee$ (State.js:15)
at tryCatch (runtime.js:62)
at Generator.invoke [as _invoke] (runtime.js:288)
at Generator.prototype.(:3000/anonymous function) [as next] (http://localhost:3000/static/js/1.chunk.js:941:21)
at asyncGeneratorStep (asyncToGenerator.js:3)
at _next (asyncToGenerator.js:25)
at asyncToGenerator.js:32
at new Promise (<anonymous>)
at CardsContainer.fetchHomeCards (asyncToGenerator.js:21)
at Home._callee$ (Home.js:9)
at tryCatch (runtime.js:62)
at Generator.invoke [as _invoke] (runtime.js:288)
at Generator.prototype.(:3000/anonymous function) [as next] (http://localhost:3000/static/js/1.chunk.js:941:21)
at asyncGeneratorStep (asyncToGenerator.js:3)
at _next (asyncToGenerator.js:25)
at asyncToGenerator.js:32
at new Promise (<anonymous>)
at Home.<anonymous> (asyncToGenerator.js:21)
at Home.componentDidMount (Home.js:12)
at commitLifeCycles (react-dom.development.js:15986)
at commitAllLifeCycles (react-dom.development.js:17388)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at commitRoot (react-dom.development.js:17549)
at completeRoot (react-dom.development.js:19002)
at performWorkOnRoot (react-dom.development.js:18924)
at performWork (react-dom.development.js:18826)
at performSyncWork (react-dom.development.js:18799)
at requestWork (react-dom.development.js:18676)
at scheduleWork (react-dom.development.js:18480)
at scheduleRootUpdate (react-dom.development.js:19186)
at updateContainerAtExpirationTime (react-dom.development.js:19212)
at updateContainer (react-dom.development.js:19280)
at ReactRoot.push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:19559)
at react-dom.development.js:19713
at unbatchedUpdates (react-dom.development.js:19064)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:19709)
at Object.render (react-dom.development.js:19776)
at Module../src/index.js (index.js:8)
at __webpack_require__ (bootstrap:782)
at fn (bootstrap:150)
at Object.0 (serviceWorker.js:131)
at __webpack_require__ (bootstrap:782)
at checkDeferredModules (bootstrap:45)
at Array.webpackJsonpCallback [as push] (bootstrap:32)
at main.chunk.js:1
I've added a very simple wrapper around fetch myself and added the ability to passing in a qs
object, which adds some parameters to the url:
const uri = new URL(url)
if (qs) {
Object.keys(qs).forEach((key) => uri.searchParams.append(key, qs[key]))
}
it's a nicer api then just adding these to the url by hand.
I could make a PR if interested.
if export the class Ky, others can write their own client with just extend Ky
I have been using this library on version 0.4.1 for some time and that works in react-native when running on the simulator with a debugger attached. Running on device results in Reference Error: self is not defined. This should be fixed in issue #53 (With commit f107e7b) which is available from version 0.5.0. After upgrading ky to 0.5.0 or 0.5.1 Running on a simulator with a debugger attached or a device results in Reference Error: document is not defined.
I import ky and export an instance as follows:
import ky from "ky";
export const api = ky.extend({prefixUrl: BASE_URL});
The error shown in the console is as follows:
Possible Unhandled Promise Rejection (id: 0):
ReferenceError: document is not defined
ReferenceError: document is not defined
at new Ky (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:111478:76)
at Function.ky.(anonymous function) [as post] (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:111772:16)
at _callee3$ (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:115504:24)
at tryCatch (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2081:19)
at Generator.invoke [as _invoke] (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2256:24)
at Generator.prototype.(anonymous function) [as next] (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2124:23)
at tryCatch (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2081:19)
at invoke (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2157:22)
at blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:2167:15
at tryCallOne (blob:file:///58581b4b-dc99-4126-b9a9-cb3f918e33f0:6115:14)
Hi, could you have a look at this alternative syntax for the constructor ? It gets rid of delete this._options.timeout;
and delete this._options.json;
. Does it look cleaner for you ?
constructor(input, {timeout = 10000, json, ...otherOptions}) {
this._input = input;
this._retryCount = 0;
this._options = {
method: 'get',
credentials: 'same-origin', // TODO: This can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
retry: 3,
...otherOptions
};
this._timeout = timeout;
const headers = new window.Headers(this._options.headers || {});
if (json) {
headers.set('content-type', 'application/json');
this._options.body = JSON.stringify(json);
}
The defaults
param will be used to deepMerge
with other options and the deepMerge
method will flat items for array argument.
Everything goes on normal and users may not know what happen if they pass in an array until they look into code. But there is something changed for options for Ky
constructor actually.
Maybe there could be some assertions for the defaults
param type as it should be an object? :)
I ran into this problem when using rollup specifically, but the issue occurs anytime someone attempts to perform a named import. ie.
import { post, get, delete } from 'ky'
The problem here is that delete is a restricted keyword and causes issues when imported and called. One suggestion is to rename it during the import like:
import { post, get, delete as del } from 'ky'
But this doesnt really solve the problem that the export is still confusing.
As a suggestion, i think adding 'del', which would just be an alias for delete would remove this problem:
import { del } from 'ky'
Hello,
What's your opinion on having a prettier config? It'd much easier for contributors to write according to your style.
From looking at the tags in the package.json file, I noticed it says XHR, but when looking at the actual repository's docs, it uses the browser fetch API. Does this mean this library does not support XHR?
We could use streams for that :)
This library doesn't work with popular tools like create-react-app
or next.js
. The reason is that it has no precompiled ES5 bundles. This is considered a bad practice as when someone is using it he has to compile it to ES5 himself to support older browsers. Also, ky
won't work on older browsers when just put into the page as a script.
I don't think it's a good idea to force users to compile every dependency to make sure it's ES5-ready. It would massively affect build times.
Hooks implementation is really a superb and extremly powerfull solution, but I would suggest some small changes to the typescript definition:
hooks.afterResponse
and beforeRequest
could be optionalBeforeRequestHook
sould be BeforeRequestHook = (options: Options) => void;
I am loving the simplicity of this module. What I also love is Next.js. However, those two unfortunately doesn't play well with each other.
Trying to call ky
inside Next's getInitialProps
throws that self
is not defined, because during first request Next.js
calls getInitialProps
on the server.
One possible solution would be to accept a user's fetch
(e.g. https://www.npmjs.com/package/isomorphic-unfetch).
I understand that this adds a complexity, but if you are willing to accept it, I can send a PR.
I generally develop frontend having "Pause on exceptions" functionality of chrome dev tools enabled. Here Ky doesn't work so good and forced me to disable that feature.
What happens is that determining if the fetch request goes well or it goes in timeout, Ky puts the actual request in race against a promise that on timeout (delay) throws an error. It's a nice looking piece of code and works fine, but when the fetch resolves correctly (in time) the other promise continues on its way and launches an uncontrolled exception that is caught by "Pause on exceptions".
A solution can be removing the throw
statement form the timeout promise and chaining the result of the promises race with another function that checks which promise won (fetch or timeout), if the latter then throw the error.
Searching for a browser usable version like ky.js / ky.min.js or a way to load ky to get it work?
Haven't found (unpkg.com, repo, readme).
I have just spent 15 minutes, because I forgot ky
name. Using keywords like fetch
, library
, tiny
etc. I failed to find this library in google, npm and github. In the end I kept scrolling in my liked tweets until I found it.
It's always true. Let's make it an option so we can turn that off.
ky.extend({ prefixUrl: '/api' }) throws error as prefix is missing on ky typings.
Ky version 0.4.0.
Something like:
ky(input, {..., hooks: {
beforeRequest: [
...
]
}})
As discussed in Pr #93:
afterResponse
hooks are not executed for the following code:
const response = await ky.get('https://example.com', {
hooks: {
afterResponse: [
response => {
// This won't get called
}
]
}
});
const data = await response.json();
I know this is not how ky
is supposed to be used, but it's easy to fall into this and see that everything is working, except the hooks.
https://github.com/sindresorhus/ky/blob/master/index.js#L113
We could completely drop self.
in self.Headers
Why not drop it ?
For some out of the box reasons for this lib. Maybe there could be some dist resources like iife, umd or whatever? Since the target env is browser and the native esm support for browser is not that popular. :)
When using .json()
or .text()
with a large json response the promise does not get resolve.
I created a gist which one can download and run.
Currently I am looking for the issue but if you (@sindresorhus) are able to find it quicker than I am I have no complaints ๐
Sindre, what's your current position on bundling Typescript typings to the repository? Somewhere I got the impression that you like Typescript and find typings useful. Do you intend to add them yourself? Will you allow someone to help with them? (but what about maintenance if you will change the API?)
Will you accept PR with initial typings?
In the future, when Ky is more mature, we should add a comparison table to the readme. Like https://github.com/sindresorhus/got#comparison
I know we should use Got for node js, but I'm building an universal app that will be rendered on both server/client side, so how should we handle that ?
I'm having to transpile the module before usage and I'm not sure if that's intentional.
This is the line which caused me pain.
Line 192 in eb4b341
Feel free to close this is if the use of export is intentional, I couldn't really tell from the docs.
Are there any docs?
szmarczak earned $40.00 by resolving this issue!
- Checkout the Issuehunt explorer to discover more funded issues.
- Need some help from other developers? Add your repositories on Issuehunt to raise funds.
Is it possible to leverage the es6 module export syntax instead of the current commonjs style?
Since this is a client side adaptation of fetch, one pro would be possible use of the file without a node bundler, and allow direct inclusion via `<script type="module">"
Example:
<script type="module">
import ky, { extend, HTTPError, TimeoutError } from './index.js';
document.addEventListener('DOMContentLoaded', () => {
console.log({ ky });
console.log({ extend });
console.log({ HTTPError });
console.log({ TimeoutError });
alert('hi');
});
</script>
My current implementation needs some help to get working:
export default createInstance();
export let extend = defaults => createInstance(defaults);
export { HTTPError, TimeoutError };
That above fails a few tests. Example: k.extend
is not defined anymore. We can instead directly add extend
as a method.
Would be nice to not allow the body
option when using ky.get()
and ky.head()
.
We could use a custom Omit type for this:
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Would also be nice to handle ky(โฆ, {method: 'get', body: โฆ})
, but not sure whether that is possible?
It would also be nice to disallow the body
option when the json
option is used.
More info: http://artsy.github.io/blog/2018/11/21/conditional-types-in-typescript/
Ky is breaking due to the use of Object Spread Operator.
I've tested it with Create-React-App. CRA supports the Object Spread Operator, however if it's used within a module, Babel does not transpile it. Interestingly enough, Ky works fine when I add into a box at Codesandbox.io.
./node_modules/ky/index.js
Module parse failed: Unexpected token (21:19)
You may need an appropriate loader to handle this file type.
| }
|
| returnValue = {...returnValue, [key]: value};
| }
| }
Create react app @ latest
Node @ v10.6.0
"ky": "^0.5.1",
"cypress": "^3.1.2",
Cypress doesn't support fetch
api call.
Chromium give following error:
GET https://raw.githubusercontent.com/parlr/lsf-data/master/ net::ERR_ABORTED 400 (Bad Request)
After trying to force fetch
polyfill by adding below code in support/index.js
Cypress.on('window:before:load', win => {
win.fetch = null;
});
I got this error:
Uncaught (in promise) ReferenceError: err is not defined
at _callee$ (actions.js:36)
at tryCatch (runtime.js:62)
at Generator.invoke [as _invoke] (runtime.js:296)
at Generator.prototype.(:8080/__/anonymous function) [as throw] (webpack:///./node_modules/regenerator-runtime/runtime.js?:114:21)
at asyncGeneratorStep (actions.js:5)
at _throw (actions.js:7)
Hi,
I was just trying to catch errors in the front-end of my react/redux app when I spotted a really odd behavior.
try {
await api.delete(`roles/${id}`);
dispatch(actions.deleteRole(id));
} catch (error) {
dispatch({
type: types.DELETE_ROLE_ERROR,
payload: {
error,
},
});
}
try {
await api.delete(`roles/${id}`).json();
dispatch(actions.deleteRole(id));
} catch (error) {
dispatch({
type: types.DELETE_ROLE_ERROR,
payload: {
error,
},
});
}
Any idea why this would happen?
hello,
are there any plans to add a afterResponse hook like axios' response interceptor?
thank you for this library!
nicolai
Like in Got: https://github.com/sindresorhus/got#baseurl
Why yet another library? Why not contribute to existing ones instead of splitting the ecosystem, making it harder for beginners to choose one lib?
Here is a very similar yet much older lib you could have contributed too https://github.com/elbywan/wretch
To simplify json calls, which is probably the major use-case of this library it might be nice to provide some wrapper methods which simplify the api calls even further for the common get, put, patch, delete http verbs.
Eg.
const json = await ky.getJson('https://some-api.com');
const json = await ky.postJson('https://some-api.com', {foo: true});
These would obviously just be some syntatic sugar around the existing json examples, but imo it would make the api even nicer to use.
Hi,
I receive this exception when trying to call an API resource at https://example.com/foo/id
My ky
instance is created as follow:
import ky from 'ky';
const config = {
prefixUrl: process.env.API_ENTRYPOINT,
headers: {
'accept': 'application/ld+json'
}
};
export default ky.extend(config);
I read the discussion related to the #11 and especially the one you wrote #11 (comment)
Sorry to be rude, but I disagree with the choice you made.
From my point of view, the only acceptable format should be await ky('/unicorn', {prefixUrl: 'https://cats.com'});
.
It is not a matter of taste, just a choice guided by the RFC3986:
As per the section 3.3:
If a URI contains an authority component, then the path component
must either be empty or begin with a slash ("/") character.
For the url https://cats.com/unicorn
we have the following parts:
https
:
separator//cats.com
(no userinfo, no port and host=cats.com
)/unicorn
Except if the path is empty, a path must start with a slash.
Can you please reconsider the choice you made in #11 and modify this library according to that RFC?
.
Mentioned it in sindresorhus/got#695 (comment)
One thing that got does, which I think it awesome, and which we don't have in ky, is setting the accept header when .json() is called.
@sholladay What's the benefit of sending this header? It works already without.
selrond earned $20.00 by resolving this issue!
- Checkout the Issuehunt explorer to discover more funded issues.
- Need some help from other developers? Add your repositories on Issuehunt to raise funds.
I know this was probably on purpose, or at least less important than the reasons pointed on the readme. however I have a really hard time dissociating this from the homonymous product ๐ค.
of course this could be a plus on describing the lib โ like "less friction on your client HTTP requests" โ and it's always nice to have a short npm
name.
on future releases we may mirror it to another name if it's commonly agreed between maintainers here.. (hey, bhr
for browser http request is still available ๐
)
Hello,
Just a simple typo in the readme most likely, I would submit a PR but I'm not sure which is actually the most correct behaviour, a default retry of 2 like in the readme or 3 like the actual default.
Cheers
In addition to accepting a number, it should accept an object with the ability to specify which methods and status codes to retry on. Same as Got: https://github.com/sindresorhus/got#retry
IssueHunt has been backed by the following sponsors. Become a sponsor
Something like:
const timeout = (promise, ms) => Promise.race([
promise,
(async () => {
await delay(ms);
+ promise.abort();
throw new TimeoutError();
})()
]);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.