GithubHelp home page GithubHelp logo

serviejs / popsicle Goto Github PK

View Code? Open in Web Editor NEW
246.0 8.0 19.0 1.14 MB

Simple HTTP requests for node and the browser

License: MIT License

TypeScript 100.00%
http transport request plugins node javascript browser promise

popsicle's People

Contributors

blakeembrey avatar cprecioso avatar dependabot[bot] avatar garethhunt avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jseip1679 avatar postatum avatar rcravago avatar v1v2r0b8 avatar xiaohanyu avatar yongpingchen 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  avatar

popsicle's Issues

Start resolving promise on `nextTick` instead of when calling `then`/`catch`

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.

Out-of-the-box browser support missing from 2.x.x?

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!

Adding 'finally' to popsicle promise

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.
  })

Mock data plugin

Provide the ability to mock requests and responses simply by overriding the request mechanism in use.

Request instances should be fully pipe-able

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.

Separate browser and server scripts

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).

Type defs not found on typings

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.

concurent calls

I am not sure how to make multiple HTTP calls at once,
could you write a quick example on how to do it ?
Thanks !

Dependent typings not resolving in compilation

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?

Error on multiple request: "possible EventEmitter memory leak detected"

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)

Add `defaults` shorthand

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]
})

Remove automatic parsing of responses

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.

PopsicleError class no longer exposed in 3.0.x

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?

Group plugin

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

awkward anonymous function

.then(function (res) {
    console.log(res.status); // => 200
    console.log(res.body); //=> { ... }
    console.log(res.get('Content-Type')); //=> 'application/json'
  });

"awkward anonymous function" - @Cheeseen

Expose `rawHeaders` from node and XMLHttpRequest

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.

x-www-form-urlencoded data is encoded using URL encoding

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.

Increment progress handler automatically

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.

Add upload progress support

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.

Parser can not handle 204 case well

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

Refactor middleware

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)
    })
}

Limit simultaneous requests

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!

getAttachCookies appends cookies even though this is against the RFC

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

Split string parsers into middleware

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.

Add progress handler

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.

When cloning options/request in middleware, slice/expose middleware position

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)).

where is the cookie jar set to requests?

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!

Popsicle needs polyfills because of ES6 features

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?

Make progress optional

Webkit is reporting Refused to get unsafe header "Content-Length" at each call

Awesome work anyway!

Add overridable `request` mechanism

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.

JSONP Plugin

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.

error TS2307: Cannot find module 'url'.

I am using popsicle in my typescript project. And following the steps in README:

  • install by npm
$ npm install popsicle 
  • install declaration file by typings
$ typings install npm:popsicle
  • reference to my ts file( src/MyRequest.ts)
/// <reference path="../typings/modules/popsicle/index.d.ts" />
import {request as Popsicle} from 'popsicle'
  • compile error
$ 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

Catch HTTP Client Errors

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);
});

Move multiple config option to `use` option

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).

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.