SlideShare a Scribd company logo
1 of 71
Download to read offline
jakobm.com
@jakobmattsson
I’m a coder first and foremost. I also help
companies recruit coders, train coders and
architect software. Sometimes I do technical
due diligence and speak at conferences.
!
Want more? Read my story or blog.
Social
coding
FishBrain is the fastest, easiest way
to log and share your fishing.

!
Get instant updates from anglers on
nearby lakes, rivers, and the coast.
Testing web APIs
Simple and readable
Example - Testing a blog API
• Create a blog
• Create two blog entries
• Create two users
• Create a lotal of three comments from
those users, on the two posts
• Request the stats for the blog and
check if the given number of entries
and comments are correct
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post’,
body: 'Here is the text of my first post'
}, function(err, entry1) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post’,
body: 'I do not know what to write any more...'
}, function(err, entry2) {
! post('/user', {
name: 'john doe’
}, function(err, visitor1) {
! post('/user', {
name: 'jane doe'
}, function(err, visitor2) {
! post('/comments', {
userId: visitor1.id,
entryId: entry1.id,
text: "well written dude"
}, function(err, comment1) {
! post('/comments', {
userId: visitor2.id,
entryId: entry1.id,
text: "like it!"
}, function(err, comment2) {
! post('/comments', {
userId: visitor2.id,
entryId: entry2.id,
text: "nah, crap"
}, function(err, comment3) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
});
});
});
});
*No, this is not a tutorial
Promises 101*
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
rainbows.then(function(result) {
// deal with it
});
var rainbows = getJSON({
url: '/somewhere/over/the/rainbow'
});
getJSON({
url: '/somewhere/over/the/rainbow',
success: function(result) {
// deal with it
}
});
rainbows.then(function(result) {
// deal with it
});
var rainbows = getJSON({
url: '/somewhere/over/the/rainbow'
});
f(rainbows);
Why is that
a good idea?
• Loosen up the coupling
• Superior error handling
• Simplified async
Why is that
a good idea?
• Loosen up the coupling
• Superior error handling
• Simplified async
But in particular, it abstracts away the temporal
dependencies in your program (or in this case, test)
That’s enough 101
(even though people barely talk about
the last - and most important - idea)
Promises are not new
Promises are not new
http://github.com/kriskowal/q
http://www.html5rocks.com/en/tutorials/es6/promises
http://domenic.me/2012/10/14/youre-missing-the-point-of-promises
http://www.promisejs.org
https://github.com/bellbind/using-promise-q
https://github.com/tildeio/rsvp.js
https://github.com/cujojs/when
They’ve even
made it into ES6
They’ve even
made it into ES6
Already implemented
natively in
Firefox 30Chrome 33
So why are you not
using them?
So why are you not
using them?
How to draw an owl
1. Draw some
circles
How to draw an owl
1. Draw some
circles
2.Draw the rest
of the owl
How to draw an owl
We want to
draw owls.
!
Not circles.
getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
!
// Map our array of chapter urls to
// an array of chapter json promises.
// This makes sture they all download parallel.
return story.chapterUrls.map(getJSON)
.reduce(function(sequence, chapterPromise) {
// Use reduce to chain the promises together,
// adding content to the page for each chapter
return sequence.then(function() {
// Wait for everything in the sequence so far,
// then wait for this chapter to arrive.
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage('All done');
}).catch(function(err) {
// catch any error that happened along the way
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
As announced
for ES6
That’s circles.
!
Nice circles!
!
Still circles.
browser.init({browserName:'chrome'}, function() {
browser.get("http://admc.io/wd/test-pages/guinea-pig.html", function() {
browser.title(function(err, title) {
title.should.include('WD');
browser.elementById('i am a link', function(err, el) {
browser.clickElement(el, function() {
browser.eval("window.location.href", function(err, href) {
href.should.include('guinea-pig2');
browser.quit();
});
});
});
});
});
});
Node.js WebDriver
Before promises
browser
.init({ browserName: 'chrome' })
.then(function() {
return browser.get("http://admc.io/wd/test-pages/guinea-pig.html");
})
.then(function() { return browser.title(); })
.then(function(title) {
title.should.include('WD');
return browser.elementById('i am a link');
})
.then(function(el) { return browser.clickElement(el); })
.then(function() {
return browser.eval("window.location.href");
})
.then(function(href) { href.should.include('guinea-pig2'); })
.fin(function() { return browser.quit(); })
.done();
After promises
Used to be
callback-hell.
!
Now it is
then-hell.
These examples are
just a different way
of doing async.
!
It’s still uncomfortable.
It’s still circles!
The point of promises:
!
Make async code
as straightforward
as sync code
The point of promises:
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Let me elaborate
Example - Testing a blog API
• Create a blog
• Create two blog entries
• Create some users
• Create some comments from those
users, on the two posts
• Request the stats for the blog and
check if the given number of entries
and comments are correct
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post’,
body: 'Here is the text of my first post'
}, function(err, entry1) {
! post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post’,
body: 'I do not know what to write any more...'
}, function(err, entry2) {
! post('/user', {
name: 'john doe’
}, function(err, visitor1) {
! post('/user', {
name: 'jane doe'
}, function(err, visitor2) {
! post('/comments', {
userId: visitor1.id,
entryId: entry1.id,
text: "well written dude"
}, function(err, comment1) {
! post('/comments', {
userId: visitor2.id,
entryId: entry1.id,
text: "like it!"
}, function(err, comment2) {
! post('/comments', {
userId: visitor2.id,
entryId: entry2.id,
text: "nah, crap"
}, function(err, comment3) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
1-naive.js
1
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! var entryData = [{
title: 'my first post',
body: 'Here is the text of my first post'
}, {
title: 'my second post',
body: 'I do not know what to write any more...'
}]
! async.forEach(entryData, function(entry, callback), {
post(concatUrl('blogs', blog.id, 'entries'), entry, callback);
}, function(err, entries) {
! var usernames = ['john doe', 'jane doe'];
! async.forEach(usernames, function(user, callback) {
post('/user', { name: user }, callback);
}, function(err, visitors) {
! var commentsData = [{
userId: visitor[0].id,
entryId: entries[0].id,
text: "well written dude"
}, {
userId: visitor[1].id,
entryId: entries[0].id,
text: "like it!"
}, {
userId: visitor[1].id,
entryId: entries[1].id,
text: "nah, crap"
}];
! async.forEach(commentsData, function(comment, callback) {
post('/comments', comment, callback);
}, function(err, comments) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
! assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
2-async.js
2
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
3-async-more-parallel.js
3
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
post('/blogs', {
name: 'My blog'
}, function(err, blog) {
! async.parallel([
function(callback) {
var entryData = [{
title: 'my first post',
body: 'Here is the text of my first post'
}, {
title: 'my second post',
body: 'I do not know what to write any more...'
}];
async.forEach(entryData, function(entry, callback), {
post(concatUrl('blogs', blog.id, 'entries'), entry, callback);
}, callback);
},
function(callback) {
var usernames = ['john doe', 'jane doe’];
async.forEach(usernames, function(user, callback) {
post('/user', { name: user }, callback);
}, callback);
}
], function(err, results) {
! var entries = results[0];
var visitors = results[1];
! var commentsData = [{
userId: visitors[0].id,
entryId: entries[0].id,
text: "well written dude"
}, {
userId: visitors[1].id,
entryId: entries[0].id,
text: "like it!"
}, {
userId: visitors[1].id,
entryId: entries[1].id,
text: "nah, crap"
}];
! async.forEach(commentsData, function(comment, callback) {
post('/comments', comment, callback);
}, function(err, comments) {
! get(concatUrl('blogs', blog.id), function(err, blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
});
post('/blogs', {
name: 'My blog'
}).then(function(blog) {
! var visitor1 = post('/user', {
name: 'john doe'
});
! var visitor2 = post('/user', {
name: 'jane doe'
});
! var entry1 = post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my first post',
body: 'Here is the text of my first post'
});
! var entry2 = post(concatUrl('blogs', blog.id, 'entries'), {
title: 'my second post',
body: 'I do not know what to write any more...'
});
! var comment1 = all(entry1, visitor1).then(function(e1, v1) {
post('/comments', {
userId: v1.id,
entryId: e1.id,
text: "well written dude"
});
});
! var comment2 = all(entry1, visitor2).then(function(e1, v2) {
post('/comments', {
userId: v2.id,
entryId: e1.id,
text: "like it!"
});
});
! var comment3 = all(entry2, visitor2).then(function(e2, v2) {
post('/comments', {
userId: v2.id,
entryId: e2.id,
text: "nah, crap"
});
});
! all(comment1, comment2, comment3).then(function() {
get(concatUrl('blogs', blog.id)).then(function(blogInfo) {
assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
});
});
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
4-promises-convoluted.js
4
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
var blog = post('/blogs', {
name: 'My blog'
});
!var entry1 = post(concatUrl('blogs', blog.get('id'), 'entries'), {
title: 'my first post',
body: 'Here is the text of my first post'
});
!var entry2 = post(concatUrl('blogs', blog.get('id'), 'entries'), {
title: 'my second post',
body: 'I do not know what to write any more...'
});
!var visitor1 = post('/user', {
name: 'john doe'
});
!var visitor2 = post('/user', {
name: 'jane doe'
});
!var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: "well written dude"
});
!var comment2 = post('/comments', {
userId: visitor2.get('id'),
entryId: entry1.get('id'),
text: "like it!"
});
!var comment3 = post('/comments', {
userId: visitor2.get('id'),
entryId: entry2.get('id'),
text: "nah, crap"
});
!var allComments = [comment1, comment2, comment2];
!var blogInfoUrl = concatUrl('blogs', blog.get('id'));
!var blogInfo = getAfter(blogInfoUrl, allComments);
!assertEquals(blogInfo, {
name: 'My blog',
numberOfEntries: 2,
numberOfComments: 3
});
https://
github.com/
jakobmattsson/
z-presentation/
blob/master/
promises-in-out/
5-promises-nice.js
5
Note: without narration, this slide lacks a lot of
context. Open the file above and read the
commented version for the full story.
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
Three requirements
Awesome!
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Augmenting objects
is a sensitive topic
Extending prototypes
!
vs
!
wrapping objects
You’re writing Course of action
An app Do whatever you want
A library
Do not modify the

damn prototypes
Complimentary
decision matrix
Promises are already
wrapped objects
_(names)
.chain()
.unique()
.shuffle()
.first(3)
.value()
Chaining usually requires a
method to ”unwrap”
or repeated wrapping
u = _(names).unique()
s = _(u).shuffle()
f = _(s).first(3)
Promises already have a
well-defined way of
unwrapping.
_(names)
.unique()
.shuffle()
.first(3)
.then(function(values) {
// do stuff with values...
})
If underscore/lodash
wrapped promises
But they don’t
Enter
!
Z
1 Deep resolution: Resolve any kind of
object/array/promise/values/whatever
2 Make functions promise-friendly: Sync or
async doesn’t matter; will accept promises
3 Augmentation for promises: jQuery/
underscore/lodash-like extensions
What is Z?
Deep resolution
var data = {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude'
};
!
Z(data).then(function(result) {
!
// result is now: {
// userId: 123,
// entryId: 456,
// text: 'well written dude'
// }
!
});
Takes any object
and resolves all
promises in it.
!
Like Q and Q.all,
but deep
1
Promise-friendly functions
var post = function(url, data, callback) {
// POSTs `data` to `url` and
// then invokes `callback`
};
!
post = Z.bindAsync(post);
!
var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude'
});
bindAsync creates
a function that
takes promises as
arguments and
returns a promise.
2
Promise-friendly functions
var add = function(x, y) {
return x + y;
};
!
add = Z.bindSync(add);
!
var sum = add(v1.get('id'), e1.get('id'));
!
var comment1 = post('/comments', {
userId: visitor1.get('id'),
entryId: entry1.get('id'),
text: 'well written dude',
likes: sum
});
2
bindSync does that
same, for functions
that are not async
Augmentation for promises
var commentData = get('/comments/42');
!
var text = commentData.get('text');
!
var lowerCased = text.then(function(text) {
return text.toLowerCase();
});
3
Without
augmentation
every operation
has to be wrapped
in ”then”
Augmentation for promises
Z.mixin({
toLowerCase: function() {
return this.value.toLowerCase();
}
});
!
var commentData = get('/comments/42');
!
commentData.get('text').toLowerCase();
3
Z has mixin to
solve this
!
Note that Z is not
explicitly applied
to the promise
Augmentation for promises
Z.mixin(zUnderscore);
Z.mixin(zBuiltins);
!
var comment = get('/comments/42');
!
comment.get('text').toLowerCase().first(5);
3
There are prepared
packages to mixin
entire libraries
1 Promises out: Always return promises -
not callback
2 Promises in: Functions should accept
promises as well as regular values
3 Promises between: Augment promises as
you augment regular objects
Three requirements
Make async code
as straightforward
as sync code
Enough with
the madness
You don’t need a lib
to do these things
But please
www.jakobm.com @jakobmattsson
!
github.com/jakobmattsson/z-core
Testing web APIs
Simple and readable

More Related Content

What's hot

What's hot (20)

jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & Tricks
 
Deploying a Location-Aware Ember Application
Deploying a Location-Aware Ember ApplicationDeploying a Location-Aware Ember Application
Deploying a Location-Aware Ember Application
 
Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)Crafting Quality PHP Applications (PHPkonf 2018)
Crafting Quality PHP Applications (PHPkonf 2018)
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)
 
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
 
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
 
Step objects
Step objectsStep objects
Step objects
 
Eugene Andruszczenko: jQuery
Eugene Andruszczenko: jQueryEugene Andruszczenko: jQuery
Eugene Andruszczenko: jQuery
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and Rspec
 
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
 
Django Heresies
Django HeresiesDjango Heresies
Django Heresies
 
Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)Best practices for crafting high quality PHP apps (php[world] 2019)
Best practices for crafting high quality PHP apps (php[world] 2019)
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le Wagon
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
Building a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profitBuilding a Single Page Application using Ember.js ... for fun and profit
Building a Single Page Application using Ember.js ... for fun and profit
 
Selenium bootcamp slides
Selenium bootcamp slides   Selenium bootcamp slides
Selenium bootcamp slides
 
Cucumber
CucumberCucumber
Cucumber
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projects
 

Viewers also liked

Александр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровеньАлександр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
Volha Banadyseva
 
Андрей Светлов. Aiohttp
Андрей Светлов. AiohttpАндрей Светлов. Aiohttp
Андрей Светлов. Aiohttp
Volha Banadyseva
 
Александр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The FutureАлександр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The Future
Volha Banadyseva
 
В погоне за производительностью
В погоне за производительностьюВ погоне за производительностью
В погоне за производительностью
FDConf
 

Viewers also liked (9)

How to survive on Magento platform
How to survive on Magento platformHow to survive on Magento platform
How to survive on Magento platform
 
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровеньАлександр Анцыпов. REST: вывод традиционных систем на новый уровень
Александр Анцыпов. REST: вывод традиционных систем на новый уровень
 
Андрей Светлов. Aiohttp
Андрей Светлов. AiohttpАндрей Светлов. Aiohttp
Андрей Светлов. Aiohttp
 
Magento performance
Magento performanceMagento performance
Magento performance
 
Александр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The FutureАлександр Белокрылов. Java 8: Create The Future
Александр Белокрылов. Java 8: Create The Future
 
Writing extensions for Xcommerce
Writing extensions for XcommerceWriting extensions for Xcommerce
Writing extensions for Xcommerce
 
В погоне за производительностью
В погоне за производительностьюВ погоне за производительностью
В погоне за производительностью
 
Если у вас нету тестов...
Если у вас нету тестов...Если у вас нету тестов...
Если у вас нету тестов...
 
Migrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to ReduxMigrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to Redux
 

Similar to Testing web APIs

Lect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptxLect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptx
zainm7032
 
Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)
Thinkful
 
Intro to javascript (6:19)
Intro to javascript (6:19)Intro to javascript (6:19)
Intro to javascript (6:19)
Thinkful
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
singingfish
 

Similar to Testing web APIs (20)

Getting Answers to Your Testing Questions
Getting Answers to Your Testing QuestionsGetting Answers to Your Testing Questions
Getting Answers to Your Testing Questions
 
Lect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptxLect-5--JavaScript-Intro-12032024-105816am.pptx
Lect-5--JavaScript-Intro-12032024-105816am.pptx
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrain
 
Controller Testing: You're Doing It Wrong
Controller Testing: You're Doing It WrongController Testing: You're Doing It Wrong
Controller Testing: You're Doing It Wrong
 
JavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdfJavaScript Interview Questions Part - 1.pdf
JavaScript Interview Questions Part - 1.pdf
 
Angular js
Angular jsAngular js
Angular js
 
Java script
Java scriptJava script
Java script
 
Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)Build a game with javascript (may 21 atlanta)
Build a game with javascript (may 21 atlanta)
 
Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014Plugin Development @ WordCamp Norway 2014
Plugin Development @ WordCamp Norway 2014
 
Intro to javascript (6:19)
Intro to javascript (6:19)Intro to javascript (6:19)
Intro to javascript (6:19)
 
JSON REST API for WordPress
JSON REST API for WordPressJSON REST API for WordPress
JSON REST API for WordPress
 
Building Better Web APIs with Rails
Building Better Web APIs with RailsBuilding Better Web APIs with Rails
Building Better Web APIs with Rails
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
 
Introdution to Node.js
Introdution to Node.jsIntrodution to Node.js
Introdution to Node.js
 
Thinkful - Intro to JavaScript
Thinkful - Intro to JavaScriptThinkful - Intro to JavaScript
Thinkful - Intro to JavaScript
 
Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!
 
Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017Intro to JavaScript - Thinkful LA, June 2017
Intro to JavaScript - Thinkful LA, June 2017
 
Testing swagger contracts without contract based testing
Testing swagger contracts without contract based testingTesting swagger contracts without contract based testing
Testing swagger contracts without contract based testing
 
Journey To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The MachineJourney To The Front End World - Part3 - The Machine
Journey To The Front End World - Part3 - The Machine
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 

More from FDConf

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.
FDConf
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
FDConf
 

More from FDConf (20)

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.
 
Игорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турИгорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный тур
 
Илья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаИлья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпа
 
Максим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруМаксим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игру
 
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
 
Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?
 
Radoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and ApolloRadoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and Apollo
 
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныВиктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
 
Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless
 
Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?
 
Dart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаDart: питание и сила для вашего проекта
Dart: питание и сила для вашего проекта
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 
JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.
 
CSSO — сжимаем CSS
CSSO — сжимаем CSSCSSO — сжимаем CSS
CSSO — сжимаем CSS
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
 
Будь первым
Будь первымБудь первым
Будь первым
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript""Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
 
«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​«I knew there had to be a better way to build mobile app»​
«I knew there had to be a better way to build mobile app»​
 
«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​«Как перестать отлаживать асинхронные вызовы и начать жить»​
«Как перестать отлаживать асинхронные вызовы и начать жить»​
 

Recently uploaded

Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
FIDO Alliance
 

Recently uploaded (20)

Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!
 
The Metaverse: Are We There Yet?
The  Metaverse:    Are   We  There  Yet?The  Metaverse:    Are   We  There  Yet?
The Metaverse: Are We There Yet?
 
Overview of Hyperledger Foundation
Overview of Hyperledger FoundationOverview of Hyperledger Foundation
Overview of Hyperledger Foundation
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The InsideCollecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
 
Google I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGoogle I/O Extended 2024 Warsaw
Google I/O Extended 2024 Warsaw
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
 
Your enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4jYour enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4j
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 
TopCryptoSupers 12thReport OrionX May2024
TopCryptoSupers 12thReport OrionX May2024TopCryptoSupers 12thReport OrionX May2024
TopCryptoSupers 12thReport OrionX May2024
 

Testing web APIs

  • 1. jakobm.com @jakobmattsson I’m a coder first and foremost. I also help companies recruit coders, train coders and architect software. Sometimes I do technical due diligence and speak at conferences. ! Want more? Read my story or blog.
  • 2.
  • 3.
  • 5. FishBrain is the fastest, easiest way to log and share your fishing. ! Get instant updates from anglers on nearby lakes, rivers, and the coast.
  • 6. Testing web APIs Simple and readable
  • 7. Example - Testing a blog API • Create a blog • Create two blog entries • Create two users • Create a lotal of three comments from those users, on the two posts • Request the stats for the blog and check if the given number of entries and comments are correct
  • 8. post('/blogs', { name: 'My blog' }, function(err, blog) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post’, body: 'Here is the text of my first post' }, function(err, entry1) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post’, body: 'I do not know what to write any more...' }, function(err, entry2) { ! post('/user', { name: 'john doe’ }, function(err, visitor1) { ! post('/user', { name: 'jane doe' }, function(err, visitor2) { ! post('/comments', { userId: visitor1.id, entryId: entry1.id, text: "well written dude" }, function(err, comment1) { ! post('/comments', { userId: visitor2.id, entryId: entry1.id, text: "like it!" }, function(err, comment2) { ! post('/comments', { userId: visitor2.id, entryId: entry2.id, text: "nah, crap" }, function(err, comment3) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); }); }); }); });
  • 9. *No, this is not a tutorial Promises 101*
  • 11. getJSON({ url: '/somewhere/over/the/rainbow', success: function(result) { // deal with it } }); rainbows.then(function(result) { // deal with it }); var rainbows = getJSON({ url: '/somewhere/over/the/rainbow' });
  • 12. getJSON({ url: '/somewhere/over/the/rainbow', success: function(result) { // deal with it } }); rainbows.then(function(result) { // deal with it }); var rainbows = getJSON({ url: '/somewhere/over/the/rainbow' }); f(rainbows);
  • 13. Why is that a good idea? • Loosen up the coupling • Superior error handling • Simplified async
  • 14. Why is that a good idea? • Loosen up the coupling • Superior error handling • Simplified async But in particular, it abstracts away the temporal dependencies in your program (or in this case, test)
  • 15. That’s enough 101 (even though people barely talk about the last - and most important - idea)
  • 17. Promises are not new http://github.com/kriskowal/q http://www.html5rocks.com/en/tutorials/es6/promises http://domenic.me/2012/10/14/youre-missing-the-point-of-promises http://www.promisejs.org https://github.com/bellbind/using-promise-q https://github.com/tildeio/rsvp.js https://github.com/cujojs/when
  • 19. They’ve even made it into ES6 Already implemented natively in Firefox 30Chrome 33
  • 20. So why are you not using them?
  • 21. So why are you not using them?
  • 22. How to draw an owl
  • 23. 1. Draw some circles How to draw an owl
  • 24. 1. Draw some circles 2.Draw the rest of the owl How to draw an owl
  • 25. We want to draw owls. ! Not circles.
  • 26. getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); ! // Map our array of chapter urls to // an array of chapter json promises. // This makes sture they all download parallel. return story.chapterUrls.map(getJSON) .reduce(function(sequence, chapterPromise) { // Use reduce to chain the promises together, // adding content to the page for each chapter return sequence.then(function() { // Wait for everything in the sequence so far, // then wait for this chapter to arrive. return chapterPromise; }).then(function(chapter) { addHtmlToPage(chapter.html); }); }, Promise.resolve()); }).then(function() { addTextToPage('All done'); }).catch(function(err) { // catch any error that happened along the way addTextToPage("Argh, broken: " + err.message); }).then(function() { document.querySelector('.spinner').style.display = 'none'; }); As announced for ES6
  • 28. browser.init({browserName:'chrome'}, function() { browser.get("http://admc.io/wd/test-pages/guinea-pig.html", function() { browser.title(function(err, title) { title.should.include('WD'); browser.elementById('i am a link', function(err, el) { browser.clickElement(el, function() { browser.eval("window.location.href", function(err, href) { href.should.include('guinea-pig2'); browser.quit(); }); }); }); }); }); }); Node.js WebDriver Before promises
  • 29. browser .init({ browserName: 'chrome' }) .then(function() { return browser.get("http://admc.io/wd/test-pages/guinea-pig.html"); }) .then(function() { return browser.title(); }) .then(function(title) { title.should.include('WD'); return browser.elementById('i am a link'); }) .then(function(el) { return browser.clickElement(el); }) .then(function() { return browser.eval("window.location.href"); }) .then(function(href) { href.should.include('guinea-pig2'); }) .fin(function() { return browser.quit(); }) .done(); After promises
  • 31.
  • 32.
  • 33. These examples are just a different way of doing async. ! It’s still uncomfortable. It’s still circles!
  • 34. The point of promises:
  • 35. ! Make async code as straightforward as sync code The point of promises:
  • 36. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 38. Example - Testing a blog API • Create a blog • Create two blog entries • Create some users • Create some comments from those users, on the two posts • Request the stats for the blog and check if the given number of entries and comments are correct
  • 39. post('/blogs', { name: 'My blog' }, function(err, blog) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post’, body: 'Here is the text of my first post' }, function(err, entry1) { ! post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post’, body: 'I do not know what to write any more...' }, function(err, entry2) { ! post('/user', { name: 'john doe’ }, function(err, visitor1) { ! post('/user', { name: 'jane doe' }, function(err, visitor2) { ! post('/comments', { userId: visitor1.id, entryId: entry1.id, text: "well written dude" }, function(err, comment1) { ! post('/comments', { userId: visitor2.id, entryId: entry1.id, text: "like it!" }, function(err, comment2) { ! post('/comments', { userId: visitor2.id, entryId: entry2.id, text: "nah, crap" }, function(err, comment3) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 1-naive.js 1 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 40. post('/blogs', { name: 'My blog' }, function(err, blog) { ! var entryData = [{ title: 'my first post', body: 'Here is the text of my first post' }, { title: 'my second post', body: 'I do not know what to write any more...' }] ! async.forEach(entryData, function(entry, callback), { post(concatUrl('blogs', blog.id, 'entries'), entry, callback); }, function(err, entries) { ! var usernames = ['john doe', 'jane doe']; ! async.forEach(usernames, function(user, callback) { post('/user', { name: user }, callback); }, function(err, visitors) { ! var commentsData = [{ userId: visitor[0].id, entryId: entries[0].id, text: "well written dude" }, { userId: visitor[1].id, entryId: entries[0].id, text: "like it!" }, { userId: visitor[1].id, entryId: entries[1].id, text: "nah, crap" }]; ! async.forEach(commentsData, function(comment, callback) { post('/comments', comment, callback); }, function(err, comments) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { ! assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 2-async.js 2 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 41. https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 3-async-more-parallel.js 3 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story. post('/blogs', { name: 'My blog' }, function(err, blog) { ! async.parallel([ function(callback) { var entryData = [{ title: 'my first post', body: 'Here is the text of my first post' }, { title: 'my second post', body: 'I do not know what to write any more...' }]; async.forEach(entryData, function(entry, callback), { post(concatUrl('blogs', blog.id, 'entries'), entry, callback); }, callback); }, function(callback) { var usernames = ['john doe', 'jane doe’]; async.forEach(usernames, function(user, callback) { post('/user', { name: user }, callback); }, callback); } ], function(err, results) { ! var entries = results[0]; var visitors = results[1]; ! var commentsData = [{ userId: visitors[0].id, entryId: entries[0].id, text: "well written dude" }, { userId: visitors[1].id, entryId: entries[0].id, text: "like it!" }, { userId: visitors[1].id, entryId: entries[1].id, text: "nah, crap" }]; ! async.forEach(commentsData, function(comment, callback) { post('/comments', comment, callback); }, function(err, comments) { ! get(concatUrl('blogs', blog.id), function(err, blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); });
  • 42. post('/blogs', { name: 'My blog' }).then(function(blog) { ! var visitor1 = post('/user', { name: 'john doe' }); ! var visitor2 = post('/user', { name: 'jane doe' }); ! var entry1 = post(concatUrl('blogs', blog.id, 'entries'), { title: 'my first post', body: 'Here is the text of my first post' }); ! var entry2 = post(concatUrl('blogs', blog.id, 'entries'), { title: 'my second post', body: 'I do not know what to write any more...' }); ! var comment1 = all(entry1, visitor1).then(function(e1, v1) { post('/comments', { userId: v1.id, entryId: e1.id, text: "well written dude" }); }); ! var comment2 = all(entry1, visitor2).then(function(e1, v2) { post('/comments', { userId: v2.id, entryId: e1.id, text: "like it!" }); }); ! var comment3 = all(entry2, visitor2).then(function(e2, v2) { post('/comments', { userId: v2.id, entryId: e2.id, text: "nah, crap" }); }); ! all(comment1, comment2, comment3).then(function() { get(concatUrl('blogs', blog.id)).then(function(blogInfo) { assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); }); }); }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 4-promises-convoluted.js 4 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 43. var blog = post('/blogs', { name: 'My blog' }); !var entry1 = post(concatUrl('blogs', blog.get('id'), 'entries'), { title: 'my first post', body: 'Here is the text of my first post' }); !var entry2 = post(concatUrl('blogs', blog.get('id'), 'entries'), { title: 'my second post', body: 'I do not know what to write any more...' }); !var visitor1 = post('/user', { name: 'john doe' }); !var visitor2 = post('/user', { name: 'jane doe' }); !var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: "well written dude" }); !var comment2 = post('/comments', { userId: visitor2.get('id'), entryId: entry1.get('id'), text: "like it!" }); !var comment3 = post('/comments', { userId: visitor2.get('id'), entryId: entry2.get('id'), text: "nah, crap" }); !var allComments = [comment1, comment2, comment2]; !var blogInfoUrl = concatUrl('blogs', blog.get('id')); !var blogInfo = getAfter(blogInfoUrl, allComments); !assertEquals(blogInfo, { name: 'My blog', numberOfEntries: 2, numberOfComments: 3 }); https:// github.com/ jakobmattsson/ z-presentation/ blob/master/ promises-in-out/ 5-promises-nice.js 5 Note: without narration, this slide lacks a lot of context. Open the file above and read the commented version for the full story.
  • 44.
  • 45. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values Three requirements
  • 47. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 48. Augmenting objects is a sensitive topic
  • 50. You’re writing Course of action An app Do whatever you want A library Do not modify the
 damn prototypes Complimentary decision matrix
  • 51.
  • 53. _(names) .chain() .unique() .shuffle() .first(3) .value() Chaining usually requires a method to ”unwrap” or repeated wrapping u = _(names).unique() s = _(u).shuffle() f = _(s).first(3)
  • 54. Promises already have a well-defined way of unwrapping.
  • 55. _(names) .unique() .shuffle() .first(3) .then(function(values) { // do stuff with values... }) If underscore/lodash wrapped promises
  • 58. 1 Deep resolution: Resolve any kind of object/array/promise/values/whatever 2 Make functions promise-friendly: Sync or async doesn’t matter; will accept promises 3 Augmentation for promises: jQuery/ underscore/lodash-like extensions What is Z?
  • 59. Deep resolution var data = { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude' }; ! Z(data).then(function(result) { ! // result is now: { // userId: 123, // entryId: 456, // text: 'well written dude' // } ! }); Takes any object and resolves all promises in it. ! Like Q and Q.all, but deep 1
  • 60. Promise-friendly functions var post = function(url, data, callback) { // POSTs `data` to `url` and // then invokes `callback` }; ! post = Z.bindAsync(post); ! var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude' }); bindAsync creates a function that takes promises as arguments and returns a promise. 2
  • 61. Promise-friendly functions var add = function(x, y) { return x + y; }; ! add = Z.bindSync(add); ! var sum = add(v1.get('id'), e1.get('id')); ! var comment1 = post('/comments', { userId: visitor1.get('id'), entryId: entry1.get('id'), text: 'well written dude', likes: sum }); 2 bindSync does that same, for functions that are not async
  • 62. Augmentation for promises var commentData = get('/comments/42'); ! var text = commentData.get('text'); ! var lowerCased = text.then(function(text) { return text.toLowerCase(); }); 3 Without augmentation every operation has to be wrapped in ”then”
  • 63.
  • 64. Augmentation for promises Z.mixin({ toLowerCase: function() { return this.value.toLowerCase(); } }); ! var commentData = get('/comments/42'); ! commentData.get('text').toLowerCase(); 3 Z has mixin to solve this ! Note that Z is not explicitly applied to the promise
  • 65. Augmentation for promises Z.mixin(zUnderscore); Z.mixin(zBuiltins); ! var comment = get('/comments/42'); ! comment.get('text').toLowerCase().first(5); 3 There are prepared packages to mixin entire libraries
  • 66. 1 Promises out: Always return promises - not callback 2 Promises in: Functions should accept promises as well as regular values 3 Promises between: Augment promises as you augment regular objects Three requirements
  • 67. Make async code as straightforward as sync code Enough with the madness
  • 68. You don’t need a lib to do these things
  • 70.