From 6057bdd2de8fec733e8eb49b0c8eb3867c2a7820 Mon Sep 17 00:00:00 2001 From: l2ig Date: Thu, 30 Dec 2021 16:14:54 +0100 Subject: [PATCH 1/3] Allow more response content types --- aqua.ts | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/aqua.ts b/aqua.ts index edb5e49..1133d95 100644 --- a/aqua.ts +++ b/aqua.ts @@ -22,12 +22,21 @@ export type Method = | "TRACE" | "PATCH"; +type ResponseContent = + | Uint8Array + | Blob + | BufferSource + | FormData + | URLSearchParams + | ReadableStream + | string; + interface ContentResponse { statusCode?: number; headers?: Record; cookies?: Record; redirect?: string; - content: string | Uint8Array; + content: ResponseContent; } interface RedirectResponse { @@ -35,11 +44,11 @@ interface RedirectResponse { headers?: Record; cookies?: Record; redirect: string; - content?: string | Uint8Array; + content?: ResponseContent; } export type ResponseObject = ContentResponse | RedirectResponse; -export type Response = string | Uint8Array | ResponseObject; +export type Response = ResponseContent | ResponseObject; export interface Request { _internal: { @@ -237,23 +246,18 @@ export default class Aqua { return urlParameters; } - private isTextContent(response: Response): response is string { - return typeof response === "string"; - } - - private isDataContent(response: Response): response is Uint8Array { - return response instanceof Uint8Array; - } - private convertResponseToResponseObject(response: Response): ResponseObject { - if (this.isTextContent(response)) { + if (typeof response === "string") { return { headers: { "Content-Type": "text/html; charset=UTF-8" }, content: response, }; } - if (this.isDataContent(response)) { + if ( + typeof response !== "object" || + (!("content" in response) && !("redirect" in response)) + ) { return { content: response }; } From ac62f233a27aa30fa4ee7c73a4e0f561275decbe Mon Sep 17 00:00:00 2001 From: l2ig Date: Thu, 30 Dec 2021 16:15:40 +0100 Subject: [PATCH 2/3] Adjust text, add streaming example --- README.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff733d1..41fe991 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ outgoing or incoming request. ```typescript app.register((req, res) => { /** - * Skip Uint8Array responses: + * Ignore non-text responses: * if (typeof res.content !== "string") return res; * * res.content = res.content.replace("Hello", "Hi"); @@ -262,3 +262,32 @@ app.get("/", (req) => { ``` Yes, that's it. Everything else should work as you are used to. :) + +### Streaming + +```typescript +app.get("/", (req) => { + const stream = new ReadableStream({ + start(controller) { + let i = 0; + const interval = setInterval(() => { + controller.enqueue(new TextEncoder().encode("hello world!")); + + if (i === 9) { + clearInterval(interval); + controller.close(); + } + + i++; + }, 500); + } + }); + + return { + content: stream, + headers: { + "Content-Type": "text/html" + } + }; +}); +``` From ec93a14163d9fa858b42e3b6dda8c276d00129e3 Mon Sep 17 00:00:00 2001 From: l2ig Date: Thu, 30 Dec 2021 16:16:21 +0100 Subject: [PATCH 3/3] Add ReadableStream test case --- tests/uptests.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/uptests.ts b/tests/uptests.ts index b3f534a..970426a 100644 --- a/tests/uptests.ts +++ b/tests/uptests.ts @@ -655,6 +655,41 @@ registerTest("Fallback handler error types working?", async () => { } }); +registerTest("Are ReadableStream responses working?", async () => { + app.get("/readable-stream", (_req) => { + const stream = new ReadableStream({ + start(controller) { + let i = 0; + const interval = setInterval(() => { + controller.enqueue(new TextEncoder().encode("hello world!")); + + if (i === 4) { + clearInterval(interval); + controller.close(); + } + + i++; + }, 50); + }, + }); + + return { + content: stream, + headers: { + "Content-Type": "text/html", + }, + }; + }); + + const content = await requestContent("/readable-stream"); + const expected = "hello world!".repeat(5); + if (content !== expected) { + throw new Error( + `Expected handler to return "${expected}". Instead got: ${content}`, + ); + } +}); + setInterval(() => { if (registeredTests === solvedTests) Deno.exit(0); }, 500);