pouchdb: Can't change ajax parameters on-the-fly

Environment (Node.js/browser/hybrid app/etc.)

node.

Adapter (IndexedDB/WebSQL/LevelDB/etc.)

all.

Server (CouchDB/Cloudant/Couchbase/PouchDB Server/etc.)

n/a.

problem statement / request

i need to be able to wrap pouchdb-ajax.

currently I can modify the inputs to the request module via new PouchDB(name, { ajax: { ... } }). this is a onetime, static customization of the request.

i need runtime, dynamic ability to change the headers. our authentication scheme requires headers adjustment periodically on sub-sequent requests. I used to be able to wrap PouchDB.utils.ajax to achieve this. unfortunately, this capability is now removed.

can we consider restoring the passing of a function to { ajax: ... }? thanks team! you guys rock

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 28 (22 by maintainers)

Commits related to this issue

Most upvoted comments

Reopening as this is something would still like to support officially

and yeh I swear I will get this one done

Hey just wanted to let you know that in Hoodie, we resolved dynamic headers by using a getter: https://github.com/hoodiehq/hoodie-client/blob/a4e3544c889cd3145f37ab837adb70ad1ce04ac9/lib/get-api.js#L20-L33

So yeh I believe the old version was as @mkazlauskas said, with

var db = new PouchDB('name', {
  ajax: function(opts, callback) { 
  }
});

I think that should be how it is exposed because the adapter/db api is generally symetrical across the adapters, this is http specific, also its going to be a comparatively rarely used so keeping the core api smaller is nicer imo, however I think we should make 2 changes, one is that we use promises, because promises, I also think we should pass in our implementation of ajax for the use case that the caller wants to modify the request but still make it, so:

var requestCount = 0;
var db = new PouchDB('name', {
  ajax: function(opts, ajax) {
     requestCount++;
     return ajax(opts);
  }
});

or

var db = new PouchDB('name', {
  ajax: function(opts, ajax) {
     return Promise.reject({
       status: 412, 
       name: 'myfakeerror'
     });
  }
});

or

var db = new PouchDB('name', {
  ajax: function(opts, ajax) {
     return doMyAuth().then(function(res) { 
       opts.headers.auth = res.auth;
       return ajax(opts);
     });
  }
});

Will need a little refactor of how we currently handle ajax internally, but totally backwards compatible and I think fairly clean + useful?

So this is happning in https://github.com/pouchdb/pouchdb/issues/6944, with a WIP PR posted that is pretty much working

Okay patching the _ajax method does work. For anyone stumbling upon this now, this is how I did it:

const db = new PouchDB("http://localhost:5984/mydb");

const ajax = db._ajax;
db._ajax = function(opts, cb) {
  const headers = Object.assign({}, opts.headers, myDynamicHeaders());
  return ajax(Object.assign({}, opts, { headers }), cb);
};

Working on this now, so one issue is opts.ajax is already a thing, so this needs a new name, using req for now but could probably do better, another is that this actually deprecates the need for opts.ajax because it can be done via req

var db = new PouchDB('name', {
  req: function(opts, req) {
     opts.headers.myauth = myAuthToken;
     return req(opts);
  }
});

replaces

var db = new PouchDB('name', {
  ajax: { 
    headers: { myauth: myAuthToken }
  }
});

However removing opts.ajax or replacing it with this functionality would be a breaking change, so I think we should add this new functionality with a different name and deprecate opts.ajax and we can take it out in a few releases whenever we do a new purge release

I know that at some point we are going to get around to fixing this but honestly it’s not likely to be for a month or two. 😦

Are there any updates on this issue? I’m deciding whether to hack db._ajax or wait for an official resolution.

Hm yeah, I see a few ways to solve this problem:

  1. make pouchdb-ajax pluggable, allow users to supply their own (hard)
  2. add a db.setAjaxOptions() API so you’re not limited to constructor time
  3. options.preRequest or similar pre-request hook

Personally I’m in favor of #2 since it’s the simplest conceptually and would probably add ~3 lines of code (we’d just need to make this a member variable), although I dislike exposing a new API method. @daleharvey ?

So it was likely that I removed this when refactoring the http adapter but surprised this is the first report about it, @yaronyg wasnt this something thali depended on?

I have seen a few use cases for this and in a step towards having the integration tests run purely against the supported API I think it would be good to reintroduce this in a way that supports the tests + users use cases:

  1. A simple ability to count requests then pass them along as they were
  2. A way to dynamically modify requests, to add a header for example
  3. To return custom data and not make the request at all