Skip to content

Add sample for cloudevents-nodejs #2446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/serving/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Serving resources and how they can be applied across common use cases.
| Name | Description | Languages |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Hello World | A quick introduction that highlights how to deploy an app using Knative Serving. | [C#](./hello-world/helloworld-csharp/README.md), [Go](./hello-world/helloworld-go/README.md), [Java (Spark)](./hello-world/helloworld-java-spark/README.md), [Java (Spring)](./hello-world/helloworld-java-spring/README.md), [Kotlin](./hello-world/helloworld-kotlin/README.md), [Node.js](./hello-world/helloworld-nodejs/README.md), [PHP](./hello-world/helloworld-php/README.md), [Python](./hello-world/helloworld-python/README.md), [Ruby](./hello-world/helloworld-ruby/README.md), [Scala](./hello-world/helloworld-scala/README.md), [Shell](./hello-world/helloworld-shell/README.md) |
| Cloud Events | A quick introduction that highlights how to send and receive Cloud Events. | [C#](./cloudevents/cloudevents-dotnet/README.md), [Go](./cloudevents/cloudevents-go/README.md) |
| Cloud Events | A quick introduction that highlights how to send and receive Cloud Events. | [C#](./cloudevents/cloudevents-dotnet/README.md), [Go](./cloudevents/cloudevents-go/README.md), [Node.js](./cloudevents/cloudevents-nodejs/README.md) |
| Advanced Deployment | Simple blue/green-like application deployment pattern illustrating the process of updating a live application without dropping any traffic. | [YAML](./blue-green-deployment.md) |
| Autoscale | A demonstration of the autoscaling capabilities of Knative. | [Go](./autoscale-go/README.md) | | | |
| Autoscale | A demonstration of the autoscaling capabilities of Knative. | [Go](./autoscale-go/README.md) |
| Github Webhook | A simple webhook handler that demonstrates interacting with Github. | [Go](./gitwebhook-go/README.md) |
| gRPC | A simple gRPC server. | [Go](./grpc-ping-go/README.md) |
| Knative Routing | An example of mapping multiple Knative services to different paths under a single domain name using the Istio VirtualService concept. | [Go](./knative-routing-go/README.md) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Dockerfile
README.md
node_modules/
npm-debug.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
npm-debug.log*
38 changes: 38 additions & 0 deletions docs/serving/samples/cloudevents/cloudevents-nodejs/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2020 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM registry.access.redhat.com/ubi8/nodejs-12

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm install on every code change.
COPY package*.json ./

# Use ci is faster and more reliable following package-lock.json
RUN npm ci --only=production

# Doc port listening port
ENV PORT 8080

EXPOSE $PORT

ARG ENV=production

ENV NODE_ENV $ENV

# Run the web service on container startup.
CMD npm run $NODE_ENV

# Copy local code to the container image.
COPY . ./
100 changes: 100 additions & 0 deletions docs/serving/samples/cloudevents/cloudevents-nodejs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
A simple web app written in Node.js that can receive and send Cloud Events that you
can use for testing. It supports running in two modes:

1. The default mode has the app reply to your input events with the output
event, which is simplest for demonstrating things working in isolation, but
is also the model for working for the Knative Eventing `Broker` concept.

2. `K_SINK` mode has the app send events to the destination encoded in
`$K_SINK`, which is useful to demonstrate how folks can synthesize events to
send to a Service or Broker when not initiated by a Broker invocation (e.g.
implementing an event source)

The application will use `$K_SINK`-mode whenever the environment variable is
specified.

Follow the steps below to create the sample code and then deploy the app to your
cluster. You can also download a working copy of the sample, by running the
following commands:

```shell
git clone -b "{{< branch >}}" https://github.com/knative/docs knative-docs
cd knative-docs/docs/serving/samples/cloudevents/cloudevents-nodejs
```

## Before you begin

- A Kubernetes cluster with Knative installed and DNS configured. Follow the
[installation instructions](../../../../install/README.md) if you need to
create one.
- [Docker](https://www.docker.com) installed and running on your local machine,
and a Docker Hub account configured (we'll use it for a container registry).

## The sample code.

1. If you look in `index.js`, you will see two key functions for the
different modes of operation:

```js
const receiveAndSend = (cloudEvent, res) => {
// This is called whenever an event is received if $K_SINK is set, and sends a new event
// to the url in $K_SINK.
}

const receiveAndReply = (cloudEvent, res) => {
// This is called whenever an event is received if $K_SINK is NOT set, and it replies with
// the new event instead.
}
```

1. If you look in `Dockerfile`, you will see how the dependencies are installed using npm.
You can build and push this to your registry of choice via:

```shell
docker build -t <image> .
docker push <image>
```

1. If you look in `service.yaml`, take the `<image>` name above and insert it
into the `image:`.

```shell
kubectl apply -f service.yaml
```

## Testing the sample

Get the URL for your Service with:

```shell
$ kubectl get ksvc
NAME URL LATESTCREATED LATESTREADY READY REASON
cloudevents-nodejs http://cloudevents-nodejs.default.1.2.3.4.xip.io cloudevents-nodejs-ss5pj cloudevents-nodejs-ss5pj True
```

Then send a cloud event to it with:

```shell
$ curl -X POST \
-H "content-type: application/json" \
-H "ce-specversion: 1.0" \
-H "ce-source: curl-command" \
-H "ce-type: curl.demo" \
-H "ce-id: 123-abc" \
-d '{"name":"Dave"}' \
http://cloudevents-nodejs.default.1.2.3.4.xip.io
```

You will get back:

```shell
{"message":"Hello, Dave"}
```

## Removing the sample app deployment

To remove the sample app from your cluster, delete the service record:

```shell
kubectl delete --filename service.yaml
```
107 changes: 107 additions & 0 deletions docs/serving/samples/cloudevents/cloudevents-nodejs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

const express = require('express')
const { CloudEvent, HTTPEmitter, HTTPReceiver } = require('cloudevents-sdk')
const PORT = process.env.PORT || 8080
const target = process.env.K_SINK
const app = express()
const receiver = new HTTPReceiver()

const main = () => {
app.listen(PORT, function () {
console.log(`Cookie monster is hungry for some cloudevents on port ${PORT}!`)
const modeMessage = target ? `send cloudevents to K_SINK: ${target}` : 'reply back with cloudevents'
console.log(`Cookie monster is going to ${modeMessage}`)
})
}

// handle shared the logic for producing the Response event from the Request.
const handle = (data) => {
return { message: `Hello, ${data.name ? data.name : 'nameless'}` }
}

// receiveAndSend responds with ack, and send a new event forward
const receiveAndSend = (cloudEvent, res) => {
const data = handle(cloudEvent.getData())
const newCloudEvent = new CloudEvent()
.type('dev.knative.docs.sample')
.source('https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-nodejs')
.time(new Date())
.data(data)

// With only an endpoint URL, this creates a v1 emitter
const emitter = new HTTPEmitter({
url: target
})
// Reply back to dispatcher/client as soon as possible
res.status(202).end()
// Send the new Event to the K_SINK
emitter.send(newCloudEvent)
.then((res) => {
console.log(`Sent event: ${JSON.stringify(newCloudEvent.format(), null, 2)}`)
console.log(`K_SINK responded: ${JSON.stringify({ status: res.status, headers: res.headers, data: res.data }, null, 2)}`)
})
.catch(console.error)
}

// receiveAndReply responds with new event
const receiveAndReply = (cloudEvent, res) => {
const data = handle(cloudEvent.getData())
const newCloudEvent = new CloudEvent()
.type('dev.knative.docs.sample')
.source('https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-nodejs')
.time(new Date())

console.log(`Reply event: ${JSON.stringify(newCloudEvent.format(), null, 2)}`)
res.set(getHeaders(newCloudEvent))
res.status(200).send(data)
}

const getHeaders = (cloudEvent) => {
/* TODO: SDK should provide a better way to get the headers from a cloudEvent, using fake url for now ¯\_(ツ)_/¯ */
const emitter = new HTTPEmitter({
url: 'http://example.com'
})
return emitter.headers(cloudEvent)
}

app.use((req, res, next) => {
let data = ''
req.setEncoding('utf8')
req.on('data', function (chunk) {
data += chunk
})
req.on('end', function () {
req.body = data
next()
})
})

app.post('/', function (req, res) {
try {
const event = receiver.accept(req.headers, req.body)
console.log(`Accepted event: ${JSON.stringify(event.format(), null, 2)}`)
target ? receiveAndSend(event, res) : receiveAndReply(event, res)
} catch (err) {
console.error(err)
res.status(415)
.header('Content-Type', 'application/json')
.send(JSON.stringify(err))
}
})

main()
8 changes: 8 additions & 0 deletions docs/serving/samples/cloudevents/cloudevents-nodejs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: "Cloud Events - Node.js"
linkTitle: "Node.js"
weight: 1
type: "docs"
---

{{% readfile file="README.md" %}}
Loading