Skip to content

Instantly share code, notes, and snippets.

@kwhinnery
Created January 24, 2024 18:13
Show Gist options
  • Save kwhinnery/4e7ddf4aee7fd8262acadee3620131af to your computer and use it in GitHub Desktop.
Save kwhinnery/4e7ddf4aee7fd8262acadee3620131af to your computer and use it in GitHub Desktop.
Example code from today's decorators presentation! Uses the older Stage 2 decorators API - look for the Stage 3 decorators API to release in Deno 1.40.
// deno-lint-ignore-file no-explicit-any
import { Hono } from "https://deno.land/x/[email protected]/mod.ts";
import { Context } from "https://deno.land/x/[email protected]/context.ts";
import * as dejs from "https://deno.land/x/[email protected]/mod.ts";
// Initialize class routes by instantiating a version of them
export function register(...args: any) {
args.forEach((C: any) => {
console.log("Mounting routes for", C.name);
new C();
});
}
// Create a single, module-scoped Hono application
export const app = new Hono();
export function route(path = "/", method = "get"): any {
return function (proto: any, _methodName: any, context: any): any {
// Register a route that calls the given method.
app.all(path, async (c, next) => {
if (c.req.method.toLowerCase() !== method.toLowerCase()) {
return next();
}
// Call original function
const originalValue = await context.value.call(proto, c);
// Render JSON or HTML body
if (typeof originalValue === "string") {
return c.html(originalValue);
} else {
return c.json(originalValue);
}
});
// Pass back wrapped function (unchanged)
return {
value: context.value,
};
};
}
export function template(templateName: string): any {
return function (
proto: any,
_methodName: any,
context: any,
): any {
async function wrapped(c: Context): Promise<any> {
const originalValue = await context.value.call(proto, c);
return dejs.renderFileToString(templateName, {
data: originalValue,
});
}
// Pass back wrapped function
return {
value: wrapped,
};
};
}
<h1>Todos</h1>
<ul>
<% data.forEach(val => { %>
<li><%= val.value.todo %></li>
<% }); %>
</ul>
import { app, register } from "./hono_decorators.ts";
import { TodoResource } from "./todo.ts";
// Register route handlers through static initialization
register(TodoResource);
// Mount Hono app to serve incoming requests
Deno.serve(app.fetch);
import { Context } from "https://deno.land/x/[email protected]/context.ts";
import { route, template } from "./hono_decorators.ts";
// Create a persistent KV database
const kv = await Deno.openKv();
export class TodoResource {
@route("/todos", "GET")
@template("list.ejs")
async listTodos() {
const iter = await kv.list({ prefix: ["todos"] });
const todos = [];
for await (const res of iter) todos.push(res);
return todos;
}
@route("/todos", "POST")
async createTodo(c: Context) {
const { todo, done } = await c.req.json();
const id = crypto.randomUUID();
return await kv.set(["todos", id], { id, todo, done });
}
@route("/todos/:id", "GET")
async getTodo(c: Context) {
const id = c.req.param("id");
return await kv.get(["todos", id]);
}
@route("/todos/:id", "POST")
async updateTodo(c: Context) {
const id = c.req.param("id");
const { todo, done } = await c.req.json();
return await kv.set(["todos", id], { id, todo, done });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment