├── .gitignore ├── 1-exploring-the-event-gateway └── README.md ├── 2-event-gateway-workflow ├── README.md └── serverless-service │ ├── .gitignore │ ├── handler.js │ └── serverless.yml ├── 3-discovering-multi-cloud ├── README.md ├── serverless-services │ ├── aws │ │ ├── .gitignore │ │ ├── handler.js │ │ └── serverless.yml │ └── gcloud │ │ ├── .gitignore │ │ ├── index.js │ │ ├── package.json │ │ └── serverless.yml └── web-discovery │ ├── index.css │ ├── index.html │ └── index.js ├── 4-offline-first-development ├── README.md └── serverless-services │ ├── marketing │ ├── .gitignore │ ├── index.js │ ├── package.json │ └── serverless.yml │ └── newsletter │ ├── .gitignore │ ├── handler.js │ ├── package.json │ └── serverless.yml ├── 5-unleashing-the-multi-cloud-power ├── README.md └── event-gateway-playground │ ├── frontend │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.png │ │ └── index.html │ └── src │ │ ├── App.js │ │ ├── actions │ │ ├── click.js │ │ ├── logout.js │ │ └── register.js │ │ ├── assets │ │ ├── Gibson-Regular.otf │ │ ├── Serverless-Regular.otf │ │ ├── index.css │ │ ├── logo.png │ │ ├── normalize.css │ │ └── serverless-logo.svg │ │ ├── index.js │ │ ├── middleware │ │ └── eventGateway.js │ │ ├── reducers │ │ ├── index.js │ │ └── session.js │ │ └── store │ │ └── configureStore.js │ ├── package.json │ ├── services │ ├── analytics │ │ ├── .gitignore │ │ ├── config.json │ │ ├── index.js │ │ ├── package.json │ │ ├── serverless.yml │ │ └── setup.js │ ├── crm │ │ ├── handler.js │ │ ├── package.json │ │ └── serverless.yml │ ├── emails │ │ ├── handler.js │ │ ├── lib │ │ │ └── emailer.js │ │ ├── package.json │ │ └── serverless.yml │ ├── errors │ │ ├── handler.js │ │ ├── package.json │ │ └── serverless.yml │ ├── users │ │ ├── handler.js │ │ ├── lib │ │ │ └── users.js │ │ ├── package.json │ │ └── serverless.yml │ └── vision │ │ ├── config.json │ │ ├── index.js │ │ ├── lib │ │ └── vision.js │ │ ├── package.json │ │ └── serverless.yml │ └── setup.js ├── Dockerfile ├── README.md ├── docker-compose.yml └── utils ├── credentials-helper ├── eg-download └── event-gateway-discovery ├── index.css ├── index.html └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.log 3 | *.csv 4 | *.dat 5 | *.out 6 | *.pid 7 | *.gz 8 | *.iml 9 | *.ipr 10 | *.iws 11 | .env 12 | .eslintcache 13 | .tags 14 | .idea 15 | .DS_Store 16 | .serverless 17 | lib-cov 18 | pids 19 | logs 20 | tmp 21 | dist 22 | node_modules 23 | npm-debug.log 24 | package-lock.json 25 | -------------------------------------------------------------------------------- /1-exploring-the-event-gateway/README.md: -------------------------------------------------------------------------------- 1 | # Exploring the Event Gateway 2 | 3 | ## Goals 4 | 5 | * Install and setup the Event Gateway 6 | * Learn about the different concepts such as function registration, subscriptions and events 7 | * Run the Event Gateway locally 8 | * Explore its capabilities 9 | 10 | ## Instructions 11 | 12 | ### Download the Event Gateway 13 | 14 | Download the Event Gateway on your local development machine using the download script. 15 | 16 | `cd` into the root of the project and run `./utils/eg-download`. 17 | 18 | ### Verify the installation 19 | 20 | Verify that the Event Gateway is downloaded and successfully installed by running `./bin/event-gateway -version`. 21 | 22 | You should see the Event Gateways version number popping up in your terminal. 23 | 24 | ### Exploring the concepts 25 | 26 | Run `./bin/event-gateway -help` to see what options you have when running the Event Gateway. 27 | 28 | Can you figure out to run the Event Gateway locally? 29 | 30 | Skim through the Event Gateways [`README`](https://github.com/serverless/event-gateway/blob/master/README.md) to read about its inner-workings, the concepts and its capabilities. 31 | 32 | ### Starting locally in `dev` mode 33 | 34 | Open up a new terminal and run `./bin/event-gateway -dev` to start the Event Gateway locally in development mode. 35 | 36 | ### Listing registered functions 37 | 38 | Run `curl http://localhost:4001/v1/functions` to see all the registered functions. You should see an empty array since we haven't registered any functions yet. 39 | 40 | ### Listing subscriptions 41 | 42 | Run `curl http://localhost:4001/v1/subscriptions` to see all subscriptions. You should see an empty array since we haven't created any subscriptions yet. 43 | 44 | ### Stopping the Event Gateway 45 | 46 | Run `ctrl + c` to stop the Event Gateway. 47 | 48 | ## Questions 49 | 50 | 1. How would you run the Event Gateway locally with enabled debugging logs? 51 | 1. What's the difference between the "Configuration API" and the "Events API"? 52 | 1. What is the `FDK`? 53 | 1. What steps do I need to take to make a remote function callable via the Event Gateway? 54 | 1. What role does `etcd` play? 55 | -------------------------------------------------------------------------------- /2-event-gateway-workflow/README.md: -------------------------------------------------------------------------------- 1 | # Event Gateway workflow 2 | 3 | ## Goals 4 | 5 | * Getting familiar with the way the Event Gateway works 6 | * Registering functions 7 | * Creating `http` subscriptions 8 | * Creating custom event subscriptions 9 | 10 | ## Instructions 11 | 12 | ### [Optional] Export your AWS keys 13 | 14 | This step is optional. 15 | 16 | You can update the `credentials-helper` file (in the `utils` directory) with your AWS credentials and run `. ../utils/credentials-helper` to set the corresponding environment variables. Otherwise you could also `export` them manually or use your default AWS profile 17 | 18 | See [our guide](https://serverless.com/framework/docs/providers/aws/guide/credentials/) on AWS credential handling for more information. 19 | 20 | ### Deploy the `serverless-service` 21 | 22 | `cd` into the `serverless-service` directory and deploy the Serverless service to AWS by running `serverless deploy`. 23 | 24 | ### Invoke the `hello` function 25 | 26 | Run `serverless invoke --function hello` to invoke the `hello` function on AWS. 27 | 28 | ### Getting the function `arn` 29 | 30 | Run `serverless info --verbose` to see the services information. 31 | 32 | Copy the shown function arn without the versioning part at the end (e.g. `arn:aws:lambda:us-east-1:XXXXX:function:serverless-service-dev-hello`). 33 | 34 | ### Starting the Event Gateway 35 | 36 | Start the Event Gateway with debugging logs in development mode via `../bin/event-gateway -dev -log-level debug`. 37 | 38 | ### Registering the `hello` function at the Event Gateway 39 | 40 | Open up a new terminal and register the `hello` function with the following `curl` call: 41 | 42 | ```sh 43 | curl --request POST \ 44 | --url http://localhost:4001/v1/functions \ 45 | --header 'content-type: application/json' \ 46 | --data '{ 47 | "functionId": "hello", 48 | "provider":{ 49 | "type": "awslambda", 50 | "arn": "arn:aws:lambda:us-east-1:XXXXX:function:serverless-service-dev-hello", 51 | "region": "us-east-1" 52 | } 53 | }' 54 | ``` 55 | 56 | ### Listing function registrations 57 | 58 | Run `curl http://localhost:4001/v1/functions` to see all the registered functions. You should see the function you've just registered. 59 | 60 | ### Create a `http` subscription 61 | 62 | Create a new `http` subscription to expose the function via a HTTP endpoint: 63 | 64 | ```sh 65 | curl --request POST \ 66 | --url http://localhost:4001/v1/subscriptions \ 67 | --header 'content-type: application/json' \ 68 | --data '{ 69 | "functionId": "hello", 70 | "event": "http", 71 | "path": "/greeter", 72 | "method": "GET" 73 | }' 74 | ``` 75 | 76 | ### Listing subscriptions 77 | 78 | Run `curl http://localhost:4001/v1/subscriptions` to see all subscriptions. You should the recently created subscription. 79 | 80 | ### Calling the `hello` function via `http` 81 | 82 | Run the following `curl` command to call the function via the Event Gateway (the Event Gateway acts as an API Gateway in that case). 83 | 84 | **Note:** We're using the Event Gateways "Event API" on port `4000` in that case! 85 | 86 | ```sh 87 | curl http://localhost:4000/greeter 88 | ``` 89 | 90 | ### Create a custom event subscription 91 | 92 | Create a new custom event subscription so that the Event Gateway calls the function whenever the defined freeform `event` is emitted. 93 | 94 | ```sh 95 | curl --request POST \ 96 | --url http://localhost:4001/v1/subscriptions \ 97 | --header 'content-type: application/json' \ 98 | --data '{ 99 | "functionId": "hello", 100 | "event": "greet.me", 101 | "path": "/custom-event" 102 | }' 103 | ``` 104 | 105 | ### Listing subscriptions 106 | 107 | Run `curl http://localhost:4001/v1/subscriptions` to see all subscriptions. You should see the recently created subscription. 108 | 109 | ### Calling the `hello` function via our custom event 110 | 111 | Run the following `curl` command to emit a `greet.me` event to the Event Gateway. 112 | 113 | **Note:** We're using the Event Gateways "Event API" on port `4000` in that case! 114 | 115 | ```sh 116 | curl --request POST \ 117 | --url http://localhost:4000 \ 118 | --header 'content-type: application/json' \ 119 | --header 'event: greet.me' \ 120 | --data '{ "firstName": "John", "lastName": "Doe" }' 121 | ``` 122 | 123 | Switch back to the terminal where the Event Gateway is running. You should now see that the Event Gateway received the event, invoked the function remotely and streamed back the result of the function invocation to the terminal. 124 | 125 | ## Tasks 126 | 127 | 1. Create a new `goodbye` function which also subscribes to the `greet.me` event 128 | 1. Test the new `goodbye` function by emitting the `greet.me` event 129 | 1. Remove the `greet.me` subscription for the `hello` function 130 | 131 | ## Cleanup 132 | 133 | Stop the Event Gateway by running `ctrl + c`. 134 | Remove the Event Gateway config via `rm -rf ../default.etcd` 135 | 136 | Remove the `serverless-sevice` by running `serverless remove` in the `serverless-service` directory. 137 | 138 | ## Questions 139 | 140 | 1. What's the main difference between a function call done via `http` and a custom `event`? 141 | 1. Other departments are registering several functions and subscriptions on a daily basis. You want to create a simple function discovery platform so that everyone can see what the Event Gateway currently exposes. How could you do that? 142 | -------------------------------------------------------------------------------- /2-event-gateway-workflow/serverless-service/.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | -------------------------------------------------------------------------------- /2-event-gateway-workflow/serverless-service/handler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports.hello = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: "Go Serverless v1.0! Your function executed successfully!", 8 | input: event 9 | }) 10 | }; 11 | 12 | callback(null, response); 13 | 14 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 15 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 16 | }; 17 | -------------------------------------------------------------------------------- /2-event-gateway-workflow/serverless-service/serverless.yml: -------------------------------------------------------------------------------- 1 | service: serverless-service 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs6.10 6 | 7 | functions: 8 | hello: 9 | handler: handler.hello 10 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/README.md: -------------------------------------------------------------------------------- 1 | # Discovering multi-cloud 2 | 3 | ## Goals 4 | 5 | * Creating an "Event Gateway Discovery" web app 6 | * Deploying a function to AWS 7 | * Deploying a function to the Google Cloud 8 | * Creating a function registration and subscription for the AWS function 9 | * Creating a function registration and subscription for the Google Cloud Function 10 | * Invoking the AWS function via the Event Gateway 11 | * Invoking the Google Cloud Function via the Event Gateway 12 | 13 | ## Instructions 14 | 15 | ### Starting the Event Gateway 16 | 17 | Open up a new terminal and start the Event Gateway with debugging logs in `dev` mode via `../bin/event-gateway -dev -log-level debug`. 18 | 19 | ### Opening up the Event Gateway Discovery web app 20 | 21 | Open up the `index.html` file in the `web-discovery` directory in your browser. 22 | 23 | You should see an alert that the Event Gateway is not reachable right now. (we'll fix that in a minute). 24 | 25 | ### Fetching all the registered functions 26 | 27 | Open up the `index.js` file in the `web-discovery` directory. Look at the `getFunctions` function and implement the logic to fetch all the registered functions from the Event Gateway. 28 | 29 | _Note:_ You could use `console.log` statements to debug your function and print your result to the browsers console. 30 | 31 | ### Fetching all the subscriptions 32 | 33 | Open up the `index.js` file in the `web-discovery` directory. Look at the `getSubscriptions` function and implement the logic to fetch all the subscriptions from the Event Gateway. 34 | 35 | _Note:_ You could use a `console.log` statement to debug your function and print your result to the browsers console. 36 | 37 | ### Validating the functionality 38 | 39 | Refresh the `index.html` page in your browser. A message should be shown that no function registrations and subscriptions are available right now. 40 | 41 | ### [Optional] Export your AWS keys 42 | 43 | This step is optional. 44 | 45 | You can update the `credentials-helper` file (in the `utils` directory) with your AWS credentials and run `. ../utils/credentials-helper` to set the corresponding environment variables. Otherwise you could also `export` them manually or use your default AWS profile 46 | 47 | See [our guide](https://serverless.com/framework/docs/providers/aws/guide/credentials/) on credential handling for more information. 48 | 49 | ### Deploying the AWS service 50 | 51 | Switch to the `serverless-services/aws` directory and deploy the service by running `serverless deploy`. 52 | 53 | ### Get the function `arn` 54 | 55 | Once deployed fetch the function `arn` by running `serverless info --verbose`. Copy the shown function arn without the versioning part at the end (e.g. `arn:aws:lambda:us-east-1:XXXXX:function:serverless-service-dev-hello`). 56 | 57 | ### Configuring and deploying the Google Cloud service 58 | 59 | Navigate to the `serverless-services/gcloud` directory and, open up the `serverless.yml` file and update the `project` and `credentials` configs. 60 | 61 | Run `npm install` to install all the dependencies. Deploy the service by running `serverless deploy`. 62 | 63 | See [our credentials guide](https://serverless.com/framework/docs/providers/google/guide/credentials/) for the correct Google Cloud setup / configuration. 64 | 65 | ### Get the function `http` endpoint 66 | 67 | Run `serverless info` in the `gcloud` service directory to see all the service information. Copy and save the Google Cloud Functions `http` endpoint. 68 | 69 | ### Registering the AWS function 70 | 71 | Run the following `curl` command to register the AWS function at the Event Gateway: 72 | 73 | ```sh 74 | curl --request POST \ 75 | --url http://localhost:4001/v1/functions \ 76 | --header 'content-type: application/json' \ 77 | --data '{ 78 | "functionId": "aws-hello", 79 | "provider":{ 80 | "type": "awslambda", 81 | "arn": "arn:aws:lambda:us-east-1:XXXXX:function:aws-dev-hello", 82 | "region": "us-east-1" 83 | } 84 | }' 85 | ``` 86 | 87 | ### Creating a custom event subscription 88 | 89 | Create a new custom event subscription so that the Event Gateway calls the AWS function. 90 | 91 | ```sh 92 | curl --request POST \ 93 | --url http://localhost:4001/v1/subscriptions \ 94 | --header 'content-type: application/json' \ 95 | --data '{ 96 | "functionId": "aws-hello", 97 | "event": "aws.hello", 98 | "path": "/aws-custom-event" 99 | }' 100 | ``` 101 | 102 | ### Registering the Google Cloud Function 103 | 104 | Run the followig `curl` command to register the Google Cloud Function at the Event Gateway: 105 | 106 | ```sh 107 | curl --request POST \ 108 | --url http://localhost:4001/v1/functions \ 109 | --header 'content-type: application/json' \ 110 | --data '{ 111 | "functionId": "gcloud-hello", 112 | "provider":{ 113 | "type": "http", 114 | "url": "https://region-and-project.cloudfunctions.net/http" 115 | } 116 | }' 117 | ``` 118 | 119 | ### Creating a custom event subscription 120 | 121 | Create a new custom event subscription so that the Event Gateway calls the Google Cloud Function. 122 | 123 | ```sh 124 | curl --request POST \ 125 | --url http://localhost:4001/v1/subscriptions \ 126 | --header 'content-type: application/json' \ 127 | --data '{ 128 | "functionId": "gcloud-hello", 129 | "event": "gcloud.hello", 130 | "path": "/gcloud-custom-event" 131 | }' 132 | ``` 133 | 134 | ### Validating our current setup 135 | 136 | Lets validate that everything is wired up correctly. Go to the "Event Gateway Discovery" app we've just created above (open the `index.html` file in your browser). 137 | 138 | You should see the registered functions and their corresponding subscriptions! 139 | 140 | Since we're running the Event Gateway with `-log-level debug` we should also see some debugging logs in the terminal where the Event Gateway is running. 141 | 142 | ### Calling the AWS function 143 | 144 | Let's call our AWS function by emitting the `aws.hello` event to the Event Gateway. This can easily be done via a `curl` call against the "Event API". 145 | 146 | ```sh 147 | curl --request POST \ 148 | --url http://localhost:4000 \ 149 | --header 'content-type: application/json' \ 150 | --header 'event: aws.hello' \ 151 | --data '{ "firstName": "Amy", "lastName": "AWS" }' 152 | ``` 153 | 154 | Watch the Event Gateways debugging logs to see the functions response! 155 | 156 | ### Calling the Google Cloud Function 157 | 158 | Calling our Google Cloud Function works the same way. We can simply emit a `gcloud.hello` event to the Event Gateways "Event API" via `curl`: 159 | 160 | ```sh 161 | curl --request POST \ 162 | --url http://localhost:4000 \ 163 | --header 'content-type: application/json' \ 164 | --header 'event: gcloud.hello' \ 165 | --data '{ "firstName": "Gregory", "lastName": "GCloud" }' 166 | ``` 167 | 168 | Watch the Event Gateways debugging logs to see the functions response! 169 | 170 | ## Tasks 171 | 172 | 1. Create a new `goodbye` function and deploy it to AWS 173 | 1. Register the `goodbye` function as a `http` function type (does your `goodbye` function need some config changes?) 174 | 1. Create a new subscription for the `goodbye` function which subscribes to the `aws.goodbye` event 175 | 1. Invoke the `goodbye` function by emitting the `aws.goodbye` event 176 | 1. Deregister the AWS `hello` function from the Event Gateway 177 | 1. Remove the `aws.hello` subscription from the Event Gateway 178 | 179 | ## Cleanup 180 | 181 | Stop the Event Gateway by running `ctrl + c`. 182 | Remove the Event Gateway config via `rm -rf ../default.etcd` 183 | 184 | Remove the `aws` service by running `serverless remove` in the `serverless-servics/aws` directory. 185 | Remove the `gcloud` service by running `serverless remove` in the `serverless-services/gcloud` directory. 186 | 187 | ## Questions 188 | 189 | 1. Is there any difference when registering an AWS function vs. a Google Cloud Function? What does that mean for FaaS in general? 190 | 1. Invoke the AWS function and the Google Cloud Function again and keep an eye on the response time. Can you spot any difference? 191 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/aws/.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/aws/handler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports.hello = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: "Hello Event Gateway! (from AWS)", 8 | input: event 9 | }) 10 | }; 11 | 12 | callback(null, response); 13 | }; 14 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/aws/serverless.yml: -------------------------------------------------------------------------------- 1 | service: aws 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs6.10 6 | 7 | functions: 8 | hello: 9 | handler: handler.hello 10 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/gcloud/.gitignore: -------------------------------------------------------------------------------- 1 | # Serverless 2 | .serverless 3 | .env 4 | tmp 5 | .coveralls.yml 6 | 7 | # Google 8 | keyfile.json 9 | 10 | # Logs 11 | *.log 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | 32 | # IDE 33 | **/.idea 34 | 35 | # OS 36 | .DS_Store 37 | .tmp 38 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/gcloud/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.http = (request, response) => { 4 | response.status(200).send("Hello Event Gateway (from the Google Cloud)!"); 5 | }; 6 | 7 | exports.event = (event, callback) => { 8 | callback(); 9 | }; 10 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/gcloud/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gcloud-service", 3 | "version": "0.1.0", 4 | "description": "Google Cloud service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-google-cloudfunctions": "^1.1.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/serverless-services/gcloud/serverless.yml: -------------------------------------------------------------------------------- 1 | service: gcloud 2 | 3 | provider: 4 | name: google 5 | runtime: nodejs 6 | project: my-project 7 | # the path to the credentials file needs to be absolute 8 | credentials: ~/.gcloud/keyfile.json 9 | 10 | plugins: 11 | - serverless-google-cloudfunctions 12 | 13 | package: 14 | exclude: 15 | - node_modules/** 16 | - .gitignore 17 | - .git/** 18 | 19 | functions: 20 | first: 21 | handler: http 22 | events: 23 | - http: path 24 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/web-discovery/index.css: -------------------------------------------------------------------------------- 1 | .centered { 2 | text-align: center; 3 | } 4 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/web-discovery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Event Gateway Discovery 4 | 5 | 6 | 7 | 8 |
9 |
10 |

