Skip to content

Commit ce099e4

Browse files
authored
Remove legacy interfaces, implement Vercel style interface (#132)
Previously there were two interfaces supported: ```ts import { ServerRequest } from 'https://deno.land/[email protected]/http/server.ts'; export default function (request: ServerRequest) { console.log(request.url); request.respond({ body: '...' }); } ``` ```ts export default function (event: Deno.RequestEvent) { console.log(event.request.url); event.respondWith(new Response('...')); } ``` Supporting both interfaces has been hard/hacky to maintain, and in 2023 there is a now a more standardized interface that also fits better with the Vercel style. This PR implements this new interface: ```ts export default function (request: Request) { console.log(request.url); return new Response('...'); } ``` This new interface matches the Vercel Edge runtime syntax. The `Request` object is passed directly as the first parameter, and a `Response` instance is expected to be returned from the handler. The runtime is a lot cleaner because the legacy code has been removed. There are also less URL imports needed since Deno supports these standard classes directly (only `base64` still needs to be imported). Closes #104.
1 parent 7965b2c commit ce099e4

File tree

6 files changed

+71
-199
lines changed

6 files changed

+71
-199
lines changed

api/dump.ts

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
11
#!/usr/bin/env deno run --location https://example.com/page
22
import ms from 'https://esm.sh/[email protected]';
3-
import { readerFromStreamReader } from 'https://deno.land/[email protected]/io/streams.ts';
4-
5-
interface HeadersObject {
6-
[name: string]: any;
7-
}
3+
import type { Handler } from "https://deno.land/[email protected]/http/server.ts";
84

95
const startTime = new Date();
106

11-
function headersToObject(headers: Headers): HeadersObject {
12-
const obj: HeadersObject = {};
13-
for (const [name, value] of headers.entries()) {
14-
obj[name] = value;
15-
}
16-
return obj;
17-
}
18-
197
function urlToObject(url: URL) {
208
return {
219
href: url.href || undefined,
@@ -32,7 +20,7 @@ function urlToObject(url: URL) {
3220
};
3321
}
3422

35-
function sortObject<T extends object>(obj: T): T {
23+
function sortObject<T extends Record<string, unknown>>(obj: T): T {
3624
const sorted: T = Object.create(Object.getPrototypeOf(obj));
3725
const keys = Object.keys(obj).sort() as (keyof T)[];
3826
for (const k of keys) {
@@ -41,7 +29,7 @@ function sortObject<T extends object>(obj: T): T {
4129
return sorted;
4230
}
4331

44-
export default async ({ request }: Deno.RequestEvent) => {
32+
const handler: Handler = async (request) => {
4533
const now = new Date();
4634
const uptime = now.getTime() - startTime.getTime();
4735
const url = new URL(request.url);
@@ -55,6 +43,8 @@ export default async ({ request }: Deno.RequestEvent) => {
5543
}
5644
}
5745

46+
const reqBody = await request.arrayBuffer();
47+
5848
const body = {
5949
now: now.getTime(),
6050
bootup: startTime.getTime(),
@@ -65,14 +55,11 @@ export default async ({ request }: Deno.RequestEvent) => {
6555
request: {
6656
method: request.method,
6757
url: urlToObject(url),
68-
headers: sortObject(headersToObject(request.headers)),
69-
body: request.body
70-
? new TextDecoder().decode(
71-
await Deno.readAll(
72-
readerFromStreamReader(request.body.getReader())
73-
)
74-
)
75-
: null,
58+
headers: sortObject(Object.fromEntries(request.headers)),
59+
body:
60+
reqBody.byteLength > 0
61+
? new TextDecoder().decode(reqBody)
62+
: null,
7663
},
7764
response: {
7865
status,
@@ -95,3 +82,5 @@ export default async ({ request }: Deno.RequestEvent) => {
9582
},
9683
});
9784
};
85+
86+
export default handler;

api/dynamic-import.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env DENO_DIR=/tmp deno run --include-files ../util/**/*
22

3-
export default async ({ request }: Deno.RequestEvent) => {
3+
export default async (request: Request) => {
44
const name = new URL(request.url).searchParams.get('name') ?? 'a';
55
const mod = await import(`../util/${name}.ts`);
66
console.log({ name, mod });

api/javascript.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export default (req) => {
2-
req.respond({ body: 'Hello from JavaScript in Deno!' });
1+
export default (_req) => {
2+
return new Response('Hello from JavaScript in Deno!');
33
};

api/oak.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { Application } from 'https://deno.land/x/oak@v9.0.0/mod.ts';
1+
import { Application } from 'https://deno.land/x/oak@v11.1.0/mod.ts';
22

33
const app = new Application();
44

55
app.use((ctx) => {
6-
ctx.response.body = 'Hello World!';
7-
console.log(ctx);
6+
ctx.response.body = 'Hello World from Oak!';
87
});
98

109
export default app.handle;

src/runtime/dev-server.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { writeAllSync } from 'https://deno.land/[email protected]/streams/conversion.ts';
2+
import type { Handler, ConnInfo } from "https://deno.land/[email protected]/http/server.ts";
23

4+
// deno-lint-ignore no-explicit-any
35
function isNetAddr(v: any): v is Deno.NetAddr {
46
return v && typeof v.port === 'number';
57
}
@@ -9,24 +11,24 @@ const entrypoint = Deno.env.get('VERCEL_DEV_ENTRYPOINT');
911
Deno.env.delete('VERCEL_DEV_ENTRYPOINT');
1012

1113
const mod = await import(`file://${entrypoint}`);
12-
const handler = mod.default;
14+
const handler: Handler = mod.default;
1315
if (typeof handler !== 'function') {
1416
throw new Error('Failed to load handler function');
1517
}
1618

1719
// Spawn HTTP server on ephemeral port
18-
const conn = await Deno.listen({ port: 0 });
20+
const listener = Deno.listen({ port: 0 });
1921

20-
if (isNetAddr(conn.addr)) {
21-
const { port } = conn.addr;
22+
if (isNetAddr(listener.addr)) {
23+
const { port } = listener.addr;
2224
const portBytes = new TextEncoder().encode(String(port));
2325

2426
try {
2527
// Write the port number to FD 3
2628
const portFd = Deno.openSync('/dev/fd/3', { read: false, write: true });
2729
writeAllSync(portFd, portBytes);
2830
Deno.close(portFd.rid);
29-
} catch (err) {
31+
} catch (_err) {
3032
// This fallback is necessary for Windows
3133
// See: https://github.com/denoland/deno/issues/6305
3234
const portFile = Deno.env.get('VERCEL_DEV_PORT_FILE');
@@ -38,12 +40,15 @@ if (isNetAddr(conn.addr)) {
3840
}
3941
}
4042

41-
const s = Deno.serveHttp(await conn.accept());
4243
// Serve HTTP requests to handler function
44+
const conn = await listener.accept();
45+
const s = Deno.serveHttp(conn);
4346
for await (const req of s) {
44-
Promise.resolve(handler(req)).then((res: Response | void) => {
45-
if (res) {
46-
return req.respondWith(res);
47-
}
48-
});
47+
const connInfo: ConnInfo = {
48+
localAddr: conn.localAddr,
49+
remoteAddr: conn.remoteAddr,
50+
};
51+
Promise.resolve(handler(req.request, connInfo)).then((res: Response) =>
52+
req.respondWith(res)
53+
);
4954
}

0 commit comments

Comments
 (0)