Skip to content

Commit 1ec98d6

Browse files
committed
Add Deno examples
1 parent 9b3a1d8 commit 1ec98d6

File tree

12 files changed

+975
-0
lines changed

12 files changed

+975
-0
lines changed

examples/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ each example.
1616
* [`bun/`](./bun) - Usage with a Bun application as the origin.
1717
* [`http-stream/`](./bun/http-stream) - HTTP streaming using GRIP.
1818
* [`websocket/`](./bun/websocket) - WebSocket-over-HTTP using GRIP.
19+
20+
* [`deno/`](./deno) - Usage with a Deno application as the origin.
21+
* [`http-stream/`](./deno/http-stream) - HTTP streaming using GRIP.
22+
* [`websocket/`](./deno/websocket) - WebSocket-over-HTTP using GRIP.

examples/deno/README.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Examples for Deno
2+
3+
The examples in this directory illustrate the use of GRIP using
4+
a [Deno](https://deno.com) application as the backend.
5+
6+
* [`http-stream/`](./http-stream) - HTTP streaming using GRIP.
7+
* [`websocket/`](./websocket) - WebSocket-over-HTTP using GRIP.
8+
9+
For details on each example, view the `README` file in its
10+
respective directory.
11+
12+
## Running the examples locally
13+
14+
Each example can be run locally by running it alongside an instance of
15+
[Pushpin](https://pushpin.org/).
16+
17+
To run the examples locally, you'll need:
18+
19+
* Deno - [installation instructions](https://docs.deno.com/runtime/manual#install-deno)
20+
* Pushpin - [installation instructions](https://pushpin.org/docs/install/)
21+
22+
> NOTE: Instead of local Pushpin, you can also run the examples using Fastly Fanout for the GRIP proxy.
23+
See [Running the examples on Fastly Fanout](#running-the-examples-with-fastly-fanout-as-the-grip-proxy) below.
24+
25+
1. Set up Pushpin by modifying the `routes` file with the following content
26+
(See [this page](https://pushpin.org/docs/configuration/) for details on
27+
Pushpin configuration):
28+
29+
```
30+
* 127.0.0.1:3000
31+
```
32+
33+
2. Start Pushpin.
34+
35+
```
36+
pushpin
37+
```
38+
39+
By default, it will listen on port 7999, with a publishing
40+
endpoint open on port 5561. Leave Pushpin running in that terminal window.
41+
42+
3. In a new terminal window, switch to the example's directory.
43+
44+
4. Start the example:
45+
46+
```
47+
deno task start
48+
```
49+
50+
This will invoke Deno to start the example application.
51+
52+
5. Go on to follow the steps under each example's `README` file.
53+
54+
## Description of common code between the examples
55+
56+
Each example has the same general structure:
57+
* Configuring GRIP and instantiating the `Publisher`
58+
* Setting up the request handler and checking GRIP status
59+
* Handling (specific to the example)
60+
* Starting the server
61+
62+
### Configuration of GRIP
63+
64+
Each example interfaces with GRIP using the `Publisher` class.
65+
66+
To configure `Publisher`, a GRIP configuration object `gripConfig` is used.
67+
The example applications give it a default value of `http://127.0.0.1:5561/` to point to
68+
local Pushpin.
69+
70+
```typescript
71+
let gripConfig: string | IGripConfig = 'http://127.0.0.1:5561/';
72+
```
73+
74+
It may be overridden using a `GRIP_URL`, which in the Deno backend application is set as an
75+
environment variable.
76+
Additionally, in the example, the utility function `parseGripUri` is used to merge in the `GRIP_VERIFY_KEY`
77+
if it's required by the proxy.
78+
79+
```typescript
80+
const gripUrl = Deno.env.GRIP_URL;
81+
if (gripUrl) {
82+
gripConfig = parseGripUri(gripUrl, { 'verify-key': Deno.env.GRIP_VERIFY_KEY });
83+
}
84+
```
85+
86+
Alternatively, the environment variables `FANOUT_SERVICE_ID` and `FANOUT_API_TOKEN`
87+
are checked, and if present, they are used with the `buildFanoutGripConfig()` function to
88+
build the `gripConfig`.
89+
90+
```typescript
91+
const fanoutServiceId = Deno.env.FANOUT_SERVICE_ID;
92+
const fanoutApiToken = Deno.env.FANOUT_API_TOKEN;
93+
if (fanoutServiceId != null && fanoutApiToken != null) {
94+
gripConfig = buildFanoutGripConfig({
95+
serviceId: fanoutServiceId,
96+
apiToken: fanoutApiToken,
97+
});
98+
}
99+
```
100+
101+
Finally, this `gripConfig` is used to instantiate `Publisher`.
102+
103+
```typescript
104+
const publisher = new Publisher(gripConfig);
105+
```
106+
107+
In the Deno example, this initialization happens outside the request handler to enable the
108+
single `Publisher` instance to be reused among incoming requests.
109+
110+
### The request handler and GRIP status
111+
112+
The application then defines a `handler` function as is standard in Deno applications:
113+
114+
```typescript
115+
async function handler(request: Request) {
116+
const requestUrl = new URL(request.url);
117+
118+
// handler code ...
119+
}
120+
```
121+
122+
The backend application is intended to be called via a GRIP proxy. When the handler runs,
123+
a GRIP proxy will have inserted a `Grip-Sig` header into the request, which it has
124+
signed with a secret or key.
125+
126+
The request handler calls `publisher.validateGripSig` to validate this header,
127+
storing the result in the `gripStatus` variable.
128+
```typescript
129+
const gripStatus = await publisher.validateGripSig(request.headers.get('grip-sig'));
130+
```
131+
132+
This result can be checked for three fields:
133+
`gripStatus.isProxied` - When `true`, indicates that the current request is behind
134+
a GRIP proxy. If `needsSigned` is `true`, then this will only be `true` if the
135+
signature validation has also succeeded.
136+
`gripStatus.needsSigned` - When `true`, indicates that the GRIP proxy specified in the
137+
configuration signs incoming requests.
138+
`gripStatus.isSigned` - When `true`, indicates that the signature validation was successful.
139+
140+
### Handling the request
141+
142+
Following this, the request handler in each example handles the request in its
143+
respective way. Refer to the README in each project for details.
144+
145+
A catch-all at the end of the handler handles unhandled requests with a `404 Not
146+
Found` error.
147+
148+
### Starting the server
149+
150+
After the request handler has been declared, the Deno application starts the
151+
server, which begins listening on port 3000.
152+
153+
```typescript
154+
Deno.serve({ port: 3000 }, handler);
155+
```
156+
157+
Refer to the README in each project for details on how to work with the example.
158+
159+
## Running the examples with Fastly Fanout as the GRIP proxy
160+
161+
By publishing these examples publicly, they can also be run behind
162+
[Fastly Fanout](https://docs.fastly.com/products/fanout) to benefit from a global
163+
network and holding client connections at the edge.
164+
165+
Aside from your backend application running publicly on the internet,
166+
you will need a separate Fastly Compute service with Fanout enabled.
167+
This Fastly service runs a small program at the edge that examines
168+
each request and performs a "handoff" to Fanout for relevant requests,
169+
allowing Fanout to hold client connections and interpret GRIP messages.
170+
171+
The [Fastly Fanout Forwarding Starter Kit (JavaScript)](https://github.com/fastly/compute-starter-kit-javascript-fanout-forward#readme)
172+
can be used for this purpose. In many cases it can be used as is,
173+
or as a starting point for further customization.
174+
175+
One simple way to do this is to host the example backend in a free
176+
[Deno Deploy](https://dash.deno.com) account, and then set up a Fastly service with a
177+
[free trial of Fanout](https://www.fastly.com/documentation/guides/concepts/real-time-messaging/fanout/#enable-fanout).
178+
179+
### Setting up Fastly and the Fanout Forwarding starter kit
180+
181+
The following steps describe the process of setting up the
182+
[Fastly Fanout Forwarding Starter Kit (JavaScript)](https://github.com/fastly/compute-starter-kit-javascript-fanout-forward#readme)
183+
on your Fastly account.
184+
185+
1. If you don't already have a Fastly account, sign up for [a free developer account](https://www.fastly.com/signup).
186+
187+
2. Create a new API token (personal access token) that has `global` scope for your
188+
account.
189+
190+
3. If you haven't already installed the Fastly CLI, [install it](https://www.fastly.com/documentation/reference/tools/cli/).
191+
192+
4. Set up the Fastly CLI with a [user profile](https://www.fastly.com/documentation/reference/tools/cli/#configuring),
193+
using your API token from above.
194+
195+
5. Create a new directory where you will set up Fastly Fanout Forwarding, and switch to the
196+
directory.
197+
198+
```
199+
mkdir fastly-fanout-forward
200+
cd fastly-fanout-forward
201+
```
202+
203+
6. Initialize the directory as a Fastly Compute application. Provide a name for the application, a description, and
204+
author info.
205+
206+
```
207+
fastly compute init --from=https://github.com/fastly/compute-starter-kit-javascript-fanout-forward
208+
```
209+
210+
7. Deploy the application to your Fastly account.
211+
212+
```
213+
fastly compute publish --status-check-off
214+
```
215+
216+
* You will be asked whether you want to create a new service. Reply `y`. Provide the following values:
217+
* **Service name**: CUse the default value, or provide a name that you like.
218+
* **Domain**: Use the default value, or choose a subdomain of **edgecompute.app** that you like.
219+
* **Backend**: For now, do not specify any backends.
220+
* Your service will be packaged and deployed to a new service.
221+
* Make a note of the new service's ID (You'll need it to configure the publisher in the next section).
222+
223+
8. You'll come back to Fastly to set up Fanout and origin host later.
224+
225+
### Setting up the example (backend) code
226+
227+
Follow the steps provided by [Deno Deploy](https://dash.deno.com/account/overview) to set up your code to be deployed to
228+
Deno's platform.
229+
230+
You'll want to deploy and keep in mind the following:
231+
232+
* You need to set up [environment variables](https://docs.deno.com/deploy/manual/environment-variables) for your
233+
Deno Deploy application to set up the environment variables needed to configure the
234+
`Publisher`.
235+
236+
You may either provide `FANOUT_SERVICE_ID` and `FANOUT_API_TOKEN`, or `GRIP_URL` and `GRIP_VERIFY_KEY`.
237+
238+
1. Using `FANOUT_SERVICE_ID` and `FANOUT_API_TOKEN`:
239+
* `FANOUT_SERVICE_ID` - Set this to your Fastly service ID.
240+
* `FANOUT_API_TOKEN` - Set this to your Fastly API token.
241+
2. Using `GRIP_URL`:
242+
* `GRIP_URL` - Set this to `'https://api.fastly.com/service/<SERVICE_ID>?key=<FASTLY_API_TOKEN>&verify-iss=fastly:<SERVICE_ID>'`.
243+
* Replace both instances of `<SERVICE_ID>` in the URL with your Fastly service ID.
244+
* Replace `<FASTLY_API_TOKEN>` in the URL with your Fastly API token.
245+
* Don't forget to put single quotes around the whole thing, so that Glitch can treat the colon and ampersand literally.
246+
* `GRIP_VERIFY_KEY` - Set this to the value `{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"CKo5A1ebyFcnmVV8SE5On-8G81JyBjSvcrx4VLetWCg\",\"y\":\"7gwJqaU6N8TP88--twjkwoB36f-pT3QsmI46nPhjO7M\"}`
247+
248+
* You'll need to note the Public domain name of your Deno Deploy application. Public domain names given by Deno may
249+
look something like this: `<name>.deno.dev`.
250+
251+
### Enable Fanout on your Fastly service, and point it at your backend
252+
253+
1. Switch back to the terminal window where you deployed your Fastly Fanout Forwarding service.
254+
255+
2. Type the following command to add the example application to your Fastly service as a backend with the name `origin`.
256+
Insert the public hostname of your example backend in the command below.
257+
258+
```
259+
fastly backend create --autoclone --version=active --name=origin --address=<example public hostname>
260+
```
261+
262+
3. Activate the newly created version.
263+
264+
```
265+
fastly service-version activate --version=latest
266+
```
267+
268+
4. Enable Fanout on your service.
269+
270+
```
271+
fastly products --enable=fanout
272+
```
273+
5. Wait a moment for the updates to deploy across Fastly's network.
274+
275+
6. Go on to follow the steps under each example's `README` file.
276+
277+
When you do this, access the application at your Fastly service's domain name (e.g., `https://<something>.edgecompute.app/`)
278+
instead of your local Pushpin address.
279+
280+
Back to [examples](../)

0 commit comments

Comments
 (0)