Event Gateway Discovery

11 |
12 |
13 |
14 |
15 |
16 |

Functions

17 |
18 |
19 |
20 |

Subscriptions

21 |
22 |
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /3-discovering-multi-cloud/web-discovery/index.js: -------------------------------------------------------------------------------- 1 | const apiVersion = "v1"; 2 | const configUrl = "http://eventgateway.url"; 3 | 4 | function getFunctions() { 5 | return fetch(`${configUrl}/${apiVersion}/functions`).then(resp => 6 | resp.json().then(data => { 7 | console.log("functions"); 8 | }) 9 | ); 10 | } 11 | 12 | function getSubscriptions() { 13 | return fetch(`${configUrl}/${apiVersion}/subscriptions`).then(resp => 14 | resp.json().then(data => { 15 | console.log("subscriptions"); 16 | }) 17 | ); 18 | } 19 | 20 | (() => { 21 | const funcsDiv = document.querySelector("#functions"); 22 | const subsDiv = document.querySelector("#subscriptions"); 23 | 24 | return Promise.all([getFunctions(), getSubscriptions()]) 25 | .then(res => { 26 | const funcs = res[0]; 27 | const subs = res[1]; 28 | 29 | if (!funcs.length) { 30 | funcsDiv.innerHTML = 31 | "

There are functions registrations available right now

"; 32 | } else { 33 | let table = 34 | '#{items}
Function ID
'; 35 | const items = funcs.map(func => ``); 36 | table = table.replace("#{items}", items.join("")); 37 | funcsDiv.innerHTML = table; 38 | } 39 | 40 | if (!subs.length) { 41 | subsDiv.innerHTML = 42 | "

There are no subscriptions available right now

"; 43 | } else { 44 | let table = 45 | '#{items}
Function IDSubscription ID
'; 46 | const items = subs.map(sub => ``); 47 | table = table.replace("#{items}", items.join("")); 48 | subsDiv.innerHTML = table; 49 | } 50 | }) 51 | .catch(error => { 52 | alert( 53 | `Error pinging the Event Gateway config URL at "${configUrl}". Is the Event Gateway running?` 54 | ); 55 | }); 56 | })(); 57 | -------------------------------------------------------------------------------- /4-offline-first-development/README.md: -------------------------------------------------------------------------------- 1 | # Offline-first development 2 | 3 | ## Goals 4 | 5 | * Getting familiar with `serverless run` 6 | * Working with AWS functions locally 7 | * Working with Google Cloud Functions locally 8 | * Emulating cross cloud function invocations 9 | * Implementing an event-driven function call flow 10 | 11 | ## Instructions 12 | 13 | ### **Aside** `serverless run` 14 | 15 | Using the Event Gateway as the centerpiece for multi-cloud applications enables whole new worlds to build flexible, inter-connected, provider-spanning serverless services. 16 | 17 | Working on such projects is a little bit harder to do since instead of dealing with one cloud provider and its services one now has to manage several different cloud providers and their services. 18 | 19 | Wouldn't it be nice if there's an offline experience which emulates parts of the providers service offerings and helps getting basic event-driven applications off the ground with low effort? 20 | 21 | At Serverless we took care about that when working on the Event Gateway. The Serverless Framework v1 ships with a locally running Event Gateway integration out of the box, making it possible to kick-start the event-driven serverless application development in an offline-first fashion. 22 | 23 | All you need to do is to `cd` into your service directory and run `serverless run`. The Serverless Framework will take care of the rest. 24 | 25 | In this chapter we'll see how offline-first local development with `serverless run` works. 26 | 27 | ### Preparing the `newsletter` service 28 | 29 | Switch into the `newsletter` directory by running `cd serverless-services/newsletter`. 30 | 31 | Install all the dependencies with `npm install`. 32 | 33 | ### Updating `serverless.yml` 34 | 35 | Open up the `newsletter` service directory with your favorite editor. 36 | 37 | In `serverless.yml` you can see all the information and configuration about the service and its functions. 38 | We can immediately see that this is an AWS powered service, meaning that it will be deployed to the AWS cloud. 39 | 40 | You should see the `register` function. We want to trigger this function every time a `user.registered` event is sent to the Event Gateway. 41 | 42 | Update the configuration code so that the functions has the corresponding `events` configuration. 43 | 44 | ### Updating `handler.js` 45 | 46 | In the `handler.js` file you should see a code which checks whether the entered E-Mail address is a VIPs address. Can you update the code so that a `marketing.vip` event is emitted to the Event Gateway once a VIP E-Mail address is detected? 47 | 48 | ### Running the service offline 49 | 50 | Once done run `serverless run` in the services directory. This will download and setup the Event Gateway, the local function emulator, register all the services functions at the Event Gateway and subscribes the events to the corresponding functions. 51 | 52 | `serverless run` will enter a session which means that all the debug data, the Event Gateway returns is streamed back to this terminal. This will help during local development. 53 | 54 | One of the first information we see is the debug information about the function registration and subscription creation. 55 | 56 | ### Validating our current setup 57 | 58 | Do you remember the "Event Gateway Discovery" project which showed all the function registrations and subscriptions we've just worked on? 59 | 60 | You can find a fully functional version of it in this projects `utils` directory. Open up the `index.html` file with your browser and you should see the function registration and event subscription we've just created. 61 | 62 | ### Preparing the `marketing` service 63 | 64 | Switch into the `marketing` directory by running `cd serverless-services/marketing`. 65 | 66 | Install all the dependencies with `npm install`. 67 | 68 | ### Updating `serverless.yml` 69 | 70 | Open up the `marketing` service directory with your favorite editor. 71 | 72 | In `serverless.yml` you can see all the information and configuration about the service and its functions. 73 | Here we can see that this is a Google Cloud powered service, meaning that it will be deployed to the Google Cloud. 74 | 75 | In `serverless.yml` we can see the `vipNotifier` function. This is the function which should be invoked once a `marketing.vip` event comes in via the Event Gateway. Update the functions `event` config so that it subscribes to the `marketing.vip` event. 76 | 77 | ### Running the service offline 78 | 79 | Once done run `serverless run` in the services directory. This time the Serverless Framework detects that another instance of the Event Gateway is already running. The Serverless Framework now re-uses the existing Event Gateway instance to register the functions and create the corresponding subscriptions. 80 | 81 | If you take a look at the other terminal window where the `serverless run` command is still running you can see that the functions were succssefully registered and all the subscriptions are set up. 82 | 83 | ### Validating our current setup 84 | 85 | Switch back to the browser and refresh the `index.html` file. You should now see two function registrations and two subscriptions. 86 | 87 | ### Testing 88 | 89 | It's time to test-drive our newsletter registration application. We do that by emitting a `user.registered` event to the Event Gateways "Event API". 90 | 91 | At first let's test our current setup with a non-VIP registration. 92 | 93 | ``` 94 | curl --request POST \ 95 | --url http://localhost:4000 \ 96 | --header 'content-type: application/json' \ 97 | --header 'event: user.registered' \ 98 | --data '{ "email": "john@doe.com" }' 99 | ``` 100 | 101 | Switch back to the terminal where your current, interactive Event Gateway session is running. You should see that the Event Gateway received a new `user.registered` event and that the registration was successful. 102 | 103 | Let's try it again with a VIP user. 104 | 105 | ``` 106 | curl --request POST \ 107 | --url http://localhost:4000 \ 108 | --header 'content-type: application/json' \ 109 | --header 'event: user.registered' \ 110 | --data '{ "email": "taylor@swift.com" }' 111 | ``` 112 | 113 | Switch back to the terminal where the Event Gateway session is running. 114 | 115 | It should show another log entry that the Event Gateway received a `user.registered` event and that the registration was successful. However this time the Marketing department should've received a notification since the `marketing.vip` event was emitted! 116 | 117 | ### Using the `serverless emit` command 118 | 119 | Emitting an event via `curl` is pretty straightforward thanks to the Event Gateways `http` "Event API". 120 | 121 | On the other hand it gets quite cumbersome to write the `curl` command every time to emit an event. Especially since the `url`, the `content-type` header and the `request` type are repeated over and over again. 122 | 123 | The Serverless Framework got you covered and comes with a built-in `emit` command which makes it possible to emit events to the "Event API" without the need to write that `curl` based boilerplate code. 124 | 125 | Run `serverless emit --help` to see the help for the `emit` command. Can you figure out how we can emit the same events we've used above using the `serverless emit` command? 126 | 127 | It's as simple as running `serverless emit --name user.registered --data '{ "email": "john@doe.com" }'` and `serverless emit --name user.registered --data '{ "email": "taylor@swift.com" }'`! 128 | 129 | Check the terminal window where the Event Gateway is running to see the Event Gateways debugging log entries. 130 | 131 | ## Tasks 132 | 133 | 1. There's a special VIP called `server@less.com`. Update the function code to filter out that VIP and emit a `marketing.serverless` event 134 | 1. The marketing team wants a special `serverlessNotifier` function which is only triggered when the `marketing.serverless` event is emitted. Implement the new `serverlessNotifier` function and ensure that it's called when the `marketing.serverless` event is emitted 135 | 1. The Marketing department decided to introduce a new `marketing.celebrity` event which should trigger the `vipNotifier` function. Update the code so that the `vipNotifier` function is invoked every time this new event is emitted to the Event Gateway. 136 | 1. the Marketing department decided to deprecate the `marketing.vip` and `marketing.celebrity` events and replace them with the `marketing.notify` event (all future data will be delivered using this event). At the same time it don't want to lose any existing data-deliveries to `marketing.vip` and `marketing.celebrity`. Introduce the new `marketing.notify` event and ensure that `marketing.vip` and `marketing.celebrity` events are correctly redirected. 137 | 138 | ## Questions 139 | 140 | 1. Which parts of your current infrastructure could you replace with such an event-driven workflow? 141 | 1. Can you think of any challenges you might face when dealing with such event-driven workflows? 142 | 1. What functionality could help you tackle those challenges? 143 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/marketing/.gitignore: -------------------------------------------------------------------------------- 1 | # Serverless 2 | .serverless 3 | .env 4 | tmp 5 | .coveralls.yml 6 | 7 | # Google 8 | keyfile.json 9 | 10 | # Logs 11 | *.log 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | 32 | # IDE 33 | **/.idea 34 | 35 | # OS 36 | .DS_Store 37 | .tmp 38 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/marketing/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.vipNotifier = (event, callback) => { 4 | const email = event.data.email; 5 | 6 | return callback(null, { 7 | message: `VIP with E-Mail address "${email}" detected.` 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/marketing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "marketing-service", 3 | "version": "0.1.0", 4 | "description": "Marketing service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-google-cloudfunctions": "^1.1.0", 13 | "serverless-remove-forced-login": "0.1.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/marketing/serverless.yml: -------------------------------------------------------------------------------- 1 | service: marketing 2 | 3 | plugins: 4 | - serverless-google-cloudfunctions 5 | - serverless-remove-forced-login 6 | 7 | custom: 8 | eventGatewayUrl: "http://localhost:4000" 9 | eventGatewayConfigUrl: "http://localhost:4001" 10 | 11 | provider: 12 | name: google 13 | runtime: nodejs 14 | project: marketing-department-utils 15 | credentials: ~/.gcloud/keyfile.json 16 | environment: 17 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 18 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 19 | 20 | functions: 21 | vipNotifier: 22 | handler: vipNotifier 23 | events: 24 | - some.event 25 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/newsletter/.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/newsletter/handler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const EVENT_GATEWAY_URL = "http://localhost:4000"; // process.env.EVENT_GATEWAY_URL; 4 | const EVENT_GATEWAY_CONFIG_URL = "http://localhost:4001"; // process.env.EVENT_GATEWAY_CONFIG_URL; 5 | 6 | const fdk = require("@serverless/fdk"); 7 | const eventGateway = fdk.eventGateway({ 8 | url: EVENT_GATEWAY_URL, 9 | configurationUrl: EVENT_GATEWAY_CONFIG_URL 10 | }); 11 | 12 | const vipEmailAddresses = [ 13 | "kim@kardashian.com", 14 | "justin@bieber.com", 15 | "taylor@swift.com" 16 | ]; 17 | 18 | function checkForVip(email) { 19 | if (vipEmailAddresses.indexOf(email) > -1) { 20 | return eventGateway.emit({ 21 | event: "some.event", 22 | data: { 23 | email: email 24 | } 25 | }); 26 | } 27 | return Promise.resolve(); 28 | } 29 | 30 | module.exports.register = (event, context, callback) => { 31 | return checkForVip(event.data.email) 32 | .then(() => { 33 | return callback(null, { 34 | message: "Newsletter registration successfull." 35 | }); 36 | }) 37 | .catch(err => { 38 | return callback({ error: err }, null); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/newsletter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "newsletter-service", 3 | "version": "0.1.0", 4 | "description": "Newsletter service.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@serverless/fdk": "^0.3.5" 13 | }, 14 | "devDependencies": { 15 | "serverless-remove-forced-login": "0.1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /4-offline-first-development/serverless-services/newsletter/serverless.yml: -------------------------------------------------------------------------------- 1 | service: newsletter 2 | 3 | plugins: 4 | - serverless-remove-forced-login 5 | 6 | custom: 7 | eventGatewayUrl: "http://localhost:4000" 8 | eventGatewayConfigUrl: "http://localhost:4001" 9 | 10 | provider: 11 | name: aws 12 | runtime: nodejs6.10 13 | stage: prod 14 | region: us-east-1 15 | environment: 16 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 17 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 18 | 19 | functions: 20 | register: 21 | handler: handler.register 22 | events: 23 | - some.event 24 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/README.md: -------------------------------------------------------------------------------- 1 | # Unleashing the multi-cloud power 2 | 3 | ## Goals 4 | 5 | * Learn about Event Gateway System Events 6 | * Work with a CRUD user app 7 | * Integrate the Event Gateway with a fully-fledged frontend application 8 | * Use Google services such as BigQuery and the CloudVision API 9 | 10 | ## Instructions 11 | 12 | ### The Event Gateway Playground 13 | 14 | In this chapter we'll use the Event Gateway Playground project which is a slightly modified version of the [`event-gateway-example` project](https://github.com/serverless/event-gateway-example). 15 | 16 | This project includes a variety of different example services to showcase various use-cases you can accomplish with the Event Gateway. 17 | 18 | ### Project setup 19 | 20 | Switch to the `event-gateway-playground` directory by running `cd event-gateway-playground`. 21 | 22 | Install the dependencies by running `npm install` and `npm run setup`. 23 | 24 | ### Exploring the Event Gateway Playground 25 | 26 | Open up the `event-gateway-example` repositories ["Step-by-step guide"](https://github.com/serverless/event-gateway-example#step-by-step-guide) and follow along. 27 | 28 | In this guide you'll see how you can implement error-handling with the help of the Event Gateways System Events, how you can integrate a frontend with your Event-Gateway based backend and how Google CloudVision and Google BigQuery can be used to analyze user profile pictures and track your users behavior. 29 | 30 | **Note:** When working through the guide keep in mind that there's a `frontend` directory which includes the webapp for the Event Gateway Playground! Watch the Event Gateways terminal output when interacting with it. 31 | 32 | --- 33 | 34 | > That's it! Congratulations. You've just finished the Event Gateway Workshop and should have a good understanding of the Event Gateway and the opportunities it enables! 35 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/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 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Frontend 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode. 10 | 11 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 12 | 13 | The page will reload if you make edits. You will also see any lint errors in the console. 14 | 15 | ### `npm run build` 16 | 17 | Builds the app for production to the `build` folder. 18 | 19 | It correctly bundles React in production mode and optimizes the build for the best performance. 20 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@serverless/fdk": "^0.5.1", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-redux": "^5.0.6", 10 | "redux": "^3.7.2", 11 | "redux-logger": "^3.0.6", 12 | "redux-thunk": "^2.2.0" 13 | }, 14 | "devDependencies": { 15 | "react-scripts": "1.0.11" 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 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serverless/event-gateway-workshop/79043161bd64b087dcd9ec82167fe73cf82aea78/5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/public/favicon.png -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Serverless Application 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { register } from './actions/register'; 4 | import { logout } from './actions/logout'; 5 | import { click } from './actions/click'; 6 | import logo from './assets/logo.png'; 7 | 8 | class App extends Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { email: '' }; 12 | } 13 | 14 | updateEmail = event => { 15 | this.setState({ 16 | email: event.target.value 17 | }); 18 | }; 19 | 20 | register = event => { 21 | event.preventDefault(); 22 | this.props.register(this.state.email); 23 | }; 24 | 25 | render() { 26 | return ( 27 |
28 |
29 |
30 | 31 | logo 32 | 33 | serverless application 34 |
35 |
36 | {this.props.session && 37 | 42 | } 43 |
44 |
45 |
46 |
ß
47 |
serverless application
48 |
build more, manage less
49 |
50 | {this.props.session 51 | ?
52 | Thanks for registering! 53 |
54 | :
55 | 61 | 62 |
} 63 |
64 |
65 |
66 |

build value, fast

67 |
68 |

69 | There is no faster way to get new projects built and to the market than to use a serverless application. 70 |

71 | 78 |
79 |
80 |
81 |

minimize overhead

82 |
83 |

84 | Serverless applications are auto-scaling with pay-per-execution 85 | pricing, reducing overhead like never before 86 |

87 | 94 |
95 |
96 |
97 |

event-driven

98 |
99 |

100 | The back-end and front-end of this serverless application is entirely event-driven. 101 |

102 | 109 |
110 |
111 |
112 | ); 113 | } 114 | } 115 | 116 | const mapStateToProps = state => ({ session: state.session }); 117 | const actions = { register, click, logout }; 118 | 119 | export default connect(mapStateToProps, actions)(App); 120 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/actions/click.js: -------------------------------------------------------------------------------- 1 | export const USER_ACTIVITY_CLICKED = 'USER_ACTIVITY_CLICKED'; 2 | 3 | export const click = target => (dispatch, getState) => { 4 | const session = getState().session; 5 | if (session) { 6 | dispatch({ 7 | type: USER_ACTIVITY_CLICKED, 8 | data: { 9 | target, 10 | session 11 | } 12 | }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/actions/logout.js: -------------------------------------------------------------------------------- 1 | export const USER_ACTIVITY_LOGOUT = 'USER_ACTIVITY_LOGOUT'; 2 | 3 | export const logout = () => (dispatch, getState) => { 4 | sessionStorage.removeItem('session'); 5 | dispatch({ 6 | type: USER_ACTIVITY_LOGOUT, 7 | data: { 8 | session: getState().session 9 | } 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/actions/register.js: -------------------------------------------------------------------------------- 1 | export const REGISTER_USER = 'REGISTER_USER'; 2 | export const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS'; 3 | export const REGISTER_USER_FAILURE = 'REGISTER_USER_FAILURE'; 4 | 5 | export const register = email => (dispatch, getState) => { 6 | dispatch({ 7 | type: REGISTER_USER, 8 | data: { 9 | email 10 | } 11 | }); 12 | fetch('http://localhost:4000/users', { 13 | method: 'POST', 14 | body: JSON.stringify({ email }), 15 | headers: { 16 | 'Content-Type': 'application/json' 17 | } 18 | }) 19 | .then(response => { 20 | if (response.status === 200) { 21 | return response.json(); 22 | } 23 | throw new Error('Status code != 200'); 24 | }) 25 | .then(response => { 26 | sessionStorage.setItem('session', response.session); 27 | dispatch({ 28 | type: REGISTER_USER_SUCCESS, 29 | data: { 30 | email, 31 | session: response.session 32 | } 33 | }); 34 | }) 35 | .catch(() => { 36 | dispatch({ 37 | type: REGISTER_USER_FAILURE, 38 | data: { 39 | email 40 | } 41 | }); 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/Gibson-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serverless/event-gateway-workshop/79043161bd64b087dcd9ec82167fe73cf82aea78/5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/Gibson-Regular.otf -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/Serverless-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serverless/event-gateway-workshop/79043161bd64b087dcd9ec82167fe73cf82aea78/5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/Serverless-Regular.otf -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Serverless; 3 | src: url("./Serverless-Regular.otf") format("opentype"); 4 | } 5 | 6 | @font-face { 7 | font-family: Gibson; 8 | src: url("./Gibson-Regular.otf") format("opentype"); 9 | } 10 | 11 | body { 12 | /*background: #222;*/ 13 | background: hsl(220, 13%, 18%); 14 | font-family: Gibson, sans-serif; 15 | font-size: 1rem; 16 | color: #fff; 17 | -webkit-font-smoothing: antialiased; 18 | -moz-osx-font-smoothing: grayscale; 19 | } 20 | 21 | h1 { 22 | font-weight: normal; 23 | } 24 | 25 | h2 { 26 | font-size: 1.7rem; 27 | color: #f15953; 28 | font-family: Serverless, sans-serif; 29 | font-weight: normal; 30 | } 31 | 32 | p { 33 | color: #fff; 34 | font-size: 1.2rem; 35 | font-weight: normal; 36 | line-height: 1.6rem; 37 | margin-bottom: 30px; 38 | } 39 | 40 | .center { 41 | text-align: center; 42 | } 43 | 44 | button:focus, input:focus { 45 | outline:0; 46 | } 47 | 48 | button:hover, input[type=submit]:hover { 49 | cursor: pointer!important; 50 | } 51 | 52 | input[type=submit]:active { 53 | background: #fff; 54 | color: #f15953; 55 | } 56 | 57 | button.flat:active { 58 | background: transparent; 59 | cursor: pointer; 60 | border: 1px solid #fff; 61 | color: #fff; 62 | } 63 | 64 | button { 65 | color: #222222; 66 | font-size: 0.8rem; 67 | font-family: Serverless, sans-serif; 68 | font-weight: normal; 69 | box-shadow: none; 70 | border-radius: 0; 71 | display: inline-block; 72 | } 73 | 74 | button.flat { 75 | color: #f15953; 76 | font-size: 1.2rem; 77 | padding: 20px 60px; 78 | background: transparent; 79 | border: 1px solid #f15953; 80 | border-radius: 3px; 81 | } 82 | 83 | form { 84 | margin: 10px auto 25px auto; 85 | width: 100%; 86 | } 87 | 88 | input[type=email] { 89 | width: 80%; 90 | padding: 20px 0; 91 | margin-top: 20px; 92 | font-family: Serverless, sans-serif; 93 | font-weight: normal; 94 | font-size: 1.1rem; 95 | text-align: center; 96 | background: transparent; 97 | border: 1px solid #999; 98 | color: #fff; 99 | } 100 | 101 | input[type=submit] { 102 | width: 80%; 103 | padding: 20px 0; 104 | margin-top: 20px; 105 | color: #fff; 106 | background-color: #f15953; 107 | border: none; 108 | font-family: Serverless, sans-serif; 109 | } 110 | 111 | input { 112 | border-radius: 3px; 113 | } 114 | 115 | input:focus { 116 | border: 1px #ffffff solid; 117 | } 118 | 119 | input[type=submit]:focus { 120 | border: none; 121 | } 122 | 123 | .nav { 124 | display: block; 125 | padding: 15px 25px 15px 25px; 126 | overflow: auto; 127 | } 128 | 129 | .nav .nav-left { 130 | display: block; 131 | float: left; 132 | height: 40px; 133 | width: 50%; 134 | padding-top: 8px; 135 | text-align: left; 136 | font-size: 1rem; 137 | color: #fff; 138 | font-family: Serverless, sans-serif; 139 | font-weight: normal; 140 | } 141 | 142 | .nav .nav-right { 143 | display: block; 144 | float: right; 145 | height: 40px; 146 | width: 50%; 147 | text-align: right; 148 | } 149 | 150 | .logo-small { 151 | float: left; 152 | margin-right: 10px; 153 | margin-top: 0px; 154 | } 155 | 156 | .nav button.flat { 157 | font-size: 0.8rem; 158 | padding: 10px 30px; 159 | } 160 | 161 | .content { 162 | margin-top: 0px; 163 | } 164 | 165 | .hero-icon { 166 | font-size: 7rem; 167 | font-family: Serverless, sans-serif; 168 | color: #f15953; 169 | } 170 | 171 | .title { 172 | color: #fff; 173 | font-size: 1.5rem; 174 | font-family: Serverless, sans-serif; 175 | font-weight: normal; 176 | margin-top: 15px; 177 | } 178 | 179 | .tagline { 180 | color: #999; 181 | font-size: 1.8rem; 182 | font-family: Serverless, sans-serif; 183 | margin-top: 15px; 184 | } 185 | 186 | .section { 187 | margin: 30px auto 100px auto; 188 | width: 400px; 189 | font-size: 1.2rem; 190 | } 191 | 192 | .success { 193 | overflow: auto; 194 | font-size: 1.3rem; 195 | color: #bbb; 196 | margin-top: 50px; 197 | height: 80px; 198 | padding-top: 60px; 199 | border: 2px #444 dashed; 200 | } 201 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serverless/event-gateway-workshop/79043161bd64b087dcd9ec82167fe73cf82aea78/5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/logo.png -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in 9 | * IE on Windows Phone and in iOS. 10 | */ 11 | 12 | html { 13 | line-height: 1.15; /* 1 */ 14 | -ms-text-size-adjust: 100%; /* 2 */ 15 | -webkit-text-size-adjust: 100%; /* 2 */ 16 | } 17 | 18 | /* Sections 19 | ========================================================================== */ 20 | 21 | /** 22 | * Remove the margin in all browsers (opinionated). 23 | */ 24 | 25 | body { 26 | margin: 0; 27 | } 28 | 29 | /** 30 | * Add the correct display in IE 9-. 31 | */ 32 | 33 | article, 34 | aside, 35 | footer, 36 | header, 37 | nav, 38 | section { 39 | display: block; 40 | } 41 | 42 | /** 43 | * Correct the font size and margin on `h1` elements within `section` and 44 | * `article` contexts in Chrome, Firefox, and Safari. 45 | */ 46 | 47 | h1 { 48 | font-size: 2em; 49 | margin: 0.67em 0; 50 | } 51 | 52 | /* Grouping content 53 | ========================================================================== */ 54 | 55 | /** 56 | * Add the correct display in IE 9-. 57 | * 1. Add the correct display in IE. 58 | */ 59 | 60 | figcaption, 61 | figure, 62 | main { /* 1 */ 63 | display: block; 64 | } 65 | 66 | /** 67 | * Add the correct margin in IE 8. 68 | */ 69 | 70 | figure { 71 | margin: 1em 40px; 72 | } 73 | 74 | /** 75 | * 1. Add the correct box sizing in Firefox. 76 | * 2. Show the overflow in Edge and IE. 77 | */ 78 | 79 | hr { 80 | box-sizing: content-box; /* 1 */ 81 | height: 0; /* 1 */ 82 | overflow: visible; /* 2 */ 83 | } 84 | 85 | /** 86 | * 1. Correct the inheritance and scaling of font size in all browsers. 87 | * 2. Correct the odd `em` font sizing in all browsers. 88 | */ 89 | 90 | pre { 91 | font-family: monospace, monospace; /* 1 */ 92 | font-size: 1em; /* 2 */ 93 | } 94 | 95 | /* Text-level semantics 96 | ========================================================================== */ 97 | 98 | /** 99 | * 1. Remove the gray background on active links in IE 10. 100 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 101 | */ 102 | 103 | a { 104 | background-color: transparent; /* 1 */ 105 | -webkit-text-decoration-skip: objects; /* 2 */ 106 | } 107 | 108 | /** 109 | * 1. Remove the bottom border in Chrome 57- and Firefox 39-. 110 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 111 | */ 112 | 113 | abbr[title] { 114 | border-bottom: none; /* 1 */ 115 | text-decoration: underline; /* 2 */ 116 | text-decoration: underline dotted; /* 2 */ 117 | } 118 | 119 | /** 120 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: inherit; 126 | } 127 | 128 | /** 129 | * Add the correct font weight in Chrome, Edge, and Safari. 130 | */ 131 | 132 | b, 133 | strong { 134 | font-weight: bolder; 135 | } 136 | 137 | /** 138 | * 1. Correct the inheritance and scaling of font size in all browsers. 139 | * 2. Correct the odd `em` font sizing in all browsers. 140 | */ 141 | 142 | code, 143 | kbd, 144 | samp { 145 | font-family: monospace, monospace; /* 1 */ 146 | font-size: 1em; /* 2 */ 147 | } 148 | 149 | /** 150 | * Add the correct font style in Android 4.3-. 151 | */ 152 | 153 | dfn { 154 | font-style: italic; 155 | } 156 | 157 | /** 158 | * Add the correct background and color in IE 9-. 159 | */ 160 | 161 | mark { 162 | background-color: #ff0; 163 | color: #000; 164 | } 165 | 166 | /** 167 | * Add the correct font size in all browsers. 168 | */ 169 | 170 | small { 171 | font-size: 80%; 172 | } 173 | 174 | /** 175 | * Prevent `sub` and `sup` elements from affecting the line height in 176 | * all browsers. 177 | */ 178 | 179 | sub, 180 | sup { 181 | font-size: 75%; 182 | line-height: 0; 183 | position: relative; 184 | vertical-align: baseline; 185 | } 186 | 187 | sub { 188 | bottom: -0.25em; 189 | } 190 | 191 | sup { 192 | top: -0.5em; 193 | } 194 | 195 | /* Embedded content 196 | ========================================================================== */ 197 | 198 | /** 199 | * Add the correct display in IE 9-. 200 | */ 201 | 202 | audio, 203 | video { 204 | display: inline-block; 205 | } 206 | 207 | /** 208 | * Add the correct display in iOS 4-7. 209 | */ 210 | 211 | audio:not([controls]) { 212 | display: none; 213 | height: 0; 214 | } 215 | 216 | /** 217 | * Remove the border on images inside links in IE 10-. 218 | */ 219 | 220 | img { 221 | border-style: none; 222 | } 223 | 224 | /** 225 | * Hide the overflow in IE. 226 | */ 227 | 228 | svg:not(:root) { 229 | overflow: hidden; 230 | } 231 | 232 | /* Forms 233 | ========================================================================== */ 234 | 235 | /** 236 | * 1. Change the font styles in all browsers (opinionated). 237 | * 2. Remove the margin in Firefox and Safari. 238 | */ 239 | 240 | button, 241 | input, 242 | optgroup, 243 | select, 244 | textarea { 245 | font-family: sans-serif; /* 1 */ 246 | font-size: 100%; /* 1 */ 247 | line-height: 1.15; /* 1 */ 248 | margin: 0; /* 2 */ 249 | } 250 | 251 | /** 252 | * Show the overflow in IE. 253 | * 1. Show the overflow in Edge. 254 | */ 255 | 256 | button, 257 | input { /* 1 */ 258 | overflow: visible; 259 | } 260 | 261 | /** 262 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 263 | * 1. Remove the inheritance of text transform in Firefox. 264 | */ 265 | 266 | button, 267 | select { /* 1 */ 268 | text-transform: none; 269 | } 270 | 271 | /** 272 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 273 | * controls in Android 4. 274 | * 2. Correct the inability to style clickable types in iOS and Safari. 275 | */ 276 | 277 | button, 278 | html [type="button"], /* 1 */ 279 | [type="reset"], 280 | [type="submit"] { 281 | -webkit-appearance: button; /* 2 */ 282 | } 283 | 284 | /** 285 | * Remove the inner border and padding in Firefox. 286 | */ 287 | 288 | button::-moz-focus-inner, 289 | [type="button"]::-moz-focus-inner, 290 | [type="reset"]::-moz-focus-inner, 291 | [type="submit"]::-moz-focus-inner { 292 | border-style: none; 293 | padding: 0; 294 | } 295 | 296 | /** 297 | * Restore the focus styles unset by the previous rule. 298 | */ 299 | 300 | button:-moz-focusring, 301 | [type="button"]:-moz-focusring, 302 | [type="reset"]:-moz-focusring, 303 | [type="submit"]:-moz-focusring { 304 | outline: 1px dotted ButtonText; 305 | } 306 | 307 | /** 308 | * Correct the padding in Firefox. 309 | */ 310 | 311 | fieldset { 312 | padding: 0.35em 0.75em 0.625em; 313 | } 314 | 315 | /** 316 | * 1. Correct the text wrapping in Edge and IE. 317 | * 2. Correct the color inheritance from `fieldset` elements in IE. 318 | * 3. Remove the padding so developers are not caught out when they zero out 319 | * `fieldset` elements in all browsers. 320 | */ 321 | 322 | legend { 323 | box-sizing: border-box; /* 1 */ 324 | color: inherit; /* 2 */ 325 | display: table; /* 1 */ 326 | max-width: 100%; /* 1 */ 327 | padding: 0; /* 3 */ 328 | white-space: normal; /* 1 */ 329 | } 330 | 331 | /** 332 | * 1. Add the correct display in IE 9-. 333 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 334 | */ 335 | 336 | progress { 337 | display: inline-block; /* 1 */ 338 | vertical-align: baseline; /* 2 */ 339 | } 340 | 341 | /** 342 | * Remove the default vertical scrollbar in IE. 343 | */ 344 | 345 | textarea { 346 | overflow: auto; 347 | } 348 | 349 | /** 350 | * 1. Add the correct box sizing in IE 10-. 351 | * 2. Remove the padding in IE 10-. 352 | */ 353 | 354 | [type="checkbox"], 355 | [type="radio"] { 356 | box-sizing: border-box; /* 1 */ 357 | padding: 0; /* 2 */ 358 | } 359 | 360 | /** 361 | * Correct the cursor style of increment and decrement buttons in Chrome. 362 | */ 363 | 364 | [type="number"]::-webkit-inner-spin-button, 365 | [type="number"]::-webkit-outer-spin-button { 366 | height: auto; 367 | } 368 | 369 | /** 370 | * 1. Correct the odd appearance in Chrome and Safari. 371 | * 2. Correct the outline style in Safari. 372 | */ 373 | 374 | [type="search"] { 375 | -webkit-appearance: textfield; /* 1 */ 376 | outline-offset: -2px; /* 2 */ 377 | } 378 | 379 | /** 380 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 381 | */ 382 | 383 | [type="search"]::-webkit-search-cancel-button, 384 | [type="search"]::-webkit-search-decoration { 385 | -webkit-appearance: none; 386 | } 387 | 388 | /** 389 | * 1. Correct the inability to style clickable types in iOS and Safari. 390 | * 2. Change font properties to `inherit` in Safari. 391 | */ 392 | 393 | ::-webkit-file-upload-button { 394 | -webkit-appearance: button; /* 1 */ 395 | font: inherit; /* 2 */ 396 | } 397 | 398 | /* Interactive 399 | ========================================================================== */ 400 | 401 | /* 402 | * Add the correct display in IE 9-. 403 | * 1. Add the correct display in Edge, IE, and Firefox. 404 | */ 405 | 406 | details, /* 1 */ 407 | menu { 408 | display: block; 409 | } 410 | 411 | /* 412 | * Add the correct display in all browsers. 413 | */ 414 | 415 | summary { 416 | display: list-item; 417 | } 418 | 419 | /* Scripting 420 | ========================================================================== */ 421 | 422 | /** 423 | * Add the correct display in IE 9-. 424 | */ 425 | 426 | canvas { 427 | display: inline-block; 428 | } 429 | 430 | /** 431 | * Add the correct display in IE. 432 | */ 433 | 434 | template { 435 | display: none; 436 | } 437 | 438 | /* Hidden 439 | ========================================================================== */ 440 | 441 | /** 442 | * Add the correct display in IE 10-. 443 | */ 444 | 445 | [hidden] { 446 | display: none; 447 | } 448 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/assets/serverless-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import './assets/normalize.css'; 5 | import './assets/index.css'; 6 | import App from './App'; 7 | import configureStore from './store/configureStore'; 8 | 9 | const initialState = { 10 | session: sessionStorage.getItem('session') 11 | }; 12 | const store = configureStore(initialState); 13 | 14 | ReactDOM.render( 15 | 16 | 17 | , 18 | document.getElementById('root') 19 | ); 20 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/middleware/eventGateway.js: -------------------------------------------------------------------------------- 1 | import fdk from '@serverless/fdk/dist/fdk.min.js'; 2 | 3 | const eventGateway = fdk.eventGateway({ 4 | url: 'http://localhost:4000' 5 | }); 6 | 7 | export default store => next => action => { 8 | let event = {}; 9 | 10 | switch (action.type) { 11 | case 'USER_ACTIVITY_CLICKED': 12 | event.event = 'user.clicked'; 13 | event.data = action.data; 14 | break; 15 | default: 16 | event = null; 17 | break; 18 | } 19 | 20 | if (event) { 21 | eventGateway 22 | .emit(event) 23 | .then(() => { 24 | console.info(`Emitted ${event.event}`); 25 | console.log(event.data); 26 | }) 27 | .catch(() => { 28 | console.error(`Failed to emit ${event.event}`); 29 | console.log(event.data); 30 | }); 31 | } 32 | 33 | return next(action); 34 | }; 35 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import session from './session'; 3 | 4 | const rootReducer = combineReducers({ 5 | session 6 | }); 7 | 8 | export default rootReducer; 9 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/reducers/session.js: -------------------------------------------------------------------------------- 1 | export default (state = null, action) => { 2 | switch (action.type) { 3 | case 'REGISTER_USER_SUCCESS': 4 | return action.data.session; 5 | case 'USER_ACTIVITY_LOGOUT': 6 | return null; 7 | default: 8 | return state; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/frontend/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { createLogger } from 'redux-logger'; 3 | import thunk from 'redux-thunk'; 4 | import rootReducer from '../reducers'; 5 | import eventGateway from '../middleware/eventGateway'; 6 | 7 | const configureStore = initialState => { 8 | const composeEnhancers = 9 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 10 | return createStore( 11 | rootReducer, 12 | initialState, 13 | composeEnhancers(applyMiddleware(eventGateway, thunk, createLogger())) 14 | ); 15 | }; 16 | 17 | export default configureStore; 18 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "event-gateway-playground", 3 | "version": "1.0.0", 4 | "description": "Event Gateway Playground.", 5 | "main": "index.js", 6 | "scripts": { 7 | "setup": "node setup.js" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "chalk": "^2.1.0", 13 | "globby": "^6.1.0", 14 | "ora": "^1.3.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/.gitignore: -------------------------------------------------------------------------------- 1 | credentials.json 2 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "CREDENTIALS_FILE": "credentials.json", 3 | "PROJECT_ID": "replace-me", 4 | "DATASET_ID": "emit_demo", 5 | "TABLE_ID": "test_events" 6 | } 7 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const BigQuery = require('@google-cloud/bigquery'); 5 | const CREDENTIALS_FILE = process.env.CREDENTIALS_FILE 6 | const PROJECT_ID = process.env.PROJECT_ID 7 | const DATASET_ID = process.env.DATASET_ID 8 | const TABLE_ID = process.env.TABLE_ID 9 | 10 | const bigquery = BigQuery({ 11 | keyFilename: path.join(__dirname, CREDENTIALS_FILE), 12 | projectId: PROJECT_ID 13 | }); 14 | 15 | // Inserts data into a table 16 | function insertRows(rows) { 17 | bigquery 18 | .dataset(DATASET_ID) 19 | .table(TABLE_ID) 20 | .insert(rows) 21 | .then((resp) => { 22 | if (resp.insertErrors && resp.insertErrors.length > 0) { 23 | //console.log('Insert errors:'); 24 | resp.insertErrors.forEach((err) => console.error(err)); 25 | } 26 | }) 27 | .catch((err) => { 28 | console.log(JSON.stringify(err)); 29 | //console.error('ERROR:', JSON.stringify(err)); 30 | }); 31 | }; 32 | 33 | exports.recordEvents= (event, callback) => { 34 | 35 | // We're not storing dataType in BigQuery because we don't care about it. 36 | // We need to serialize the `data` object to a string before storing, since it's arbitrary JSON. 37 | // BigQuery timestamps are in seconds, so need to adjust the `receivedAt` field. 38 | var row = event; 39 | delete row.dataType; 40 | row.data = JSON.stringify(row.data); 41 | row.receivedAt = row.receivedAt / 1000.0; 42 | const rows = [row] 43 | 44 | insertRows(rows); 45 | callback(null, { 46 | message: 'Inserted row to BigQuery.', 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "analytics-service", 3 | "version": "0.1.0", 4 | "description": "Analytics service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@google-cloud/bigquery": "^0.9.6" 13 | }, 14 | "devDependencies": { 15 | "serverless-google-cloudfunctions": "^1.1.1", 16 | "serverless-remove-forced-login": "^0.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/serverless.yml: -------------------------------------------------------------------------------- 1 | service: analytics 2 | 3 | plugins: 4 | - serverless-google-cloudfunctions 5 | - serverless-remove-forced-login 6 | 7 | provider: 8 | name: google 9 | runtime: nodejs 10 | project: ${file(./config.json):PROJECT_ID} 11 | credentials: ~/.gcloud/keyfile.json 12 | environment: 13 | CREDENTIALS_FILE: ${file(./config.json):CREDENTIALS_FILE} 14 | PROJECT_ID: ${file(./config.json):PROJECT_ID} 15 | DATASET_ID: ${file(./config.json):DATASET_ID} 16 | TABLE_ID: ${file(./config.json):TABLE_ID} 17 | 18 | functions: 19 | analytics: 20 | handler: recordEvents 21 | events: 22 | - user.registered 23 | - user.clicked 24 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/analytics/setup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const path = require("path"); 4 | const BigQuery = require("@google-cloud/bigquery"); 5 | const config = require("./config.json"); 6 | const CREDENTIALS_FILE = config.CREDENTIALS_FILE; 7 | const PROJECT_ID = config.PROJECT_ID; 8 | const DATASET_ID = config.DATASET_ID; 9 | const TABLE_ID = config.TABLE_ID; 10 | 11 | const bigquery = BigQuery({ 12 | keyFilename: path.join(__dirname, CREDENTIALS_FILE), 13 | projectId: PROJECT_ID 14 | }); 15 | 16 | const dataset = bigquery.dataset(DATASET_ID); 17 | const opts = { 18 | schema: "event:string,id:string,receivedAt:timestamp,data:string", 19 | autoCreate: true 20 | }; 21 | 22 | // Get a dataset if it exists or create it if it doesn't 23 | dataset.get(opts, function(err, dataset, apiResponse) { 24 | if (err) { 25 | console.log("Error creating dataset"); 26 | throw new Error(err); 27 | } else { 28 | console.log("Dataset " + DATASET_ID + " created successfully."); 29 | 30 | // make sure to call createTable only on success 31 | dataset.createTable(TABLE_ID, opts, function(err, table, apiResponse) { 32 | if (err) { 33 | if (err.errors.length === 1 && err.errors[0].reason == "duplicate") { 34 | console.log("Table " + TABLE_ID + " already exists."); 35 | } else { 36 | console.log("Error creating table"); 37 | throw new Error(err); 38 | } 39 | } else { 40 | console.log("Table " + TABLE_ID + " created successfully."); 41 | } 42 | }); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/crm/handler.js: -------------------------------------------------------------------------------- 1 | module.exports.addUserToCrm = (event, context, callback) => { 2 | throw new Error('Can\'t add user to the CRM') 3 | } 4 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/crm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crm-service", 3 | "version": "1.0.0", 4 | "description": "CRM service.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-remove-forced-login": "^0.1.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/crm/serverless.yml: -------------------------------------------------------------------------------- 1 | service: 2 | name: crm 3 | description: 'A service connecting the app to the CRM system' 4 | 5 | plugins: 6 | - serverless-remove-forced-login 7 | 8 | custom: 9 | eventGatewayUrl: "http://localhost:4000" 10 | eventGatewayConfigUrl: "http://localhost:4001" 11 | 12 | provider: 13 | name: aws 14 | runtime: nodejs6.10 15 | stage: prod 16 | region: us-east-1 17 | environment: 18 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 19 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 20 | 21 | functions: 22 | addUserToCrm: 23 | handler: handler.addUserToCrm 24 | events: 25 | - user.registered 26 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/emails/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const emailer = require('./lib/emailer'); 4 | 5 | const EVENT_GATEWAY_URL = 'http://localhost:4000'; // process.env.EVENT_GATEWAY_URL; 6 | const EVENT_GATEWAY_CONFIG_URL = 'http://localhost:4001'; // process.env.EVENT_GATEWAY_CONFIG_URL; 7 | const fdk = require('@serverless/fdk'); 8 | const eventGateway = fdk.eventGateway({ 9 | url: EVENT_GATEWAY_URL, 10 | configurationUrl: EVENT_GATEWAY_CONFIG_URL 11 | }); 12 | 13 | module.exports.sendWelcomeEmail = (event, context, callback) => { 14 | 15 | // TODO: Send email here... 16 | 17 | // Emit event 'email.sent' 18 | eventGateway 19 | .emit({ 20 | event: 'email.sent', 21 | data: { 22 | "id": event.data.id, 23 | "name": event.data.name, 24 | "email": event.data.email 25 | } 26 | }) 27 | .then(() => { 28 | return callback(null, { message: 'Email sent.' }); 29 | }) 30 | .catch(err => { 31 | return callback({ error: err }, null); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/emails/lib/emailer.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // const MAILGUN_APIKEY = process.env.MAILGUN_APIKEY; 4 | // const MAILGUN_DOMAIN = process.env.MAILGUN_DOMAIN; 5 | // 6 | // const mailgun = require('mailgun-js')({ 7 | // apiKey: MAILGUN_APIKEY, 8 | // domain: MAILGUN_DOMAIN 9 | // }); 10 | // 11 | // const fromAddress = ``; 12 | // const subjectText = 'Serverless Emit Demo'; 13 | // const messageText = 'Welcome user email notification.'; 14 | // const messageHtml = ` 15 | // 16 | // Serverless Emit Demo 17 | // 18 | //
19 | //

Serverless Emit Demo

20 | // Welcome user email notification. 21 | //
22 | // 23 | // 24 | // `; 25 | 26 | module.exports = msg => { 27 | 28 | // var toAddress = ''; 29 | // 30 | // if (event.dataType === 'application/json') { 31 | // try { 32 | // // toAddress = JSON.parse(event.data).user.email || ""; 33 | // toAddress = event.data.user.email || ''; 34 | // } catch (e) { 35 | // console.log('**********\nError parsing email data', e); 36 | // } 37 | // } 38 | // 39 | // if (toAddress !== '') { 40 | // const emailData = { 41 | // from: fromAddress, 42 | // to: toAddress, 43 | // subject: subjectText, 44 | // text: messageText, 45 | // html: messageHtml 46 | // }; 47 | // 48 | // // send email 49 | // mailgun.messages().send(emailData, (error, body) => { 50 | // if (error) { 51 | // // log error response 52 | // console.log(error); 53 | // const response = { 54 | // statusCode: 400, 55 | // body: JSON.stringify({ 56 | // message: error, 57 | // input: body 58 | // }) 59 | // }; 60 | // callback(null, response); 61 | // } else { 62 | // const response = { 63 | // statusCode: 202, 64 | // body: JSON.stringify({ 65 | // message: 'Request to send email is successful.', 66 | // input: body 67 | // }) 68 | // }; 69 | // callback(null, response); 70 | // } 71 | // }); 72 | // } else { 73 | // const err = { 74 | // statusCode: 422, 75 | // body: JSON.stringify({ 76 | // message: 'Bad input data or missing email address.', 77 | // input: event.body 78 | // }) 79 | // }; 80 | // callback(null, err); 81 | // } 82 | } 83 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/emails/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email-service", 3 | "version": "1.0.0", 4 | "description": "E-Mail service.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "dependencies": { 12 | "mailgun-js": "^0.11.2", 13 | "@serverless/fdk": "^0.3.5" 14 | }, 15 | "devDependencies": { 16 | "serverless-remove-forced-login": "^0.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/emails/serverless.yml: -------------------------------------------------------------------------------- 1 | # A serverless service that sends out emails via Mailgun 2 | 3 | service: 4 | name: emails 5 | description: 'A service that sends out emails.' 6 | 7 | plugins: 8 | - serverless-remove-forced-login 9 | 10 | custom: 11 | eventGatewayUrl: "http://localhost:4000" 12 | eventGatewayConfigUrl: "http://localhost:4001" 13 | 14 | provider: 15 | name: aws 16 | runtime: nodejs6.10 17 | stage: prod 18 | region: us-east-1 19 | environment: 20 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 21 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 22 | 23 | functions: 24 | sendWelcomeEmail: 25 | handler: handler.sendWelcomeEmail 26 | events: 27 | - user.registered 28 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/errors/handler.js: -------------------------------------------------------------------------------- 1 | module.exports.alertAdmin = (event, context, callback) => { 2 | callback(null, { message: 'Admin informed.' }) 3 | } 4 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/errors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "errors-service", 3 | "version": "1.0.0", 4 | "description": "Errors service.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-remove-forced-login": "^0.1.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/errors/serverless.yml: -------------------------------------------------------------------------------- 1 | service: 2 | name: errors 3 | description: 'A service to act on Event Gateway system errors' 4 | 5 | plugins: 6 | - serverless-remove-forced-login 7 | 8 | custom: 9 | eventGatewayUrl: "http://localhost:4000" 10 | eventGatewayConfigUrl: "http://localhost:4001" 11 | 12 | provider: 13 | name: aws 14 | runtime: nodejs6.10 15 | stage: prod 16 | region: us-east-1 17 | environment: 18 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 19 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 20 | 21 | functions: 22 | alertAdmin: 23 | handler: handler.alertAdmin 24 | events: 25 | - gateway.info.functionError 26 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/users/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fdk = require('@serverless/fdk'); 4 | const users = require('./lib/users.js') 5 | 6 | const eventGateway = fdk.eventGateway({ 7 | url: 'http://localhost:4000' 8 | }); 9 | 10 | module.exports.register = (event, context, callback) => { 11 | 12 | // Validate 13 | if (!event.data || !event.data.body || !event.data.body.email) { 14 | return callback(null, { 15 | statusCode: 400, 16 | body: JSON.stringify({message: 'Email is required'}) 17 | }) 18 | } 19 | 20 | // Register user 21 | users.register({ 22 | email: event.data.body.email, 23 | name: event.data.body.name 24 | }, function(data) { 25 | 26 | // Emit event 27 | eventGateway 28 | .emit({ 29 | event: 'user.registered', 30 | data: data 31 | }) 32 | .then(() => { 33 | return callback(null, data); 34 | }) 35 | .catch(err => { 36 | return callback({ error: err }, null); 37 | }); 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/users/lib/users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | 5 | module.exports.register = (user, cb) => { 6 | return cb({ 7 | id: Math.floor(Math.random() * 100 + 1), 8 | session: crypto.createHash('md5').update(user.email).digest('hex'), 9 | email: user.email, 10 | name: user.name 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/users/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "users-service", 3 | "version": "1.0.0", 4 | "description": "Users service.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@serverless/fdk": "^0.3.5" 13 | }, 14 | "devDependencies": { 15 | "serverless-remove-forced-login": "^0.1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/users/serverless.yml: -------------------------------------------------------------------------------- 1 | # users-api crud service 2 | 3 | service: 4 | name: users 5 | description: 'Users CRUD service.' 6 | 7 | plugins: 8 | - serverless-remove-forced-login 9 | 10 | custom: 11 | eventGatewayUrl: "http://localhost:4000" 12 | eventGatewayConfigUrl: "http://localhost:4001" 13 | 14 | provider: 15 | name: aws 16 | runtime: nodejs6.10 17 | stage: prod 18 | region: us-east-1 19 | environment: 20 | EVENT_GATEWAY_URL: ${self:custom.eventGatewayUrl} 21 | EVENT_GATEWAY_CONFIG_URL: ${self:custom.eventGatewayConfigUrl} 22 | 23 | functions: 24 | register: 25 | handler: handler.register 26 | events: 27 | - http: 28 | path: /users 29 | method: POST 30 | # cors has to be commented out until we change how data is sent to the Event Gateway 31 | # cors: true 32 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/vision/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_KEY": "replace-me", 3 | "PROJECT_ID": "replace-me" 4 | } 5 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/vision/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fdk = require('@serverless/fdk'); 4 | const vision = require('./lib/vision'); 5 | 6 | const eventGateway = fdk.eventGateway({ 7 | url: 'http://localhost:4000' 8 | }); 9 | 10 | exports.annotateUser = (event, callback) => { 11 | 12 | const email = event.data.email; 13 | 14 | vision.getEntities(email, function(data) { 15 | 16 | // Emit event 17 | eventGateway 18 | .emit({ 19 | event: 'user.annotated', 20 | data: data 21 | }) 22 | .then(() => { 23 | return callback(null, data); 24 | }) 25 | .catch(err => { 26 | return callback({error: err}, null); 27 | }) 28 | }) 29 | }; 30 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/vision/lib/vision.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fetch = require('node-fetch'); 4 | const md5 = require('md5'); 5 | const API_KEY = process.env.API_KEY; 6 | 7 | module.exports.getEntities = (email, cb) => { 8 | const imageUri = "http://www.gravatar.com/avatar/" + md5(email); 9 | 10 | return annotateImage(imageUri) 11 | .then(function(json) { 12 | const webEntities = json.responses[0].webDetection.webEntities; 13 | const entities = webEntities.map(function(d) {return d.description}); 14 | return cb({ 15 | email: email, 16 | entities: entities 17 | }) 18 | }); 19 | } 20 | 21 | const annotateImage = (imageUri) => { 22 | var body = { 23 | "requests": [ 24 | { 25 | "image": { 26 | "source": { 27 | "imageUri": imageUri 28 | } 29 | }, 30 | "features": [ 31 | { 32 | "type": "WEB_DETECTION", 33 | "maxResults": 5 34 | } 35 | ] 36 | } 37 | ] 38 | }; 39 | 40 | return fetch('https://vision.googleapis.com/v1/images:annotate?key=' + API_KEY, { method: 'POST', body: JSON.stringify(body) }) 41 | .then((res) => res.json()) 42 | } 43 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/vision/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vision-service", 3 | "version": "0.1.0", 4 | "description": "Vision service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "serverless.com", 10 | "license": "MIT", 11 | "dependencies": { 12 | "md5": "^2.2.1", 13 | "node-fetch": "^1.7.2" 14 | }, 15 | "devDependencies": { 16 | "serverless-google-cloudfunctions": "^1.1.1", 17 | "serverless-remove-forced-login": "^0.1.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/services/vision/serverless.yml: -------------------------------------------------------------------------------- 1 | service: vision 2 | 3 | plugins: 4 | - serverless-google-cloudfunctions 5 | - serverless-remove-forced-login 6 | 7 | provider: 8 | name: google 9 | runtime: nodejs 10 | project: ${file(./config.json):PROJECT_ID} 11 | credentials: ~/.gcloud/keyfile.json 12 | environment: 13 | API_KEY: ${file(./config.json):API_KEY} 14 | 15 | functions: 16 | annotate: 17 | handler: annotateUser 18 | events: 19 | - user.registered 20 | -------------------------------------------------------------------------------- /5-unleashing-the-multi-cloud-power/event-gateway-playground/setup.js: -------------------------------------------------------------------------------- 1 | /* streamline exmple setup ⊂◉‿◉つ */ 2 | const path = require("path"); 3 | const globby = require("globby"); 4 | const chalk = require("chalk"); 5 | const ora = require("ora"); 6 | const exec = require("child_process").exec; 7 | 8 | console.log(`Welcome to the Serverless Event Gateway Playground`); 9 | console.log("Hold tight while we install the dependencies for you"); 10 | 11 | globby([ 12 | "{,!(node_modules)/**/}package.json", 13 | "!node_modules{,/**}", 14 | "!*/**/node_modules{,/**}" 15 | ]).then(paths => { 16 | // Now run npm install 17 | const files = paths.filter(i => { 18 | return i !== "package.json"; 19 | }); 20 | 21 | const command = `npm install`; 22 | let count = 0; 23 | files.forEach(p => { 24 | var t = path.join(__dirname, p); 25 | var dirPath = path.dirname(t); 26 | var dirName = path.basename(dirPath); 27 | var niceName = path.basename(path.dirname(dirPath)) + "/" + dirName; 28 | let spinner = ora("Installing dependencies").start(); 29 | spinner.color = "yellow"; 30 | spinner.text = `Installing dependencies for ${niceName}`; 31 | 32 | if (niceName === "event-gateway-example/frontend") { 33 | setTimeout(() => { 34 | spinner.text = `Still Installing dependencies for ${niceName}. Hang tight`; 35 | }, 15000); 36 | } 37 | 38 | const child = exec( 39 | command, 40 | { 41 | cwd: path.dirname(t), 42 | stdio: [0, 1, 2] 43 | }, 44 | (error, stdout, stderr) => { 45 | if (error) { 46 | console.warn(error); 47 | } 48 | } 49 | ); 50 | child.stdout.on("data", data => {}); 51 | child.stderr.on("data", data => {}); 52 | child.on("close", code => { 53 | spinner.color = "green"; 54 | spinner.text = `Successfully installed dependencies ${niceName}`; 55 | spinner.succeed(); 56 | spinner.stop(); 57 | count++; 58 | if (count === files.length) { 59 | // ALL done 60 | console.log(chalk.green("You are all set")); 61 | console.log("---------"); 62 | console.log(chalk.yellow("To run a service with the gateway: ")); 63 | console.log("- cd into a service folder e.g. services/users"); 64 | console.log("- then run `sls run`"); 65 | console.log("---------"); 66 | console.log(chalk.yellow("To run the frontend run:")); 67 | console.log("- cd into ./frontend"); 68 | console.log("- then run `npm start`"); 69 | process.exit(0); 70 | } 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update -y && apt-get upgrade -y \ 4 | && apt-get install -y screen rsync curl git python-dev python-pip 5 | 6 | # upgrade pip 7 | RUN pip install --upgrade pip 8 | 9 | # install Node.js and update npm 10 | RUN curl -sL https://deb.nodesource.com/setup_9.x | bash - 11 | RUN apt-get update -y \ 12 | && apt-get upgrade -y \ 13 | && apt-get install -y nodejs build-essential \ 14 | && npm install npm@latest -g 15 | 16 | # install yarn 17 | RUN curl -o- -L https://yarnpkg.com/install.sh | bash 18 | 19 | # install awscli 20 | RUN pip install awscli 21 | 22 | # install the Serverless Framework 23 | RUN npm install --global serverless 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Event Gateway Workshop 2 | 3 | Learn what the [Event Gateway](https://github.com/serverless/event-gateway) is, how it works and build your first event-driven multi-cloud application! 4 | 5 | ## Manual setup 6 | 7 | ### Install Node.js 8 | 9 | Download and install the Node.js version for your platform from the official [download page](https://nodejs.org/en/download/). 10 | 11 | ### Install the Serverless Framework 12 | 13 | Run `npm install --global serverless` 14 | 15 | ## Docker-driven setup 16 | 17 | Run `docker-compose run -p 3000:3000 -p 4000:4000 -p 4001:4001 event-gateway-workshop bash` 18 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | event-gateway-workshop: 4 | build: 5 | context: ./ 6 | working_dir: /app 7 | volumes: 8 | - .:/app 9 | - ~/.aws/:/root/.aws 10 | - ~/.gcloud/:/root/.gcloud 11 | expose: 12 | - '3000' 13 | - '4000' 14 | - '4001' 15 | ports: 16 | - '3000:3000' 17 | - '4000:4000' 18 | - '4001:4001' 19 | -------------------------------------------------------------------------------- /utils/credentials-helper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | accessKeyId=REPLACEME 4 | secretAccessKey=REPLACEME 5 | 6 | export AWS_ACCESS_KEY_ID=$accessKeyId && export AWS_SECRET_ACCESS_KEY=$secretAccessKey 7 | -------------------------------------------------------------------------------- /utils/eg-download: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl https://raw.githubusercontent.com/serverless/event-gateway/master/install.sh | sh 4 | -------------------------------------------------------------------------------- /utils/event-gateway-discovery/index.css: -------------------------------------------------------------------------------- 1 | .centered { 2 | text-align: center; 3 | } 4 | -------------------------------------------------------------------------------- /utils/event-gateway-discovery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Event Gateway Discovery 4 | 5 | 6 | 7 | 8 |
9 |
10 |

Event Gateway Discovery

11 |
12 |
13 |
14 |
15 |
16 |

Functions

17 |
18 |
19 |
20 |

Subscriptions

21 |
22 |
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /utils/event-gateway-discovery/index.js: -------------------------------------------------------------------------------- 1 | const apiVersion = "v1"; 2 | const configUrl = "http://localhost:4001"; 3 | 4 | function getFunctions() { 5 | return fetch(`${configUrl}/${apiVersion}/functions`).then(resp => 6 | resp.json().then(data => data.functions) 7 | ); 8 | } 9 | 10 | function getSubscriptions() { 11 | return fetch(`${configUrl}/${apiVersion}/subscriptions`).then(resp => 12 | resp.json().then(data => data.subscriptions) 13 | ); 14 | } 15 | 16 | (() => { 17 | const funcsDiv = document.querySelector("#functions"); 18 | const subsDiv = document.querySelector("#subscriptions"); 19 | 20 | return Promise.all([getFunctions(), getSubscriptions()]) 21 | .then(res => { 22 | const funcs = res[0]; 23 | const subs = res[1]; 24 | 25 | if (!funcs.length) { 26 | funcsDiv.innerHTML = 27 | "

There are functions registrations available right now

"; 28 | } else { 29 | let table = 30 | '#{items}
Function ID
'; 31 | const items = funcs.map(func => `${func.functionId}`); 32 | table = table.replace("#{items}", items.join("")); 33 | funcsDiv.innerHTML = table; 34 | } 35 | 36 | if (!subs.length) { 37 | subsDiv.innerHTML = 38 | "

There are no subscriptions available right now

"; 39 | } else { 40 | let table = 41 | '#{items}
Function IDSubscription ID
'; 42 | const items = subs.map( 43 | sub => 44 | `${sub.functionId}${sub.subscriptionId}` 45 | ); 46 | table = table.replace("#{items}", items.join("")); 47 | subsDiv.innerHTML = table; 48 | } 49 | }) 50 | .catch(error => { 51 | alert( 52 | `Error pinging the Event Gateway config URL at "${configUrl}". Is the Event Gateway running?` 53 | ); 54 | }); 55 | })(); 56 | --------------------------------------------------------------------------------