-
-
Notifications
You must be signed in to change notification settings - Fork 957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to merge instances #510
Conversation
What is the use case for this?
Does this imply that an app would be using three instances of got? Seems that this could just be handled by constructing / merging numerous config objects together instead of mashing instances together. |
test/create.js
Outdated
@@ -99,7 +99,7 @@ test('custom endpoint with custom headers (extend)', async t => { | |||
json: true | |||
})).body; | |||
t.is(headers.unicorn, 'rainbow'); | |||
t.is(headers['user-agent'] === undefined, false); | |||
t.false(headers['user-agent'] === undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.not(headers['user-agent'], undefined);
Same with the other test.
I'm also struggling to imagine a use-case for this. What actual (not just example) problem does this solve? I'm not saying it's not a good feature, I just don't see when I would use it. |
advanced-creation.md
Outdated
@@ -114,3 +112,31 @@ const unicorn = got.create(settings); | |||
// Same as: | |||
const unicorn = got.extend({headers: {unicorn: 'rainbow'}}); | |||
``` | |||
|
|||
#### got.forward(instance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think forward
is a confusing name as it sounds like you're forwarding the request. If this were to be added, it would make more sense to just let got.extend
and got.create
accept a parent instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if you use two different libs (instances of got
)? Then you have no possibility to do that. Wait, you could do that this way: got.extend(instance)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got.extend(instance)
people would think it'll only merge options (not handlers), the same as got.extend(instance.defaults.options)
but no the same as got.forward(instance)
. I'll rename it to got.merge
.
@brandon93s You're right, I should've documented that better.
No. But it says so, I need to change the docs then.
That's how it's done! Note: this comment is outdated. |
I used to do Instead of const instance = process.merge(limit);
instance(url, { limit: bytes }) |
Real example (note: not tested): https://gist.github.com/szmarczak/86217216ad2fbc0c8a3e833e5f290460 |
@szmarczak You got a comment on your gist: https://gist.github.com/szmarczak/86217216ad2fbc0c8a3e833e5f290460#gistcomment-2642454 (Mentioning since there are no notifications for gists). |
@brandon93s Can you do your gist comment here instead? As it's easier to follow the discussion here. |
@brandon93s Yeah. We could do something like this: const merge = (a, b) => got.create({
methods: a.defaults.methods,
options: got.assignOptions(a.defaults.options, b.defaults.options),
handler: (options, next) => a.defaults.handler(options, options => b.defaults.handler(options, next));
});
const ghLimit = merge(ghGot, limit); But consider merging many instances. Think about plugins, like |
advanced-creation.md
Outdated
@@ -11,7 +11,8 @@ Configure a new `got` instance with the provided settings.<br> | |||
|
|||
##### [options](readme.md#options) | |||
|
|||
To inherit from parent, set it as `got.defaults.options` or use [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals). | |||
To inherit from parent, set it as `got.defaults.options` or use `got.assignOptions(defaults.options, options)`.<br> | |||
Avoid using [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) as it may give unwanted result. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const a = {headers: {cat: 'meow'}};
const b = {headers: {dog: 'woof'}};
{...a, ...b} // => {headers: {dog: 'woof'}}
got.assignOptions(a, b) // => {headers: {cat: 'meow', dog: 'woof'}}
@jstewmon Can you review this? I'd be very grateful if you left some notes 😃 |
e389280
to
39982d8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not convinced this is necessary. It adds complexity (maintenance risk) to the code base for a very advanced used case. Since extensive documentation is already needed for it, we could offer tips on how to merge instances in the readme as opposed to offering it in core. A separate module could also support this need.
source/as-stream.js
Outdated
@@ -14,6 +14,8 @@ module.exports = options => { | |||
|
|||
options.gotRetry.retries = () => 0; | |||
|
|||
options.gotRetry.retries = () => 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this the same as line 15?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I forgot to remove it when I was resolving a merge conflict.
advanced-creation.md
Outdated
|
||
#### got.merge(instances, [methods]) | ||
|
||
Merges many instances into a single one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would suggest we document the merge strategy. Which options are merged, in what order, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Maybe.
👍
A separate file? Of course, but it's very hard to do so. Another idea: got.register('functionName', function() {});
got.functionName(); |
There might be use-cases for this, but I'm a little bit reluctant as this locks us into supporting the ability to arbitrarily merge instances. There might be features we want to add in the future that makes this difficult. Like @brandon93s said, it also adds some maintenance overhead. And we have yet to figure out a way to support plugins, which might or might not overlap or conflict with this. So in short, I just feel like this is rushing into supporting a huge API surface without enough time and exploration to see what problems it solves and the alternatives. |
We should consider what other ways there are to solve these problems. |
Indeed.
That's with every single feature, isn't it? :)
Understood. Better to consider all the alternatives we have here. I'll leave this PR open. This feature is too complicated to release it now. Tomorrow I'll send two PRs with these changes:
|
advanced-creation.md
Outdated
|
||
##### [[methods]](#methods) | ||
|
||
Default: `instances[0].defaults.methods` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the use-case for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not needed at all (that was an old idea). These are just an aliases to the instance. (got.get()
, got.post()
etc) Hang on, I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
advanced-creation.md
Outdated
|
||
##### [instances](readme.md#instances) | ||
|
||
## Usage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the examples be moved to the top?
@@ -102,7 +102,6 @@ test('extend merges URL instances', t => { | |||
test('create', async t => { | |||
const instance = got.create({ | |||
options: {}, | |||
methods: ['get'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you suddenly removing all the methods
fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are just aliases. If methods
are set to ['get']
you can't do got.post()
but you can do got(url, {method: 'POST'});
. I see no reason why we should let users to modify the aliases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree 👍
source/normalize-arguments.js
Outdated
@@ -11,7 +11,7 @@ const urlToOptions = require('./url-to-options'); | |||
const isFormData = require('./is-form-data'); | |||
|
|||
const retryAfterStatusCodes = new Set([413, 429, 503]); | |||
const knownHookEvents = ['beforeRequest']; | |||
const knownHookEvents = require('./known-hook-events'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
require
statements should be at the top of the file. In this case, line 12.
advanced-creation.md
Outdated
- options are merged using [`got.mergeOptions()`](readme.md#gotmergeoptionsparentoptions-newoptions) (+ hooks are merged too), | ||
- handlers are stored in an array. | ||
|
||
## Usage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Examples
@@ -111,3 +112,119 @@ const unicorn = got.create(settings); | |||
// Same as: | |||
const unicorn = got.extend({headers: {unicorn: 'rainbow'}}); | |||
``` | |||
|
|||
### Merging instances |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an entry to the Highlights section in the readme called Composable
, which links to this section?
@@ -111,3 +112,119 @@ const unicorn = got.create(settings); | |||
// Same as: | |||
const unicorn = got.extend({headers: {unicorn: 'rainbow'}}); | |||
``` | |||
|
|||
### Merging instances | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nice to have something like this as an intro. Feel free to improve it.
Got supports composing multiple instances together. This is very powerful. You can create a client that limits download speed and then compose it with an instance that signs a request. It's like plugins without any of the plugin mess. You just create instances and then compose them together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good!
advanced-creation.md
Outdated
- handlers are stored in an array. | ||
|
||
## Usage | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some examples of what kind of instances you could compose together.
advanced-creation.md
Outdated
}); | ||
``` | ||
|
||
#### Limiting download & upload (in case your machine's got a little amount of RAM) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in case your machine's got a little amount of RAM)
should be in text below the title.
advanced-creation.md
Outdated
|
||
If these ^^^ are different modules and you don't want to rewrite them, use `got.mergeInstances()`. | ||
|
||
**Note**: `noUserAgent` must be placed at the end of chain as the instances are merged serially. Other modules do have the `user-agent` header. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noUserAgent
=> The noUserAgent
instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are merged serially
=> are merged in order
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other modules
=> Other instances
advanced-creation.md
Outdated
``` | ||
|
||
If these ^^^ are different modules and you don't want to rewrite them, use `got.mergeInstances()`. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a header here called #### Putting it all together
or something.
This is looking good now :) |
WHY?
Imagine there are
got
plugins. You can limit download & upload, use GitHub API, send random User Agent and many more. The possibilities are infinite. What if you want to merge some of them into one single piece? Well,got.merge()
comes with help.DONE
advanced-creation.md
assignOptions
#530 & Pass normalized options to the handler #532TODO
DROPPED TASKS
Removing instances from a chain
Checking if a chain has chosen instance
Getting an array of used instances:
got.instances
.Why these tasks were dropped?
That's because defaults are merged, so it's another single instance now. The instances you have provided aren't stored.