├── .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 |
`);
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 |
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 | : }
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 |