├── 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 | 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 | 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 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /Chapter05/react-shopping-cart/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Serverless Store 9 | 10 | 11 | 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 | logo 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 | 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 | 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 | 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 | 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 | 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 | 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 |
9 | 10 |
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 | product 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 |
10 | 12 |
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 |
10 | 14 |
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 |
10 | 14 |
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 |
10 | 14 |
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 |
10 | 14 |
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 |
11 | 16 |
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 |
11 | 16 |
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 | product 8 |
9 |

{this.props.product.name}

10 |
US$ {this.props.product.price}
11 |
12 | 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 | 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 | 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 | 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 | 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 |
36 |

Login

37 |
38 |
39 | 40 | E-mail 41 | 42 | 43 | 44 | Password 45 | 46 | 47 |
48 | 51 |
52 |
53 |
54 |
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 |
36 |

Login

37 |
38 |
39 | 40 | E-mail 41 | 42 | 43 | 44 | Password 45 | 46 | 47 |
48 | 51 |
52 |
53 |
54 |
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 |
36 |

Login

37 |
38 |
39 | 40 | E-mail 41 | 42 | 43 | 44 | Password 45 | 46 | 47 |
48 | 51 |
52 |
53 |
54 |
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 |
34 |

Products

35 | 36 |
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 | product 14 | 15 |
16 |

{this.props.product.name}

17 |
US$ {this.props.product.price}
18 |
19 | 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 | product 14 | 15 |
16 |

{this.props.product.name}

17 |
US$ {this.props.product.price}
18 |
19 | 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 | product 14 | 15 |
16 |

{this.props.product.name}

17 |
US$ {this.props.product.price}
18 |
19 | 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 | --------------------------------------------------------------------------------