SlideShare une entreprise Scribd logo
1  sur  72
Télécharger pour lire hors ligne
S E R V E R L E S S F U N C T I O N S
A N D V U E . J S
S U C C E S S !
N O T FA I L …
S E R V E R L E S S
A N A C T U A L LY I N T E R E S T I N G T H I N G W I T H A C L I C K B A I T Y T I T L E
F a a S
F U N C T I O N S A S A S E R V I C E
S A R A H D R A S N E R
@ S A R A H _ E D O
B E N E F I T S
• You pay only for what you use (usually a lot less)
• Less time babysitting a server
• Same idea as functional programming, breaking things
into small bits
• Principle of least power
L I N K T O C O D E P E N
L I N K T O C O D E P E N
S E R V E R L E S S
A L L T H E
T H I N G S ?
N O , N O T R E A L LY.
S O W H AT I S I T G O O D F O R ?
• Clean data on a cron job ⏰
• Take data and use it to create data
visualizations 📊
• Crop images uploaded by the user and
create a user profile 🖼
Consumption Plan
Free account signup
V U E . J S , S T R I P E , A N D
S E R V E R L E S S
F I R S T U S E C A S E
S A M P L E V U E S H O P
V I S I T T H E S I T E
T H E A P P L I C AT I O N
V I S I T T H E R E P O
U N D E R A P I
app.get('/', (req, res) => res.render('index.pug', { keyPublishable }));
app.post('/charge', (req, res) => {
let amount = 500;
stripe.customers
.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer =>
stripe.charges.create({
amount,
description: 'Sample Charge',
currency: 'usd',
customer: customer.id
})
)
.then(charge => res.render('charge.pug'));
});
app.listen(4567);
What Stripe expects: Express
Where we’re going we don’t need Express!
Kick things off!
var stripe = require('stripe')('sk_test_whateveryourtestingkeyisgoeshere');
// ^ this is a stripe testing key
module.exports = function(context, req) {
context.log('starting to get down');
If we have what we need,
create the customer and then the charge
if (
req.body &&
req.body.stripeEmail &&
req.body.stripeToken &&
req.body.stripeAmt
){
stripe.customers
.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer => {
context.log('starting the stripe charges');
stripe.charges.create({
amount: req.body.stripeAmt,
description: 'Sample Charge',
currency: 'usd',
customer: customer.id
});
})
...
Then finish,
otherwise error logs
...
.then(charge => {
context.log('finished the stripe charges');
context.res = {
// status: 200
body: 'This has been completed'
};
context.done();
})
.catch(err => {
context.log(err);
context.done();
});
} else {
context.log(req.body);
context.res = {
status: 400,
body: "We're missing something"
};
context.done();
}
};
S U C C E S S !
P O S T O N C S S - T R I C K S
O U R C A R T
V U E X H A S A M A N I F E S T O F A L L O F O U R P R O D U C T S , I T E M S , A N D T O TA L
<div v-if="cartTotal > 0">
<!--we'll add our checkout here-->
</div>
<div v-else-if="cartTotal === 0 && success === false" class="empty">
<!--we'll add our empty state here-->
</div>
<div v-else>
<!--we'll add success here-->
</div>
O U R C A R T
<div v-if="cartTotal > 0">
<h1>Cart</h1>
<div class="cartitems"
v-for="item in cart"
key="item">
<div class="carttext">
<h4>{{ item.name }}</h4>
<p>{{ item.price | usdollar }} x {{ item.count }}</p>
<p>Total for this item: <strong>{{ item.price * item.count }}</strong></p>
</div>
<img class="cartimg" :src="`/${item.img}`" :alt="`Image of ${item.name}`">
</div>
<div class="total">
<h3>Total: {{ total | usdollar }}</h3>
</div>
<!--we're going to add our checkout here-->
</div>
computed: {
...
total() {
return Object.values(this.cart)
.reduce((acc, el) => acc + (el.count * el.price), 0)
.toFixed(2);
}
}
V U E S T R I P E
C H E C K O U T
E A S I E S T WAY
R E P O
S T R I P E E L E M E N T S
W E ’ L L U S E :
O R
npm i vue-stripe-elements-plus --save
yarn add vue-stripe-elements-plus
D E FA U LT S T R I P E - E L E M E N T
<template>
<div id='app'>
<h1>Please give us your payment details:</h1>
<card class='stripe-card'
:class='{ complete }'
stripe='pk_test_XXXXXXXXXXXXXXXXXXXXXXXX'
:options='stripeOptions'
@change='complete = $event.complete'
/>
<button class='pay-with-stripe'
@click='pay'
:disabled='!complete'
>
Pay with credit card
</button>
</div>
</template>
D E FA U LT S T R I P E - E L E M E N T
import { stripeKey, stripeOptions } from './stripeConfig.json'
import { Card, createToken } from 'vue-stripe-elements-plus'
export default {
data () {
return {
complete: false,
stripeOptions: {
// see https://stripe.com/docs/stripe.js#element-options for details
}
}
},
components: { Card },
methods: {
pay() {
// createToken returns a Promise which resolves in a result object with
// either a token or an error key.
createToken().then(data => console.log(data.token))
}
}
}
W H AT W E ’ L L N E E D :
data() {
return {
submitted: false,
complete: false,
status: '',
response: '',
stripeOptions: {
// you can configure that cc element.
},
stripeEmail: ''
}
},
W H AT W E ’ L L N E E D :
props: {
total: {
type: [Number, String],
default: '50.00'
},
success: {
type: Boolean,
default: false
}
},
H E R E W E G O !
pay() {
createToken().then(data => {
// we'll change this to know it was submitted
this.submitted = true;
// this is a token we would use for the stripeToken below
console.log(data.token);
axios
.post(
'https://sdras-stripe.azurewebsites.net/api/charge?
code=zWwbn6LLqMxuyvwbWpTFXdRxFd7a27KCRCEseL7zEqbM9ijAgj1c1w==',
{
stripeEmail: this.stripeEmail, // send the email
stripeToken: data.token.id, // testing token
stripeAmt: this.total // send the amount
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
...
H E R E W E G O !
...
.then(response => {
this.status = 'success';
this.$emit('successSubmit');
this.$store.commit('clearCartCount');
// console logs for you :)
this.response = JSON.stringify(response, null, 2);
console.log(this.response);
})
.catch(error => {
this.status = 'failure';
// console logs for you :)
this.response = 'Error: ' + JSON.stringify(error, null, 2);
console.log(this.response);
});
});
pay()
• Uses Axios to post to our function to our function URL
• Tracks whether we've submitted the form or not, with
this.submitted
• It sends the email, token, and total to our serverless
function
• If it's successful, commits to our Vuex store, mutation
clears our cart, and emits to the parent cart component
that the payment was successful. 
• If it errors, it changes the status to failure, and logs the
error response for help with debugging
W H I L E T H E F U N C T I O N W O R K S I T S M A G I C ✨
L I N K T O C O D E P E N
I N T H E C A S E O F FA I L U R E
Template
Script
<div v-if="status === 'failure'">
<h3>Oh No!</h3>
<p>Something went wrong!</p>
<button @click="clearCheckout">Please try again</button>
</div>
clearCheckout() {
this.submitted = false;
this.status = '';
this.complete = false;
this.response = '';
}
I N T H E C A S E O F S U C C E S S
AppSuccess.vue
window.setTimeout(() => this.$emit('restartCart'), 3000);
T H I S C O D E P E N
<div v-if="cartTotal > 0">
<!--we'll add our checkout here-->
</div>
<div v-else-if="cartTotal === 0 && success === false" class="empty">
<!--we'll add our empty state here-->
</div>
<div v-else>
<!--we'll add success here-->
</div>
<div v-if="cartTotal > 0">
<h1>Cart</h1>
...
<app-checkout :total="total" @successSubmit="success = true"></app-checkout>
</div>
<div v-else-if="cartTotal === 0 && success === false" class="empty">
<h1>Cart</h1>
<h3>Your cart is empty.</h3>
<nuxt-link exact to="/"><button>Fill 'er up!</button></nuxt-link>
</div>
<div v-else>
<app-success @restartCart="success = false"/>
<h2>Success!</h2>
<p>Your order has been processed, it will be delivered shortly.</p>
</div>
S E C O N D U S E C A S E
L E T ’ S G E T V I S U A L
G O O G L E M A P S A P I P O W E R E D D ATA V I S
Series: Exploring data with Serverless and Vue
D E M O   A N D   R E P O W / O S S C O D E
[
{
"Name": "Simona Cotin",
"Conference": "DLD 2017 Tel Aviv Israel",
"From": "9/4/2017",
"To": "9/7/2017",
"Location": "Tel Aviv",
"Link": “"
},
...
]
The function updates our cda-data.json…
…which we pull into our Vuex store
M A K E T H E F U N C T I O N
getGeo(makeIterator(content), (updatedContent, err) => {
if (!err) {
// we need to base64 encode the JSON to embed it into the PUT (dear god, why)
let updatedContentB64 = new Buffer(
JSON.stringify(updatedContent, null, 2)
).toString('base64');
let pushData = {
path: GH_FILE,
message: 'Looked up locations, beep boop.',
content: updatedContentB64,
sha: data.sha
};
...
};
We're going to retrieve the geo-information
for each item in the original data
function getGeo(itr, cb) {
let curr = itr.next();
if (curr.done) {
// All done processing- pass the (now-populated) entries to the next callback
cb(curr.data);
return;
}
let location = curr.value.Location;
[
{
"Name": "Simona Cotin",
"Conference": "DLD 2017 Tel Aviv Israel",
"From": "9/4/2017",
"To": "9/7/2017",
"Location": "Tel Aviv",
"Link": “"
},
...
]
The function updates our cda-data.json…
…which we pull into our Vuex store
[
{
"Name": "Simona Cotin",
"Conference": "DLD 2017 Tel Aviv Israel",
"From": "9/4/2017",
"To": "9/7/2017",
"Location": "Tel Aviv",
"Link": "",
"Latitude": 32.0852999,
"Longitude": 34.78176759999999
},
...
]
The function updates our cda-data.json…
…which we pull into our Vuex store
computed: {
speakerData() {
return this.$store.state.speakerData;
},
columns() {
return this.$store.state.speakingColumns;
},
filteredData() {
const x = this.selectedFilter,
filter = new RegExp(this.filteredText, 'i')
return this.speakerData.filter(el => {
if (el[x] !== undefined) { return el[x].match(filter) }
else return true;
})
}
}
<table class="scroll">
<thead>
<tr>
<th v-for="key in columns">
{{ key }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(post, i) in filteredData">
<td v-for="entry in columns">
<a :href="post.Link" target="_blank">
{{ post[entry] }}
</a>
</td>
</tr>
</tbody>
</table>
this.speakerData.forEach(function(index) {
...
if (val in endUnit) {
//if we already have this location (stored together as key) let's
increment it
if (key in endUnit[val]) {
endUnit[val][key][2] += magBase;
} else {
endUnit[val][key] = [lat, long, magBase];
}
} else {
let y = {};
y[key] = [lat, long, magBase];
endUnit[val] = y;
}
})
T H R E E . J S
Single element
<div ref="container"></div>
Call on mounted
mounted() {
//we have to load the texture when it's mounted and pass it in
let earthmap = THREE.ImageUtils.loadTexture('/world7.jpg');
this.initGlobe(earthmap);
}
//from
const geometry = new THREE.SphereGeometry(200, 40, 30);
//to
const geometry = new THREE.IcosahedronGeometry(200, 0);
V U E . J S + S E R V E R L E S S
T H A N K Y O U !
@sarah_edo

Contenu connexe

Tendances

Data Mining Open Ap Is
Data Mining Open Ap IsData Mining Open Ap Is
Data Mining Open Ap Is
oscon2007
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
Michelangelo van Dam
 
Dataiku - Paris JUG 2013 - Hadoop is a batch
Dataiku - Paris JUG 2013 - Hadoop is a batch Dataiku - Paris JUG 2013 - Hadoop is a batch
Dataiku - Paris JUG 2013 - Hadoop is a batch
Dataiku
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
ady36
 

Tendances (19)

Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
 
Convidar para page !!
Convidar para page !!Convidar para page !!
Convidar para page !!
 
Gta v savegame
Gta v savegameGta v savegame
Gta v savegame
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
Data Mining Open Ap Is
Data Mining Open Ap IsData Mining Open Ap Is
Data Mining Open Ap Is
 
Coding part
Coding partCoding part
Coding part
 
Angular js - 4developers 12 kwietnia 2013
Angular js - 4developers 12 kwietnia 2013Angular js - 4developers 12 kwietnia 2013
Angular js - 4developers 12 kwietnia 2013
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Page Caching Resurrected
Page Caching ResurrectedPage Caching Resurrected
Page Caching Resurrected
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Inc
IncInc
Inc
 
Dataiku - Paris JUG 2013 - Hadoop is a batch
Dataiku - Paris JUG 2013 - Hadoop is a batch Dataiku - Paris JUG 2013 - Hadoop is a batch
Dataiku - Paris JUG 2013 - Hadoop is a batch
 
Hospital management
Hospital managementHospital management
Hospital management
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
 
Wsomdp
WsomdpWsomdp
Wsomdp
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)
 

Similaire à Serverless Functions and Vue.js

Supersize me
Supersize meSupersize me
Supersize me
dominion
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
Remy Sharp
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
PL dream
 

Similaire à Serverless Functions and Vue.js (20)

A Journey with React
A Journey with ReactA Journey with React
A Journey with React
 
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
 
Puppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with PuppetPuppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with Puppet
 
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze..."Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-python
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-python
 
WordPressでIoTをはじめよう
WordPressでIoTをはじめようWordPressでIoTをはじめよう
WordPressでIoTをはじめよう
 
What's New in ZF 1.10
What's New in ZF 1.10What's New in ZF 1.10
What's New in ZF 1.10
 
SQL Server 2008 Portfolio
SQL Server 2008 PortfolioSQL Server 2008 Portfolio
SQL Server 2008 Portfolio
 
Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January
Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January
Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January
 
Shangz R Brown Presentation
Shangz R Brown PresentationShangz R Brown Presentation
Shangz R Brown Presentation
 
Xenogenetics
XenogeneticsXenogenetics
Xenogenetics
 
Xenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practicesXenogenetics for PL/SQL - infusing with Java best practices
Xenogenetics for PL/SQL - infusing with Java best practices
 
Web lab programs
Web lab programsWeb lab programs
Web lab programs
 
Supersize me
Supersize meSupersize me
Supersize me
 
Practical PHP by example Jan Leth-Kjaer
Practical PHP by example   Jan Leth-KjaerPractical PHP by example   Jan Leth-Kjaer
Practical PHP by example Jan Leth-Kjaer
 
Exploring the Sweet Spot: Geolocation, Health, and Gov-data
Exploring the Sweet Spot: Geolocation, Health, and Gov-data Exploring the Sweet Spot: Geolocation, Health, and Gov-data
Exploring the Sweet Spot: Geolocation, Health, and Gov-data
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
 
Books
BooksBooks
Books
 

Dernier

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Dernier (20)

TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 

Serverless Functions and Vue.js

  • 1. S E R V E R L E S S F U N C T I O N S A N D V U E . J S
  • 2.
  • 3. S U C C E S S !
  • 4.
  • 5.
  • 6. N O T FA I L …
  • 7.
  • 8. S E R V E R L E S S A N A C T U A L LY I N T E R E S T I N G T H I N G W I T H A C L I C K B A I T Y T I T L E F a a S F U N C T I O N S A S A S E R V I C E
  • 9. S A R A H D R A S N E R @ S A R A H _ E D O
  • 10. B E N E F I T S • You pay only for what you use (usually a lot less) • Less time babysitting a server • Same idea as functional programming, breaking things into small bits • Principle of least power
  • 11. L I N K T O C O D E P E N
  • 12. L I N K T O C O D E P E N
  • 13. S E R V E R L E S S A L L T H E T H I N G S ? N O , N O T R E A L LY.
  • 14. S O W H AT I S I T G O O D F O R ? • Clean data on a cron job ⏰ • Take data and use it to create data visualizations 📊 • Crop images uploaded by the user and create a user profile 🖼
  • 16.
  • 17. V U E . J S , S T R I P E , A N D S E R V E R L E S S F I R S T U S E C A S E
  • 18. S A M P L E V U E S H O P V I S I T T H E S I T E
  • 19. T H E A P P L I C AT I O N V I S I T T H E R E P O
  • 20. U N D E R A P I
  • 21. app.get('/', (req, res) => res.render('index.pug', { keyPublishable })); app.post('/charge', (req, res) => { let amount = 500; stripe.customers .create({ email: req.body.stripeEmail, source: req.body.stripeToken }) .then(customer => stripe.charges.create({ amount, description: 'Sample Charge', currency: 'usd', customer: customer.id }) ) .then(charge => res.render('charge.pug')); }); app.listen(4567); What Stripe expects: Express
  • 22. Where we’re going we don’t need Express!
  • 23. Kick things off! var stripe = require('stripe')('sk_test_whateveryourtestingkeyisgoeshere'); // ^ this is a stripe testing key module.exports = function(context, req) { context.log('starting to get down');
  • 24. If we have what we need, create the customer and then the charge if ( req.body && req.body.stripeEmail && req.body.stripeToken && req.body.stripeAmt ){ stripe.customers .create({ email: req.body.stripeEmail, source: req.body.stripeToken }) .then(customer => { context.log('starting the stripe charges'); stripe.charges.create({ amount: req.body.stripeAmt, description: 'Sample Charge', currency: 'usd', customer: customer.id }); }) ...
  • 25. Then finish, otherwise error logs ... .then(charge => { context.log('finished the stripe charges'); context.res = { // status: 200 body: 'This has been completed' }; context.done(); }) .catch(err => { context.log(err); context.done(); }); } else { context.log(req.body); context.res = { status: 400, body: "We're missing something" }; context.done(); } };
  • 26.
  • 27. S U C C E S S ! P O S T O N C S S - T R I C K S
  • 28.
  • 29.
  • 30. O U R C A R T V U E X H A S A M A N I F E S T O F A L L O F O U R P R O D U C T S , I T E M S , A N D T O TA L
  • 31. <div v-if="cartTotal > 0"> <!--we'll add our checkout here--> </div> <div v-else-if="cartTotal === 0 && success === false" class="empty"> <!--we'll add our empty state here--> </div> <div v-else> <!--we'll add success here--> </div>
  • 32. O U R C A R T <div v-if="cartTotal > 0"> <h1>Cart</h1> <div class="cartitems" v-for="item in cart" key="item"> <div class="carttext"> <h4>{{ item.name }}</h4> <p>{{ item.price | usdollar }} x {{ item.count }}</p> <p>Total for this item: <strong>{{ item.price * item.count }}</strong></p> </div> <img class="cartimg" :src="`/${item.img}`" :alt="`Image of ${item.name}`"> </div> <div class="total"> <h3>Total: {{ total | usdollar }}</h3> </div> <!--we're going to add our checkout here--> </div>
  • 33. computed: { ... total() { return Object.values(this.cart) .reduce((acc, el) => acc + (el.count * el.price), 0) .toFixed(2); } }
  • 34.
  • 35. V U E S T R I P E C H E C K O U T E A S I E S T WAY R E P O
  • 36. S T R I P E E L E M E N T S W E ’ L L U S E :
  • 37. O R npm i vue-stripe-elements-plus --save yarn add vue-stripe-elements-plus
  • 38.
  • 39. D E FA U LT S T R I P E - E L E M E N T <template> <div id='app'> <h1>Please give us your payment details:</h1> <card class='stripe-card' :class='{ complete }' stripe='pk_test_XXXXXXXXXXXXXXXXXXXXXXXX' :options='stripeOptions' @change='complete = $event.complete' /> <button class='pay-with-stripe' @click='pay' :disabled='!complete' > Pay with credit card </button> </div> </template>
  • 40. D E FA U LT S T R I P E - E L E M E N T import { stripeKey, stripeOptions } from './stripeConfig.json' import { Card, createToken } from 'vue-stripe-elements-plus' export default { data () { return { complete: false, stripeOptions: { // see https://stripe.com/docs/stripe.js#element-options for details } } }, components: { Card }, methods: { pay() { // createToken returns a Promise which resolves in a result object with // either a token or an error key. createToken().then(data => console.log(data.token)) } } }
  • 41. W H AT W E ’ L L N E E D : data() { return { submitted: false, complete: false, status: '', response: '', stripeOptions: { // you can configure that cc element. }, stripeEmail: '' } },
  • 42. W H AT W E ’ L L N E E D : props: { total: { type: [Number, String], default: '50.00' }, success: { type: Boolean, default: false } },
  • 43. H E R E W E G O ! pay() { createToken().then(data => { // we'll change this to know it was submitted this.submitted = true; // this is a token we would use for the stripeToken below console.log(data.token); axios .post( 'https://sdras-stripe.azurewebsites.net/api/charge? code=zWwbn6LLqMxuyvwbWpTFXdRxFd7a27KCRCEseL7zEqbM9ijAgj1c1w==', { stripeEmail: this.stripeEmail, // send the email stripeToken: data.token.id, // testing token stripeAmt: this.total // send the amount }, { headers: { 'Content-Type': 'application/json' } } ) ...
  • 44.
  • 45. H E R E W E G O ! ... .then(response => { this.status = 'success'; this.$emit('successSubmit'); this.$store.commit('clearCartCount'); // console logs for you :) this.response = JSON.stringify(response, null, 2); console.log(this.response); }) .catch(error => { this.status = 'failure'; // console logs for you :) this.response = 'Error: ' + JSON.stringify(error, null, 2); console.log(this.response); }); });
  • 46. pay() • Uses Axios to post to our function to our function URL • Tracks whether we've submitted the form or not, with this.submitted • It sends the email, token, and total to our serverless function • If it's successful, commits to our Vuex store, mutation clears our cart, and emits to the parent cart component that the payment was successful.  • If it errors, it changes the status to failure, and logs the error response for help with debugging
  • 47. W H I L E T H E F U N C T I O N W O R K S I T S M A G I C ✨ L I N K T O C O D E P E N
  • 48. I N T H E C A S E O F FA I L U R E
  • 49. Template Script <div v-if="status === 'failure'"> <h3>Oh No!</h3> <p>Something went wrong!</p> <button @click="clearCheckout">Please try again</button> </div> clearCheckout() { this.submitted = false; this.status = ''; this.complete = false; this.response = ''; }
  • 50. I N T H E C A S E O F S U C C E S S
  • 51.
  • 52.
  • 54. <div v-if="cartTotal > 0"> <!--we'll add our checkout here--> </div> <div v-else-if="cartTotal === 0 && success === false" class="empty"> <!--we'll add our empty state here--> </div> <div v-else> <!--we'll add success here--> </div> <div v-if="cartTotal > 0"> <h1>Cart</h1> ... <app-checkout :total="total" @successSubmit="success = true"></app-checkout> </div> <div v-else-if="cartTotal === 0 && success === false" class="empty"> <h1>Cart</h1> <h3>Your cart is empty.</h3> <nuxt-link exact to="/"><button>Fill 'er up!</button></nuxt-link> </div> <div v-else> <app-success @restartCart="success = false"/> <h2>Success!</h2> <p>Your order has been processed, it will be delivered shortly.</p> </div>
  • 55.
  • 56. S E C O N D U S E C A S E L E T ’ S G E T V I S U A L G O O G L E M A P S A P I P O W E R E D D ATA V I S
  • 57. Series: Exploring data with Serverless and Vue D E M O   A N D   R E P O W / O S S C O D E
  • 58. [ { "Name": "Simona Cotin", "Conference": "DLD 2017 Tel Aviv Israel", "From": "9/4/2017", "To": "9/7/2017", "Location": "Tel Aviv", "Link": “" }, ... ] The function updates our cda-data.json… …which we pull into our Vuex store
  • 59. M A K E T H E F U N C T I O N
  • 60. getGeo(makeIterator(content), (updatedContent, err) => { if (!err) { // we need to base64 encode the JSON to embed it into the PUT (dear god, why) let updatedContentB64 = new Buffer( JSON.stringify(updatedContent, null, 2) ).toString('base64'); let pushData = { path: GH_FILE, message: 'Looked up locations, beep boop.', content: updatedContentB64, sha: data.sha }; ... }; We're going to retrieve the geo-information for each item in the original data
  • 61. function getGeo(itr, cb) { let curr = itr.next(); if (curr.done) { // All done processing- pass the (now-populated) entries to the next callback cb(curr.data); return; } let location = curr.value.Location;
  • 62.
  • 63. [ { "Name": "Simona Cotin", "Conference": "DLD 2017 Tel Aviv Israel", "From": "9/4/2017", "To": "9/7/2017", "Location": "Tel Aviv", "Link": “" }, ... ] The function updates our cda-data.json… …which we pull into our Vuex store
  • 64. [ { "Name": "Simona Cotin", "Conference": "DLD 2017 Tel Aviv Israel", "From": "9/4/2017", "To": "9/7/2017", "Location": "Tel Aviv", "Link": "", "Latitude": 32.0852999, "Longitude": 34.78176759999999 }, ... ] The function updates our cda-data.json… …which we pull into our Vuex store
  • 65. computed: { speakerData() { return this.$store.state.speakerData; }, columns() { return this.$store.state.speakingColumns; }, filteredData() { const x = this.selectedFilter, filter = new RegExp(this.filteredText, 'i') return this.speakerData.filter(el => { if (el[x] !== undefined) { return el[x].match(filter) } else return true; }) } }
  • 66. <table class="scroll"> <thead> <tr> <th v-for="key in columns"> {{ key }} </th> </tr> </thead> <tbody> <tr v-for="(post, i) in filteredData"> <td v-for="entry in columns"> <a :href="post.Link" target="_blank"> {{ post[entry] }} </a> </td> </tr> </tbody> </table>
  • 67.
  • 68. this.speakerData.forEach(function(index) { ... if (val in endUnit) { //if we already have this location (stored together as key) let's increment it if (key in endUnit[val]) { endUnit[val][key][2] += magBase; } else { endUnit[val][key] = [lat, long, magBase]; } } else { let y = {}; y[key] = [lat, long, magBase]; endUnit[val] = y; } })
  • 69. T H R E E . J S Single element <div ref="container"></div> Call on mounted mounted() { //we have to load the texture when it's mounted and pass it in let earthmap = THREE.ImageUtils.loadTexture('/world7.jpg'); this.initGlobe(earthmap); }
  • 70. //from const geometry = new THREE.SphereGeometry(200, 40, 30); //to const geometry = new THREE.IcosahedronGeometry(200, 0);
  • 71. V U E . J S + S E R V E R L E S S
  • 72. T H A N K Y O U ! @sarah_edo