├── Chapter10
├── Testing
│ ├── backend
│ │ ├── test
│ │ │ ├── mocha.opts
│ │ │ ├── integration
│ │ │ │ └── test-upload file.js
│ │ │ └── unit
│ │ │ │ ├── test-greetings.js
│ │ │ │ └── test-orders.js
│ │ ├── .gitignore
│ │ ├── lib
│ │ │ ├── db.js
│ │ │ ├── notifier.js
│ │ │ └── order.js
│ │ ├── functions
│ │ │ ├── greetings.js
│ │ │ └── orders.js
│ │ ├── serverless.yml
│ │ └── package.json
│ └── frontend
│ │ ├── src
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── App.test.js
│ │ ├── App.css
│ │ └── App.js
│ │ ├── public
│ │ ├── favicon.ico
│ │ ├── manifest.json
│ │ └── index.html
│ │ ├── .gitignore
│ │ └── package.json
├── Deployment
│ ├── .gitignore
│ ├── package.json
│ ├── handler.js
│ └── serverless.yml
└── serverless-store-chap10
│ ├── README.md
│ ├── frontend
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── index.js
│ │ ├── components
│ │ │ ├── NoMatch.js
│ │ │ ├── Error.js
│ │ │ ├── Comment.js
│ │ │ ├── ShoppingCartItem.js
│ │ │ ├── CommentList.js
│ │ │ ├── ProductList.js
│ │ │ └── CommentBox.js
│ │ ├── lib
│ │ │ ├── config.js
│ │ │ └── iot.js
│ │ └── css
│ │ │ └── site.css
│ ├── .gitignore
│ └── package.json
│ ├── backend
│ ├── package.json
│ ├── functions
│ │ ├── comments.js
│ │ └── products.js
│ ├── lib
│ │ ├── cart.js
│ │ ├── checkout.js
│ │ ├── products.js
│ │ └── utils.js
│ ├── repositories
│ │ └── fakedb.js
│ └── serverless.yml
│ └── scripts
│ └── package.json
├── Chapter06
├── serverless-store-chap6
│ ├── backend
│ │ ├── repositories
│ │ │ ├── dynamodb.js
│ │ │ ├── simpledb.js
│ │ │ └── fakedb.js
│ │ ├── package.json
│ │ ├── lib
│ │ │ ├── checkout.js
│ │ │ ├── cart.js
│ │ │ ├── products.js
│ │ │ └── utils.js
│ │ ├── serverless.yml
│ │ └── functions
│ │ │ └── products.js
│ ├── README.md
│ └── frontend
│ │ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ │ ├── src
│ │ ├── index.js
│ │ ├── lib
│ │ │ ├── config.js
│ │ │ └── services.js
│ │ ├── components
│ │ │ ├── NoMatch.js
│ │ │ ├── Error.js
│ │ │ ├── Comment.js
│ │ │ ├── CommentList.js
│ │ │ ├── ShoppingCartItem.js
│ │ │ ├── ProductList.js
│ │ │ ├── Login.js
│ │ │ └── Product.js
│ │ └── css
│ │ │ └── site.css
│ │ ├── .gitignore
│ │ └── package.json
├── using-multiple-services
│ ├── service1
│ │ ├── greetings.js
│ │ ├── serverless.yml
│ │ ├── package.json
│ │ └── handler.js
│ └── service2
│ │ ├── serverless.yml
│ │ ├── handler.js
│ │ └── package.json
└── graphql
│ ├── .gitignore
│ ├── serverless.yml
│ ├── package.json
│ └── handler.js
├── Chapter03
├── hello-serverless
│ ├── event.json
│ ├── .gitignore
│ ├── serverless.yml
│ └── handler.js
├── serve-html
│ ├── .gitignore
│ ├── serverless.yml
│ └── handler.js
├── lambda-events
│ ├── .gitignore
│ ├── serverless.yml
│ └── handler.js
├── serverless-plugin
│ ├── .gitignore
│ ├── serverless.yml
│ ├── handler.ts
│ └── package.json
├── test-role-statements
│ ├── .gitignore
│ ├── serverless.yml
│ └── handler.js
└── using-external-modules
│ ├── .gitignore
│ ├── package.json
│ ├── serverless.yml
│ └── handler.js
├── Chapter05
├── react-ajax
│ ├── send-data
│ │ ├── src
│ │ │ ├── css
│ │ │ │ └── site.css
│ │ │ ├── index.js
│ │ │ └── components
│ │ │ │ ├── ShoppingCartItem.js
│ │ │ │ ├── ShoppingCart.js
│ │ │ │ └── App.js
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── index.html
│ │ ├── .gitignore
│ │ └── package.json
│ ├── backend
│ │ ├── .gitignore
│ │ ├── serverless.yml
│ │ └── handler.js
│ ├── request-data
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── index.html
│ │ ├── src
│ │ │ ├── images
│ │ │ │ ├── lonely-bird.jpg
│ │ │ │ └── solid-friendship.jpg
│ │ │ ├── index.js
│ │ │ ├── css
│ │ │ │ └── site.css
│ │ │ └── components
│ │ │ │ ├── ProductList.js
│ │ │ │ ├── Product.js
│ │ │ │ └── App.js
│ │ ├── .gitignore
│ │ └── package.json
│ └── README.md
├── serverless-store-chap5
│ ├── README.md
│ └── frontend
│ │ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ │ ├── src
│ │ ├── lib
│ │ │ ├── config.js
│ │ │ └── services.js
│ │ ├── images
│ │ │ ├── lonely-bird.jpg
│ │ │ └── solid-friendship.jpg
│ │ ├── index.js
│ │ ├── components
│ │ │ ├── NoMatch.js
│ │ │ ├── Error.js
│ │ │ ├── Comment.js
│ │ │ ├── CommentList.js
│ │ │ ├── ShoppingCartItem.js
│ │ │ ├── ProductList.js
│ │ │ ├── Login.js
│ │ │ └── Product.js
│ │ └── css
│ │ │ └── site.css
│ │ ├── .gitignore
│ │ └── package.json
├── react-router
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── index.js
│ │ └── components
│ │ │ ├── Footer.js
│ │ │ ├── Header.js
│ │ │ ├── NoMatch.js
│ │ │ ├── ShoppingCart.js
│ │ │ ├── Product.js
│ │ │ ├── ProductList.js
│ │ │ └── App.js
│ ├── .gitignore
│ └── package.json
├── react-shopping-cart
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── images
│ │ │ ├── lonely-bird.jpg
│ │ │ └── solid-friendship.jpg
│ │ ├── index.js
│ │ ├── css
│ │ │ └── site.css
│ │ └── components
│ │ │ ├── ProductList.js
│ │ │ ├── ShoppingCartItem.js
│ │ │ ├── Product.js
│ │ │ └── ShoppingCart.js
│ ├── .gitignore
│ └── package.json
├── prerender
│ └── prerender.js
└── react-hello-world
│ └── index.html
├── Chapter07
├── serverless-store-chap7
│ ├── README.md
│ ├── frontend
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── index.html
│ │ ├── src
│ │ │ ├── index.js
│ │ │ ├── lib
│ │ │ │ ├── config.js
│ │ │ │ └── services.js
│ │ │ ├── components
│ │ │ │ ├── NoMatch.js
│ │ │ │ ├── Error.js
│ │ │ │ ├── Comment.js
│ │ │ │ ├── CommentList.js
│ │ │ │ ├── ShoppingCartItem.js
│ │ │ │ ├── ProductList.js
│ │ │ │ ├── Login.js
│ │ │ │ └── Product.js
│ │ │ └── css
│ │ │ │ └── site.css
│ │ ├── .gitignore
│ │ └── package.json
│ ├── backend
│ │ ├── package.json
│ │ ├── lib
│ │ │ ├── checkout.js
│ │ │ ├── cart.js
│ │ │ ├── products.js
│ │ │ └── utils.js
│ │ ├── serverless.yml
│ │ ├── repositories
│ │ │ └── fakedb.js
│ │ └── functions
│ │ │ └── products.js
│ └── scripts
│ │ └── package.json
├── S3
│ ├── recover-object.js
│ ├── package.json
│ ├── signed-url.js
│ └── list-object-versions.js
├── DynamoDB
│ ├── package.json
│ ├── scan.js
│ ├── query.js
│ ├── put-item.js
│ ├── create-table.js
│ └── table-with-indexes.js
└── SimpleDB
│ ├── package.json
│ ├── permissions
│ ├── handler.js
│ └── serverless.yml
│ ├── create-domain.js
│ ├── read-data.js
│ ├── insert-data.js
│ └── conditional-operation.js
├── Chapter08
├── serverless-store-chap8
│ ├── README.md
│ ├── frontend
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── index.html
│ │ ├── src
│ │ │ ├── index.js
│ │ │ ├── components
│ │ │ │ ├── NoMatch.js
│ │ │ │ ├── Error.js
│ │ │ │ ├── Comment.js
│ │ │ │ ├── CommentList.js
│ │ │ │ ├── ShoppingCartItem.js
│ │ │ │ └── ProductList.js
│ │ │ ├── lib
│ │ │ │ └── config.js
│ │ │ └── css
│ │ │ │ └── site.css
│ │ ├── .gitignore
│ │ └── package.json
│ ├── backend
│ │ ├── package.json
│ │ ├── lib
│ │ │ ├── checkout.js
│ │ │ ├── cart.js
│ │ │ ├── products.js
│ │ │ └── utils.js
│ │ ├── repositories
│ │ │ └── fakedb.js
│ │ ├── serverless.yml
│ │ └── functions
│ │ │ └── products.js
│ └── scripts
│ │ └── package.json
└── iam-policies
│ ├── unauthenticated.json
│ └── authenticated.json
├── Chapter09
└── serverless-store-chap9
│ ├── README.md
│ ├── frontend
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── index.js
│ │ ├── components
│ │ │ ├── NoMatch.js
│ │ │ ├── Error.js
│ │ │ ├── Comment.js
│ │ │ ├── ShoppingCartItem.js
│ │ │ ├── CommentList.js
│ │ │ ├── ProductList.js
│ │ │ └── CommentBox.js
│ │ ├── lib
│ │ │ ├── config.js
│ │ │ └── iot.js
│ │ └── css
│ │ │ └── site.css
│ ├── .gitignore
│ └── package.json
│ ├── backend
│ ├── package.json
│ ├── functions
│ │ ├── comments.js
│ │ └── products.js
│ ├── lib
│ │ ├── cart.js
│ │ ├── checkout.js
│ │ ├── products.js
│ │ └── utils.js
│ ├── repositories
│ │ └── fakedb.js
│ └── serverless.yml
│ └── scripts
│ └── package.json
├── Chapter02
├── list-s3-buckets
│ ├── index.js
│ └── package.json
└── lambda-function-process-log
│ ├── package.json
│ ├── s3-test-event.json
│ ├── lambda-permissions.json
│ └── index.js
├── .gitattributes
├── .gitignore
└── LICENSE
/Chapter10/Testing/backend/test/mocha.opts:
--------------------------------------------------------------------------------
1 | test/unit
2 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/repositories/dynamodb.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/repositories/simpledb.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Chapter03/hello-serverless/event.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Serverless"
3 | }
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/test/integration/test-upload file.js:
--------------------------------------------------------------------------------
1 | // empty
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/src/css/site.css:
--------------------------------------------------------------------------------
1 | .hasSaved {
2 | color: green;
3 | }
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service1/greetings.js:
--------------------------------------------------------------------------------
1 | module.exports.saySomething = () => 'hello';
2 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter03/serve-html/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter06/graphql/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 | **Backend**: serverless.yml
5 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 | **Backend**: serverless.yml
5 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 | **Backend**: serverless.yml
5 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 | **Backend**: serverless.yml
5 |
--------------------------------------------------------------------------------
/Chapter10/Deployment/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter03/hello-serverless/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter03/lambda-events/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/README.md:
--------------------------------------------------------------------------------
1 | # Configuration files
2 |
3 | **Frontend**: src/lib/config
4 | **Backend**: serverless.yml
5 |
--------------------------------------------------------------------------------
/Chapter03/serverless-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter03/test-role-statements/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter05/react-ajax/backend/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter03/using-external-modules/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/lib/db.js:
--------------------------------------------------------------------------------
1 | module.exports.saveOrder = (order, callback) => {
2 | console.log('Order saved...'); // fake
3 | callback(null);
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter05/react-router/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-router/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/lib/notifier.js:
--------------------------------------------------------------------------------
1 | module.exports.sendEmail = (email, callback) => {
2 | console.log('E-mail sent...'); // fake
3 | callback(null);
4 | }
5 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter10/Testing/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-ajax/send-data/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-shopping-cart/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-ajax/request-data/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/images/lonely-bird.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-shopping-cart/src/images/lonely-bird.jpg
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/images/lonely-bird.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-ajax/request-data/src/images/lonely-bird.jpg
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/serverless-store-chap5/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter06/serverless-store-chap6/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter07/serverless-store-chap7/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter08/serverless-store-chap8/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter09/serverless-store-chap9/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/images/solid-friendship.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-shopping-cart/src/images/solid-friendship.jpg
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter10/serverless-store-chap10/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/images/solid-friendship.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/react-ajax/request-data/src/images/solid-friendship.jpg
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/functions/greetings.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.hello = (event, context, callback) => {
4 | const message = `Hello, ${event.name}!`
5 | callback(null, message);
6 | };
7 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | }
6 | }
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/images/lonely-bird.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/serverless-store-chap5/frontend/src/images/lonely-bird.jpg
--------------------------------------------------------------------------------
/Chapter05/react-router/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 |
5 | ReactDOM.render(
6 | ,
7 | document.getElementById('root')
8 | );
9 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/images/solid-friendship.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Building-Serverless-Web-Applications/HEAD/Chapter05/serverless-store-chap5/frontend/src/images/solid-friendship.jpg
--------------------------------------------------------------------------------
/Chapter06/graphql/serverless.yml:
--------------------------------------------------------------------------------
1 | service: graphql-example
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | store:
9 | handler: handler.store
10 | events:
11 | - http: POST query
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-store",
3 | "version": "1.0.0",
4 | "description": "Backend implementation of the Serverless Store.",
5 | "author": "Diego Zanon",
6 | "license": "MIT"
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-store",
3 | "version": "1.0.0",
4 | "description": "Backend implementation of the Serverless Store.",
5 | "author": "Diego Zanon",
6 | "license": "MIT"
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-store",
3 | "version": "1.0.0",
4 | "description": "Backend implementation of the Serverless Store.",
5 | "author": "Diego Zanon",
6 | "license": "MIT"
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-store",
3 | "version": "1.0.0",
4 | "description": "Backend implementation of the Serverless Store.",
5 | "author": "Diego Zanon",
6 | "license": "MIT"
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-store",
3 | "version": "1.0.0",
4 | "description": "Backend implementation of the Serverless Store.",
5 | "author": "Diego Zanon",
6 | "license": "MIT"
7 | }
8 |
--------------------------------------------------------------------------------
/Chapter07/S3/recover-object.js:
--------------------------------------------------------------------------------
1 | const params = {
2 | Bucket: 'my-bucket-name',
3 | Key: 'file-path',
4 | VersionId: 'id'
5 | };
6 |
7 | s3.getObject(params, (err, data) => {
8 | // get contents and call putObject to replace the current version
9 | });
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service1/serverless.yml:
--------------------------------------------------------------------------------
1 | service: service1
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | hello:
9 | handler: handler.hello
10 | events:
11 | - http: GET greeting
12 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service2/serverless.yml:
--------------------------------------------------------------------------------
1 | service: service2
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | hello:
9 | handler: handler.hello
10 | events:
11 | - http: GET greeting
12 |
--------------------------------------------------------------------------------
/Chapter03/serve-html/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serve-html
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | memorySize: 128
7 |
8 | functions:
9 | hello:
10 | handler: handler.hello
11 | events:
12 | - http: GET page
13 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter07/S3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "s3",
3 | "version": "1.0.0",
4 | "description": "Examples of how to retrieve S3 signed URLs.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.85.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter02/list-s3-buckets/index.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const s3 = new AWS.S3();
3 |
4 | s3.listBuckets((err, data) => {
5 | if (err) console.log(err, err.stack); // an error occurred
6 | else console.log(data.Buckets); // successful response
7 | });
8 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dynamodb",
3 | "version": "1.0.0",
4 | "description": "Examples of how to use DynamoDB.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.85.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simpledb",
3 | "version": "1.0.0",
4 | "description": "Examples of how to use SimpleDB.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.85.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter03/serverless-plugin/serverless.yml:
--------------------------------------------------------------------------------
1 | service: hello-typescript
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | hello:
9 | handler: handler.hello
10 | memorySize: 128
11 |
12 | plugins:
13 | - serverless-plugin-typescript
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/functions/comments.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../lib/utils');
4 |
5 | module.exports.handler = (event, context, callback) => {
6 |
7 | console.log(event);
8 | utils.successHandler(event, callback);
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/functions/comments.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../lib/utils');
4 |
5 | module.exports.handler = (event, context, callback) => {
6 |
7 | console.log(event);
8 | utils.successHandler(event, callback);
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 | import './css/site.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "using-multiple-services1",
3 | "version": "1.0.0",
4 | "description": "An example of how to use multiple Serverless services.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT"
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/css/site.css:
--------------------------------------------------------------------------------
1 | .product-image {
2 | width: 250px;
3 | }
4 |
5 | .product-box {
6 | display: inline-block;
7 | margin: 10px;
8 | }
9 |
10 | .x-mark {
11 | float: right;
12 | cursor: pointer;
13 | }
14 |
15 | .btn-danger:focus {
16 | outline-color: #761c19;
17 | }
--------------------------------------------------------------------------------
/Chapter06/graphql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "graphql-example",
3 | "version": "1.0.0",
4 | "description": "An example of how to use GraphQL.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "dependencies": {
9 | "graphql": "^0.10.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: testing
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | hello:
9 | handler: functions/greetings.hello
10 | order:
11 | handler: functions/orders.saveOrder
12 |
13 | package:
14 | exclude:
15 | - test/**
--------------------------------------------------------------------------------
/Chapter03/serverless-plugin/handler.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | export async function hello(event, context, callback) {
4 |
5 | const response = {
6 | statusCode: 200,
7 | body: JSON.stringify({
8 | message: 'Hello, TypeScript!'
9 | })
10 | };
11 |
12 | callback(null, response);
13 | }
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 |
7 | ReactDOM.render( , document.getElementById('root'));
8 | registerServiceWorker();
9 |
--------------------------------------------------------------------------------
/Chapter02/list-s3-buckets/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "list-s3-buckets",
3 | "version": "1.0.0",
4 | "description": "An example of how to use the AWS SDK with S3.",
5 | "main": "index.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "dependencies": {
9 | "aws-sdk": "^2.48.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/scan.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const documentClient = new AWS.DynamoDB.DocumentClient();
3 |
4 | const params = {
5 | TableName: 'Products'
6 | };
7 |
8 | documentClient.scan(params, (err, data) => {
9 | if (err) console.log(err, err.stack);
10 | else console.log(data);
11 | });
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scripts",
3 | "version": "1.0.0",
4 | "description": "Create tables and insert the initial data.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.92.0",
9 | "uuid": "^3.1.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scripts",
3 | "version": "1.0.0",
4 | "description": "Create tables and insert the initial data.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.92.0",
9 | "uuid": "^3.1.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scripts",
3 | "version": "1.0.0",
4 | "description": "Create tables and insert the initial data.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.92.0",
9 | "uuid": "^3.1.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scripts",
3 | "version": "1.0.0",
4 | "description": "Create tables and insert the initial data.",
5 | "author": "Diego Zanon",
6 | "license": "MIT",
7 | "dependencies": {
8 | "aws-sdk": "^2.92.0",
9 | "uuid": "^3.1.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Footer extends Component {
4 | render() {
5 | return (
6 |
7 |
this is a footer
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Footer;
14 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Header extends Component {
4 | render() {
5 | return (
6 |
7 |
Serverless Store
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Header;
14 |
--------------------------------------------------------------------------------
/Chapter10/Deployment/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "warmup",
3 | "version": "1.0.0",
4 | "description": "An example of how to use the WarmUP plugin.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "devDependencies": {
9 | "serverless-plugin-warmup": "^3.0.5-rc.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/functions/orders.js:
--------------------------------------------------------------------------------
1 | const db = require('../lib/db');
2 | const notifier = require('../lib/notifier');
3 | const Order = require('../lib/order');
4 |
5 | const order = new Order(db, notifier);
6 |
7 | module.exports.saveOrder = (event, context, callback) => {
8 | order.save(event.order, event.email, callback);
9 | };
--------------------------------------------------------------------------------
/Chapter03/hello-serverless/serverless.yml:
--------------------------------------------------------------------------------
1 | service: hello-serverless
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | memorySize: 512
7 | timeout: 30
8 |
9 | functions:
10 | hello:
11 | handler: handler.hello
12 | memorySize: 128
13 | timeout: 10
14 | events:
15 | - http: GET my-service/resource
16 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/README.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | Before running the frontend examples, you need to deploy the backend (running `serverless deploy`) and replace the frontend API address (inside `src/components/app.js`) with your deployed backend address.
4 |
5 | The frontend is a Create-React-App. Run `npm install` to install and `npm start` to execute.
6 |
--------------------------------------------------------------------------------
/Chapter02/lambda-function-process-log/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lambda-function-process-log",
3 | "version": "1.0.0",
4 | "description": "A log processor to execute as a Lambda function.",
5 | "main": "index.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "dependencies": {
9 | "aws-sdk": "^2.48.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | },
6 | "services": {
7 | "PRODUCTS": "products",
8 | "CART": "cart",
9 | "CHECKOUT": "checkout"
10 | }
11 | }
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | },
6 | "services": {
7 | "PRODUCTS": "products",
8 | "CART": "cart",
9 | "CHECKOUT": "checkout"
10 | }
11 | }
--------------------------------------------------------------------------------
/Chapter03/using-external-modules/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "using-external-modules",
3 | "version": "1.0.0",
4 | "description": "An example of how to use the AWS Lambda with external modules.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "dependencies": {
9 | "cat-names": "^1.0.2"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter03/using-external-modules/serverless.yml:
--------------------------------------------------------------------------------
1 | service: cat-names
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 |
7 | functions:
8 | catNames:
9 | handler: handler.catNames
10 | memorySize: 128
11 |
12 | package:
13 | exclude:
14 | - package.json
15 | - event.json
16 | - tests/**
17 | - LICENSE
18 | - README.md
--------------------------------------------------------------------------------
/Chapter10/Deployment/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.hello = (event, context, callback) => {
4 |
5 | if (event.source === 'serverless-plugin-warmup') {
6 | console.log('WarmUP - Lambda is warm!')
7 | return callback(null, 'Lambda is warm!')
8 | }
9 |
10 | callback(null, { message: 'Hello!' });
11 | };
12 |
--------------------------------------------------------------------------------
/Chapter03/serverless-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-typescript",
3 | "version": "1.0.0",
4 | "description": "An example of how to use plugins with the Serverless Framework.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "devDependencies": {
9 | "serverless-plugin-typescript": "^0.1.10"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "testing",
3 | "version": "1.0.0",
4 | "scripts": {
5 | "test": "mocha"
6 | },
7 | "description": "An example of how to test Lambda functions.",
8 | "author": "Diego Zanon",
9 | "license": "MIT",
10 | "devDependencies": {
11 | "mocha": "^3.4.2",
12 | "sinon": "^2.3.6"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter02/lambda-function-process-log/s3-test-event.json:
--------------------------------------------------------------------------------
1 | {
2 | "Records": [
3 | {
4 | "s3": {
5 | "bucket": {
6 | "name": "my-bucket-name"
7 | },
8 | "object": {
9 | "key": "logs/log1.txt"
10 | }
11 | }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/lib/checkout.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/fakedb');
2 | const utils = require('./utils');
3 |
4 | module.exports.processCheckout = (id, callback) => {
5 | db.processCheckout(id, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service1/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const greetings = require('./greetings');
4 |
5 | module.exports.hello = (event, context, callback) => {
6 | const response = {
7 | statusCode: 200,
8 | body: JSON.stringify({
9 | message: greetings.saySomething()
10 | })
11 | };
12 |
13 | callback(null, response);
14 | };
15 |
--------------------------------------------------------------------------------
/Chapter07/S3/signed-url.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const s3 = new AWS.S3();
3 |
4 | const params = {
5 | Bucket: 'bucket',
6 | Key: 'key'
7 | };
8 |
9 | const operation = 'putObject'; // upload operation
10 | // const operation = 'getObject'; // download operation
11 |
12 | s3.getSignedUrl(operation, params, (err, url) => {
13 | // return the url
14 | });
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/lib/checkout.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.processCheckout = (id, callback) => {
5 | db.processCheckout(id, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/lib/checkout.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.processCheckout = (id, callback) => {
5 | db.processCheckout(id, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter10/Deployment/serverless.yml:
--------------------------------------------------------------------------------
1 | service: warm
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | iamRoleStatements:
7 | - Effect: 'Allow'
8 | Action:
9 | - 'lambda:InvokeFunction'
10 | Resource: "*"
11 |
12 | functions:
13 | hello:
14 | handler: handler.hello
15 | warmup: true
16 |
17 | plugins:
18 | - serverless-plugin-warmup
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/lib/cart.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/fakedb');
2 | const utils = require('./utils');
3 |
4 | module.exports.saveCart = (userId, products, callback) => {
5 | db.saveCart(userId, products, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter03/using-external-modules/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.catNames = (event, context, callback) => {
4 |
5 | const catNames = require('cat-names');
6 |
7 | const response = {
8 | statusCode: 200,
9 | body: JSON.stringify({
10 | message: catNames.random()
11 | })
12 | };
13 |
14 | callback(null, response);
15 | };
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/lib/cart.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.saveCart = (userId, products, callback) => {
5 | db.saveCart(userId, products, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/lib/cart.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.saveCart = (userId, products, callback) => {
5 | db.saveCart(userId, products, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/lib/cart.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.saveCart = (userId, products, callback) => {
5 | db.saveCart(userId, products, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/lib/cart.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.saveCart = (userId, products, callback) => {
5 | db.saveCart(userId, products, (err, res) => {
6 | if (err) utils.errorHandler(err, callback);
7 | else utils.successHandler(res, callback);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service2/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const greetings = require('using-multiple-services1/greetings');
4 |
5 | module.exports.hello = (event, context, callback) => {
6 | const response = {
7 | statusCode: 200,
8 | body: JSON.stringify({
9 | message: greetings.saySomething()
10 | })
11 | };
12 |
13 | callback(null, response);
14 | };
15 |
--------------------------------------------------------------------------------
/Chapter07/S3/list-object-versions.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const s3 = AWS.S3();
3 |
4 | const params = {
5 | Bucket: 'my-bucket-name',
6 | Prefix: 'folder-or-file-path'
7 | };
8 |
9 | s3.listObjectVersions(params, (err, data) => {
10 | if (err) console.log(err, err.stack);
11 | else console.log(data.Versions); // array containing VersionId and LastModified (Date)
12 | });
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/permissions/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const AWS = require('aws-sdk');
4 | const simpledb = new AWS.SimpleDB();
5 |
6 | module.exports.query = (event, context, callback) => {
7 |
8 | const selectParams = {
9 | SelectExpression: 'select * from Products where Name = "Lonely Bird"'
10 | };
11 |
12 | simpledb.select(selectParams, callback);
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Navbar extends Component {
4 | render() {
5 | return (
6 |
7 |
Page not found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Navbar;
14 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter05/react-router/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter06/using-multiple-services/service2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "using-multiple-services2",
3 | "version": "1.0.0",
4 | "description": "An example of how to use multiple Serverless services.",
5 | "main": "handler.js",
6 | "author": "Diego Zanon",
7 | "license": "MIT",
8 | "dependencies": {
9 | "using-multiple-services1": "file:../service1/using-multiple-services1-1.0.0.tgz"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/query.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const documentClient = new AWS.DynamoDB.DocumentClient();
3 |
4 | const params = {
5 | TableName: "Products",
6 | KeyConditionExpression: "ID = :id",
7 | ExpressionAttributeValues: { ":id": "lonely-bird" }
8 | };
9 |
10 | documentClient.query(params, function(err, data) {
11 | if (err) console.log(err);
12 | else console.log(data);
13 | });
--------------------------------------------------------------------------------
/Chapter02/lambda-function-process-log/lambda-permissions.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": ["s3:GetObject"],
7 | "Resource": "arn:aws:s3:::my-bucket-name"
8 | },
9 | {
10 | "Effect": "Allow",
11 | "Action": ["sns:Publish"],
12 | "Resource": "arn:aws:sns:us-east-1:1234567890:email-alerts"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class NoMatch extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
Page not found
9 |
10 |
11 | );
12 | }
13 | }
14 |
15 | export default NoMatch;
16 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/css/site.css:
--------------------------------------------------------------------------------
1 | .product-image {
2 | width: 250px;
3 | }
4 |
5 | .product-box {
6 | display: inline-block;
7 | margin: 10px;
8 | }
9 |
10 | .spin {
11 | font-size: 30px;
12 | margin-top: 10px;
13 | animation: spin-frames 1s infinite linear;
14 | }
15 |
16 | @keyframes spin-frames {
17 | from { transform: scale(1) rotate(0deg); }
18 | to { transform: scale(1) rotate(360deg); }
19 | }
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/Error.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Error extends Component {
4 | render() {
5 | return (
6 |
7 |
There was an error while processing your request.
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/ShoppingCart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class NoMatch extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
Shopping Cart page
9 |
10 |
11 | );
12 | }
13 | }
14 |
15 | export default NoMatch;
16 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import { mount } from 'enzyme';
5 |
6 | it('renders without crashing', () => {
7 | mount( );
8 | });
9 |
10 | it('renders with "Welcome to React"', () => {
11 | const wrapper = mount( );
12 | const welcome = Welcome to React ;
13 | expect(wrapper.contains(welcome)).toEqual(true);
14 | });
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
7 | {this.props.product.name}: US$ {this.props.product.price}
8 |
9 | );
10 | }
11 | }
12 |
13 | export default ShoppingCartItem;
14 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/Chapter03/test-role-statements/serverless.yml:
--------------------------------------------------------------------------------
1 | service: test-role-statements
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | memorySize: 128
7 | iamRoleStatements:
8 | - Effect: "Allow"
9 | Action:
10 | - 's3:PutObject'
11 | - 's3:GetObject'
12 | Resource: "arn:aws:s3:::my-bucket-name/*" # use a new bucket name
13 |
14 | functions:
15 | testPermissions:
16 | handler: handler.testPermissions
17 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ProductDetails extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
Product Details for ID: {this.props.match.params.id}
9 |
10 |
11 | );
12 | }
13 | }
14 |
15 | export default ProductDetails;
16 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-intro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes App-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-store
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | stage: dev
7 | region: us-east-1
8 | memorySize: 128
9 | timeout: 30
10 |
11 | functions:
12 | products:
13 | handler: functions/products.handler
14 | events:
15 | - http: GET products
16 | - http: POST cart
17 | - http: OPTIONS cart
18 | - http: PUT checkout
19 | - http: OPTIONS checkout
20 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^15.5.4",
7 | "react-dom": "^15.5.4"
8 | },
9 | "devDependencies": {
10 | "react-scripts": "1.0.2"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "react-scripts build",
15 | "test": "react-scripts test --env=jsdom",
16 | "eject": "react-scripts eject"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: request-data
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | memorySize: 128
7 | timeout: 30
8 |
9 | functions:
10 | products:
11 | handler: handler.products
12 | events:
13 | - http: GET store/products
14 | save:
15 | handler: handler.save
16 | events:
17 | - http: POST shopping-cart/save
18 | - http: OPTIONS shopping-cart/save # the OPTIONs verb is needed when you want to support the POST verb
19 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/create-domain.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const simpledb = new AWS.SimpleDB();
3 |
4 | const params = {
5 | DomainName: 'Products'
6 | };
7 |
8 | simpledb.createDomain(params, (err, data) => {
9 | if (err) console.log(err, err.stack);
10 | else console.log(data);
11 | });
12 |
13 | params.DomainName = 'ShoppingCart';
14 |
15 | simpledb.createDomain(params, (err, data) => {
16 | if (err) console.log(err, err.stack);
17 | else console.log(data);
18 | });
--------------------------------------------------------------------------------
/Chapter03/hello-serverless/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.hello = (event, context, callback) => {
4 | const response = {
5 | statusCode: 200,
6 | headers: {
7 | "Access-Control-Allow-Origin": "*"
8 | },
9 | body: JSON.stringify({
10 | message: `Hello, ${event.name}!`
11 | // message: `Hello, ${event.queryStringParameters.name}!` // use this piece of code when testing with the browser or API Gateway
12 | }),
13 | };
14 |
15 | callback(null, response);
16 | };
17 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/permissions/serverless.yml:
--------------------------------------------------------------------------------
1 | service: simpledb-example
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | iamRoleStatements:
7 | - Effect: "Allow"
8 | Action:
9 | - "sdb:batchPutAttributes"
10 | - "sdb:PutAttributes"
11 | - "sdb:Select"
12 | Resource: [
13 | "arn:aws:sdb:us-east-1:*:domain/Products",
14 | "arn:aws:sdb:us-east-1:*:domain/ShopingCart"
15 | ]
16 |
17 | functions:
18 | query:
19 | handler: handler.query
20 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-request-data",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.16.1",
7 | "react": "^15.5.4",
8 | "react-dom": "^15.5.4"
9 | },
10 | "devDependencies": {
11 | "react-scripts": "1.0.2"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test --env=jsdom",
17 | "eject": "react-scripts eject"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.16.1",
7 | "react": "^15.5.4",
8 | "react-dom": "^15.5.4"
9 | },
10 | "devDependencies": {
11 | "react-scripts": "1.0.2"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test --env=jsdom",
17 | "eject": "react-scripts eject"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter05/react-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^15.5.4",
7 | "react-dom": "^15.5.4",
8 | "react-router-dom": "^4.1.1"
9 | },
10 | "devDependencies": {
11 | "react-scripts": "1.0.2"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test --env=jsdom",
17 | "eject": "react-scripts eject"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/lib/order.js:
--------------------------------------------------------------------------------
1 | class Order {
2 |
3 | // Dependency Injection
4 | constructor(db, notifier) {
5 | this.db = db;
6 | this.notifier = notifier;
7 | }
8 |
9 | save(order, email, callback) {
10 | this.db.saveOrder(order, (err) => {
11 | if (err) {
12 | callback(err);
13 | } else {
14 | this.notifier.sendEmail(email, callback);
15 | }
16 | });
17 | }
18 | }
19 |
20 | module.exports = Order;
--------------------------------------------------------------------------------
/Chapter05/prerender/prerender.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const webPage = require('webpage');
3 | const page = webPage.create();
4 |
5 | const path = 'page1';
6 | const url = 'https://example.com/' + path;
7 |
8 | page.open(url, (status) => {
9 |
10 | if (status != 'success') {
11 | console.log('Error trying to prerender ' + url);
12 | phantom.exit();
13 | }
14 |
15 | const content = page.content;
16 | fs.write(path + '.html', content, 'w');
17 |
18 | console.log("The file was saved.");
19 | phantom.exit();
20 | });
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend-test",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^15.6.1",
7 | "react-dom": "^15.6.1"
8 | },
9 | "devDependencies": {
10 | "enzyme": "^2.9.1",
11 | "react-scripts": "1.0.10",
12 | "react-test-renderer": "^15.6.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test --env=jsdom",
18 | "eject": "react-scripts eject"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/read-data.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const simpledb = new AWS.SimpleDB();
3 |
4 | const selectParams = {
5 | SelectExpression: 'select * from Products where Name = "Lonely Bird"'
6 | };
7 |
8 | simpledb.select(selectParams, (err, data) => {
9 | if (err) console.log(err, err.stack);
10 | else if (data.Items) {
11 | data.Items.map(item => {
12 | item.Attributes.map(attr => {
13 | console.log(attr);
14 | });
15 | });
16 | }
17 | else console.log('No results');
18 | });
--------------------------------------------------------------------------------
/Chapter03/serve-html/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.hello = (event, context, callback) => {
4 |
5 | const html = `
6 |
7 |
8 |
9 | Page Title
10 |
11 |
12 | Hello
13 |
14 | `;
15 |
16 | const response = {
17 | statusCode: 200,
18 | headers: {
19 | 'Access-Control-Allow-Origin': '*',
20 | 'Content-Type': 'text/html'
21 | },
22 | body: html
23 | };
24 |
25 | callback(null, response);
26 | };
27 |
--------------------------------------------------------------------------------
/Chapter05/react-router/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | },
6 | "services": {
7 | "PRODUCTS": "products",
8 | "CART": "cart",
9 | "CHECKOUT": "checkout"
10 | },
11 | "cognito": {
12 | "USER_POOL_ID" : "us-east-1_aBcdeFghi",
13 | "APP_CLIENT_ID" : "abcdefghijklmnopqrstuvwxyz",
14 | "IDENTITY_POOL_ID": "us-east-1:abcdefghi-1234-5678-9012-abcdefghijkl",
15 | "REGION": "us-east-1"
16 | }
17 | }
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
Welcome to React
12 |
13 |
14 | To get started, edit src/App.js and save to reload.
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Serverless Store
9 |
10 |
11 |
12 | You need to enable JavaScript to run this app.
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const productList = this.props.products.map(product => {
7 | return (
8 |
11 | )
12 | });
13 |
14 | return (
15 |
16 | {productList}
17 |
18 | );
19 | }
20 | }
21 |
22 | export default ProductList;
23 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.16.2",
7 | "react": "^15.5.4",
8 | "react-bootstrap": "^0.31.0",
9 | "react-dom": "^15.5.4",
10 | "react-router-bootstrap": "^0.24.2",
11 | "react-router-dom": "^4.1.1"
12 | },
13 | "devDependencies": {
14 | "react-scripts": "1.0.2"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.16.2",
7 | "react": "^15.5.4",
8 | "react-bootstrap": "^0.31.0",
9 | "react-dom": "^15.5.4",
10 | "react-router-bootstrap": "^0.24.2",
11 | "react-router-dom": "^4.1.1"
12 | },
13 | "devDependencies": {
14 | "react-scripts": "1.0.2"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.16.2",
7 | "react": "^15.5.4",
8 | "react-bootstrap": "^0.31.0",
9 | "react-dom": "^15.5.4",
10 | "react-router-bootstrap": "^0.24.2",
11 | "react-router-dom": "^4.1.1"
12 | },
13 | "devDependencies": {
14 | "react-scripts": "1.0.2"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/Comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Comment extends Component {
4 | render() {
5 | return (
6 |
7 |
8 | {this.props.comment.username} commented {this.props.comment.age}
9 |
10 |
11 | {this.props.comment.text}
12 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Comment;
19 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "amazon-cognito-identity-js": "^1.19.0",
7 | "axios": "^0.16.2",
8 | "react": "^15.5.4",
9 | "react-bootstrap": "^0.31.0",
10 | "react-dom": "^15.5.4",
11 | "react-router-bootstrap": "^0.24.2",
12 | "react-router-dom": "^4.1.1"
13 | },
14 | "devDependencies": {
15 | "react-scripts": "1.0.2"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test --env=jsdom",
21 | "eject": "react-scripts eject"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 |
4 | class CommentList extends Component {
5 | render() {
6 |
7 | const comments = this.props.comments.map(comment => {
8 | return (
9 |
10 |
11 |
12 | )
13 | });
14 |
15 | return (
16 |
17 |
Customer Reviews
18 | {comments}
19 |
20 | );
21 | }
22 | }
23 |
24 | export default CommentList;
25 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 |
4 | class CommentList extends Component {
5 | render() {
6 |
7 | const comments = this.props.comments.map(comment => {
8 | return (
9 |
10 |
11 |
12 | )
13 | });
14 |
15 | return (
16 |
17 |
Customer Reviews
18 | {comments}
19 |
20 | );
21 | }
22 | }
23 |
24 | export default CommentList;
25 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 |
4 | class CommentList extends Component {
5 | render() {
6 |
7 | const comments = this.props.comments.map(comment => {
8 | return (
9 |
10 |
11 |
12 | )
13 | });
14 |
15 | return (
16 |
17 |
Customer Reviews
18 | {comments}
19 |
20 | );
21 | }
22 | }
23 |
24 | export default CommentList;
25 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 |
4 | class CommentList extends Component {
5 | render() {
6 |
7 | const comments = this.props.comments.map(comment => {
8 | return (
9 |
10 |
11 |
12 | )
13 | });
14 |
15 | return (
16 |
17 |
Customer Reviews
18 | {comments}
19 |
20 | );
21 | }
22 | }
23 |
24 | export default CommentList;
25 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import lonelyBird from '../images/lonely-bird.jpg';
3 | import solidFriendship from '../images/solid-friendship.jpg';
4 |
5 | class Product extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
{this.props.product.name}
12 |
US$ {this.props.product.price}
13 |
14 |
15 | );
16 | }
17 | }
18 |
19 | export default Product;
20 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const productList = this.props.products.map(product => {
8 | return (
9 |
13 | )
14 | });
15 |
16 | return (
17 |
18 | {productList}
19 |
20 | );
21 | }
22 | }
23 |
24 | export default ProductList;
25 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 | Product 1
12 |
13 |
14 |
15 |
16 | Product 2
17 |
18 |
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | export default ProductList;
26 |
--------------------------------------------------------------------------------
/Chapter05/react-hello-world/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello, World!
5 |
6 |
7 |
8 |
9 |
10 |
11 |
26 |
27 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "amazon-cognito-identity-js": "^1.19.0",
7 | "aws-iot-device-sdk": "^2.0.0",
8 | "aws-sdk": "^2.77.0",
9 | "axios": "^0.16.2",
10 | "react": "^15.5.4",
11 | "react-bootstrap": "^0.31.0",
12 | "react-dom": "^15.5.4",
13 | "react-router-bootstrap": "^0.24.2",
14 | "react-router-dom": "^4.1.1",
15 | "uuid": "^3.1.0"
16 | },
17 | "devDependencies": {
18 | "react-scripts": "1.0.2"
19 | },
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "build": "react-scripts build",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-shopping-cart",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "amazon-cognito-identity-js": "^1.19.0",
7 | "aws-iot-device-sdk": "^2.0.0",
8 | "aws-sdk": "^2.77.0",
9 | "axios": "^0.16.2",
10 | "react": "^15.5.4",
11 | "react-bootstrap": "^0.31.0",
12 | "react-dom": "^15.5.4",
13 | "react-router-bootstrap": "^0.24.2",
14 | "react-router-dom": "^4.1.1",
15 | "uuid": "^3.1.0"
16 | },
17 | "devDependencies": {
18 | "react-scripts": "1.0.2"
19 | },
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "build": "react-scripts build",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/ShoppingCartItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ShoppingCartItem extends Component {
4 | render() {
5 | return (
6 |
17 | );
18 | }
19 | }
20 |
21 | export default ShoppingCartItem;
22 |
--------------------------------------------------------------------------------
/Chapter03/test-role-statements/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.testPermissions = (event, context, callback) => {
4 |
5 | const AWS = require('aws-sdk');
6 | const s3 = new AWS.S3();
7 | const bucket = 'my-bucket-name';
8 | const key = 'my-file-name';
9 | const write = {
10 | Bucket: bucket,
11 | Key: key,
12 | Body: 'Test'
13 | };
14 |
15 | s3.putObject(write, (err, data) => {
16 | if (err) return callback(err);
17 |
18 | const read = {
19 | Bucket: bucket,
20 | Key: key
21 | };
22 |
23 | s3.getObject(read, (err, data) => {
24 | if (err) return callback(err);
25 |
26 | const response = {
27 | statusCode: 200,
28 | body: data.Body.toString()
29 | };
30 |
31 | callback(null, response);
32 | });
33 | });
34 | };
35 |
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/insert-data.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const simpledb = new AWS.SimpleDB();
3 |
4 | const insertParams = {
5 | DomainName: 'Products',
6 | Items: [
7 | {
8 | Attributes: [
9 | {
10 | Name: 'Name',
11 | Value: 'Lonely Bird'
12 | },
13 | {
14 | Name: 'Price',
15 | Value: '2999'
16 | },
17 | // more attributes
18 | ],
19 | // needs to be unique
20 | Name: 'lonely-bird'
21 | },
22 | // more items
23 | ]
24 | };
25 |
26 | simpledb.batchPutAttributes(insertParams, (err, data) => {
27 | if (err) console.log(err, err.stack);
28 | else console.log(data);
29 | });
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/lib/checkout.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const db = require('../repositories/dynamodb');
3 | const utils = require('./utils');
4 |
5 | module.exports.processCheckout = (id, callback) => {
6 | db.processCheckout(id, (err, res) => {
7 | if (err) utils.errorHandler(err, callback);
8 | else {
9 | const iotdata = new AWS.IotData({endpoint: process.env.IOT_ENDPOINT});
10 | const params = {
11 | topic: 'serverless-store-' + id,
12 | payload: 'Your payment was confirmed.'
13 | };
14 |
15 | iotdata.publish(params, (err, res) => {
16 | if (err) utils.errorHandler(err, callback);
17 | else utils.successHandler(res, callback);
18 | });
19 | }
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/lib/checkout.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const db = require('../repositories/dynamodb');
3 | const utils = require('./utils');
4 |
5 | module.exports.processCheckout = (id, callback) => {
6 | db.processCheckout(id, (err, res) => {
7 | if (err) utils.errorHandler(err, callback);
8 | else {
9 | const iotdata = new AWS.IotData({endpoint: process.env.IOT_ENDPOINT});
10 | const params = {
11 | topic: 'serverless-store-' + id,
12 | payload: 'Your payment was confirmed.'
13 | };
14 |
15 | iotdata.publish(params, (err, res) => {
16 | if (err) utils.errorHandler(err, callback);
17 | else utils.successHandler(res, callback);
18 | });
19 | }
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/Chapter02/lambda-function-process-log/index.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const s3 = new AWS.S3();
3 | const sns = new AWS.SNS();
4 |
5 | exports.handler = (event, context, callback) => {
6 | const bucketName = event.Records[0].s3.bucket.name;
7 | const objectKey = event.Records[0].s3.object.key;
8 | const s3Params = { Bucket: bucketName, Key: objectKey };
9 |
10 | s3.getObject(s3Params, (err, data) => {
11 | if (err) throw err;
12 |
13 | // check if file have errors to report
14 | const fileContent = data.Body.toString();
15 | if (fileContent.indexOf('error') !== -1) {
16 | const msg = `file ${objectKey} has errors`;
17 | const snsParams = { Message: msg, TopicArn: 'my-topic-arn' };
18 | sns.publish(snsParams, callback);
19 | }
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | },
6 | "services": {
7 | "PRODUCTS": "products",
8 | "CART": "cart",
9 | "CHECKOUT": "checkout"
10 | },
11 | "cognito": {
12 | "USER_POOL_ID" : "us-east-1_aBcdeFghi",
13 | "APP_CLIENT_ID" : "abcdefghijklmnopqrstuvwxyz",
14 | "IDENTITY_POOL_ID": "us-east-1:abcdefghi-1234-5678-9012-abcdefghijkl",
15 | "REGION": "us-east-1"
16 | },
17 | "iot": {
18 | "ENDPOINT": "abcdefghijklm.iot.us-east-1.amazonaws.com",
19 | "REGION": "us-east-1",
20 | "topics": {
21 | "COMMENTS": "serverless-store-comments"
22 | },
23 | "POLICY_NAME": "iot-policy"
24 | }
25 | }
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/lib/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "apiGateway": {
3 | "ADDRESS": "https://abc123.execute-api.us-east-1.amazonaws.com",
4 | "STAGE": "dev"
5 | },
6 | "services": {
7 | "PRODUCTS": "products",
8 | "CART": "cart",
9 | "CHECKOUT": "checkout"
10 | },
11 | "cognito": {
12 | "USER_POOL_ID" : "us-east-1_aBcdeFghi",
13 | "APP_CLIENT_ID" : "abcdefghijklmnopqrstuvwxyz",
14 | "IDENTITY_POOL_ID": "us-east-1:abcdefghi-1234-5678-9012-abcdefghijkl",
15 | "REGION": "us-east-1"
16 | },
17 | "iot": {
18 | "ENDPOINT": "abcdefghijklm.iot.us-east-1.amazonaws.com",
19 | "REGION": "us-east-1",
20 | "topics": {
21 | "COMMENTS": "serverless-store-comments"
22 | },
23 | "POLICY_NAME": "iot-policy"
24 | }
25 | }
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const productList = this.props.products.map(product => {
8 | return (
9 |
15 | )
16 | });
17 |
18 | return (
19 |
20 |
List of Products
21 | {productList}
22 |
23 | );
24 | }
25 | }
26 |
27 | export default ProductList;
28 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const productList = this.props.products.map(product => {
8 | return (
9 |
15 | )
16 | });
17 |
18 | return (
19 |
20 |
List of Products
21 | {productList}
22 |
23 | );
24 | }
25 | }
26 |
27 | export default ProductList;
28 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const productList = this.props.products.map(product => {
8 | return (
9 |
15 | )
16 | });
17 |
18 | return (
19 |
20 |
List of Products
21 | {productList}
22 |
23 | );
24 | }
25 | }
26 |
27 | export default ProductList;
28 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const productList = this.props.products.map(product => {
8 | return (
9 |
15 | )
16 | });
17 |
18 | return (
19 |
20 |
List of Products
21 | {productList}
22 |
23 | );
24 | }
25 | }
26 |
27 | export default ProductList;
28 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 | import CommentBox from './CommentBox';
4 |
5 | class CommentList extends Component {
6 | render() {
7 |
8 | const comments = this.props.comments.map(comment => {
9 | return (
10 |
11 |
12 |
13 | )
14 | });
15 |
16 | return (
17 |
18 |
Customer Reviews
19 | {comments}
20 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default CommentList;
28 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/CommentList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Comment from './Comment';
3 | import CommentBox from './CommentBox';
4 |
5 | class CommentList extends Component {
6 | render() {
7 |
8 | const comments = this.props.comments.map(comment => {
9 | return (
10 |
11 |
12 |
13 | )
14 | });
15 |
16 | return (
17 |
18 |
Customer Reviews
19 | {comments}
20 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default CommentList;
28 |
--------------------------------------------------------------------------------
/Chapter03/lambda-events/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-events
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | memorySize: 128
7 | iamRoleStatements:
8 | - Effect: "Allow"
9 | Action:
10 | - 's3:GetObject'
11 | Resource: "arn:aws:s3:::my-bucket-name/*" # use a new bucket name
12 | - Effect: "Allow"
13 | Action:
14 | - 'sns:Publish'
15 | Resource: "arn:aws:sns:us-east-1:1234567890:email-alerts" # use you account number and SNS topic
16 |
17 | functions:
18 | processLog:
19 | handler: handler.processLog
20 | events:
21 | - s3:
22 | bucket: my-bucket-name # use a new bucket name
23 | event: s3:ObjectCreated:*
24 | rules:
25 | - prefix: logs/
26 | - suffix: .txt
27 | processTask:
28 | handler: handler.processTask
29 | events:
30 | - schedule: rate(15 minutes)
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/lib/products.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/fakedb');
2 | const utils = require('./utils');
3 |
4 | module.exports.retrieveAll = (userId, callback) => {
5 | db.retrieveAllProducts((err, products) => {
6 | if (err) return utils.errorHandler(err, callback);
7 |
8 | db.retrieveCart(userId, (err, selectedProducts) => {
9 | if (err) utils.errorHandler(err, callback);
10 | else {
11 |
12 | if (selectedProducts) {
13 | selectedProducts.forEach(selectedProduct => {
14 | const index = products.map(i => i.id).indexOf(selectedProduct.id);
15 | products[index].isSelected = true;
16 | });
17 | }
18 |
19 | utils.successHandler(products, callback);
20 | }
21 | });
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/lib/products.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.retrieveAll = (userId, callback) => {
5 | db.retrieveAllProducts((err, products) => {
6 | if (err) return utils.errorHandler(err, callback);
7 |
8 | db.retrieveCart(userId, (err, selectedProducts) => {
9 | if (err) utils.errorHandler(err, callback);
10 | else {
11 |
12 | if (selectedProducts) {
13 | selectedProducts.forEach(selectedProduct => {
14 | const index = products.map(i => i.id).indexOf(selectedProduct.id);
15 | products[index].isSelected = true;
16 | });
17 | }
18 |
19 | utils.successHandler(products, callback);
20 | }
21 | });
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/lib/products.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.retrieveAll = (userId, callback) => {
5 | db.retrieveAllProducts((err, products) => {
6 | if (err) return utils.errorHandler(err, callback);
7 |
8 | db.retrieveCart(userId, (err, selectedProducts) => {
9 | if (err) utils.errorHandler(err, callback);
10 | else {
11 |
12 | if (selectedProducts) {
13 | selectedProducts.forEach(selectedProduct => {
14 | const index = products.map(i => i.id).indexOf(selectedProduct.id);
15 | products[index].isSelected = true;
16 | });
17 | }
18 |
19 | utils.successHandler(products, callback);
20 | }
21 | });
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/lib/products.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.retrieveAll = (userId, callback) => {
5 | db.retrieveAllProducts((err, products) => {
6 | if (err) return utils.errorHandler(err, callback);
7 |
8 | db.retrieveCart(userId, (err, selectedProducts) => {
9 | if (err) utils.errorHandler(err, callback);
10 | else {
11 |
12 | if (selectedProducts) {
13 | selectedProducts.forEach(selectedProduct => {
14 | const index = products.map(i => i.id).indexOf(selectedProduct.id);
15 | products[index].isSelected = true;
16 | });
17 | }
18 |
19 | utils.successHandler(products, callback);
20 | }
21 | });
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/lib/products.js:
--------------------------------------------------------------------------------
1 | const db = require('../repositories/dynamodb');
2 | const utils = require('./utils');
3 |
4 | module.exports.retrieveAll = (userId, callback) => {
5 | db.retrieveAllProducts((err, products) => {
6 | if (err) return utils.errorHandler(err, callback);
7 |
8 | db.retrieveCart(userId, (err, selectedProducts) => {
9 | if (err) utils.errorHandler(err, callback);
10 | else {
11 |
12 | if (selectedProducts) {
13 | selectedProducts.forEach(selectedProduct => {
14 | const index = products.map(i => i.id).indexOf(selectedProduct.id);
15 | products[index].isSelected = true;
16 | });
17 | }
18 |
19 | utils.successHandler(products, callback);
20 | }
21 | });
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const onComment = this.props.onComment;
8 | const productList = this.props.products.map(product => {
9 | return (
10 |
17 | )
18 | });
19 |
20 | return (
21 |
22 |
List of Products
23 | {productList}
24 |
25 | );
26 | }
27 | }
28 |
29 | export default ProductList;
30 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/ProductList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Product from './Product';
3 |
4 | class ProductList extends Component {
5 | render() {
6 | const onSelect = this.props.onSelect;
7 | const onComment = this.props.onComment;
8 | const productList = this.props.products.map(product => {
9 | return (
10 |
17 | )
18 | });
19 |
20 | return (
21 |
22 |
List of Products
23 | {productList}
24 |
25 | );
26 | }
27 | }
28 |
29 | export default ProductList;
30 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/put-item.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const documentClient = new AWS.DynamoDB.DocumentClient();
3 |
4 | const params = {
5 | TableName: "Products",
6 | Item: {
7 | ID: "lonely-bird",
8 | Name: "Lonely Bird",
9 | Price: 29.99,
10 | Image: "https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg",
11 | Comments: [
12 | {
13 | ID: "ABC",
14 | Username: "John Doe",
15 | Date: "2016-12-24T17:15:10+00:00",
16 | Text: "I liked it."
17 | },
18 | {
19 | ID: "XYZ",
20 | Username: "Jane Smith",
21 | Date: "2016-12-24T18:15:10+00:00",
22 | Text: "I liked it too."
23 | }
24 | ]
25 | }
26 | };
27 |
28 | documentClient.put(params, (err, data) => {
29 | if (err) console.log(err, err.stack);
30 | else console.log(data);
31 | });
32 |
--------------------------------------------------------------------------------
/Chapter05/react-router/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | BrowserRouter as Router,
4 | Route,
5 | Switch
6 | } from 'react-router-dom';
7 | import Header from './Header';
8 | import Footer from './Footer';
9 | import Product from './Product';
10 | import ProductList from './ProductList';
11 | import ShoppingCart from './ShoppingCart';
12 | import NoMatch from './NoMatch';
13 |
14 | class App extends Component {
15 |
16 | render() {
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 | }
33 |
34 | export default App;
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-store
2 |
3 | provider:
4 | name: aws
5 | runtime: nodejs6.10
6 | stage: dev
7 | region: us-east-1
8 | memorySize: 128
9 | timeout: 30
10 | iamRoleStatements:
11 | - Effect: "Allow"
12 | Action:
13 | - "sdb:BatchPutAttributes"
14 | - "sdb:PutAttributes"
15 | - "sdb:Select"
16 | Resource: [
17 | "arn:aws:sdb:us-east-1:*:domain/Products",
18 | "arn:aws:sdb:us-east-1:*:domain/ShoppingCart"
19 | ]
20 | - Effect: "Allow"
21 | Action:
22 | - "dynamodb:Scan"
23 | - "dynamodb:Query"
24 | - "dynamodb:PutItem"
25 | - "dynamodb:DeleteItem"
26 | - "dynamodb:BatchWriteItem"
27 | Resource: [
28 | "arn:aws:dynamodb:us-east-1:*:table/Products",
29 | "arn:aws:dynamodb:us-east-1:*:table/ShoppingCart"
30 | ]
31 |
32 | functions:
33 | products:
34 | handler: functions/products.handler
35 | events:
36 | - http: GET products
37 | - http: POST cart
38 | - http: OPTIONS cart
39 | - http: PUT checkout
40 | - http: OPTIONS checkout
41 |
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Product extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
{this.props.product.name}
10 |
US$ {this.props.product.price}
11 |
12 | {
14 | const product = this.props.product;
15 | product.isSelected = !product.isSelected;
16 | this.props.onSelect(product);
17 | }}>
18 | {this.props.product.isSelected ? 'Remove' : 'Add to cart'}
19 |
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default Product;
28 |
--------------------------------------------------------------------------------
/Chapter08/iam-policies/unauthenticated.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": [
7 | "mobileanalytics:PutEvents",
8 | "cognito-sync:*",
9 | "cognito-identity:*"
10 | ],
11 | "Resource": [
12 | "*"
13 | ]
14 | },
15 | {
16 | "Effect": "Allow",
17 | "Action": [
18 | "iot:Connect"
19 | ],
20 | "Resource": [
21 | "*"
22 | ]
23 | },
24 | {
25 | "Effect": "Allow",
26 | "Action": [
27 | "iot:Publish",
28 | "iot:Receive"
29 | ],
30 | "Resource": [
31 | "arn:aws:iot:::topic/serverless-store-comments"
32 | ]
33 | },
34 | {
35 | "Effect": "Allow",
36 | "Action": [
37 | "iot:Subscribe"
38 | ],
39 | "Resource": [
40 | "arn:aws:iot:::topicfilter/serverless-store-comments"
41 | ]
42 | }
43 | ]
44 | }
--------------------------------------------------------------------------------
/Chapter05/react-shopping-cart/src/components/ShoppingCart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ShoppingCartItem from './ShoppingCartItem';
3 |
4 | class ShoppingCart extends Component {
5 | getTotal() {
6 | return this.props
7 | .selectedProducts
8 | .map(p => p.price)
9 | .reduce((a, b) => a + b, 0);
10 | }
11 |
12 | render() {
13 | const onDeselect = this.props.onDeselect;
14 | const products = this.props.selectedProducts.map(product => {
15 | return (
16 |
20 | )
21 | });
22 |
23 | const empty = Shopping Cart is empty
;
24 |
25 | return (
26 |
27 |
28 | {products.length > 0 ? products : empty}
29 |
Total: US$ {this.getTotal()}
30 |
31 |
32 | );
33 | }
34 | }
35 |
36 | export default ShoppingCart;
37 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/lib/services.js:
--------------------------------------------------------------------------------
1 | // import axios from 'axios'; // not used here for simplicity
2 | import lonelyBird from '../images/lonely-bird.jpg';
3 | import solidFriendship from '../images/solid-friendship.jpg';
4 |
5 | const comments = [{
6 | id: 1,
7 | username: "John Doe",
8 | age: "3 days ago",
9 | text: "I'm using this to decorate my desk. I liked it."
10 | }, {
11 | id: 2,
12 | username: "Jane Smith",
13 | age: "7 days ago",
14 | text: "This product was very well made."
15 | }];
16 |
17 | const products = [{
18 | id: "lonely-bird",
19 | name: "Lonely Bird",
20 | image: lonelyBird,
21 | price: 29.99,
22 | isSelected: false,
23 | comments: comments
24 | }, {
25 | id: "solid-friendship",
26 | name: "Solid Friendship",
27 | image: solidFriendship,
28 | price: 19.99,
29 | isSelected: false,
30 | comments: comments
31 | }];
32 |
33 | class Services {
34 |
35 | static getProducts(callback) {
36 | const res = {
37 | data: {
38 | products: products
39 | }
40 | }
41 |
42 | setTimeout(() => { callback(null, res); }, 500); // simulate an async request
43 | }
44 | }
45 |
46 | export default Services;
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/test/unit/test-greetings.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const greetings = require('../../functions/greetings');
3 |
4 | // list the unit tests of the greetings function
5 | describe('Greetings', () => {
6 |
7 | // this is the only test that we have for this file
8 | describe('#hello()', () => {
9 |
10 | // the `done` argument must be used only for
11 | // async tests, like this one
12 | it('should return hello + name', (done) => {
13 |
14 | // set the event variable as expected by the function
15 | const event = {
16 | name: 'John'
17 | };
18 |
19 | // context can be null in this test
20 | const context = null;
21 |
22 | // invoke the function locally
23 | greetings.hello(event, context, (err, response) => {
24 |
25 | const expected = 'Hello, John!';
26 | const actual = response;
27 |
28 | // testing if the result is the expected
29 | assert.equal(expected, actual);
30 |
31 | // exiting successfully if `err` variable is null
32 | done(err);
33 | });
34 | });
35 | });
36 | });
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/components/CommentBox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class CommentBox extends Component {
4 |
5 | constructor() {
6 | super();
7 |
8 | this.state = {
9 | input: ''
10 | }
11 |
12 | this.handleChange = this.handleChange.bind(this);
13 | this.handleClick = this.handleClick.bind(this);
14 | }
15 |
16 | handleChange(e) {
17 | this.setState({input: e.target.value});
18 | }
19 |
20 | handleClick() {
21 | this.props.onComment(this.state.input, this.props.productId);
22 | this.setState({input: ''});
23 | }
24 |
25 | render() {
26 | return (
27 |
28 |
31 |
33 | Send
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export default CommentBox;
41 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/components/CommentBox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class CommentBox extends Component {
4 |
5 | constructor() {
6 | super();
7 |
8 | this.state = {
9 | input: ''
10 | }
11 |
12 | this.handleChange = this.handleChange.bind(this);
13 | this.handleClick = this.handleClick.bind(this);
14 | }
15 |
16 | handleChange(e) {
17 | this.setState({input: e.target.value});
18 | }
19 |
20 | handleClick() {
21 | this.props.onComment(this.state.input, this.props.productId);
22 | this.setState({input: ''});
23 | }
24 |
25 | render() {
26 | return (
27 |
28 |
31 |
33 | Send
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export default CommentBox;
41 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/create-table.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const dynamodb = new AWS.DynamoDB();
3 |
4 | let params = {
5 | TableName: 'Products',
6 | AttributeDefinitions: [
7 | {
8 | AttributeName: 'ID',
9 | AttributeType: 'S'
10 | }
11 | ],
12 | KeySchema: [
13 | {
14 | AttributeName: 'ID',
15 | KeyType: 'HASH'
16 | }
17 | ],
18 | ProvisionedThroughput: {
19 | ReadCapacityUnits: 5,
20 | WriteCapacityUnits: 5
21 | }
22 | };
23 |
24 | dynamodb.createTable(params, function(err, data) {
25 | if (err) console.log(err, err.stack);
26 | else console.log(data);
27 | });
28 |
29 | params = {
30 | TableName: 'ShoppingCart',
31 | AttributeDefinitions: [
32 | {
33 | AttributeName: 'UserID',
34 | AttributeType: 'S'
35 | }
36 | ],
37 | KeySchema: [
38 | {
39 | AttributeName: 'UserID',
40 | KeyType: 'HASH'
41 | }
42 | ],
43 | ProvisionedThroughput: {
44 | ReadCapacityUnits: 5,
45 | WriteCapacityUnits: 5
46 | }
47 | };
48 |
49 | dynamodb.createTable(params, (err, data) => {
50 | if (err) console.log(err, err.stack);
51 | else console.log(data);
52 | });
--------------------------------------------------------------------------------
/Chapter07/SimpleDB/conditional-operation.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const simpledb = new AWS.SimpleDB();
3 |
4 | // Insert some data first
5 | const insertParams = {
6 | DomainName: 'Products',
7 | Items: [
8 | {
9 | Attributes: [
10 | {
11 | Name: 'Counter',
12 | Value: '9'
13 | }
14 | ],
15 | Name: '123'
16 | }
17 | ]
18 | };
19 |
20 | simpledb.batchPutAttributes(insertParams, (err, data) => {
21 | if (err) console.log(err, err.stack);
22 | else {
23 | const params = {
24 | Attributes: [
25 | {
26 | Name: 'Counter',
27 | Value: '10', // new value
28 | Replace: true
29 | }
30 | ],
31 | DomainName: 'Products',
32 | ItemName: '123', // identifier
33 | Expected: {
34 | Exists: true,
35 | Name: 'Counter',
36 | Value: '9' // previous value
37 | }
38 | };
39 |
40 | simpledb.putAttributes(params, (err, data) => {
41 | if (err) console.log(err, err.stack);
42 | else console.log(data);
43 | });
44 | }
45 | });
46 |
--------------------------------------------------------------------------------
/Chapter03/lambda-events/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const AWS = require('aws-sdk');
4 | const s3 = new AWS.S3();
5 | const sns = new AWS.SNS();
6 |
7 | module.exports.processLog = (event, context, callback) => {
8 |
9 | const bucketName = event.Records[0].s3.bucket.name;
10 | const objectKey = event.Records[0].s3.object.key;
11 | const s3Params = {
12 | Bucket: bucketName,
13 | Key: objectKey
14 | };
15 |
16 | s3.getObject(s3Params, (err, data) => {
17 | if (err) throw err;
18 |
19 | // check if file have errors to report
20 | const fileContent = data.Body.toString();
21 | if (fileContent.indexOf('error') !== -1) {
22 | const msg = `file ${objectKey} has errors`;
23 | const snsParams = {
24 | Message: msg,
25 | TopicArn: 'arn:aws:sns:us-east-1:1234567890:email-alerts' // use you account number and SNS topic
26 | };
27 |
28 | sns.publish(snsParams, callback);
29 | }
30 | });
31 | };
32 |
33 | module.exports.processTask = (event, context, callback) => {
34 |
35 | const time = new Date().toUTCString();
36 | const msg = `Lambda triggered on ${time}`;
37 | const snsParams = {
38 | Message: msg,
39 | TopicArn: 'arn:aws:sns:us-east-1:1234567890:email-alerts' // use you account number and SNS topic
40 | };
41 |
42 | sns.publish(snsParams, callback);
43 | };
44 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/lib/services.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import config from './config';
3 |
4 | class Services {
5 |
6 | static getProducts(callback) {
7 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.PRODUCTS}`;
8 | axiosRequest('get', url, null, callback);
9 | }
10 |
11 | static saveCart(selectedProducts, callback) {
12 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.CART}`;
13 | axiosRequest('post', url, { "products": selectedProducts }, callback);
14 | }
15 |
16 | static processCheckout(callback) {
17 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.CHECKOUT}`;
18 | axiosRequest('put', url, { "id": 1 }, callback);
19 | }
20 | }
21 |
22 | const axiosRequest = (method, url, data, callback) => {
23 |
24 | const config = {
25 | method: method,
26 | url: url
27 | };
28 |
29 | if (data) {
30 | config.data = data;
31 | config.headers = { "Content-Type": "application/json" };
32 | }
33 |
34 | axios(config)
35 | .then(res => {
36 | callback(null, res);
37 | })
38 | .catch(error => {
39 | callback(error);
40 | });
41 | }
42 |
43 |
44 | export default Services;
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/lib/services.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import config from './config';
3 |
4 | class Services {
5 |
6 | static getProducts(callback) {
7 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.PRODUCTS}`;
8 | axiosRequest('get', url, null, callback);
9 | }
10 |
11 | static saveCart(selectedProducts, callback) {
12 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.CART}`;
13 | axiosRequest('post', url, { "products": selectedProducts }, callback);
14 | }
15 |
16 | static processCheckout(callback) {
17 | const url = `${config.apiGateway.ADDRESS}/${config.apiGateway.STAGE}/${config.services.CHECKOUT}`;
18 | axiosRequest('put', url, { "id": 1 }, callback);
19 | }
20 | }
21 |
22 | const axiosRequest = (method, url, data, callback) => {
23 |
24 | const config = {
25 | method: method,
26 | url: url
27 | };
28 |
29 | if (data) {
30 | config.data = data;
31 | config.headers = { "Content-Type": "application/json" };
32 | }
33 |
34 | axios(config)
35 | .then(res => {
36 | callback(null, res);
37 | })
38 | .catch(error => {
39 | callback(error);
40 | });
41 | }
42 |
43 |
44 | export default Services;
--------------------------------------------------------------------------------
/Chapter05/react-ajax/backend/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports.products = (event, context, callback) => {
4 | const response = {
5 | statusCode: 200,
6 | headers: {
7 | 'Access-Control-Allow-Origin': '*'
8 | },
9 | body: JSON.stringify({
10 | products: [
11 | {
12 | id: 1,
13 | name: 'Lonely Bird',
14 | price: 29.99,
15 | isSelected: false
16 | },
17 | {
18 | id: 2,
19 | name: 'Solid Friendship',
20 | price: 19.99,
21 | isSelected: false
22 | }
23 | ]
24 | }),
25 | };
26 |
27 | callback(null, response);
28 | };
29 |
30 | module.exports.save = (event, context, callback) => {
31 |
32 | let response = {};
33 |
34 | if (event.httpMethod === 'POST') {
35 | response = {
36 | statusCode: 200,
37 | headers: {
38 | 'Access-Control-Allow-Origin': '*'
39 | },
40 | body: JSON.stringify({ saved: true })
41 | }
42 | } else if (event.httpMethod === 'OPTIONS') {
43 | response = {
44 | statusCode: 200,
45 | headers: {
46 | 'Access-Control-Allow-Origin': '*',
47 | 'Access-Control-Allow-Headers': 'origin, content-type, accept',
48 | 'Access-Control-Allow-Methods': 'POST, PUT, OPTIONS'
49 | }
50 | }
51 | }
52 |
53 | callback(null, response);
54 | };
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/lib/utils.js:
--------------------------------------------------------------------------------
1 | const corsHeaders = {
2 | 'Access-Control-Allow-Origin': '*'
3 | };
4 |
5 | // Success
6 | module.exports.successHandler = (obj, callback) => {
7 | callback(null, {
8 | statusCode: 200,
9 | headers: corsHeaders,
10 | body: JSON.stringify(obj)
11 | });
12 | };
13 |
14 | // Internal Server Error
15 | module.exports.errorHandler = (err, callback) => {
16 | callback(null, {
17 | statusCode: 500,
18 | headers: corsHeaders,
19 | body: JSON.stringify({
20 | message: 'Internal Server Error',
21 | error: err.toString()
22 | })
23 | });
24 | };
25 |
26 | // Not Found
27 | module.exports.notFoundHandler = (callback) => {
28 | callback(null, {
29 | statusCode: 404,
30 | headers: corsHeaders,
31 | body: JSON.stringify({
32 | message: 'Not Found'
33 | })
34 | });
35 | };
36 |
37 | // OPTIONS
38 | module.exports.optionsHandler = (callback) => {
39 | callback(null, {
40 | statusCode: 200,
41 | headers: {
42 | "Access-Control-Allow-Origin": "*",
43 | "Access-Control-Allow-Methods":
44 | "GET, POST, PUT, PATCH, DELETE, OPTIONS",
45 | "Access-Control-Allow-Headers":
46 | "Accept, Content-Type, Origin"
47 | }
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/lib/utils.js:
--------------------------------------------------------------------------------
1 | const corsHeaders = {
2 | 'Access-Control-Allow-Origin': '*'
3 | };
4 |
5 | // Success
6 | module.exports.successHandler = (obj, callback) => {
7 | callback(null, {
8 | statusCode: 200,
9 | headers: corsHeaders,
10 | body: JSON.stringify(obj)
11 | });
12 | };
13 |
14 | // Internal Server Error
15 | module.exports.errorHandler = (err, callback) => {
16 | callback(null, {
17 | statusCode: 500,
18 | headers: corsHeaders,
19 | body: JSON.stringify({
20 | message: 'Internal Server Error',
21 | error: err.toString()
22 | })
23 | });
24 | };
25 |
26 | // Not Found
27 | module.exports.notFoundHandler = (callback) => {
28 | callback(null, {
29 | statusCode: 404,
30 | headers: corsHeaders,
31 | body: JSON.stringify({
32 | message: 'Not Found'
33 | })
34 | });
35 | };
36 |
37 | // OPTIONS
38 | module.exports.optionsHandler = (callback) => {
39 | callback(null, {
40 | statusCode: 200,
41 | headers: {
42 | "Access-Control-Allow-Origin": "*",
43 | "Access-Control-Allow-Methods":
44 | "GET, POST, PUT, PATCH, DELETE, OPTIONS",
45 | "Access-Control-Allow-Headers":
46 | "Accept, Content-Type, Origin"
47 | }
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | /* products */
35 |
36 | .product-display {
37 | display: inline-block;
38 | }
39 |
40 | .product-box {
41 | margin: 10px;
42 | }
43 |
44 | .product-image {
45 | width: 250px;
46 | }
47 |
48 | /* comments */
49 |
50 | .comment-list-title {
51 | margin-bottom: 20px;
52 | }
53 |
54 | /* shopping cart */
55 |
56 | .shopping-button {
57 | margin-right: 10px;
58 | margin-top: 10px;
59 | }
60 |
61 | .x-mark {
62 | float: right;
63 | cursor: pointer;
64 | }
65 |
66 | /* login */
67 |
68 | .login {
69 | max-width: 480px;
70 | margin: 0 auto;
71 | }
72 |
73 | .login button {
74 | width: 100px;
75 | }
76 |
77 | /* signup */
78 |
79 | .signup {
80 | max-width: 480px;
81 | margin: 0 auto;
82 | }
83 |
84 | .signup button {
85 | width: 100px;
86 | }
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | /* products */
35 |
36 | .product-display {
37 | display: inline-block;
38 | }
39 |
40 | .product-box {
41 | margin: 10px;
42 | }
43 |
44 | .product-image {
45 | width: 250px;
46 | }
47 |
48 | /* comments */
49 |
50 | .comment-list-title {
51 | margin-bottom: 20px;
52 | }
53 |
54 | /* shopping cart */
55 |
56 | .shopping-button {
57 | margin-right: 10px;
58 | margin-top: 10px;
59 | }
60 |
61 | .x-mark {
62 | float: right;
63 | cursor: pointer;
64 | }
65 |
66 | /* login */
67 |
68 | .login {
69 | max-width: 480px;
70 | margin: 0 auto;
71 | }
72 |
73 | .login button {
74 | width: 100px;
75 | }
76 |
77 | /* signup */
78 |
79 | .signup {
80 | max-width: 480px;
81 | margin: 0 auto;
82 | }
83 |
84 | .signup button {
85 | width: 100px;
86 | }
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | /* products */
35 |
36 | .product-display {
37 | display: inline-block;
38 | }
39 |
40 | .product-box {
41 | margin: 10px;
42 | }
43 |
44 | .product-image {
45 | width: 250px;
46 | }
47 |
48 | /* comments */
49 |
50 | .comment-list-title {
51 | margin-bottom: 20px;
52 | }
53 |
54 | /* shopping cart */
55 |
56 | .shopping-button {
57 | margin-right: 10px;
58 | margin-top: 10px;
59 | }
60 |
61 | .x-mark {
62 | float: right;
63 | cursor: pointer;
64 | }
65 |
66 | /* login */
67 |
68 | .login {
69 | max-width: 480px;
70 | margin: 0 auto;
71 | }
72 |
73 | .login button {
74 | width: 100px;
75 | }
76 |
77 | /* signup */
78 |
79 | .signup {
80 | max-width: 480px;
81 | margin: 0 auto;
82 | }
83 |
84 | .signup button {
85 | width: 100px;
86 | }
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | /* products */
35 |
36 | .product-display {
37 | display: inline-block;
38 | }
39 |
40 | .product-box {
41 | margin: 10px;
42 | }
43 |
44 | .product-image {
45 | width: 250px;
46 | }
47 |
48 | /* comments */
49 |
50 | .comment-list-title {
51 | margin-bottom: 20px;
52 | }
53 |
54 | /* shopping cart */
55 |
56 | .shopping-button {
57 | margin-right: 10px;
58 | margin-top: 10px;
59 | }
60 |
61 | .x-mark {
62 | float: right;
63 | cursor: pointer;
64 | }
65 |
66 | /* login */
67 |
68 | .login {
69 | max-width: 480px;
70 | margin: 0 auto;
71 | }
72 |
73 | .login button {
74 | width: 100px;
75 | }
76 |
77 | /* signup */
78 |
79 | .signup {
80 | max-width: 480px;
81 | margin: 0 auto;
82 | }
83 |
84 | .signup button {
85 | width: 100px;
86 | }
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/lib/utils.js:
--------------------------------------------------------------------------------
1 | const corsHeaders = {
2 | 'Access-Control-Allow-Origin': '*'
3 | };
4 |
5 | // Success
6 | module.exports.successHandler = (obj, callback) => {
7 | callback(null, {
8 | statusCode: 200,
9 | headers: corsHeaders,
10 | body: JSON.stringify(obj)
11 | });
12 | };
13 |
14 | // Internal Server Error
15 | module.exports.errorHandler = (err, callback) => {
16 | callback(null, {
17 | statusCode: 500,
18 | headers: corsHeaders,
19 | body: JSON.stringify({
20 | message: 'Internal Server Error',
21 | error: err.toString()
22 | })
23 | });
24 | };
25 |
26 | // Not Found
27 | module.exports.notFoundHandler = (callback) => {
28 | callback(null, {
29 | statusCode: 404,
30 | headers: corsHeaders,
31 | body: JSON.stringify({
32 | message: 'Not Found'
33 | })
34 | });
35 | };
36 |
37 | // OPTIONS
38 | module.exports.optionsHandler = (callback) => {
39 | callback(null, {
40 | statusCode: 200,
41 | headers: {
42 | "Access-Control-Allow-Origin": "*",
43 | "Access-Control-Allow-Methods":
44 | "GET, POST, PUT, PATCH, DELETE, OPTIONS",
45 | "Access-Control-Allow-Headers":
46 | "Accept, Authorization, Content-Type, Origin"
47 | }
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/lib/utils.js:
--------------------------------------------------------------------------------
1 | const corsHeaders = {
2 | 'Access-Control-Allow-Origin': '*'
3 | };
4 |
5 | // Success
6 | module.exports.successHandler = (obj, callback) => {
7 | callback(null, {
8 | statusCode: 200,
9 | headers: corsHeaders,
10 | body: JSON.stringify(obj)
11 | });
12 | };
13 |
14 | // Internal Server Error
15 | module.exports.errorHandler = (err, callback) => {
16 | callback(null, {
17 | statusCode: 500,
18 | headers: corsHeaders,
19 | body: JSON.stringify({
20 | message: 'Internal Server Error',
21 | error: err.toString()
22 | })
23 | });
24 | };
25 |
26 | // Not Found
27 | module.exports.notFoundHandler = (callback) => {
28 | callback(null, {
29 | statusCode: 404,
30 | headers: corsHeaders,
31 | body: JSON.stringify({
32 | message: 'Not Found'
33 | })
34 | });
35 | };
36 |
37 | // OPTIONS
38 | module.exports.optionsHandler = (callback) => {
39 | callback(null, {
40 | statusCode: 200,
41 | headers: {
42 | "Access-Control-Allow-Origin": "*",
43 | "Access-Control-Allow-Methods":
44 | "GET, POST, PUT, PATCH, DELETE, OPTIONS",
45 | "Access-Control-Allow-Headers":
46 | "Accept, Authorization, Content-Type, Origin"
47 | }
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/src/components/ShoppingCart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ShoppingCartItem from './ShoppingCartItem';
3 |
4 | class ShoppingCart extends Component {
5 | getTotal() {
6 | return this.props
7 | .selectedProducts
8 | .map(p => p.price)
9 | .reduce((a, b) => a + b, 0);
10 | }
11 |
12 | render() {
13 | const products = this.props.selectedProducts.map(product => {
14 | return (
15 |
18 | )
19 | });
20 |
21 | const empty = Cart is empty
;
22 |
23 | return (
24 |
25 |
26 | {products.length > 0 ? products : empty}
27 |
Total: US$ {this.getTotal()}
28 |
{this.props.onSave();}}>
30 | Save
31 |
32 | {this.props.hasSaved ?
saved
: ''}
33 |
34 |
35 | );
36 | }
37 | }
38 |
39 | export default ShoppingCart;
40 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/lib/utils.js:
--------------------------------------------------------------------------------
1 | const corsHeaders = {
2 | 'Access-Control-Allow-Origin': '*'
3 | };
4 |
5 | // Success
6 | module.exports.successHandler = (obj, callback) => {
7 | callback(null, {
8 | statusCode: 200,
9 | headers: corsHeaders,
10 | body: JSON.stringify(obj)
11 | });
12 | };
13 |
14 | // Internal Server Error
15 | module.exports.errorHandler = (err, callback) => {
16 | callback(null, {
17 | statusCode: 500,
18 | headers: corsHeaders,
19 | body: JSON.stringify({
20 | message: 'Internal Server Error',
21 | error: err.toString()
22 | })
23 | });
24 | };
25 |
26 | // Not Found
27 | module.exports.notFoundHandler = (callback) => {
28 | callback(null, {
29 | statusCode: 404,
30 | headers: corsHeaders,
31 | body: JSON.stringify({
32 | message: 'Not Found'
33 | })
34 | });
35 | };
36 |
37 | // OPTIONS
38 | module.exports.optionsHandler = (callback) => {
39 | callback(null, {
40 | statusCode: 200,
41 | headers: {
42 | "Access-Control-Allow-Origin": "*",
43 | "Access-Control-Allow-Methods":
44 | "GET, POST, PUT, PATCH, DELETE, OPTIONS",
45 | "Access-Control-Allow-Headers":
46 | "Accept, Authorization, Content-Type, Origin"
47 | }
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/repositories/fakedb.js:
--------------------------------------------------------------------------------
1 | module.exports.retrieveAllProducts = (callback) => {
2 | const comments = [{
3 | id: 1,
4 | username: "John Doe",
5 | age: "3 days ago",
6 | text: "I'm using this to decorate my desk. I liked it."
7 | }, {
8 | id: 2,
9 | username: "Jane Smith",
10 | age: "7 days ago",
11 | text: "This product was very well made."
12 | }];
13 |
14 | const products = [{
15 | id: "lonely-bird",
16 | name: "Lonely Bird",
17 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg',
18 | price: 29.99,
19 | comments: comments
20 | }, {
21 | id: "solid-friendship",
22 | name: "Solid Friendship",
23 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/solid-friendship.jpg',
24 | price: 19.99,
25 | comments: comments
26 | }];
27 |
28 | callback(null, products);
29 | };
30 |
31 | module.exports.retrieveCart = (userId, callback) => {
32 |
33 | const selectedProducts = [{
34 | id: "lonely-bird"
35 | }];
36 |
37 | callback(null, selectedProducts);
38 | };
39 |
40 | module.exports.saveCart = (userId, products, callback) => {
41 | // do nothing
42 | callback(null);
43 | };
44 |
45 | module.exports.processCheckout = (id, callback) => {
46 | // do nothing
47 | callback(null);
48 | };
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/repositories/fakedb.js:
--------------------------------------------------------------------------------
1 | module.exports.retrieveAllProducts = (callback) => {
2 | const comments = [{
3 | id: 1,
4 | username: "John Doe",
5 | age: "3 days ago",
6 | text: "I'm using this to decorate my desk. I liked it."
7 | }, {
8 | id: 2,
9 | username: "Jane Smith",
10 | age: "7 days ago",
11 | text: "This product was very well made."
12 | }];
13 |
14 | const products = [{
15 | id: "lonely-bird",
16 | name: "Lonely Bird",
17 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg',
18 | price: 29.99,
19 | comments: comments
20 | }, {
21 | id: "solid-friendship",
22 | name: "Solid Friendship",
23 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/solid-friendship.jpg',
24 | price: 19.99,
25 | comments: comments
26 | }];
27 |
28 | callback(null, products);
29 | };
30 |
31 | module.exports.retrieveCart = (userId, callback) => {
32 |
33 | const selectedProducts = [{
34 | id: "lonely-bird"
35 | }];
36 |
37 | callback(null, selectedProducts);
38 | };
39 |
40 | module.exports.saveCart = (userId, products, callback) => {
41 | // do nothing
42 | callback(null);
43 | };
44 |
45 | module.exports.processCheckout = (id, callback) => {
46 | // do nothing
47 | callback(null);
48 | };
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/repositories/fakedb.js:
--------------------------------------------------------------------------------
1 | module.exports.retrieveAllProducts = (callback) => {
2 | const comments = [{
3 | id: 1,
4 | username: "John Doe",
5 | age: "3 days ago",
6 | text: "I'm using this to decorate my desk. I liked it."
7 | }, {
8 | id: 2,
9 | username: "Jane Smith",
10 | age: "7 days ago",
11 | text: "This product was very well made."
12 | }];
13 |
14 | const products = [{
15 | id: "lonely-bird",
16 | name: "Lonely Bird",
17 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg',
18 | price: 29.99,
19 | comments: comments
20 | }, {
21 | id: "solid-friendship",
22 | name: "Solid Friendship",
23 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/solid-friendship.jpg',
24 | price: 19.99,
25 | comments: comments
26 | }];
27 |
28 | callback(null, products);
29 | };
30 |
31 | module.exports.retrieveCart = (userId, callback) => {
32 |
33 | const selectedProducts = [{
34 | id: "lonely-bird"
35 | }];
36 |
37 | callback(null, selectedProducts);
38 | };
39 |
40 | module.exports.saveCart = (userId, products, callback) => {
41 | // do nothing
42 | callback(null);
43 | };
44 |
45 | module.exports.processCheckout = (id, callback) => {
46 | // do nothing
47 | callback(null);
48 | };
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/repositories/fakedb.js:
--------------------------------------------------------------------------------
1 | module.exports.retrieveAllProducts = (callback) => {
2 | const comments = [{
3 | id: 1,
4 | username: "John Doe",
5 | age: "3 days ago",
6 | text: "I'm using this to decorate my desk. I liked it."
7 | }, {
8 | id: 2,
9 | username: "Jane Smith",
10 | age: "7 days ago",
11 | text: "This product was very well made."
12 | }];
13 |
14 | const products = [{
15 | id: "lonely-bird",
16 | name: "Lonely Bird",
17 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg',
18 | price: 29.99,
19 | comments: comments
20 | }, {
21 | id: "solid-friendship",
22 | name: "Solid Friendship",
23 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/solid-friendship.jpg',
24 | price: 19.99,
25 | comments: comments
26 | }];
27 |
28 | callback(null, products);
29 | };
30 |
31 | module.exports.retrieveCart = (userId, callback) => {
32 |
33 | const selectedProducts = [{
34 | id: "lonely-bird"
35 | }];
36 |
37 | callback(null, selectedProducts);
38 | };
39 |
40 | module.exports.saveCart = (userId, products, callback) => {
41 | // do nothing
42 | callback(null);
43 | };
44 |
45 | module.exports.processCheckout = (id, callback) => {
46 | // do nothing
47 | callback(null);
48 | };
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/repositories/fakedb.js:
--------------------------------------------------------------------------------
1 | module.exports.retrieveAllProducts = (callback) => {
2 | const comments = [{
3 | id: 1,
4 | username: "John Doe",
5 | age: "3 days ago",
6 | text: "I'm using this to decorate my desk. I liked it."
7 | }, {
8 | id: 2,
9 | username: "Jane Smith",
10 | age: "7 days ago",
11 | text: "This product was very well made."
12 | }];
13 |
14 | const products = [{
15 | id: "lonely-bird",
16 | name: "Lonely Bird",
17 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/lonely-bird.jpg',
18 | price: 29.99,
19 | comments: comments
20 | }, {
21 | id: "solid-friendship",
22 | name: "Solid Friendship",
23 | image: 'https://s3.amazonaws.com/serverless-store-media/product-images/solid-friendship.jpg',
24 | price: 19.99,
25 | comments: comments
26 | }];
27 |
28 | callback(null, products);
29 | };
30 |
31 | module.exports.retrieveCart = (userId, callback) => {
32 |
33 | const selectedProducts = [{
34 | id: "lonely-bird"
35 | }];
36 |
37 | callback(null, selectedProducts);
38 | };
39 |
40 | module.exports.saveCart = (userId, products, callback) => {
41 | // do nothing
42 | callback(null);
43 | };
44 |
45 | module.exports.processCheckout = (id, callback) => {
46 | // do nothing
47 | callback(null);
48 | };
--------------------------------------------------------------------------------
/Chapter08/iam-policies/authenticated.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": [
7 | "mobileanalytics:PutEvents",
8 | "cognito-sync:*",
9 | "cognito-identity:*"
10 | ],
11 | "Resource": [
12 | "*"
13 | ]
14 | },
15 | {
16 | "Effect": "Allow",
17 | "Action": [
18 | "iot:Connect",
19 | "iot:AttachPrincipalPolicy"
20 | ],
21 | "Resource": [
22 | "*"
23 | ]
24 | },
25 | {
26 | "Effect": "Allow",
27 | "Action": [
28 | "iot:Publish",
29 | "iot:Receive"
30 | ],
31 | "Resource": [
32 | "arn:aws:iot:::topic/serverless-store-comments",
33 | "arn:aws:iot:::topic/serverless-store-${cognito-identity.amazonaws.com:sub}"
34 | ]
35 | },
36 | {
37 | "Effect": "Allow",
38 | "Action": [
39 | "iot:Subscribe"
40 | ],
41 | "Resource": [
42 | "arn:aws:iot:::topicfilter/serverless-store-comments",
43 | "arn:aws:iot:::topicfilter/serverless-store-${cognito-identity.amazonaws.com:sub}"
44 | ]
45 | }
46 | ]
47 | }
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/backend/functions/products.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const products = require('../lib/products');
4 | const checkout = require('../lib/checkout');
5 | const cart = require('../lib/cart');
6 | const utils = require('../lib/utils');
7 |
8 | module.exports.handler = (event, context, callback) => {
9 |
10 | const userId = '1'; // TODO: retrieve from authentication headers
11 |
12 | try {
13 | switch(`${event.httpMethod} ${event.resource}`) {
14 |
15 | case 'GET /products':
16 | products.retrieveAll(userId, callback);
17 | break;
18 |
19 | case 'POST /cart':
20 | const selectedProducts = JSON.parse(event.body).products;
21 | cart.saveCart(userId, selectedProducts, callback);
22 | break;
23 |
24 | case 'OPTIONS /cart':
25 | utils.optionsHandler(callback);
26 | break;
27 |
28 | case 'PUT /checkout':
29 | const id = JSON.parse(event.body).id;
30 | checkout.processCheckout(id, callback);
31 | break;
32 |
33 | case 'OPTIONS /checkout':
34 | utils.optionsHandler(callback);
35 | break;
36 |
37 | default:
38 | utils.notFoundHandler(callback);
39 | }
40 | } catch (err) {
41 | utils.errorHandler(err, callback);
42 | }
43 | };
44 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/backend/functions/products.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const products = require('../lib/products');
4 | const checkout = require('../lib/checkout');
5 | const cart = require('../lib/cart');
6 | const utils = require('../lib/utils');
7 |
8 | module.exports.handler = (event, context, callback) => {
9 |
10 | const userId = '1'; // TODO: retrieve from authentication headers
11 |
12 | try {
13 | switch(`${event.httpMethod} ${event.resource}`) {
14 |
15 | case 'GET /products':
16 | products.retrieveAll(userId, callback);
17 | break;
18 |
19 | case 'POST /cart':
20 | const selectedProducts = JSON.parse(event.body).products;
21 | cart.saveCart(userId, selectedProducts, callback);
22 | break;
23 |
24 | case 'OPTIONS /cart':
25 | utils.optionsHandler(callback);
26 | break;
27 |
28 | case 'PUT /checkout':
29 | const id = JSON.parse(event.body).id;
30 | checkout.processCheckout(id, callback);
31 | break;
32 |
33 | case 'OPTIONS /checkout':
34 | utils.optionsHandler(callback);
35 | break;
36 |
37 | default:
38 | utils.notFoundHandler(callback);
39 | }
40 | } catch (err) {
41 | utils.errorHandler(err, callback);
42 | }
43 | };
44 |
--------------------------------------------------------------------------------
/Chapter06/graphql/handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { graphql, buildSchema } = require('graphql');
4 |
5 | const schema = buildSchema(`
6 | type Query {
7 | cart: ShoppingCart
8 | }
9 |
10 | type ShoppingCart {
11 | products: [Product],
12 | promotionCode: String,
13 | discountPercentage: Int
14 | }
15 |
16 | type Product {
17 | name: String,
18 | code: String,
19 | quantity: Int,
20 | price: Int
21 | }
22 | `);
23 |
24 | const data = {
25 | "cart": {
26 | "products": [
27 | {
28 | "name": "Lonely Bird",
29 | "code": "FOO",
30 | "quantity": 1,
31 | "price": 2999
32 | },
33 | {
34 | "name": "Solid Friendship",
35 | "code": "BAR",
36 | "quantity": 1,
37 | "price": 1999
38 | }
39 | ],
40 | promotionCode: null,
41 | discountPercentage: 0
42 | }
43 | };
44 |
45 | module.exports.store = (event, context, callback) => {
46 |
47 | // this query would be received in the event.body
48 | // to make the example simpler, I've hardcoded it here
49 | const query = `{
50 | cart {
51 | products {
52 | name
53 | quantity
54 | price
55 | }
56 | discountPercentage
57 | }
58 | }`;
59 |
60 | graphql(schema, query, data).then((resp) => {
61 | const response = {
62 | statusCode: 200,
63 | body: JSON.stringify(resp)
64 | };
65 |
66 | callback(null, response);
67 | });
68 | };
--------------------------------------------------------------------------------
/Chapter10/Testing/backend/test/unit/test-orders.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const sinon = require('sinon');
3 | const Order = require('../../lib/order');
4 |
5 | describe('Order', () => {
6 | describe('#saveOrder()', () => {
7 | it('should call db and notifier', (done) => {
8 |
9 | // define the behavior of the fake functions
10 | const dbMock = {
11 | saveOrder: (order, callback) => {
12 | callback(null);
13 | }
14 | }
15 |
16 | const notifierMock = {
17 | sendEmail: (email, callback) => {
18 | callback(null);
19 | }
20 | }
21 |
22 | // spy the objects to identify when and how they are executed
23 | sinon.spy(dbMock, 'saveOrder');
24 | sinon.spy(notifierMock, 'sendEmail');
25 |
26 | // define the input event
27 | const event = {
28 | order: { id: 1 },
29 | email: 'example@example.com'
30 | };
31 |
32 | // inject the mocked objects
33 | const order = new Order(dbMock, notifierMock);
34 |
35 | // execute the function
36 | order.save(event.order, event.email, (err, res) => {
37 |
38 | // assert if the mocked functions were used as expected
39 | assert(dbMock.saveOrder.calledOnce, true);
40 | assert(notifierMock.sendEmail.calledOnce, true);
41 | assert(dbMock.saveOrder.calledWith(event.order), true);
42 | assert(notifierMock.sendEmail.calledWith(event.email), true);
43 |
44 | done(err);
45 | })
46 | });
47 | });
48 | });
--------------------------------------------------------------------------------
/Chapter10/Testing/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 | You need to enable JavaScript to run this app.
27 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-store
2 |
3 | custom:
4 | awsAccountId: 1234567890
5 | cognitoAuthorizer: arn:aws:cognito-idp:us-east-1:${self:custom.awsAccountId}:userpool/us-east-1_aBcdeFghi
6 |
7 | provider:
8 | name: aws
9 | runtime: nodejs6.10
10 | stage: dev
11 | region: us-east-1
12 | memorySize: 128
13 | timeout: 30
14 | iamRoleStatements:
15 | - Effect: "Allow"
16 | Action:
17 | - "sdb:BatchPutAttributes"
18 | - "sdb:PutAttributes"
19 | - "sdb:Select"
20 | Resource: [
21 | "arn:aws:sdb:us-east-1:*:domain/Products",
22 | "arn:aws:sdb:us-east-1:*:domain/ShoppingCart"
23 | ]
24 | - Effect: "Allow"
25 | Action:
26 | - "dynamodb:Scan"
27 | - "dynamodb:Query"
28 | - "dynamodb:PutItem"
29 | - "dynamodb:DeleteItem"
30 | - "dynamodb:BatchWriteItem"
31 | Resource: [
32 | "arn:aws:dynamodb:us-east-1:*:table/Products",
33 | "arn:aws:dynamodb:us-east-1:*:table/ShoppingCart"
34 | ]
35 |
36 | functions:
37 | products:
38 | handler: functions/products.handler
39 | events:
40 | - http: GET products
41 | - http:
42 | method: GET
43 | path: productsAuth
44 | authorizer:
45 | arn: ${self:custom.cognitoAuthorizer}
46 | - http: OPTIONS productsAuth
47 | - http:
48 | method: POST
49 | path: cart
50 | authorizer:
51 | arn: ${self:custom.cognitoAuthorizer}
52 | - http: OPTIONS cart
53 | - http:
54 | method: PUT
55 | path: checkout
56 | authorizer:
57 | arn: ${self:custom.cognitoAuthorizer}
58 | - http: OPTIONS checkout
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/functions/products.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const products = require('../lib/products');
4 | const checkout = require('../lib/checkout');
5 | const cart = require('../lib/cart');
6 | const utils = require('../lib/utils');
7 |
8 | module.exports.handler = (event, context, callback) => {
9 |
10 | let userId = null;
11 |
12 | if (event.requestContext.authorizer)
13 | userId = event.requestContext.authorizer.claims.sub;
14 |
15 | try {
16 | switch(`${event.httpMethod} ${event.resource}`) {
17 |
18 | case 'GET /products':
19 | products.retrieveAll(null, callback);
20 | break;
21 |
22 | case 'GET /productsAuth':
23 | products.retrieveAll(userId, callback);
24 | break;
25 |
26 | case 'OPTIONS /productsAuth':
27 | utils.optionsHandler(callback);
28 | break;
29 |
30 | case 'POST /cart':
31 | const selectedProducts = JSON.parse(event.body).products;
32 | cart.saveCart(userId, selectedProducts, callback);
33 | break;
34 |
35 | case 'OPTIONS /cart':
36 | utils.optionsHandler(callback);
37 | break;
38 |
39 | case 'PUT /checkout':
40 | const id = JSON.parse(event.body).id;
41 | checkout.processCheckout(id, callback);
42 | break;
43 |
44 | case 'OPTIONS /checkout':
45 | utils.optionsHandler(callback);
46 | break;
47 |
48 | default:
49 | utils.notFoundHandler(callback);
50 | }
51 | } catch (err) {
52 | utils.errorHandler(err, callback);
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/functions/products.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const products = require('../lib/products');
4 | const checkout = require('../lib/checkout');
5 | const cart = require('../lib/cart');
6 | const utils = require('../lib/utils');
7 |
8 | module.exports.handler = (event, context, callback) => {
9 |
10 | let userId = null;
11 |
12 | if (event.requestContext.authorizer)
13 | userId = event.requestContext.authorizer.claims.sub;
14 |
15 | try {
16 | switch(`${event.httpMethod} ${event.resource}`) {
17 |
18 | case 'GET /products':
19 | products.retrieveAll(null, callback);
20 | break;
21 |
22 | case 'GET /productsAuth':
23 | products.retrieveAll(userId, callback);
24 | break;
25 |
26 | case 'OPTIONS /productsAuth':
27 | utils.optionsHandler(callback);
28 | break;
29 |
30 | case 'POST /cart':
31 | const selectedProducts = JSON.parse(event.body).products;
32 | cart.saveCart(userId, selectedProducts, callback);
33 | break;
34 |
35 | case 'OPTIONS /cart':
36 | utils.optionsHandler(callback);
37 | break;
38 |
39 | case 'PUT /checkout':
40 | const id = JSON.parse(event.body).id;
41 | checkout.processCheckout(id, callback);
42 | break;
43 |
44 | case 'OPTIONS /checkout':
45 | utils.optionsHandler(callback);
46 | break;
47 |
48 | default:
49 | utils.notFoundHandler(callback);
50 | }
51 | } catch (err) {
52 | utils.errorHandler(err, callback);
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/Chapter08/serverless-store-chap8/backend/functions/products.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const products = require('../lib/products');
4 | const checkout = require('../lib/checkout');
5 | const cart = require('../lib/cart');
6 | const utils = require('../lib/utils');
7 |
8 | module.exports.handler = (event, context, callback) => {
9 |
10 | let userId = null;
11 |
12 | if (event.requestContext.authorizer)
13 | userId = event.requestContext.authorizer.claims.sub;
14 |
15 | try {
16 | switch(`${event.httpMethod} ${event.resource}`) {
17 |
18 | case 'GET /products':
19 | products.retrieveAll(null, callback);
20 | break;
21 |
22 | case 'GET /productsAuth':
23 | products.retrieveAll(userId, callback);
24 | break;
25 |
26 | case 'OPTIONS /productsAuth':
27 | utils.optionsHandler(callback);
28 | break;
29 |
30 | case 'POST /cart':
31 | const selectedProducts = JSON.parse(event.body).products;
32 | cart.saveCart(userId, selectedProducts, callback);
33 | break;
34 |
35 | case 'OPTIONS /cart':
36 | utils.optionsHandler(callback);
37 | break;
38 |
39 | case 'PUT /checkout':
40 | const id = JSON.parse(event.body).id;
41 | checkout.processCheckout(id, callback);
42 | break;
43 |
44 | case 'OPTIONS /checkout':
45 | utils.optionsHandler(callback);
46 | break;
47 |
48 | default:
49 | utils.notFoundHandler(callback);
50 | }
51 | } catch (err) {
52 | utils.errorHandler(err, callback);
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | FormGroup,
4 | FormControl,
5 | ControlLabel,
6 | } from 'react-bootstrap';
7 |
8 | class Login extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {
14 | email: '',
15 | password: ''
16 | };
17 | }
18 |
19 | handleChange = (event) => {
20 | this.setState({
21 | [event.target.id]: event.target.value
22 | });
23 | }
24 |
25 | handleSubmit = (event) => {
26 | event.preventDefault();
27 | }
28 |
29 | validateForm() {
30 | return this.state.email.length > 0 && this.state.password.length > 0;
31 | }
32 |
33 | render() {
34 | return (
35 |
55 | );
56 | }
57 | }
58 |
59 | export default Login;
60 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | FormGroup,
4 | FormControl,
5 | ControlLabel,
6 | } from 'react-bootstrap';
7 |
8 | class Login extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {
14 | email: '',
15 | password: ''
16 | };
17 | }
18 |
19 | handleChange = (event) => {
20 | this.setState({
21 | [event.target.id]: event.target.value
22 | });
23 | }
24 |
25 | handleSubmit = (event) => {
26 | event.preventDefault();
27 | }
28 |
29 | validateForm() {
30 | return this.state.email.length > 0 && this.state.password.length > 0;
31 | }
32 |
33 | render() {
34 | return (
35 |
55 | );
56 | }
57 | }
58 |
59 | export default Login;
60 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | FormGroup,
4 | FormControl,
5 | ControlLabel,
6 | } from 'react-bootstrap';
7 |
8 | class Login extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {
14 | email: '',
15 | password: ''
16 | };
17 | }
18 |
19 | handleChange = (event) => {
20 | this.setState({
21 | [event.target.id]: event.target.value
22 | });
23 | }
24 |
25 | handleSubmit = (event) => {
26 | event.preventDefault();
27 | }
28 |
29 | validateForm() {
30 | return this.state.email.length > 0 && this.state.password.length > 0;
31 | }
32 |
33 | render() {
34 | return (
35 |
55 | );
56 | }
57 | }
58 |
59 | export default Login;
60 |
--------------------------------------------------------------------------------
/Chapter05/react-ajax/request-data/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import axios from 'axios';
3 | import ProductList from './ProductList';
4 |
5 | const apiAddress = 'https://abc123.execute-api.us-east-1.amazonaws.com';
6 | const stage = 'dev';
7 | const service = 'store/products';
8 |
9 | class App extends Component {
10 |
11 | constructor() {
12 | super();
13 |
14 | this.state = {
15 | products: [],
16 | ready: false
17 | };
18 | }
19 |
20 | render() {
21 | return (
22 |
23 |
24 |
25 |
Serverless Store
26 |
27 |
28 |
29 |
30 | {
31 | this.state.ready
32 | ?
33 |
37 | :
38 |
39 |
40 |
41 | }
42 |
43 |
44 |
45 | );
46 | }
47 |
48 | componentDidMount() {
49 |
50 | axios
51 | .get(`${apiAddress}/${stage}/${service}`)
52 | .then(res => {
53 | this.setState({
54 | products: res.data.products,
55 | ready: true
56 | });
57 | })
58 | .catch(error => {
59 | console.log(error);
60 | });
61 | }
62 | }
63 |
64 | export default App;
65 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/lib/iot.js:
--------------------------------------------------------------------------------
1 | import awsIot from 'aws-iot-device-sdk';
2 | import config from './config';
3 |
4 | export default class IoT {
5 |
6 | constructor(keys, messageCallback) {
7 | this.client = null;
8 | this.accessKey = keys.accessKey;
9 | this.secretKey = keys.secretKey;
10 | this.sessionToken = keys.sessionToken;
11 | this.messageCallback = messageCallback;
12 |
13 | this.handleConnect = this.handleConnect.bind(this);
14 | this.handleMessage = this.handleMessage.bind(this);
15 | }
16 |
17 | connect() {
18 | this.client = awsIot.device({
19 | region: config.iot.REGION,
20 | host: config.iot.ENDPOINT,
21 | accessKeyId: this.accessKey,
22 | secretKey: this.secretKey,
23 | sessionToken: this.sessionToken,
24 | port: 443,
25 | protocol: 'wss' // WebSocket with TLS
26 | });
27 |
28 | this.client.on('connect', this.handleConnect);
29 | this.client.on('message', this.handleMessage);
30 | this.client.on('close', this.handleClose);
31 | this.client.on('error', this.handleError);
32 | this.client.on('reconnect', this.handleReconnect);
33 | this.client.on('offline', this.handleOffline);
34 | }
35 |
36 | publish(topic, message) {
37 | this.client.publish(topic, message);
38 | }
39 |
40 | subscribe(topic) {
41 | this.client.subscribe(topic);
42 | }
43 |
44 | handleConnect() {
45 | console.log('Connected to IoT');
46 | }
47 |
48 | handleMessage(topic, message) {
49 | this.messageCallback(topic, message);
50 | }
51 |
52 | handleClose() {
53 | console.log('IoT: Connection closed');
54 | }
55 |
56 | handleError() {
57 | console.log('Error with the IoT connection');
58 | }
59 |
60 | handleReconnect() {
61 | console.log('Trying to reconnect to IoT');
62 | }
63 |
64 | handleOffline() {
65 | console.log('IoT: Offline');
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/lib/iot.js:
--------------------------------------------------------------------------------
1 | import awsIot from 'aws-iot-device-sdk';
2 | import config from './config';
3 |
4 | export default class IoT {
5 |
6 | constructor(keys, messageCallback) {
7 | this.client = null;
8 | this.accessKey = keys.accessKey;
9 | this.secretKey = keys.secretKey;
10 | this.sessionToken = keys.sessionToken;
11 | this.messageCallback = messageCallback;
12 |
13 | this.handleConnect = this.handleConnect.bind(this);
14 | this.handleMessage = this.handleMessage.bind(this);
15 | }
16 |
17 | connect() {
18 | this.client = awsIot.device({
19 | region: config.iot.REGION,
20 | host: config.iot.ENDPOINT,
21 | accessKeyId: this.accessKey,
22 | secretKey: this.secretKey,
23 | sessionToken: this.sessionToken,
24 | port: 443,
25 | protocol: 'wss' // WebSocket with TLS
26 | });
27 |
28 | this.client.on('connect', this.handleConnect);
29 | this.client.on('message', this.handleMessage);
30 | this.client.on('close', this.handleClose);
31 | this.client.on('error', this.handleError);
32 | this.client.on('reconnect', this.handleReconnect);
33 | this.client.on('offline', this.handleOffline);
34 | }
35 |
36 | publish(topic, message) {
37 | this.client.publish(topic, message);
38 | }
39 |
40 | subscribe(topic) {
41 | this.client.subscribe(topic);
42 | }
43 |
44 | handleConnect() {
45 | console.log('Connected to IoT');
46 | }
47 |
48 | handleMessage(topic, message) {
49 | this.messageCallback(topic, message);
50 | }
51 |
52 | handleClose() {
53 | console.log('IoT: Connection closed');
54 | }
55 |
56 | handleError() {
57 | console.log('Error with the IoT connection');
58 | }
59 |
60 | handleReconnect() {
61 | console.log('Trying to reconnect to IoT');
62 | }
63 |
64 | handleOffline() {
65 | console.log('IoT: Offline');
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | .new-notification {
35 | color: #f51b1b;
36 | }
37 |
38 | /* products */
39 |
40 | .product-display {
41 | display: inline-block;
42 | }
43 |
44 | .product-box {
45 | margin: 10px;
46 | }
47 |
48 | .product-image {
49 | width: 250px;
50 | }
51 |
52 | /* comments */
53 |
54 | .comment-list-title {
55 | margin-bottom: 20px;
56 | }
57 |
58 | .comment-box {
59 | width: 100%;
60 | float: left;
61 | margin-bottom: 40px;
62 | background-color: #f5f5f5;
63 | border-radius: 3px;
64 | border-color: #ddd;
65 | border-style: solid;
66 | border-width: 1px;
67 | }
68 |
69 | .comment-box input {
70 | width: 100%;
71 | outline: none;
72 | border-radius: 3px 3px 0 0;
73 | border-color: #ddd;
74 | border-width: 0px 0px 1px 0px;
75 | }
76 |
77 | .comment-box button {
78 | float: right;
79 | margin: 3px 10px 3px 0px;
80 | }
81 |
82 | .comment-box button > i {
83 | margin-right: 7px;
84 | }
85 |
86 | /* shopping cart */
87 |
88 | .shopping-button {
89 | margin-right: 10px;
90 | margin-top: 10px;
91 | }
92 |
93 | .x-mark {
94 | float: right;
95 | cursor: pointer;
96 | }
97 |
98 | /* login */
99 |
100 | .login {
101 | max-width: 480px;
102 | margin: 0 auto;
103 | }
104 |
105 | .login button {
106 | width: 100px;
107 | }
108 |
109 | /* signup */
110 |
111 | .signup {
112 | max-width: 480px;
113 | margin: 0 auto;
114 | }
115 |
116 | .signup button {
117 | width: 100px;
118 | }
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/frontend/src/css/site.css:
--------------------------------------------------------------------------------
1 | /* general */
2 |
3 | .btn-danger:focus {
4 | outline-color: #761c19;
5 | }
6 |
7 | .spin {
8 | font-size: 30px;
9 | margin-top: 10px;
10 | animation: spin-frames 1s infinite linear;
11 | }
12 |
13 | @keyframes spin-frames {
14 | from { transform: scale(1) rotate(0deg); }
15 | to { transform: scale(1) rotate(360deg); }
16 | }
17 |
18 | /* navbar */
19 |
20 | .navbar {
21 | margin-top: 20px;
22 | margin-bottom: 20px;
23 | }
24 |
25 | #notification {
26 | padding: 10px;
27 | cursor: pointer;
28 | }
29 |
30 | #notification span {
31 | font-size: 25px;
32 | }
33 |
34 | .new-notification {
35 | color: #f51b1b;
36 | }
37 |
38 | /* products */
39 |
40 | .product-display {
41 | display: inline-block;
42 | }
43 |
44 | .product-box {
45 | margin: 10px;
46 | }
47 |
48 | .product-image {
49 | width: 250px;
50 | }
51 |
52 | /* comments */
53 |
54 | .comment-list-title {
55 | margin-bottom: 20px;
56 | }
57 |
58 | .comment-box {
59 | width: 100%;
60 | float: left;
61 | margin-bottom: 40px;
62 | background-color: #f5f5f5;
63 | border-radius: 3px;
64 | border-color: #ddd;
65 | border-style: solid;
66 | border-width: 1px;
67 | }
68 |
69 | .comment-box input {
70 | width: 100%;
71 | outline: none;
72 | border-radius: 3px 3px 0 0;
73 | border-color: #ddd;
74 | border-width: 0px 0px 1px 0px;
75 | }
76 |
77 | .comment-box button {
78 | float: right;
79 | margin: 3px 10px 3px 0px;
80 | }
81 |
82 | .comment-box button > i {
83 | margin-right: 7px;
84 | }
85 |
86 | /* shopping cart */
87 |
88 | .shopping-button {
89 | margin-right: 10px;
90 | margin-top: 10px;
91 | }
92 |
93 | .x-mark {
94 | float: right;
95 | cursor: pointer;
96 | }
97 |
98 | /* login */
99 |
100 | .login {
101 | max-width: 480px;
102 | margin: 0 auto;
103 | }
104 |
105 | .login button {
106 | width: 100px;
107 | }
108 |
109 | /* signup */
110 |
111 | .signup {
112 | max-width: 480px;
113 | margin: 0 auto;
114 | }
115 |
116 | .signup button {
117 | width: 100px;
118 | }
--------------------------------------------------------------------------------
/Chapter05/react-ajax/send-data/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import axios from 'axios';
3 | import ShoppingCart from './ShoppingCart';
4 |
5 | const apiAddress = 'https://abc0123456.execute-api.us-east-1.amazonaws.com';
6 | const stage = 'dev';
7 | const service = 'shopping-cart/save';
8 |
9 | const products = [{
10 | id: 1,
11 | name: 'Lonely Bird',
12 | price: 29.99,
13 | isSelected: true
14 | }, {
15 | id: 2,
16 | name: 'Solid Friendship',
17 | price: 19.99,
18 | isSelected: true
19 | }];
20 |
21 | class App extends Component {
22 |
23 | constructor() {
24 | super();
25 |
26 | this.state = {
27 | products: products,
28 | hasSaved: false
29 | };
30 |
31 | // bind the component's "this" to the callback
32 | this.handleSave = this.handleSave.bind(this);
33 | }
34 |
35 | handleSave() {
36 | axios
37 | .post(`${apiAddress}/${stage}/${service}`, {
38 | products: this.state.products
39 | })
40 | .then(res => {
41 | this.setState({
42 | products: this.state.products,
43 | hasSaved: true
44 | });
45 | })
46 | .catch(error => {
47 | console.log(error);
48 | });
49 | }
50 |
51 | render() {
52 | return (
53 |
54 |
55 |
56 |
Serverless Store
57 |
58 |
59 |
60 |
61 |
Shopping Cart
62 | p.isSelected)}
64 | hasSaved={this.state.hasSaved}
65 | onSave={this.handleSave} />
66 |
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | export default App;
74 |
--------------------------------------------------------------------------------
/Chapter09/serverless-store-chap9/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-store
2 |
3 | custom:
4 | awsAccountId: 1234567890
5 | cognitoAuthorizer: arn:aws:cognito-idp:us-east-1:${self:custom.awsAccountId}:userpool/us-east-1_aBcdeFghi
6 |
7 | provider:
8 | name: aws
9 | runtime: nodejs6.10
10 | stage: dev
11 | region: us-east-1
12 | memorySize: 128
13 | timeout: 30
14 | environment:
15 | IOT_ENDPOINT: abcdefghijklm.iot.us-east-1.amazonaws.com
16 | iamRoleStatements:
17 | - Effect: "Allow"
18 | Action:
19 | - "sdb:BatchPutAttributes"
20 | - "sdb:PutAttributes"
21 | - "sdb:Select"
22 | Resource: [
23 | "arn:aws:sdb:us-east-1:*:domain/Products",
24 | "arn:aws:sdb:us-east-1:*:domain/ShoppingCart"
25 | ]
26 | - Effect: "Allow"
27 | Action:
28 | - "dynamodb:Scan"
29 | - "dynamodb:Query"
30 | - "dynamodb:PutItem"
31 | - "dynamodb:DeleteItem"
32 | - "dynamodb:BatchWriteItem"
33 | Resource: [
34 | "arn:aws:dynamodb:us-east-1:*:table/Products",
35 | "arn:aws:dynamodb:us-east-1:*:table/ShoppingCart"
36 | ]
37 | - Effect: "Allow"
38 | Action:
39 | - "iot:Publish"
40 | Resource:
41 | "arn:aws:iot:${self:provider.region}:${self:custom.awsAccountId}:topic/serverless-store-*"
42 |
43 | functions:
44 | products:
45 | handler: functions/products.handler
46 | events:
47 | - http: GET products
48 | - http:
49 | method: GET
50 | path: productsAuth
51 | authorizer:
52 | arn: ${self:custom.cognitoAuthorizer}
53 | - http: OPTIONS productsAuth
54 | - http:
55 | method: POST
56 | path: cart
57 | authorizer:
58 | arn: ${self:custom.cognitoAuthorizer}
59 | - http: OPTIONS cart
60 | - http:
61 | method: PUT
62 | path: checkout
63 | authorizer:
64 | arn: ${self:custom.cognitoAuthorizer}
65 | - http: OPTIONS checkout
66 |
67 | comments:
68 | handler: functions/comments.handler
69 | events:
70 | - iot:
71 | sql: "SELECT * FROM 'serverless-store-comments'"
72 |
--------------------------------------------------------------------------------
/Chapter10/serverless-store-chap10/backend/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-store
2 |
3 | custom:
4 | awsAccountId: 1234567890
5 | cognitoAuthorizer: arn:aws:cognito-idp:us-east-1:${self:custom.awsAccountId}:userpool/us-east-1_aBcdeFghi
6 |
7 | provider:
8 | name: aws
9 | runtime: nodejs6.10
10 | stage: dev
11 | region: us-east-1
12 | memorySize: 128
13 | timeout: 30
14 | environment:
15 | IOT_ENDPOINT: abcdefghijklm.iot.us-east-1.amazonaws.com
16 | iamRoleStatements:
17 | - Effect: "Allow"
18 | Action:
19 | - "sdb:BatchPutAttributes"
20 | - "sdb:PutAttributes"
21 | - "sdb:Select"
22 | Resource: [
23 | "arn:aws:sdb:us-east-1:*:domain/Products",
24 | "arn:aws:sdb:us-east-1:*:domain/ShoppingCart"
25 | ]
26 | - Effect: "Allow"
27 | Action:
28 | - "dynamodb:Scan"
29 | - "dynamodb:Query"
30 | - "dynamodb:PutItem"
31 | - "dynamodb:DeleteItem"
32 | - "dynamodb:BatchWriteItem"
33 | Resource: [
34 | "arn:aws:dynamodb:us-east-1:*:table/Products",
35 | "arn:aws:dynamodb:us-east-1:*:table/ShoppingCart"
36 | ]
37 | - Effect: "Allow"
38 | Action:
39 | - "iot:Publish"
40 | Resource:
41 | "arn:aws:iot:${self:provider.region}:${self:custom.awsAccountId}:topic/serverless-store-*"
42 |
43 | functions:
44 | products:
45 | handler: functions/products.handler
46 | events:
47 | - http: GET products
48 | - http:
49 | method: GET
50 | path: productsAuth
51 | authorizer:
52 | arn: ${self:custom.cognitoAuthorizer}
53 | - http: OPTIONS productsAuth
54 | - http:
55 | method: POST
56 | path: cart
57 | authorizer:
58 | arn: ${self:custom.cognitoAuthorizer}
59 | - http: OPTIONS cart
60 | - http:
61 | method: PUT
62 | path: checkout
63 | authorizer:
64 | arn: ${self:custom.cognitoAuthorizer}
65 | - http: OPTIONS checkout
66 |
67 | comments:
68 | handler: functions/comments.handler
69 | events:
70 | - iot:
71 | sql: "SELECT * FROM 'serverless-store-comments'"
72 |
--------------------------------------------------------------------------------
/Chapter07/DynamoDB/table-with-indexes.js:
--------------------------------------------------------------------------------
1 | const AWS = require('aws-sdk');
2 | const dynamodb = new AWS.DynamoDB();
3 |
4 | const params = {
5 | TableName: 'TableWithIndexes',
6 | AttributeDefinitions: [
7 | {
8 | AttributeName: 'ID',
9 | AttributeType: 'S'
10 | },
11 | {
12 | AttributeName: 'MyOtherAttribute',
13 | AttributeType: 'S'
14 | },
15 | {
16 | AttributeName: 'MyLocalAttribute',
17 | AttributeType: 'S'
18 | },
19 | {
20 | AttributeName: 'MyGlobalAttribute',
21 | AttributeType: 'S'
22 | }
23 | ],
24 | KeySchema: [
25 | {
26 | AttributeName: 'ID',
27 | KeyType: 'HASH'
28 | },
29 | {
30 | AttributeName: 'MyOtherAttribute',
31 | KeyType: 'RANGE'
32 | }
33 | ],
34 | ProvisionedThroughput: {
35 | ReadCapacityUnits: 5,
36 | WriteCapacityUnits: 5
37 | },
38 | LocalSecondaryIndexes: [
39 | {
40 | IndexName: 'MyLocalIndex',
41 | KeySchema: [
42 | {
43 | AttributeName: 'ID',
44 | KeyType: 'HASH'
45 | },
46 | {
47 | AttributeName: 'MyLocalAttribute',
48 | KeyType: 'RANGE'
49 | }
50 | ],
51 | Projection: {
52 | ProjectionType: 'ALL'
53 | }
54 | }
55 | ],
56 | GlobalSecondaryIndexes: [
57 | {
58 | IndexName: 'MyGlobalIndex',
59 | KeySchema: [
60 | {
61 | AttributeName: 'MyGlobalAttribute',
62 | KeyType: 'HASH'
63 | }
64 | ],
65 | Projection: {
66 | ProjectionType: 'ALL'
67 | },
68 | ProvisionedThroughput: {
69 | ReadCapacityUnits: 5,
70 | WriteCapacityUnits: 5
71 | }
72 | }
73 | ]
74 | };
75 |
76 | dynamodb.createTable(params, (err, data) => {
77 | if (err) console.log(err, err.stack);
78 | else console.log(data);
79 | });
--------------------------------------------------------------------------------
/Chapter05/serverless-store-chap5/frontend/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import CommentList from './CommentList';
4 |
5 | class Product extends Component {
6 | render() {
7 |
8 | let product = null;
9 | if (this.props.product) {
10 | product =
11 |
12 |
13 |
14 |
15 |
16 |
{this.props.product.name}
17 |
US$ {this.props.product.price}
18 |
19 | {
21 | const product = this.props.product;
22 | product.isSelected = !product.isSelected;
23 | this.props.onSelect(product);
24 | }}>
25 | {this.props.product.isSelected ? 'Remove' : 'Add to cart'}
26 |
27 |
28 |
29 |
30 | } else {
31 | product =
32 |
33 |
Product not found
34 |
35 | }
36 |
37 | return (
38 |
39 |
40 | {this.props.fromList ? "":
Product }
41 |
42 | {product}
43 |
44 |
45 |
46 | {this.props.fromList ? "": }
47 |
48 |
49 | );
50 | }
51 | }
52 |
53 | export default Product;
54 |
--------------------------------------------------------------------------------
/Chapter06/serverless-store-chap6/frontend/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import CommentList from './CommentList';
4 |
5 | class Product extends Component {
6 | render() {
7 |
8 | let product = null;
9 | if (this.props.product) {
10 | product =
11 |
12 |
13 |
14 |
15 |
16 |
{this.props.product.name}
17 |
US$ {this.props.product.price}
18 |
19 | {
21 | const product = this.props.product;
22 | product.isSelected = !product.isSelected;
23 | this.props.onSelect(product);
24 | }}>
25 | {this.props.product.isSelected ? 'Remove' : 'Add to cart'}
26 |
27 |
28 |
29 |
30 | } else {
31 | product =
32 |
33 |
Product not found
34 |
35 | }
36 |
37 | return (
38 |
39 |
40 | {this.props.fromList ? "":
Product }
41 |
42 | {product}
43 |
44 |
45 |
46 | {this.props.fromList ? "": }
47 |
48 |
49 | );
50 | }
51 | }
52 |
53 | export default Product;
54 |
--------------------------------------------------------------------------------
/Chapter07/serverless-store-chap7/frontend/src/components/Product.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import CommentList from './CommentList';
4 |
5 | class Product extends Component {
6 | render() {
7 |
8 | let product = null;
9 | if (this.props.product) {
10 | product =
11 |
12 |
13 |
14 |
15 |
16 |
{this.props.product.name}
17 |
US$ {this.props.product.price}
18 |
19 | {
21 | const product = this.props.product;
22 | product.isSelected = !product.isSelected;
23 | this.props.onSelect(product);
24 | }}>
25 | {this.props.product.isSelected ? 'Remove' : 'Add to cart'}
26 |
27 |
28 |
29 |
30 | } else {
31 | product =
32 |
33 |
Product not found
34 |
35 | }
36 |
37 | return (
38 |
39 |
40 | {this.props.fromList ? "":
Product }
41 |
42 | {product}
43 |
44 |
45 |
46 | {this.props.fromList ? "": }
47 |
48 |
49 | );
50 | }
51 | }
52 |
53 | export default Product;
54 |
--------------------------------------------------------------------------------