Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

promise.all for request transforms #31

Merged
merged 19 commits into from
Feb 6, 2017
Merged

promise.all for request transforms #31

merged 19 commits into from
Feb 6, 2017

Conversation

skibz
Copy link
Contributor

@skibz skibz commented Sep 23, 2016

let me know what you think 馃槃
from issue

@skellock
Copy link
Contributor

Wow! Nice! In my brain, it looked a lot more complicated.

One side effect this has is that we now run these in parallel. The order might matter to some people.

Also, adding the async keyword will need us to bring in a new babel transform as we ship in ES5 mode. And now with promises, we'll need to provide instructions for polyfilling on older browsers.

I'm ok with all that stuff, just thinking outloud.

Thank you kindly for adding the tests. I'll take a closer look this weekend!

@skibz
Copy link
Contributor Author

skibz commented Sep 26, 2016

thanks for the feedback!

agreed on the note of serial transform execution. how do you think this would be best handled?

@skellock
Copy link
Contributor

Maybe two phases.

Phase 1 is what we have now (pre-PR). We synchronously loop. Phase 2 is what you're proposing, a Promise.all free for all.

Have the guts just run them back to back? I'd be down for that.

@craigcartmell
Copy link

craigcartmell commented Dec 5, 2016

Any news on this?

I'm attempting to get a token from AsyncStorage in the addRequestTransform method but it's not working out for me.

// Force Authorization header on all requests
  api.addRequestTransform(async request => {
    const jwt = await AsyncStorage.getItem(jwtStoreKey)

    if (jwt) {
      request.headers.Authorization = String(jwt)
    }
  })

Any ideas on a workaround in the meantime before this is fully resolved or should I attempt to use this branch?

@skellock
Copy link
Contributor

skellock commented Dec 5, 2016

The thing that's holding me back on this is, we're going to have to do a few things:

  1. Introduce a breaking API change unless we have 2nd set of transform for the async flavour.
  2. Introduce another babel transform for environments that aren't React... unless we just say, "Bring your own Promise polyfill"... which i'm kinda ok with.

If you do checkout this branch, lemme know how it goes in your app! Might help alleviate my concerns with this.

@craigcartmell
Copy link

No problem, I'll give it a whirl. This must be a fairly common API use-case though, getting a token from storage and sending it in a request?

Is there another way I could accomplish this using apisauce?

@skellock
Copy link
Contributor

skellock commented Dec 5, 2016

Not sure of your set up there, but one option is to create the api every request. Some kind of factory to set it all up. Part of that setup process, you'd go out to AsyncStorage and grab that key.

The call to this factory function would be async.

Essentially creating an stateless version.

Which is really great... and the cost of a small performance it. (which would be trivial since we're talking to the internet!).

@skellock
Copy link
Contributor

skellock commented Dec 5, 2016

This async feature should be a thing though. I want it too! :)

@craigcartmell
Copy link

Good idea re: the factory, cheers!

@craigcartmell
Copy link

craigcartmell commented Dec 8, 2016

This is working perfectly for me in my react-native project (based on the Ignite framework). Nice work @skibz.

@skellock: How about adding it as a separate method as oppose to adding the functionality into addRequestTransform as per this PR?

Maybe a simple addAsyncRequestTransform to keep it backwards compatible?

Then as you say, the user can implement their own polyfill if they want to take advantage of it.

@skellock
Copy link
Contributor

skellock commented Dec 8, 2016

Ya, I'm down with that!

@skellock
Copy link
Contributor

skellock commented Dec 8, 2016

I seem to be having an issue with this. The transforms aren't being applied serially. I think we want to keep the same intention which is chaining. We just want to do it async. Lemme know if I'm wrong here.

@craigcartmell
Copy link

I'm not sure I completely follow. Could you post an example of what you have currently?

@skellock
Copy link
Contributor

Sorry, I didn't explain that well at all. Ha!

This implementation is parallel + fast fail. All transforms would be run parallel and when they all pass, control flow continues. Should any fail, they all get rejected.

A ...
B ...
C .......
         ... continue

The way current transforms work is that they happened first-come first-serve with swallowed errors.

A ...
     B ...
          C ...
               ... continue

It's not that this new way is wrong, it's just that it's not like how it currently works.

Actually this implementation is both faster and more inline with people expect with promises.

So I'll kick this back to you guys...

Is this what you're looking for?

Should we have two different async types?

.addSerialRequestTransform( x => x )
.addParallelRequestTransform( y => y)

or

.addRequestTransformAsync( x => x ) // default serial
.addRequestTransformAsync( y => y, true ) // opt-in parallel

I think once we lock this down, I'll call this 1.0.

@craigcartmell
Copy link

Ah, I see now.

Default to serial and opt in flag looks good to me!

@skibz
Copy link
Contributor Author

skibz commented Dec 12, 2016

hey @skellock

sorry for taking so long to update all of this!

i've changed this branch to use addAsyncRequestTransform function. doRequest will now execute asynchronous transforms first and will not execute synchronous transforms until asynchronous ones are complete.

i see that you've begun discussing different ways of operating (opt-in parallel and such) so i'm not sure if you all would be satisfied with what i've done 馃槃

to test the async request transforms, run:

npm i mocha
./node_modules/.bin/mocha --compilers js:babel-core/register test/mocha-asyncRequestTransformTests.js

i added test cases with mocha because the ava test suite was hanging for more than four to five minutes at a time (i have a positively diminutive computer 馃槄 )

so please let me know if the ava tests are broken as i cannot run them!

@skellock
Copy link
Contributor

Thanks for all this work! I appreciate it.

ava will kick the crap out of your computer. That's a feature! But it shouldn't take 4-5 minutes. What happens if you run ava -s? This turns off the parallel support and tests are executed serially.

The promise.all call will run things in parallel, but I believe serial should be the default.

Once I get a block of contiguous time (hopefully this week), I'll merge this in and make a few changes.

Thank you!

@skibz
Copy link
Contributor Author

skibz commented Dec 12, 2016

that did the trick, thanks!

@skibz
Copy link
Contributor Author

skibz commented Dec 12, 2016

@skellock i had a crack at making the transformers run serially - let me know if the approach i used is 馃憤 /馃憥 ?

(i'm not too happy with my solution, a higher-order promise function would be far nicer to read here. something like Promise.seq, if there were one.)

@craigcartmell
Copy link

How's this looking? :)

@skellock
Copy link
Contributor

Haven't had the bandwidth just yet, sorry. It is a useful feature and I want this PR, however, I might tweak the implementation a bit. I have such a hard time wrapping my head around reduce for flow control. Or reduce in general for that matter. =)

@skibz
Copy link
Contributor Author

skibz commented Jan 21, 2017

yeah, the reduce usage is not pretty. 馃様
i always thought it was weird that the standard doesn't include a function for serially processing a collection of promises.

@skellock
Copy link
Contributor

Maybe a little help from this?

https://github.com/sindresorhus/p-waterfall

@skibz
Copy link
Contributor Author

skibz commented Jan 23, 2017

i think we have exorcised the ugly code demons

@skellock skellock merged commit e668def into infinitered:master Feb 6, 2017
@skellock
Copy link
Contributor

skellock commented Feb 6, 2017

Sorry for the long cycle here. Thank you for contribution. I'll get a build out shortly with this.

@skibz
Copy link
Contributor Author

skibz commented Feb 6, 2017

thank you so much for letting me make this feature addition!

@skibz skibz mentioned this pull request Feb 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants