From 86b6f2326f23b24e2d5b22451c9ba5e0c9e62d88 Mon Sep 17 00:00:00 2001 From: Bri Ward Date: Fri, 8 Nov 2024 11:52:15 +0000 Subject: [PATCH 1/5] Tidy up and refactor the middleware processing. --- src/http/context.ts | 2 +- src/http/processor.ts | 58 ++++++++++++++++++++++++++++++++++++++++ src/kernel.ts | 62 +++++++------------------------------------ 3 files changed, 68 insertions(+), 54 deletions(-) create mode 100644 src/http/processor.ts diff --git a/src/http/context.ts b/src/http/context.ts index 874a7ae..fec4795 100644 --- a/src/http/context.ts +++ b/src/http/context.ts @@ -1,7 +1,7 @@ /** * The context definition. */ -export default class Context implements Context { +export default class Context { /** * Initialise an HTTP context. * diff --git a/src/http/processor.ts b/src/http/processor.ts new file mode 100644 index 0000000..c8fe255 --- /dev/null +++ b/src/http/processor.ts @@ -0,0 +1,58 @@ +// deno-lint-ignore-file no-explicit-any + +import type Context from "./context.ts"; + +export default class Processor { + /** + * Initialise the HTTP processor. + * + * @param context The current HTTP context. + * @constructor + */ + constructor(private context : Context) {} + + /** + * Process a body into a valid Response object. + * + * @param body A body value to process. + * @returns A valid HTTP response object. + */ + public process(body: any): Response { + // If the middleware provides a Response object, use it. + if (body instanceof Response) { + return body; + } + + const hasContentType = this.context.response.headers.get("content-type"); + + // If the middleware returns an object, process it as JSON. + if (typeof body === "object") { + if (!hasContentType) { + this.context.response.headers.set("content-type", "application/json"); + } + + return new Response(JSON.stringify(body), { + headers: this.context.response.headers, + }); + } + + // If the middleware returns a string, process plain text or HTML. + if (typeof body === "string") { + const isHtml = (new RegExp(/<[a-z/][\s\S]*>/i)).test(body); + + if (!hasContentType) { + this.context.response.headers.set("content-type", "text/plain"); + } + + if (isHtml && !hasContentType) { + this.context.response.headers.set("content-type", "text/html"); + } + + return new Response(body as string, { + headers: this.context.response.headers, + }); + } + + return new Response(body as string); + } +} diff --git a/src/kernel.ts b/src/kernel.ts index efa05e1..36b5e54 100644 --- a/src/kernel.ts +++ b/src/kernel.ts @@ -1,6 +1,5 @@ -// deno-lint-ignore-file no-explicit-any - import Context from "./http/context.ts"; +import Processor from "./http/processor.ts"; import type { Error } from "./error/interfaces/error.ts"; @@ -8,6 +7,11 @@ import type { Error } from "./error/interfaces/error.ts"; * The root initialiser for the framework. */ export default class Kernel { + /** + * The response processor for the kernel. + */ + private processor : Processor; + /** * The current HTTP context. */ @@ -18,11 +22,6 @@ export default class Kernel { */ private middleware: CallableFunction[] = []; - /** - * The current middleware index. - */ - private currentIndex: number = 0; - /** * Initialise the kernel. * @@ -33,6 +32,8 @@ export default class Kernel { new Request(Deno.env.get("APP_URL") as string), new Response(null), ); + + this.processor = new Processor(this.context); } /** @@ -92,7 +93,7 @@ export default class Kernel { ); if (!called) { - this.context.response = this.process(body); + this.context.response = this.processor.process(body); } } }; @@ -101,51 +102,6 @@ export default class Kernel { await execute(0); } - /** - * Process middleware into an HTTP response. - * - * @param body The response body. - * @returns - */ - private process(body: any): Response { - // If the middleware provides a Response object, use it. - if (body instanceof Response) { - return body; - } - - const hasContentType = this.context.response.headers.get("content-type"); - - // If the middleware returns an object, process it as JSON. - if (typeof body === "object") { - if (!hasContentType) { - this.context.response.headers.set("content-type", "application/json"); - } - - return new Response(JSON.stringify(body), { - headers: this.context.response.headers, - }); - } - - // If the middleware returns a string, process plain text or HTML. - if (typeof body === "string") { - const isHtml = (new RegExp(/<[a-z/][\s\S]*>/i)).test(body); - - if (!hasContentType) { - this.context.response.headers.set("content-type", "text/plain"); - } - - if (isHtml && !hasContentType) { - this.context.response.headers.set("content-type", "text/html"); - } - - return new Response(body as string, { - headers: this.context.response.headers, - }); - } - - return new Response(body as string); - } - /** * Handles an error and returns a response. * From 6fe39cd791ea2116b616901ff8a9c81645daf2fb Mon Sep 17 00:00:00 2001 From: Bri Ward Date: Fri, 8 Nov 2024 11:52:56 +0000 Subject: [PATCH 2/5] Update the README with improved documentation. --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fced8e7..9684ddf 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ The following middleware response will be automatically detected as `application ```ts app.add(() => ({ - name: 'Ian Malcolm', + name: 'Dr Ian Malcolm', })); ``` @@ -83,9 +83,7 @@ app.add((context: Context) => { context.response.headers.set('content-type', 'application/hal+json'); return { - data: { - name: 'Ian Malcolm' - } + name: 'Dr Ian Malcolm' } }); ``` @@ -114,7 +112,7 @@ app.add((_context: Context, next: CallableFunction) => { }); app.add(() => ({ - name: 'Ellie Sattler' + name: 'Dr Ellie Sattler' })); ``` From 829ee4075407ea30cd3bc92a1ba0e0d500ff7813 Mon Sep 17 00:00:00 2001 From: Bri Ward Date: Fri, 8 Nov 2024 11:57:11 +0000 Subject: [PATCH 3/5] Upgrade to 0.4.1 --- deno.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deno.json b/deno.json index 1279863..91a4cae 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@raptor/framework", - "version": "0.4.0", + "version": "0.4.1", "exports": "./mod.ts", "publish": { "exclude": [ From 28d6543e8931d676a2f7c36fb8252de27297ce80 Mon Sep 17 00:00:00 2001 From: Bri Ward Date: Fri, 8 Nov 2024 11:58:10 +0000 Subject: [PATCH 4/5] Run the formatting and linting. --- src/http/processor.ts | 2 +- src/kernel.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/processor.ts b/src/http/processor.ts index c8fe255..94971c0 100644 --- a/src/http/processor.ts +++ b/src/http/processor.ts @@ -9,7 +9,7 @@ export default class Processor { * @param context The current HTTP context. * @constructor */ - constructor(private context : Context) {} + constructor(private context: Context) {} /** * Process a body into a valid Response object. diff --git a/src/kernel.ts b/src/kernel.ts index 36b5e54..c029328 100644 --- a/src/kernel.ts +++ b/src/kernel.ts @@ -10,7 +10,7 @@ export default class Kernel { /** * The response processor for the kernel. */ - private processor : Processor; + private processor: Processor; /** * The current HTTP context. From b35b1c6328b3944c2fc15ef0fc057f3e6b653f14 Mon Sep 17 00:00:00 2001 From: Bri Ward Date: Fri, 8 Nov 2024 12:00:06 +0000 Subject: [PATCH 5/5] Make sure tests are using the deno.json file task names. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 232beb7..a5827b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,4 +22,4 @@ jobs: run: deno lint - name: run tests - run: deno test + run: deno task test