-
-
Notifications
You must be signed in to change notification settings - Fork 917
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
Simplify wrapping got
#503
Conversation
I'm a little bit worried that we're exposing too many internals now, especially |
What's the difference between |
I really like how much it simplifies |
Fork - forks the options from parent instance (squashes them into a new piece, performs Create - imagine there are no options, no methods, no handler. You set it up from scratch. Like another got, not inherited from any instance. |
We should list |
A common use-case is just overriding a few defaults when creating a new instance. I don't like how you now need to specify a nested object to set a few options. I think So const client = got.fork({headers: {'x-foo': 'bar'}); Also, is |
source/as-stream.js
Outdated
options.stream = true; | ||
module.exports = (url, options) => { | ||
const normalizedArgs = normalizeArguments(url, options); | ||
normalizedArgs.stream = true; |
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.
normalizedArgs
=> normalizedOptions
would be more accurate, but that's quite verbose.
What's wrong with just:
options = normalizeArguments(url, options);
Do we need the original options somewhere?
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.
Fixed that.
readme.md
Outdated
#### got.create(settings) | ||
|
||
Configure a new `got` instance with provided settings: | ||
|
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.
Since we plan to use this for gh-got
, I think we should just link to it as an example now.
readme.md
Outdated
|
||
##### methods | ||
|
||
Array of supported 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.
methods
=> request 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.
Maybe also document how to just use the defaults methods: methods: got.defaults.methods
?
source/index.js
Outdated
headers: { | ||
'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)` | ||
handler: (url, options, next) => { | ||
return next(url, options); |
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 handler
could use next
directly. Like handler: next
source/create.js
Outdated
} | ||
} | ||
if (options.endpoint) { | ||
url = /^https?/.test(path) ? path : options.endpoint + path; |
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.
This should be:
if (options.endpoint && !/^https?/.test(path)) {
url = options.endpoint + path;
}
source/create.js
Outdated
} catch (error) { | ||
return Promise.reject(error); | ||
} | ||
} | ||
|
||
got.create = (options = {}) => create(assignOptions(defaults, options)); | ||
got.create = newDefaults => create(newDefaults); |
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.
This should be:
got.create = create;
source/create.js
Outdated
} | ||
} | ||
if (options.endpoint && !/^https?/.test(path)) { | ||
url = options.endpoint + path; |
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 we should do url = (new URLGlobal(path, options.endpoint)).toString()
so it handles things like options.endpoint
ending in a slash and path
starting with a slash. That would end up with https://foo.com//path
here (Could you add a test for the specifically too?).
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.
The above if (options.endpoint && !/^https?/.test(path)) {
check can actually be simplified to just if (options.endpoint) {
then.
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.
Yeah, I was using that in my app but forgot about it :D
source/create.js
Outdated
continue; | ||
} | ||
} | ||
if (options.endpoint && !/^https?/.test(path)) { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
readme.md
Outdated
@@ -99,6 +99,14 @@ Properties from `options` will override properties in the parsed `url`. | |||
|
|||
If no protocol is specified, it will default to `https`. | |||
|
|||
##### endpoint |
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 not sure about the word endpoint
anymore. It is too much connected to REST APIs. This one is more generic. Maybe we should follow new URL()
and just call it base
or baseUrl
? I prefer the latter.
readme.md
Outdated
Type: `string` `Object` | ||
|
||
When specified, `url` will be preceded by `endpoint`. | ||
|
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 also mention that this one is especially useful with got.extend()
to create niche specific Got instances?
readme.md
Outdated
|
||
##### methods | ||
|
||
Type: `object` |
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.
Object
readme.md
Outdated
|
||
##### handler | ||
|
||
Type: `function`<br> |
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.
Function
readme.md
Outdated
Function making additional changes to the request. | ||
|
||
To inherit from parent, set it as `got.defaults.handler`.<br> | ||
To use the default handler, set it as `null` or `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.
Couldn't this just be: To use the default handler, just omit specifying this.
?
readme.md
Outdated
|
||
##### [options](#options) | ||
|
||
To inherit from parent, set it as `got.defaults.options` or use [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). |
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.
use [destructuring assignment]
Did you mean to say "object spread"?
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.
Yep, naming is mixed up in my head sometimes
readme.md
Outdated
|
||
###### [options](#options) | ||
|
||
###### next |
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.
next
=> next()
Can you add a small tip to the Tips section (https://github.com/sindresorhus/got#tips) on how to use the |
readme.md
Outdated
|
||
Example: [gh-got](https://github.com/sindresorhus/gh-got/blob/master/index.js) | ||
|
||
Configure a new `got` instance with provided settings: |
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.
We should be more explicit here about got.create()
having no good defaults included by default and how it's different from got.extend()
.
I'm a bit concerned that a user is going to be confused as to whether they should be using
Looking elsewhere, axios has |
readme.md
Outdated
|
||
Type: `string` `Object` | ||
|
||
When specified, `url` will be preceded by `baseUrl`.<br> |
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.
"will be prepended with baseUrl
" is a bit more clear.
Should we note that this only applies to relative URLs? If you specify an absolute URL it will skip the baseUrl
.
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.
The placement in the docs has this as a separate parameter to the got
api. I think it's just part of the options, however. If that's the case it should be moved into the options section below.
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, it's an option. Done in next commit.
readme.md
Outdated
|
||
Configure a new `got` instance with default `options`: | ||
Configure a new `got` instance with default `options` and custom `baseUrl` (optional): |
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.
See other notes, baseUrl
is an option. This feels redundant.
readme.md
Outdated
|
||
Configure a new `got` instance with default `options`: | ||
Configure a new `got` instance with default `options` and custom `baseUrl` (optional): | ||
|
||
```js | ||
(async () => { |
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.
This example is a bit unclear if you're not familiar with httpbin.org
and knowing that this endpoint will reflect headers back in the body. Maybe something like this would help illustrate:
const client = got.extend({
baseUrl: 'https://example.com',
headers: {
'x-unicorn': 'rainbow'
}
});
client.get('/demo')
/* HTTP Request =>
* GET /demo HTTP/1.1
* Host: example.com
* x-unicorn: rainbow
*/
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 know about httpbin.org
but I didn't think of it. I'll change this to httpbin.org
and provide the commented 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.
Oh wait, you mean users may not be familiar with httpbin.org
? Then yes too. I'll replace that.
source/create.js
Outdated
got[method] = (url, options) => got(url, {...options, method}); | ||
got.stream[method] = (url, options) => got.stream(url, {...options, method}); | ||
} | ||
|
||
Object.assign(got, errors); | ||
Object.assign(got, {defaults}); |
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.
Exposing this and having it used in the closure could lead to some unexpected behavior if defaults are modified:
test('tampering with defaults', async t => {
const instance = got.create({
handler: got.defaults.handler,
methods: got.defaults.methods,
options: { ...got.defaults.options,
baseUrl: 'example'
}
});
const instance2 = instance.create({
handler: instance.defaults.handler,
methods: instance.defaults.methods,
options: instance.defaults.options
});
// Tamper Time
instance.defaults.options.baseUrl = 'http://google.com'
t.is(instance.defaults.options.baseUrl, instance2.defaults.options.baseUrl);
});
I think I'd expect two instances created with .create
to be independent and not impact each other. Similar tampering could be performed on the global got.defaults
that the module exports.
Thoughts?
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.
You're right. We should deep freeze those or clone.
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.
We can deep clone it with the extend
dependency, I think.
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.
Deep cloning may lead to false information because it's still writable. Used deep freeze.
@brandon93s Good point. Let's move it out into a separate file like you've described. |
@brandon93s I would leave the names unchanged. Previously |
@szmarczak I don't think @brandon93s was suggesting we rename it, but rather just pointing out the benefit of moving |
@sindresorhus So I'll do that tomorrow then 🦄 |
source/create.js
Outdated
const deepFreeze = obj => { | ||
const keys = Object.keys(obj); | ||
|
||
for (let i = 0; i < keys.length; i++) { |
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.
Use a for-of
loop and Object.entries()
.
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.
Wouldn't it be better: for-of
and Object.keys
? I don't see much difference.
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.
Object.entries()
is better as it gives you the value too right away, instead of having to do options.headers[key]
.
source/create.js
Outdated
const keys = Object.keys(obj); | ||
|
||
for (let i = 0; i < keys.length; i++) { | ||
if (typeof obj[keys[i]] === 'object' && obj[keys[i]] !== null) { |
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.
Use the is
module here: is.object
advanced-creation.md
Outdated
|
||
> Make calling REST APIs easier by creating niche-specific `got` instances. | ||
|
||
#### got.extend([options]) |
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()
should stay in the readme, it was only got.create()
that supposed to be moved out.
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.
Oh, right.
This is perfect now. Amazing work @szmarczak 🙌 |
Fixes #203.
Real example:
https://gist.github.com/szmarczak/6255d5fa9e2f0f0e15ef2264be867478