serviejs / popsicle Goto Github PK
View Code? Open in Web Editor NEWSimple HTTP requests for node and the browser
License: MIT License
Simple HTTP requests for node and the browser
License: MIT License
See title. This is might sound like an odd case, but someone new to the library will likely find it confusing that the request is not being made when they write popsicle('http://example.com')
. However, this comes with a side-effect that you can't pass around a request and attach behaviour asynchronously. Hopefully no one is doing that, but would be interesting to actually find out.
I noticed that commit 8844172 removed popsicle.js
, making 1.4.0
the last release with out-of-the-box browser support (unless I'm missing something). This would seem to cause problems if installing and consuming via Bower. If this is intentional, perhaps the documentation could be updated.
Thanks for Popsicle and your hard work!
Have you considered adding a finally notation to the popsicle promise?
E.g.
popsicle.get('/users')
.then(function (res) {
// Success!
})
.catch(function (err) {
// Something broke.
})
.finally(function (err) {
// Something to happen regardless of success or failure.
})
Provide the ability to mock requests and responses simply by overriding the request
mechanism in use.
A helpful plugin to make sure HTTP requests are retried when there's a network issue. Can easily use the options key and just wrap Request
/Response
instances (should be simple).
Right now, you can use Request#stream
to get an instance of the stream to pipe into and Request#pipe
to pipe from, but it should be completely transparent like request
is on node.
Right now the script is very small and compact in a single file with zero dependencies, but it's might not be 100% correct. It's using a window === undefined
check right now, which is causing the library to use XMLHttpRequest
over require('http')
in desktop applications like Atom. What is the correct behaviour here? Using require('http')
might come with different benefits but XMLHttpRequest
is heavily tied in with developer tools (like the web inspector). Do we really want to change this "feature"? Of course, you can't access any raw buffer or steams with just XMLHttpRequest
(yet).
I searched for Popsicle, but nothing came up:
$ typings search popsicle
> No results found for search
However, when installing with the syntax listed in the README everything is fine:
$ typings install npm:popsicle -S
[email protected]
├─┬ any-promise
│ └── es6-promise
├── arrify
├── concat-stream
├── form-data
├─┬ [email protected]
│ └── make-error
├── methods
├── tough-cookie
└── xtend
Why? I didn't see any mention of the install npm:package
syntax (as opposed to install npm~package
) in the typings docs, so it feels like this is a bit cryptic.
If we say parse('json')
and the Accepts
header is not set, set it to be application/json
.
I am not sure how to make multiple HTTP calls at once,
could you write a quick example on how to do it ?
Thanks !
so when I install the typings for this project, I get errors from child typings inside popsicle not resolving.
typings.json
{
"dependencies": {
"popsicle": "npm:popsicle"
}
}
_typings install output_
i:node austin$ typings install
├─┬ popsicle
│ ├── arrify
│ ├── concat-stream
│ ├── form-data
│ ├── infinity-agent
│ ├─┬ make-error-cause
│ │ └── make-error
│ ├── methods
│ ├─┬ native-or-bluebird
│ │ └── es6-promise
│ ├── tough-cookie
│ └── xtend
then when i run tsc
I get:
node austin$ tsc
1 import makeErrorCause = require('make-error-cause');
~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/error.d.ts(1,33): error TS2307: Cannot find module 'make-error-cause'.
1 import Promise = require('native-or-bluebird');
~~~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/index.d.ts(1,26): error TS2307: Cannot find module 'native-or-bluebird'.
1 import { CookieJar } from 'tough-cookie';
~~~~~~~~~~~~~~
node_modules/popsicle/dist/jar.d.ts(1,27): error TS2307: Cannot find module 'tough-cookie'.
1 import Promise = require('native-or-bluebird');
~~~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/request.d.ts(1,26): error TS2307: Cannot find module 'native-or-bluebird'.
1 import makeErrorCause = require('make-error-cause');
~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/error.d.ts(1,33): error TS2307: Cannot find module 'make-error-cause'.
1 import Promise = require('native-or-bluebird');
~~~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/index.d.ts(1,26): error TS2307: Cannot find module 'native-or-bluebird'.
1 import { CookieJar } from 'tough-cookie';
~~~~~~~~~~~~~~
node_modules/popsicle/dist/jar.d.ts(1,27): error TS2307: Cannot find module 'tough-cookie'.
1 import Promise = require('native-or-bluebird');
~~~~~~~~~~~~~~~~~~~~
node_modules/popsicle/dist/request.d.ts(1,26): error TS2307: Cannot find module 'native-or-bluebird'.
32 async cypher(statement: string, parameters: any = {}) {
~~~~~~
Shouldn't it resolve those automatically for me?
I'm using one request to get cookies from a POST
, oncee set, I'm making another one, but then I get this error:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
at Request.addListener (events.js:160:15)
at Request.start (/Users/wachunei/Desktop/D/testvm/node_modules/popsicle/node_modules/request/request.js:947:8)
at Request.end (/Users/wachunei/Desktop/D/testvm/node_modules/popsicle/node_modules/request/request.js:1732:10)
at end (/Users/wachunei/Desktop/D/testvm/node_modules/popsicle/node_modules/request/request.js:704:14)
at Object._onImmediate (/Users/wachunei/Desktop/D/testvm/node_modules/popsicle/node_modules/request/request.js:718:7)
at processImmediate [as _immediateCallback] (timers.js:354:15)
Create reusable Popsicle instances from a "defaults" command. Populates the default object to use that will be merged later.
var jsonpRequest = popsicle.defaults({
use: [popsicle.plugins.jsonp]
})
Previous versions have heavily relied on automatic parsing of responses, which is largely because of the supported clients. Moving forward with releases, I'd like to move to Response
methods (similar to the fetch API) since it's easier to emit based on expectations. For instance, parsing as JSON can error on the wrong content type response before trying to parse, etc.
Thanks for Popsicle! It's been a joy to use. 😄
In 2.0.x, the PopsicleError
class was exposed at require('popsicle').Error
, which was handy for doing instanceof
checks. As of 3.0.0, it's no longer exposed there. Was this intentional?
It looks like I can still get the error class with require('popsicle/dist/error')
, but that feels a bit like I'm poking around in innards that might change. What would you recommend?
Add a plugin that enable group options. For example:
var group = require('popsicle-group')()
var popsicle = require('popsicle')
popsicle('/').use(group)
popsicle('/foo').use(group)
group.abort() // Aborts all active requests.
group.use() // All requests automatically use this middleware
.then(function (res) {
console.log(res.status); // => 200
console.log(res.body); //=> { ... }
console.log(res.get('Content-Type')); //=> 'application/json'
});
"awkward anonymous function" - @Cheeseen
Helpful for rendering headers into a UI-type view.
Edit: This'll probably change the way headers are passed into Popsicle, making it a breaking change. E.g. headers: string[]
instead of headers: { [key: string]: string | string[] }
.
Edit 2: Actually, I could just continue accepting both downgrading this to a semver minor release.
This almost certainly isn't a real problem but as I was debugging my queries I noticed that space characters in form data are encoded as %20 rather than +
http://stackoverflow.com/questions/1211229/in-a-url-should-spaces-be-encoded-using-20-or
Before I discovered popsicle I was using my own hacked up promised web session code and I ended up using the form-urlencoded package for my encoding. But my decision was based on using the first package I found rather than any careful analysis.
When the progess event is triggered, but the progress is Infinity
because we didn't have data on the endpoint it should automatically increment slightly. Not sure how much exactly, but maybe it can be a little adaptive. Start off at 0.1
and go down (halves?) so it never reaches the end but moves enough to simulate progress.
popsicle.post('http://example.com')
, popsicle.delete({ url: '/foo' })
, etc.
Upload progress in the browser is simple, but I will need to investigate support for node. Upload should emit progress events, as well as have a Request#uploaded()
method to check progress manually.
From version v8.0.0, need to define response parser, by callinguse(popsicle.plugins.parse([...]))
.
However, for PUT
, or DELETE
, usually the successful response is 204 code without response body. And for failure response, usually with json type response body.
If I don't define response parser, for succeeded response is ok. But need to manually parse string type of failure response.
I think need to improve this line of code by confirm status code wether is 204
Aborting, by default, should probably not error in the response stream. It's handy for some things, but is awkward to handle.
Create a plugin for generating HAR archive files (see http://www.softwareishard.com/blog/har-12-spec/).
Using before
, after
and always
is kind of tricky and there are a couple of edge-cases. Middleware could be better served with a slightly different paradigm - make middleware just a function call that wraps the request. In a way, the request starts to look more like async middleware. We could probably even re-create Koa-like interfaces.
function retry (next: Function) {
var ctx = this
return next()
.then(function () {
if (ctx.response.type() === 5) {
return new popsicle.Request(ctx.options())
}
}, function (err) {
if (err.code === 'EUNAVAILABLE') {
return new popsicle.Request(ctx.options())
}
return Promise.reject(err)
})
}
Is there a way to limit simultaneous requests?
I've tried to set this but doesn't seem to have any effect:
import request from 'popsicle';
import auth from 'popsicle-basic-auth';
import http from 'http';
http.globalAgent.maxSockets = 10;
Any suggestion ? 😄
Thanks!
Trying to use popsicle with typescript 2.0 gave me the error: test.ts (1,22): Cannot find module 'popsicle'. (2307)
According to https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html it seem like a types
or typings
property needs to be added.
Should I build this repository by myself to generate a JS file for browser use case?
Using a cookies jar, I was having issues with after login POST, future requests still behaved as if I wasn't logged in.
I traced this down to getAttachedCookies which calls request.set('Cookie', /* original cookies from request*/) followed by request.append('Cookie', /* Jar cookies */)
The server I was connecting to was obviously taking offense to the multiple cookie headers and according to the RFC it is correct to do so.
http://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request
Currently JSON and URL-encoding is a "type", but that's kind of wrong. Better implemented as middleware using request(foo).use(parse('json'))
instead.
This was an oversight, all built-in middleware should be functions - purely for consistency.
Add a Request#progress(fn)
implementation to trigger any time there's progress on the request (since progress isn't part of the ES6 promise spec). It should emit an object like:
{
upload: 0.9,
download: 0,
total: 0.45
}
When the request has resolved, make sure we remove all references to the progress function callbacks to avoid unintentional memory leaks.
Hi,
I think you miss a semicolon in the following line
https://github.com/blakeembrey/popsicle/blob/master/popsicle.js#L1383
and it's a problem is somebody concat this with other libraries.
https://github.com/kevinbeaty/any-promise
this implementation supports more promise implementations and allows the end-user to configure the promise implementation.
https://github.com/davepacheco/node-verror looks useful, I could inherit from it for Popsicle error instance.
This allows nested requests to work better. E.g. if you clone a request at b
in [a, b, c, d]
, the middleware would be set to [b, c, d]
by default as it assumes you'll be returning the request inside the same loop. That way a
has already been processed and still runs on the response anyway (since it's been replaced with the clone).
The other approach requires that middleware becomes a public interface member and you just do request.middleware.slice(request.middleware.indexOf(currentFn))
.
I'm having problems with the cookie jar not working (cookies are not persisted through redirects in a GET call).
I'm reading through the code, and I couldn't find where the jar variable is set to the request instance. I'm trying to debug what I'm doing wrong.
I'm doing this:
this.cookies = popsicle.jar()
this.request = popsicle.defaults({
options: { jar: this.cookies }
})
and then doing the request like so:
this.request.get({
url: this.info.url,
})
.then((response) => {
var fs = require('fs');
fs.writeFileSync('output.html', response.body)
})
The URL I'm GETting redirects 2 times, setting cookies.
But from the result and debugging the requests, the cookies are not being set and sent in the 2nd and 3rd requests.
I've been following the jar
option down to https://github.com/blakeembrey/popsicle/blob/v1.2.1/lib/base.ts#L46 and it doesn't seem to be set. Could it be that it's not set, or that I'm doing something wrong? Could you point to the line where the jar option is set?
Thanks for your time!
Hi!
First of all, this is a very good library with awesome API, thanks for the job.
I just face a small issue when using Popsicle with PhantomJS or on not-so-old browser like IE10: the library uses the ES6 method Object.assign
and since TypeScript does not "compiled" it into ES5-friendly code, Popsicle simply crashes.
We have a similary with Promises.
The workaround is simple, we just need to add polyfills for Object.assign
and Promises
and everything is OK.
But... I feel it's quite sad that a developer needs to include polyfills if he wants to use a library.
I don't know what is your feelings about it?
Webkit is reporting Refused to get unsafe header "Content-Length"
at each call
Awesome work anyway!
This is the core of the logic. By default, request
would be set to either XMLHttpRequest
in browsers or require('http')
in node. This could be overridden for JSONP, for example, but also for other customisations.
It should be really easy to write. Just a before and after request hook to receive the data coming back from the global function that will be exposed in the before hook.
I am using popsicle in my typescript project. And following the steps in README:
$ npm install popsicle
$ typings install npm:popsicle
src/MyRequest.ts
)/// <reference path="../typings/modules/popsicle/index.d.ts" />
import {request as Popsicle} from 'popsicle'
$ tsc src/MyRequest.ts
with the following error:
typings/modules/popsicle/index.d.ts(82,21): error TS2307: Cannot find module 'url'.
And problem part of index.d.ts
code like this:
...
// Source: node_modules/popsicle/dist/base.d.ts
declare module '~popsicle/dist/base' {
import { Url } from 'url'; // problem here
export interface Query {
[key: string]: string | string[];
}
export interface Headers {
[name: string]: string | string[];
}
export type RawHeaders = string[];
export interface BaseOptions {
url?: string;
query?: string | Query;
headers?: Headers;
rawHeaders?: RawHeaders;
}
export default class Base {
Url: Url;
rawHeaders: RawHeaders;
constructor({url, headers, rawHeaders, query}: BaseOptions);
url: string;
query: string | Query;
headers: Headers;
...
tsc version: Version 1.8.10
typings version: 1.3.1
Hello, I am using popsicle
and I like it pretty much. In my code I use it this way:
popsicle.request({
method: 'POST',
url: `${self.user.backendURL}/clients`,
body: clientInfo,
headers: {
'Authorization': `Bearer ${decodeURIComponent(self.user.accessToken)}`,
'Content-Type': 'application/json; charset=utf-8'
}
})
.use(popsicle.plugins.parse('json'))
.then(function (response) {
console.log('Response', response.body);
});
Doing so, I realized that I always end up in the then
block when there is a HTTP response (no matter if it is a 2xx response or a 4xx response). Is there the possibility in popsicle
to reject 4xx status codes (like 400, 412, etc.), so I need to catch them?
What I am thinking of is something like this:
popsicle.request({
method: 'POST',
url: `${self.user.backendURL}/clients`,
body: clientInfo,
headers: {
'Authorization': `Bearer ${decodeURIComponent(self.user.accessToken)}`,
'Content-Type': 'application/json; charset=utf-8'
}
})
.use(popsicle.plugins.parse('json'))
.then(function (response) {
// 2xx responses go here
console.log('Success', response.body);
})
.catch(function (response) {
// 4xx responses go here
console.log('Client Error', response.body);
});
What we're doing internally is just using a bunch of plugins. We should make this more transparent and remove the obscure options like parse
, raw
, etc. and replace with { use: [popsicle.use.default] }
or similar.
Note: This is a major breaking change and will bump the library to 1.0
. I believe the current API is highly stable and useful right now, especially once this gets fixed (it was the only awkward API left).
Hi,
im having a problem with this because the API im using don't implement the OPTIONS
type and it returning an "EUNAVAILABLE"
for me.
Thanks
Investigate enabling HTTP2 transports.
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.