├── .gitignore ├── README.md ├── amplify ├── .config │ └── project-config.json └── backend │ ├── api │ └── api7d641705 │ │ ├── api-params.json │ │ ├── api7d641705-cloudformation-template.json │ │ └── parameters.json │ ├── backend-config.json │ ├── function │ └── testing067f3506 │ │ ├── function-parameters.json │ │ ├── src │ │ ├── app.js │ │ ├── event.json │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json │ │ └── testing067f3506-cloudformation-template.json │ └── storage │ └── dynamob1b4533e │ ├── dynamob1b4533e-cloudformation-template.json │ ├── parameters.json │ └── storage-params.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg └── serviceWorker.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | #amplify 26 | amplify/team-provider-info.json 27 | amplify/\#current-cloud-backend 28 | amplify/.config/local-* 29 | amplify/mock-data 30 | amplify/backend/amplify-meta.json 31 | amplify/backend/awscloudformation 32 | build/ 33 | dist/ 34 | node_modules/ 35 | aws-exports.js 36 | awsconfiguration.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Basic serverless API 2 | 3 | Building a basic serverless API with DynamoDB, API Gateway, and AWS Lambda 4 | 5 | ## Getting started 6 | 7 | Create the React project, install dependencies 8 | 9 | ```sh 10 | $ npx create-react-app serverless-api 11 | 12 | $ cd serverless-api 13 | 14 | $ npm install aws-amplify 15 | ``` 16 | 17 | Next, create the amplify project and add the database: 18 | 19 | ```sh 20 | $ amplify init 21 | 22 | $ amplify add storage 23 | 24 | ? Please select from one of the below mentioned services: NoSQL Database 25 | ``` 26 | 27 | Create a database with the following columns: 28 | 29 | ``` 30 | id: string 31 | name: string 32 | description: string 33 | price: number 34 | 35 | ? Please choose partition key for the table: id 36 | ? Do you want to add a sort key to your table? Y 37 | ? Please choose sort key for the table: name 38 | ? Do you want to add global secondary indexes to your table? N 39 | ? Do you want to add a Lambda Trigger for your Table? N 40 | ``` 41 | 42 | Next, create the API: 43 | 44 | ```sh 45 | $ amplify add api 46 | 47 | ? Please select from one of the below mentioned services: REST 48 | ? Provide a friendly name for your resource to be used as a label for this category in the project: productapi 49 | ? Provide a path (e.g., /items) /products 50 | ? Choose a Lambda source: Create a new Lambda function 51 | ? Provide a friendly name for your resource to be used as a label for this category in the project: 52 | ? Provide the AWS Lambda function name: 53 | ? Choose the function template that you want to use: Serverless express function (Integration with Amazon API Gateway) 54 | ? Do you want to access other resources created in this project from your Lambda function? Yes 55 | ? Select the category: storage 56 | Storage category has a resource called 57 | ? Select the operations you want to permit for create, read, update, delete 58 | ? Do you want to edit the local lambda function now? Yes 59 | File will open in your editor. We will edit this file in the next step, but for now press enter to continue. 60 | ? Press enter to continue 61 | ? Would you like to restrict API access? N 62 | ? Would you like to add another path? N 63 | ``` 64 | 65 | Next, update the function with the following changes: 66 | 67 | ```javascript 68 | /* amplify/backend/function//src/app.js */ 69 | 70 | /* region and table name available in comments of lambda function */ 71 | const region = process.env.REGION 72 | const ddb_table_name = process.env. 73 | 74 | const AWS = require('aws-sdk') 75 | const uuid = require('uuid/v4') 76 | const docClient = new AWS.DynamoDB.DocumentClient({region}) 77 | 78 | // update the /products "get" and "post" endpoints 79 | 80 | app.get('/products', async function(req, res) { 81 | try { 82 | var params = { 83 | TableName: ddb_table_name, 84 | } 85 | const data = await docClient.scan(params).promise() 86 | res.json({ 87 | data: data 88 | }) 89 | } catch (err) { 90 | res.json({ 91 | error: err 92 | }) 93 | } 94 | }) 95 | 96 | app.post('/products', async function(req, res) { 97 | const { body } = req 98 | try { 99 | const input = { ...body, id: uuid() } 100 | var params = { 101 | TableName: ddb_table_name, 102 | Item: input 103 | } 104 | await docClient.put(params).promise() 105 | res.json({ 106 | success: 'item saved to database..' 107 | }) 108 | } catch (err) { 109 | res.json({ 110 | error: err 111 | }) 112 | } 113 | }) 114 | ``` 115 | 116 | Next, update the dependencies in the lambda function to include __uuid__: 117 | 118 | __amplify/backend/function//src/package.json__ 119 | 120 | ```json 121 | "dependencies": { 122 | "aws-serverless-express": "^3.3.5", 123 | "body-parser": "^1.17.1", 124 | "express": "^4.15.2", 125 | "uuid": "^3.3.3" 126 | }, 127 | ``` 128 | 129 | Next, deploy the back end: 130 | 131 | ```sh 132 | $ amplify push 133 | ``` 134 | 135 | ### Client-side code 136 | 137 | Next, open __src/index.js__ and add the following: 138 | 139 | ```javascript 140 | import Amplify from 'aws-amplify' 141 | import config from './aws-exports' 142 | Amplify.configure(config) 143 | ``` 144 | 145 | Next, open __src/App.js__ and add the following code: 146 | 147 | ```javascript 148 | import React, { useEffect, useState } from 'react'; 149 | import logo from './logo.svg'; 150 | import './App.css'; 151 | import { API } from 'aws-amplify' 152 | 153 | const initialState = { 154 | name: '', 155 | description: '', 156 | price: '' 157 | } 158 | 159 | function App() { 160 | const [products, setProducts] = useState([]) 161 | const [product, updateProduct] = useState(initialState) 162 | async function fetchProducts() { 163 | const products = await API.get('productapi', '/products') 164 | setProducts(products.data.Items) 165 | } 166 | async function createProduct() { 167 | const { name, description, price } = product 168 | if (!name || !description || !price) return 169 | const data = { 170 | body: { ...product, price: parseInt(product.price) } 171 | } 172 | await API.post('productapi', '/products', data) 173 | console.log('product successfully created...') 174 | updateProduct(initialState) 175 | fetchProducts() 176 | } 177 | const updateProductInput = key => event => { 178 | updateProduct({ ...product, [key]: event.target.value }) 179 | } 180 | useEffect(() => { 181 | fetchProducts() 182 | }, []) 183 | return ( 184 |
185 | { 186 | products.map((product, index) => ( 187 |
188 |

{product.name}

189 |

{product.description}

190 |

${product.price}

191 |
192 | )) 193 | } 194 |
195 | 201 | 207 | 213 | 214 |
215 |
216 | ); 217 | } 218 | 219 | const button = { 220 | padding: '10px 40px', 221 | width: 400, 222 | margin: '0px auto' 223 | } 224 | 225 | const input = { 226 | padding: 7, 227 | width: 400, 228 | margin: '0px auto 6px' 229 | } 230 | 231 | const form = { 232 | display: 'flex', flexDirection: 'column', padding: 60 233 | } 234 | 235 | export default App; 236 | ``` 237 | 238 | ### Test everything out 239 | 240 | ```sh 241 | $ npm start 242 | ``` 243 | -------------------------------------------------------------------------------- /amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "testing", 3 | "version": "2.0", 4 | "frontend": "javascript", 5 | "javascript": { 6 | "framework": "react", 7 | "config": { 8 | "SourceDir": "src", 9 | "DistributionDir": "build", 10 | "BuildCommand": "npm run-script build", 11 | "StartCommand": "npm run-script start" 12 | } 13 | }, 14 | "providers": [ 15 | "awscloudformation" 16 | ] 17 | } -------------------------------------------------------------------------------- /amplify/backend/api/api7d641705/api-params.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": [ 3 | { 4 | "name": "/products", 5 | "lambdaFunction": "testing067f3506", 6 | "privacy": { 7 | "open": true 8 | } 9 | } 10 | ], 11 | "resourceName": "api7d641705", 12 | "apiName": "api7d641705", 13 | "functionArns": [ 14 | { 15 | "lambdaFunction": "testing067f3506" 16 | } 17 | ], 18 | "privacy": { 19 | "auth": 0, 20 | "unauth": 0, 21 | "authRoleName": "amplify-testing-testenv-142557-authRole", 22 | "unAuthRoleName": "amplify-testing-testenv-142557-unauthRole" 23 | }, 24 | "dependsOn": [ 25 | { 26 | "category": "function", 27 | "resourceName": "testing067f3506", 28 | "attributes": [ 29 | "Name", 30 | "Arn" 31 | ] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /amplify/backend/api/api7d641705/api7d641705-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "API Gateway resource stack creation using Amplify CLI", 4 | 5 | "Parameters": { 6 | "authRoleName": { 7 | "Type": "String" 8 | }, 9 | "unauthRoleName": { 10 | "Type": "String" 11 | }, 12 | "env": { 13 | "Type": "String" 14 | }, 15 | 16 | 17 | "functiontesting067f3506Name": { 18 | "Type": "String", 19 | "Default": "functiontesting067f3506Name" 20 | }, 21 | 22 | 23 | "functiontesting067f3506Arn": { 24 | "Type": "String", 25 | "Default": "functiontesting067f3506Arn" 26 | } 27 | 28 | 29 | 30 | 31 | }, 32 | "Conditions": { 33 | "ShouldNotCreateEnvResources": { 34 | "Fn::Equals": [ 35 | { 36 | "Ref": "env" 37 | }, 38 | "NONE" 39 | ] 40 | } 41 | }, 42 | "Resources": { 43 | 44 | 45 | 46 | 47 | 48 | "api7d641705": { 49 | "Type": "AWS::ApiGateway::RestApi", 50 | "Properties": { 51 | "Description": "", 52 | "Name": "api7d641705", 53 | "Body": { 54 | "swagger": "2.0", 55 | "info": { 56 | "version": "2018-05-24T17:52:00Z", 57 | "title": "api7d641705" 58 | }, 59 | "host": { 60 | "Fn::Join": [ 61 | "", 62 | [ 63 | "apigateway.", 64 | { 65 | "Ref": "AWS::Region" 66 | }, 67 | ".amazonaws.com" 68 | ] 69 | ] 70 | }, 71 | "basePath": { 72 | "Fn::If": [ 73 | "ShouldNotCreateEnvResources", 74 | "/Prod", 75 | { 76 | "Fn::Join": [ 77 | "", 78 | [ 79 | "/", 80 | { 81 | "Ref": "env" 82 | } 83 | ] 84 | ] 85 | } 86 | ] 87 | }, 88 | "schemes": [ 89 | "https" 90 | ], 91 | "paths": { 92 | 93 | "/products": { 94 | "options": { 95 | "consumes": [ 96 | "application/json" 97 | ], 98 | "produces": [ 99 | "application/json" 100 | ], 101 | "responses": { 102 | "200": { 103 | "description": "200 response", 104 | "headers": { 105 | "Access-Control-Allow-Origin": { 106 | "type": "string" 107 | }, 108 | "Access-Control-Allow-Methods": { 109 | "type": "string" 110 | }, 111 | "Access-Control-Allow-Headers": { 112 | "type": "string" 113 | } 114 | } 115 | } 116 | }, 117 | "x-amazon-apigateway-integration": { 118 | "responses": { 119 | "default": { 120 | "statusCode": "200", 121 | "responseParameters": { 122 | "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", 123 | "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'", 124 | "method.response.header.Access-Control-Allow-Origin": "'*'" 125 | } 126 | } 127 | }, 128 | "requestTemplates": { 129 | "application/json": "{\"statusCode\": 200}" 130 | }, 131 | "passthroughBehavior": "when_no_match", 132 | "type": "mock" 133 | } 134 | }, 135 | "x-amazon-apigateway-any-method": { 136 | "consumes": [ 137 | "application/json" 138 | ], 139 | "produces": [ 140 | "application/json" 141 | ], 142 | "parameters": [ 143 | { 144 | "in": "body", 145 | "name": "RequestSchema", 146 | "required": false, 147 | "schema": { 148 | "$ref": "#/definitions/RequestSchema" 149 | } 150 | } 151 | ], 152 | "responses": { 153 | "200": { 154 | "description": "200 response", 155 | "schema": { 156 | "$ref": "#/definitions/ResponseSchema" 157 | } 158 | } 159 | }, 160 | 161 | "x-amazon-apigateway-integration": { 162 | "responses": { 163 | "default": { 164 | "statusCode": "200" 165 | } 166 | }, 167 | "uri": { 168 | "Fn::Join": [ 169 | "", 170 | [ 171 | "arn:aws:apigateway:", 172 | { 173 | "Ref": "AWS::Region" 174 | }, 175 | ":lambda:path/2015-03-31/functions/", 176 | 177 | { 178 | 179 | "Ref": "functiontesting067f3506Arn" 180 | }, 181 | 182 | "/invocations" 183 | ] 184 | ] 185 | }, 186 | "passthroughBehavior": "when_no_match", 187 | "httpMethod": "POST", 188 | "type": "aws_proxy" 189 | } 190 | } 191 | }, 192 | "/products/{proxy+}": { 193 | "options": { 194 | "consumes": [ 195 | "application/json" 196 | ], 197 | "produces": [ 198 | "application/json" 199 | ], 200 | "responses": { 201 | "200": { 202 | "description": "200 response", 203 | "headers": { 204 | "Access-Control-Allow-Origin": { 205 | "type": "string" 206 | }, 207 | "Access-Control-Allow-Methods": { 208 | "type": "string" 209 | }, 210 | "Access-Control-Allow-Headers": { 211 | "type": "string" 212 | } 213 | } 214 | } 215 | }, 216 | "x-amazon-apigateway-integration": { 217 | "responses": { 218 | "default": { 219 | "statusCode": "200", 220 | "responseParameters": { 221 | "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'", 222 | "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'", 223 | "method.response.header.Access-Control-Allow-Origin": "'*'" 224 | } 225 | } 226 | }, 227 | "requestTemplates": { 228 | "application/json": "{\"statusCode\": 200}" 229 | }, 230 | "passthroughBehavior": "when_no_match", 231 | "type": "mock" 232 | } 233 | }, 234 | "x-amazon-apigateway-any-method": { 235 | "consumes": [ 236 | "application/json" 237 | ], 238 | "produces": [ 239 | "application/json" 240 | ], 241 | "parameters": [ 242 | { 243 | "in": "body", 244 | "name": "RequestSchema", 245 | "required": false, 246 | "schema": { 247 | "$ref": "#/definitions/RequestSchema" 248 | } 249 | } 250 | ], 251 | "responses": { 252 | "200": { 253 | "description": "200 response", 254 | "schema": { 255 | "$ref": "#/definitions/ResponseSchema" 256 | } 257 | } 258 | }, 259 | 260 | "x-amazon-apigateway-integration": { 261 | "responses": { 262 | "default": { 263 | "statusCode": "200" 264 | } 265 | }, 266 | "uri": { 267 | "Fn::Join": [ 268 | "", 269 | [ 270 | "arn:aws:apigateway:", 271 | { 272 | "Ref": "AWS::Region" 273 | }, 274 | ":lambda:path/2015-03-31/functions/", 275 | 276 | { 277 | 278 | "Ref": "functiontesting067f3506Arn" 279 | }, 280 | 281 | "/invocations" 282 | ] 283 | ] 284 | }, 285 | "passthroughBehavior": "when_no_match", 286 | "httpMethod": "POST", 287 | "type": "aws_proxy" 288 | } 289 | } 290 | } 291 | 292 | }, 293 | "securityDefinitions": { 294 | "sigv4": { 295 | "type": "apiKey", 296 | "name": "Authorization", 297 | "in": "header", 298 | "x-amazon-apigateway-authtype": "awsSigv4" 299 | } 300 | }, 301 | "definitions": { 302 | "RequestSchema": { 303 | "type": "object", 304 | "required": [ 305 | "request" 306 | ], 307 | "properties": { 308 | "request": { 309 | "type": "string" 310 | } 311 | }, 312 | "title": "Request Schema" 313 | }, 314 | "ResponseSchema": { 315 | "type": "object", 316 | "required": [ 317 | "response" 318 | ], 319 | "properties": { 320 | "response": { 321 | "type": "string" 322 | } 323 | }, 324 | "title": "Response Schema" 325 | } 326 | } 327 | }, 328 | "FailOnWarnings": true 329 | } 330 | }, 331 | 332 | 333 | 334 | 335 | "functiontesting067f3506Permissionapi7d641705": { 336 | "Type": "AWS::Lambda::Permission", 337 | "Properties": { 338 | "FunctionName": 339 | { 340 | "Ref": "functiontesting067f3506Name" 341 | }, 342 | 343 | "Action": "lambda:InvokeFunction", 344 | "Principal": "apigateway.amazonaws.com", 345 | "SourceArn": { 346 | "Fn::Join": [ 347 | "", 348 | [ 349 | "arn:aws:execute-api:", 350 | { 351 | "Ref": "AWS::Region" 352 | }, 353 | ":", 354 | { 355 | "Ref": "AWS::AccountId" 356 | }, 357 | ":", 358 | { 359 | "Ref": "api7d641705" 360 | }, 361 | "/*/*/*" 362 | ] 363 | ] 364 | } 365 | } 366 | }, 367 | 368 | 369 | 370 | "DeploymentAPIGWapi7d641705": { 371 | "Type": "AWS::ApiGateway::Deployment", 372 | "Properties": { 373 | "Description": "The Development stage deployment of your API.", 374 | "StageName": { 375 | "Fn::If": [ 376 | "ShouldNotCreateEnvResources", 377 | "Prod", 378 | { 379 | "Ref": "env" 380 | } 381 | ] 382 | }, 383 | "RestApiId": { 384 | "Ref": "api7d641705" 385 | } 386 | } 387 | } 388 | }, 389 | "Outputs": { 390 | "RootUrl": { 391 | "Description": "Root URL of the API gateway", 392 | "Value": {"Fn::Join": ["", ["https://", {"Ref": "api7d641705"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} 393 | }, 394 | "ApiName": { 395 | "Description": "API Friendly name", 396 | "Value": "api7d641705" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /amplify/backend/api/api7d641705/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "authRoleName": { 3 | "Ref": "AuthRoleName" 4 | }, 5 | "unauthRoleName": { 6 | "Ref": "UnauthRoleName" 7 | } 8 | } -------------------------------------------------------------------------------- /amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "storage": { 3 | "dynamob1b4533e": { 4 | "service": "DynamoDB", 5 | "providerPlugin": "awscloudformation" 6 | } 7 | }, 8 | "function": { 9 | "testing067f3506": { 10 | "service": "Lambda", 11 | "providerPlugin": "awscloudformation", 12 | "build": true, 13 | "dependsOn": [ 14 | { 15 | "category": "storage", 16 | "resourceName": "dynamob1b4533e", 17 | "attributes": [ 18 | "Name", 19 | "Arn" 20 | ] 21 | } 22 | ] 23 | } 24 | }, 25 | "api": { 26 | "api7d641705": { 27 | "service": "API Gateway", 28 | "providerPlugin": "awscloudformation", 29 | "dependsOn": [ 30 | { 31 | "category": "function", 32 | "resourceName": "testing067f3506", 33 | "attributes": [ 34 | "Name", 35 | "Arn" 36 | ] 37 | } 38 | ] 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/function-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "storage": { 4 | "dynamob1b4533e": [ 5 | "create", 6 | "read", 7 | "update", 8 | "delete" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/src/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 - 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at 4 | http://aws.amazon.com/apache2.0/ 5 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6 | See the License for the specific language governing permissions and limitations under the License. 7 | */ 8 | 9 | 10 | /* Amplify Params - DO NOT EDIT 11 | You can access the following resource attributes as environment variables from your Lambda function 12 | var environment = process.env.ENV 13 | var region = process.env.REGION 14 | var storageDynamob1b4533eName = process.env.STORAGE_DYNAMOB1B4533E_NAME 15 | var storageDynamob1b4533eArn = process.env.STORAGE_DYNAMOB1B4533E_ARN 16 | 17 | Amplify Params - DO NOT EDIT */ 18 | 19 | var express = require('express') 20 | var bodyParser = require('body-parser') 21 | var awsServerlessExpressMiddleware = require('aws-serverless-express/middleware') 22 | 23 | const AWS = require('aws-sdk') 24 | const uuid = require('uuid/v4') 25 | var region = process.env.REGION 26 | var ddb_table_name = process.env.STORAGE_DYNAMOB1B4533E_NAME 27 | const docClient = new AWS.DynamoDB.DocumentClient({region}) 28 | 29 | // declare a new express app 30 | var app = express() 31 | app.use(bodyParser.json()) 32 | app.use(awsServerlessExpressMiddleware.eventContext()) 33 | 34 | // Enable CORS for all methods 35 | app.use(function(req, res, next) { 36 | res.header("Access-Control-Allow-Origin", "*") 37 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") 38 | next() 39 | }); 40 | 41 | 42 | /********************** 43 | * Example get method * 44 | **********************/ 45 | 46 | app.get('/products', async function(req, res) { 47 | try { 48 | var params = { 49 | TableName: ddb_table_name, 50 | } 51 | const data = await docClient.scan(params).promise() 52 | res.json({ 53 | data: data 54 | }) 55 | } catch (err) { 56 | res.json({ 57 | error: err 58 | }) 59 | } 60 | }) 61 | 62 | app.get('/products/*', function(req, res) { 63 | // Add your code here 64 | res.json({success: 'get call succeed!', url: req.url}); 65 | }); 66 | 67 | /**************************** 68 | * Example post method * 69 | ****************************/ 70 | 71 | app.post('/products', async function(req, res) { 72 | const { body } = req 73 | try { 74 | const input = { ...body, id: uuid() } 75 | var params = { 76 | TableName: ddb_table_name, 77 | Item: input 78 | } 79 | await docClient.put(params).promise() 80 | res.json({ 81 | success: 'item saved to database..' 82 | }) 83 | } catch (err) { 84 | res.json({ 85 | error: err 86 | }) 87 | } 88 | }); 89 | 90 | 91 | app.post('/products/*', function(req, res) { 92 | // Add your code here 93 | res.json({success: 'post call succeed!', url: req.url, body: req.body}) 94 | }); 95 | 96 | /**************************** 97 | * Example put method * 98 | ****************************/ 99 | 100 | app.put('/products', function(req, res) { 101 | // Add your code here 102 | res.json({success: 'put call succeed!', url: req.url, body: req.body}) 103 | }); 104 | 105 | app.put('/products/*', function(req, res) { 106 | // Add your code here 107 | res.json({success: 'put call succeed!', url: req.url, body: req.body}) 108 | }); 109 | 110 | /**************************** 111 | * Example delete method * 112 | ****************************/ 113 | 114 | app.delete('/products', function(req, res) { 115 | // Add your code here 116 | res.json({success: 'delete call succeed!', url: req.url}); 117 | }); 118 | 119 | app.delete('/products/*', function(req, res) { 120 | // Add your code here 121 | res.json({success: 'delete call succeed!', url: req.url}); 122 | }); 123 | 124 | app.listen(3000, function() { 125 | console.log("App started") 126 | }); 127 | 128 | // Export the app object. When executing the application local this does nothing. However, 129 | // to port it to AWS Lambda we will create a wrapper around that will load the app from 130 | // this file 131 | module.exports = app 132 | -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/src/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": "value1", 3 | "key2": "value2", 4 | "key3": "value3" 5 | } -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/src/index.js: -------------------------------------------------------------------------------- 1 | const awsServerlessExpress = require('aws-serverless-express'); 2 | const app = require('./app'); 3 | 4 | const server = awsServerlessExpress.createServer(app); 5 | 6 | exports.handler = (event, context) => { 7 | console.log(`EVENT: ${JSON.stringify(event)}`); 8 | awsServerlessExpress.proxy(server, event, context); 9 | }; 10 | -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/src/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testing067f3506", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "aws-serverless-express": { 22 | "version": "3.3.6", 23 | "resolved": "https://registry.npmjs.org/aws-serverless-express/-/aws-serverless-express-3.3.6.tgz", 24 | "integrity": "sha512-VTn8YQpPpMAEdMeGjyaSygy7Rc0057C9MUjeZION0NBqmwTyphpu9Tc5DCHRNF4qNFQ9x1xcOte6OXKzJvvDhw==", 25 | "requires": { 26 | "binary-case": "^1.0.0", 27 | "type-is": "^1.6.16" 28 | } 29 | }, 30 | "binary-case": { 31 | "version": "1.1.4", 32 | "resolved": "https://registry.npmjs.org/binary-case/-/binary-case-1.1.4.tgz", 33 | "integrity": "sha512-9Kq8m6NZTAgy05Ryuh7U3Qc4/ujLQU1AZ5vMw4cr3igTdi5itZC6kCNrRr2X8NzPiDn2oUIFTfa71DKMnue/Zg==" 34 | }, 35 | "body-parser": { 36 | "version": "1.19.0", 37 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 38 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 39 | "requires": { 40 | "bytes": "3.1.0", 41 | "content-type": "~1.0.4", 42 | "debug": "2.6.9", 43 | "depd": "~1.1.2", 44 | "http-errors": "1.7.2", 45 | "iconv-lite": "0.4.24", 46 | "on-finished": "~2.3.0", 47 | "qs": "6.7.0", 48 | "raw-body": "2.4.0", 49 | "type-is": "~1.6.17" 50 | } 51 | }, 52 | "bytes": { 53 | "version": "3.1.0", 54 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 55 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 56 | }, 57 | "content-disposition": { 58 | "version": "0.5.3", 59 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 60 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 61 | "requires": { 62 | "safe-buffer": "5.1.2" 63 | } 64 | }, 65 | "content-type": { 66 | "version": "1.0.4", 67 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 68 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 69 | }, 70 | "cookie": { 71 | "version": "0.4.0", 72 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 73 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 74 | }, 75 | "cookie-signature": { 76 | "version": "1.0.6", 77 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 78 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 79 | }, 80 | "debug": { 81 | "version": "2.6.9", 82 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 83 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 84 | "requires": { 85 | "ms": "2.0.0" 86 | } 87 | }, 88 | "depd": { 89 | "version": "1.1.2", 90 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 91 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 92 | }, 93 | "destroy": { 94 | "version": "1.0.4", 95 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 96 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 97 | }, 98 | "ee-first": { 99 | "version": "1.1.1", 100 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 101 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 102 | }, 103 | "encodeurl": { 104 | "version": "1.0.2", 105 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 106 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 107 | }, 108 | "escape-html": { 109 | "version": "1.0.3", 110 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 111 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 112 | }, 113 | "etag": { 114 | "version": "1.8.1", 115 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 116 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 117 | }, 118 | "express": { 119 | "version": "4.17.1", 120 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 121 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 122 | "requires": { 123 | "accepts": "~1.3.7", 124 | "array-flatten": "1.1.1", 125 | "body-parser": "1.19.0", 126 | "content-disposition": "0.5.3", 127 | "content-type": "~1.0.4", 128 | "cookie": "0.4.0", 129 | "cookie-signature": "1.0.6", 130 | "debug": "2.6.9", 131 | "depd": "~1.1.2", 132 | "encodeurl": "~1.0.2", 133 | "escape-html": "~1.0.3", 134 | "etag": "~1.8.1", 135 | "finalhandler": "~1.1.2", 136 | "fresh": "0.5.2", 137 | "merge-descriptors": "1.0.1", 138 | "methods": "~1.1.2", 139 | "on-finished": "~2.3.0", 140 | "parseurl": "~1.3.3", 141 | "path-to-regexp": "0.1.7", 142 | "proxy-addr": "~2.0.5", 143 | "qs": "6.7.0", 144 | "range-parser": "~1.2.1", 145 | "safe-buffer": "5.1.2", 146 | "send": "0.17.1", 147 | "serve-static": "1.14.1", 148 | "setprototypeof": "1.1.1", 149 | "statuses": "~1.5.0", 150 | "type-is": "~1.6.18", 151 | "utils-merge": "1.0.1", 152 | "vary": "~1.1.2" 153 | } 154 | }, 155 | "finalhandler": { 156 | "version": "1.1.2", 157 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 158 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 159 | "requires": { 160 | "debug": "2.6.9", 161 | "encodeurl": "~1.0.2", 162 | "escape-html": "~1.0.3", 163 | "on-finished": "~2.3.0", 164 | "parseurl": "~1.3.3", 165 | "statuses": "~1.5.0", 166 | "unpipe": "~1.0.0" 167 | } 168 | }, 169 | "forwarded": { 170 | "version": "0.1.2", 171 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 172 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 173 | }, 174 | "fresh": { 175 | "version": "0.5.2", 176 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 177 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 178 | }, 179 | "http-errors": { 180 | "version": "1.7.2", 181 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 182 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 183 | "requires": { 184 | "depd": "~1.1.2", 185 | "inherits": "2.0.3", 186 | "setprototypeof": "1.1.1", 187 | "statuses": ">= 1.5.0 < 2", 188 | "toidentifier": "1.0.0" 189 | } 190 | }, 191 | "iconv-lite": { 192 | "version": "0.4.24", 193 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 194 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 195 | "requires": { 196 | "safer-buffer": ">= 2.1.2 < 3" 197 | } 198 | }, 199 | "inherits": { 200 | "version": "2.0.3", 201 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 202 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 203 | }, 204 | "ipaddr.js": { 205 | "version": "1.9.0", 206 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 207 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 208 | }, 209 | "media-typer": { 210 | "version": "0.3.0", 211 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 212 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 213 | }, 214 | "merge-descriptors": { 215 | "version": "1.0.1", 216 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 217 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 218 | }, 219 | "methods": { 220 | "version": "1.1.2", 221 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 222 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 223 | }, 224 | "mime": { 225 | "version": "1.6.0", 226 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 227 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 228 | }, 229 | "mime-db": { 230 | "version": "1.42.0", 231 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", 232 | "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" 233 | }, 234 | "mime-types": { 235 | "version": "2.1.25", 236 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", 237 | "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", 238 | "requires": { 239 | "mime-db": "1.42.0" 240 | } 241 | }, 242 | "ms": { 243 | "version": "2.0.0", 244 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 245 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 246 | }, 247 | "negotiator": { 248 | "version": "0.6.2", 249 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 250 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 251 | }, 252 | "on-finished": { 253 | "version": "2.3.0", 254 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 255 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 256 | "requires": { 257 | "ee-first": "1.1.1" 258 | } 259 | }, 260 | "parseurl": { 261 | "version": "1.3.3", 262 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 263 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 264 | }, 265 | "path-to-regexp": { 266 | "version": "0.1.7", 267 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 268 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 269 | }, 270 | "proxy-addr": { 271 | "version": "2.0.5", 272 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 273 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 274 | "requires": { 275 | "forwarded": "~0.1.2", 276 | "ipaddr.js": "1.9.0" 277 | } 278 | }, 279 | "qs": { 280 | "version": "6.7.0", 281 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 282 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 283 | }, 284 | "range-parser": { 285 | "version": "1.2.1", 286 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 287 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 288 | }, 289 | "raw-body": { 290 | "version": "2.4.0", 291 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 292 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 293 | "requires": { 294 | "bytes": "3.1.0", 295 | "http-errors": "1.7.2", 296 | "iconv-lite": "0.4.24", 297 | "unpipe": "1.0.0" 298 | } 299 | }, 300 | "safe-buffer": { 301 | "version": "5.1.2", 302 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 303 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 304 | }, 305 | "safer-buffer": { 306 | "version": "2.1.2", 307 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 308 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 309 | }, 310 | "send": { 311 | "version": "0.17.1", 312 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 313 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 314 | "requires": { 315 | "debug": "2.6.9", 316 | "depd": "~1.1.2", 317 | "destroy": "~1.0.4", 318 | "encodeurl": "~1.0.2", 319 | "escape-html": "~1.0.3", 320 | "etag": "~1.8.1", 321 | "fresh": "0.5.2", 322 | "http-errors": "~1.7.2", 323 | "mime": "1.6.0", 324 | "ms": "2.1.1", 325 | "on-finished": "~2.3.0", 326 | "range-parser": "~1.2.1", 327 | "statuses": "~1.5.0" 328 | }, 329 | "dependencies": { 330 | "ms": { 331 | "version": "2.1.1", 332 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 333 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 334 | } 335 | } 336 | }, 337 | "serve-static": { 338 | "version": "1.14.1", 339 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 340 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 341 | "requires": { 342 | "encodeurl": "~1.0.2", 343 | "escape-html": "~1.0.3", 344 | "parseurl": "~1.3.3", 345 | "send": "0.17.1" 346 | } 347 | }, 348 | "setprototypeof": { 349 | "version": "1.1.1", 350 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 351 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 352 | }, 353 | "statuses": { 354 | "version": "1.5.0", 355 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 356 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 357 | }, 358 | "toidentifier": { 359 | "version": "1.0.0", 360 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 361 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 362 | }, 363 | "type-is": { 364 | "version": "1.6.18", 365 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 366 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 367 | "requires": { 368 | "media-typer": "0.3.0", 369 | "mime-types": "~2.1.24" 370 | } 371 | }, 372 | "unpipe": { 373 | "version": "1.0.0", 374 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 375 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 376 | }, 377 | "utils-merge": { 378 | "version": "1.0.1", 379 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 380 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 381 | }, 382 | "uuid": { 383 | "version": "3.3.3", 384 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 385 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 386 | }, 387 | "vary": { 388 | "version": "1.1.2", 389 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 390 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testing067f3506", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "aws-serverless-express": "^3.3.5", 8 | "body-parser": "^1.17.1", 9 | "express": "^4.15.2", 10 | "uuid": "^3.3.3" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "author": "", 17 | "license": "ISC" 18 | } 19 | -------------------------------------------------------------------------------- /amplify/backend/function/testing067f3506/testing067f3506-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Lambda resource stack creation using Amplify CLI", 4 | "Parameters": { 5 | "env": { 6 | "Type": "String" 7 | }, 8 | "storagedynamob1b4533eName": { 9 | "Type": "String", 10 | "Default": "storagedynamob1b4533eName" 11 | }, 12 | "storagedynamob1b4533eArn": { 13 | "Type": "String", 14 | "Default": "storagedynamob1b4533eArn" 15 | } 16 | }, 17 | "Conditions": { 18 | "ShouldNotCreateEnvResources": { 19 | "Fn::Equals": [ 20 | { 21 | "Ref": "env" 22 | }, 23 | "NONE" 24 | ] 25 | } 26 | }, 27 | "Resources": { 28 | "LambdaFunction": { 29 | "Type": "AWS::Lambda::Function", 30 | "Metadata": { 31 | "aws:asset:path": "./src", 32 | "aws:asset:property": "Code" 33 | }, 34 | "Properties": { 35 | "Handler": "index.handler", 36 | "FunctionName": { 37 | "Fn::If": [ 38 | "ShouldNotCreateEnvResources", 39 | "testing067f3506", 40 | { 41 | "Fn::Join": [ 42 | "", 43 | [ 44 | "testing067f3506", 45 | "-", 46 | { 47 | "Ref": "env" 48 | } 49 | ] 50 | ] 51 | } 52 | ] 53 | }, 54 | "Environment": { 55 | "Variables": { 56 | "ENV": { 57 | "Ref": "env" 58 | }, 59 | "REGION": { 60 | "Ref": "AWS::Region" 61 | }, 62 | "STORAGE_DYNAMOB1B4533E_NAME": { 63 | "Ref": "storagedynamob1b4533eName" 64 | }, 65 | "STORAGE_DYNAMOB1B4533E_ARN": { 66 | "Ref": "storagedynamob1b4533eArn" 67 | } 68 | } 69 | }, 70 | "Role": { 71 | "Fn::GetAtt": [ 72 | "LambdaExecutionRole", 73 | "Arn" 74 | ] 75 | }, 76 | "Runtime": "nodejs10.x", 77 | "Timeout": "25", 78 | "Code": { 79 | "S3Bucket": "amplify-testing-testenv-142557-deployment", 80 | "S3Key": "amplify-builds/testing067f3506-38454554344539706776-build.zip" 81 | } 82 | } 83 | }, 84 | "LambdaExecutionRole": { 85 | "Type": "AWS::IAM::Role", 86 | "Properties": { 87 | "RoleName": { 88 | "Fn::If": [ 89 | "ShouldNotCreateEnvResources", 90 | "testingLambdaRole9ad35d52", 91 | { 92 | "Fn::Join": [ 93 | "", 94 | [ 95 | "testingLambdaRole9ad35d52", 96 | "-", 97 | { 98 | "Ref": "env" 99 | } 100 | ] 101 | ] 102 | } 103 | ] 104 | }, 105 | "AssumeRolePolicyDocument": { 106 | "Version": "2012-10-17", 107 | "Statement": [ 108 | { 109 | "Effect": "Allow", 110 | "Principal": { 111 | "Service": [ 112 | "lambda.amazonaws.com" 113 | ] 114 | }, 115 | "Action": [ 116 | "sts:AssumeRole" 117 | ] 118 | } 119 | ] 120 | } 121 | } 122 | }, 123 | "lambdaexecutionpolicy": { 124 | "DependsOn": [ 125 | "LambdaExecutionRole" 126 | ], 127 | "Type": "AWS::IAM::Policy", 128 | "Properties": { 129 | "PolicyName": "lambda-execution-policy", 130 | "Roles": [ 131 | { 132 | "Ref": "LambdaExecutionRole" 133 | } 134 | ], 135 | "PolicyDocument": { 136 | "Version": "2012-10-17", 137 | "Statement": [ 138 | { 139 | "Effect": "Allow", 140 | "Action": [ 141 | "logs:CreateLogGroup", 142 | "logs:CreateLogStream", 143 | "logs:PutLogEvents" 144 | ], 145 | "Resource": { 146 | "Fn::Sub": [ 147 | "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", 148 | { 149 | "region": { 150 | "Ref": "AWS::Region" 151 | }, 152 | "account": { 153 | "Ref": "AWS::AccountId" 154 | }, 155 | "lambda": { 156 | "Ref": "LambdaFunction" 157 | } 158 | } 159 | ] 160 | } 161 | } 162 | ] 163 | } 164 | } 165 | }, 166 | "AmplifyResourcesPolicy": { 167 | "DependsOn": [ 168 | "LambdaExecutionRole" 169 | ], 170 | "Type": "AWS::IAM::Policy", 171 | "Properties": { 172 | "PolicyName": "amplify-lambda-execution-policy", 173 | "Roles": [ 174 | { 175 | "Ref": "LambdaExecutionRole" 176 | } 177 | ], 178 | "PolicyDocument": { 179 | "Version": "2012-10-17", 180 | "Statement": [ 181 | { 182 | "Effect": "Allow", 183 | "Action": [ 184 | "dynamodb:Put*", 185 | "dynamodb:Create*", 186 | "dynamodb:BatchWriteItem", 187 | "dynamodb:Get*", 188 | "dynamodb:BatchGetItem", 189 | "dynamodb:List*", 190 | "dynamodb:Describe*", 191 | "dynamodb:Scan", 192 | "dynamodb:Query", 193 | "dynamodb:Update*", 194 | "dynamodb:RestoreTable*", 195 | "dynamodb:Delete*" 196 | ], 197 | "Resource": [ 198 | { 199 | "Ref": "storagedynamob1b4533eArn" 200 | } 201 | ] 202 | } 203 | ] 204 | } 205 | } 206 | } 207 | }, 208 | "Outputs": { 209 | "Name": { 210 | "Value": { 211 | "Ref": "LambdaFunction" 212 | } 213 | }, 214 | "Arn": { 215 | "Value": { 216 | "Fn::GetAtt": [ 217 | "LambdaFunction", 218 | "Arn" 219 | ] 220 | } 221 | }, 222 | "Region": { 223 | "Value": { 224 | "Ref": "AWS::Region" 225 | } 226 | }, 227 | "LambdaExecutionRole": { 228 | "Value": { 229 | "Ref": "LambdaExecutionRole" 230 | } 231 | } 232 | } 233 | } -------------------------------------------------------------------------------- /amplify/backend/storage/dynamob1b4533e/dynamob1b4533e-cloudformation-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "DynamoDB resource stack creation using Amplify CLI", 4 | "Parameters": { 5 | "partitionKeyName": { 6 | "Type": "String" 7 | }, 8 | "partitionKeyType": { 9 | "Type": "String" 10 | }, 11 | "env": { 12 | "Type": "String" 13 | }, 14 | 15 | "sortKeyName": { 16 | "Type": "String" 17 | }, 18 | "sortKeyType": { 19 | "Type": "String" 20 | }, 21 | 22 | "tableName": { 23 | "Type": "String" 24 | } 25 | }, 26 | "Conditions": { 27 | "ShouldNotCreateEnvResources": { 28 | "Fn::Equals": [ 29 | { 30 | "Ref": "env" 31 | }, 32 | "NONE" 33 | ] 34 | } 35 | }, 36 | "Resources": { 37 | "DynamoDBTable": { 38 | "Type": "AWS::DynamoDB::Table", 39 | "Properties": { 40 | "AttributeDefinitions": [ 41 | 42 | { 43 | "AttributeName": "id", 44 | "AttributeType": "S" 45 | } , 46 | 47 | { 48 | "AttributeName": "name", 49 | "AttributeType": "S" 50 | } 51 | 52 | ], 53 | "KeySchema": [ 54 | 55 | { 56 | "AttributeName": "id", 57 | "KeyType": "HASH" 58 | } , 59 | 60 | { 61 | "AttributeName": "name", 62 | "KeyType": "RANGE" 63 | } 64 | 65 | ], 66 | "ProvisionedThroughput": { 67 | "ReadCapacityUnits": "5", 68 | "WriteCapacityUnits": "5" 69 | }, 70 | "StreamSpecification": { 71 | "StreamViewType": "NEW_IMAGE" 72 | }, 73 | "TableName": { 74 | "Fn::If": [ 75 | "ShouldNotCreateEnvResources", 76 | { 77 | "Ref": "tableName" 78 | }, 79 | { 80 | 81 | "Fn::Join": [ 82 | "", 83 | [ 84 | { 85 | "Ref": "tableName" 86 | }, 87 | "-", 88 | { 89 | "Ref": "env" 90 | } 91 | ] 92 | ] 93 | } 94 | ] 95 | } 96 | 97 | } 98 | } 99 | }, 100 | "Outputs": { 101 | "Name": { 102 | "Value": { 103 | "Ref": "DynamoDBTable" 104 | } 105 | }, 106 | "Arn": { 107 | "Value": { 108 | "Fn::GetAtt": [ 109 | "DynamoDBTable", 110 | "Arn" 111 | ] 112 | } 113 | }, 114 | "StreamArn": { 115 | "Value": { 116 | "Fn::GetAtt": [ 117 | "DynamoDBTable", 118 | "StreamArn" 119 | ] 120 | } 121 | }, 122 | "PartitionKeyName": { 123 | "Value": { 124 | "Ref": "partitionKeyName" 125 | } 126 | }, 127 | "PartitionKeyType": { 128 | "Value": { 129 | "Ref": "partitionKeyType" 130 | } 131 | }, 132 | 133 | "SortKeyName": { 134 | "Value": { 135 | "Ref": "sortKeyName" 136 | } 137 | }, 138 | "SortKeyType": { 139 | "Value": { 140 | "Ref": "sortKeyType" 141 | } 142 | }, 143 | 144 | "Region": { 145 | "Value": { 146 | "Ref": "AWS::Region" 147 | } 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /amplify/backend/storage/dynamob1b4533e/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "tableName": "dynamob1b4533e", 3 | "partitionKeyName": "id", 4 | "partitionKeyType": "S", 5 | "sortKeyName": "name", 6 | "sortKeyType": "S" 7 | } -------------------------------------------------------------------------------- /amplify/backend/storage/dynamob1b4533e/storage-params.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "aws-amplify": "^1.2.4", 7 | "react": "^16.11.0", 8 | "react-dom": "^16.11.0", 9 | "react-scripts": "3.2.0" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test", 15 | "eject": "react-scripts eject" 16 | }, 17 | "eslintConfig": { 18 | "extends": "react-app" 19 | }, 20 | "browserslist": { 21 | "production": [ 22 | ">0.2%", 23 | "not dead", 24 | "not op_mini all" 25 | ], 26 | "development": [ 27 | "last 1 chrome version", 28 | "last 1 firefox version", 29 | "last 1 safari version" 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/basic-serverless-api/529724469072907c8d4485486f2d6c6a4e407f66/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/basic-serverless-api/529724469072907c8d4485486f2d6c6a4e407f66/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/basic-serverless-api/529724469072907c8d4485486f2d6c6a4e407f66/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | } 8 | 9 | .App-header { 10 | background-color: #282c34; 11 | min-height: 100vh; 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | justify-content: center; 16 | font-size: calc(10px + 2vmin); 17 | color: white; 18 | } 19 | 20 | .App-link { 21 | color: #09d3ac; 22 | } 23 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import { API } from 'aws-amplify' 5 | 6 | const initialState = { 7 | name: '', 8 | description: '', 9 | price: '' 10 | } 11 | 12 | function App() { 13 | const [products, setProducts] = useState([]) 14 | const [product, updateProduct] = useState(initialState) 15 | async function fetchProducts() { 16 | const products = await API.get('api7d641705', '/products') 17 | setProducts(products.data.Items) 18 | } 19 | async function createProduct() { 20 | const { name, description, price } = product 21 | if (!name || !description || !price) return 22 | const data = { 23 | body: { ...product, price: parseInt(product.price) } 24 | } 25 | await API.post('api7d641705', '/products', data) 26 | console.log('product successfully created...') 27 | updateProduct(initialState) 28 | fetchProducts() 29 | } 30 | const updateProductInput = key => event => { 31 | updateProduct({ ...product, [key]: event.target.value }) 32 | } 33 | useEffect(() => { 34 | fetchProducts() 35 | }, []) 36 | return ( 37 |
38 | { 39 | products.map((product, index) => ( 40 |
41 |

{product.name}

42 |

{product.description}

43 |

${product.price}

44 |
45 | )) 46 | } 47 |
48 | 54 | 60 | 66 | 67 |
68 |
69 | ); 70 | } 71 | 72 | const button = { 73 | padding: '10px 40px', 74 | width: 400, 75 | margin: '0px auto' 76 | } 77 | 78 | const input = { 79 | padding: 7, 80 | width: 400, 81 | margin: '0px auto 6px' 82 | } 83 | 84 | const form = { 85 | display: 'flex', flexDirection: 'column', padding: 60 86 | } 87 | 88 | export default App; 89 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /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 * as serviceWorker from './serviceWorker'; 6 | 7 | import Amplify from 'aws-amplify' 8 | import config from './aws-exports' 9 | Amplify.configure(config) 10 | 11 | ReactDOM.render(, document.getElementById('root')); 12 | 13 | // If you want your app to work offline and load faster, you can change 14 | // unregister() to register() below. Note this comes with some pitfalls. 15 | // Learn more about service workers: https://bit.ly/CRA-PWA 16 | serviceWorker.unregister(); 17 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | --------------------------------------------------------------------------------