diff --git a/README.md b/README.md
index 2b8abdd2..f5966c16 100644
--- a/README.md
+++ b/README.md
@@ -9,28 +9,28 @@
-
+
Server
-
+
Routing
-
+
Request handling
-
+
Response caching
@@ -54,170 +54,73 @@
-Stateless HTTP(S) apps that are:
+Stateless HTTP(S) apps that are:
-- Featherweight - Browser-native JavaScript + Deno std library + no build-time tooling
+- Featherweight - Browser-native JavaScript + Deno std library
-- Functional - [Express](https://github.com/expressjs/express)-like API + full-stack library
+- Functional - [Express](https://github.com/expressjs/express)-like API + full-stack tooling
-- Production-ready - High test coverage + stable Deno APIs + server profiling utility
+- Production-ready - High test coverage + stable APIs + server profiling
- Community-driven - Popular tool integrations + contributions encouraged
-Try the Preact demo
-
-1. Deno is sick. [Install it](https://deno.land/manual/getting_started/installation).
-
-2. `$ git clone https://github.com/sebringrose/peko.git`
-
-3. `$ deno task start:dev`
-
-Note: [Lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) VS Code plugin recommended.
-
-Deployment
-
-- [Deno Deploy](https://dash.deno.com/projects) (fork and deploy the examples if you fancy 💖)
-- Docker (coming soon...)
-
-App showcase
-
-[iiisun.art](https://iiisun.art) - artistic storefront built with Deno, Peko, React, ImageMagick_deno [source](https://github.com/sebringrose/third-sun/blob/main/server.ts)
-
-[shineponics.org](https://shineponics.org) - smart-farming PaaS built with Deno, Peko, React, Google Cloud Platform [source](https://github.com/shine-systems/shineponics/blob/main/server.ts)
-
-[peko-auth.deno.dev](https://peko-auth.deno.dev) - demo app built with Deno, Peko, Preact [source](https://github.com/sebringrose/peko/blob/main/examples/auth/app.ts)
-
-PR to add your project to the showcase 🙌
-
-What does stateless mean?
-
-Peko apps are designed to boot from scratch at request time and disappear once the request is served. Therefore, storing data in memory between requests (stateful logic) is not reliable. Instead we should use stateless logic and store data within the client or external services.
-
-This paradigm is often referred to as "serverless" or "edge computing" on cloud platforms, which offer code execution on shared server hardware. This is [much more resource efficient](https://developer.ibm.com/blogs/the-future-is-serverless/) than traditional server provisioning.
-
-Because our stateless apps cold-start it is important to keep their codebases small. The preact demo app only imports Peko and Preact as external dependencies and is very fast as a result - [https://peko.deno.dev](https://peko.deno.dev)!
-
-Note: In reality a single app instance will serve multiple requests, we just can't guarantee it. This is why caching is still an effective optimization strategy but in-memory user sessions are not an effective authentication strategy.
-
-Library overview
-Server
-
-The TypeScript `server.ts` module describes a small framework for building HTTP servers on top of the Deno http/server module.
-
-Here are the main components:
-
-- **Server class**: which manages the HTTP server, the routes, and the middleware.
-- **RequestContext class:** holds information about the server, the request, and state to be shared between middleware.
-
-Main types (`types.ts`):
-
-- **Route**: an object with path, method, middleware, and handler properties.
-- **Middleware**: a function that receives a RequestContext and updates state or generates a response.
-- **Handler**: a function that handles requests by receiving a RequestContext and generating a response.
-
-The Server class has several methods for adding and removing routes and middleware, as well as starting the server and handling requests:
-
-- **use(middleware: Middleware | Middleware[] | Router)**: add global middleware or a router.
-- **addRoute(route: Route)**: adds a route to the server.
-- **addRoutes(routes: Route[])**: adds multiple routes to the server.
-- **removeRoute(route: string)**: removes a route from the server.
-- **removeRoutes(routes: string[])**: removes multiple routes from the server.
-- **listen(port?: number, onListen?: callback)**: starts listening to HTTP requests on the specified port.
-- **close()**: stops to HTTP listener process.
+Getting started
```js
-import * as Peko from "https://deno.land/x/peko/mod.ts"; // or "../server.ts" for super featherweight
+import * as Peko from "https://deno.land/x/peko/mod.ts";
+// import from ".../peko/lib/Server.ts" for featherweight mode
const server = new Peko.Server();
server.use(Peko.logger(console.log));
-server.addRoute("/hello", () => new Response("Hello world!"));
+server.get("/hello", () => new Response("Hello world!"));
server.listen(7777, () => console.log("Peko server started - let's go!"));
```
-Routing
-
-Routes can be added to a Server instance directly or a Router instance. Below you can see the different ways routes can be added with `addRoute`.
-
-```js
-import * as Peko from "https://deno.land/x/peko/mod.ts"; // or "https://deno.land/x/peko/server.ts"
-
-const server = new Peko.Server()
-server.addRoute("/hello", () => new Response("Hello world!"))
-server.removeRoute("/hello");
-
-const router = new Peko.Router()
-
-router.addRoute("/shorthand-route", async (ctx, next) => { await next(); console.log(ctx.request.headers); }, () => new Response("Hello world!"));
-
-router.addRoute({
- path: "/object-route",
- middleware: async (ctx, next) => { await next(); console.log(ctx.request.headers); }, // can also be array of middleware
- handler: () => new Response("Hello world!")
-})
-
-router.addRoutes([ /* array of route objects */ ])
-
-server.use(router)
-
-server.listen()
-```
-
-Request handling
+App showcase
-Each route must have a handler
function that generates a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response). Upon receiving a request the `Server` will construct a [RequestContext](https://deno.land/x/peko/server.ts?s=RequestContext) and cascade it through any global middleware, then route middleware and finally the route handler. Global and route middleware are invoked in the order they are added. If a response is returned by any middleware along the chain no subsequent middleware/handler will run.
+PR to add your project 🙌
-Peko comes with a library of utilities, middleware and handlers for common route use-cases, such as:
-- server-side-rendering
-- opening WebSockets
-- JWT signing/verifying & authentication
-- logging
-- caching
+### [iiisun.art](https://iiisun.art) - artistic storefront
+- **Stack:** React, ImageMagick_deno
+- **Features:** CI resized-image precaching, Gelato & Stripe integrations, Parallax CSS
+- [source](https://github.com/sebringrose/third-sun/blob/main/server.ts)
-See `handlers`, `mmiddleware` or `utils` for source, or dive into `examples` for demo implementations.
+### [shineponics.org](https://shineponics.org) - smart-farming PaaS
+- **Stack:** React, Google Cloud Platform
+- **Features:** Google Sheet analytics, GCP email list, Markdown rendering
+- [source](https://github.com/shine-systems/shineponics/blob/main/server.ts)
-The second argument to any middleware is the `next` fcn. This returns a promise that resolves to the first response returned by any subsequent middleware/handler. This is useful for error-handling as well as post-response operations such as logging. See the below snippet or `middleware/logger.ts` for examples.
+### [peko-auth.deno.dev](https://peko-auth.deno.dev) - basic authentication demo
+- **Stack:** HTML5
+- **Features:** JWT-based auth
+- [source](https://github.com/sebringrose/peko/blob/main/examples/auth/app.ts)
-If no matching route is found for a request an empty 404 response is sent. If an error occurs in handling a request an empty 500 response is sent. Both of these behaviours can be overwritten with the following middleware:
+**Note:** [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) and [es6-string-css](https://marketplace.visualstudio.com/items?itemName=bashmish.es6-string-css) VS Code extensions recommended.
-```js
-server.use(async (_, next) => {
- const response = await next();
- if (!response) return new Response("Would you look at that? Nothing's here!", { status: 404 });
-});
-```
+Deployment
-```js
-server.use(async (_, next) => {
- try {
- await next();
- } catch(e) {
- console.log(e);
- return new Response("Oh no! An error occured :(", { status: 500 });
- }
-});
-```
+- [Deno Deploy](https://dash.deno.com/projects) (fork and deploy the examples if you fancy 💖)
+- Docker (coming soon...)
-Response caching
+What does stateless mean?
-In stateless computing, memory should only be used for source code and disposable cache data. Response caching ensures that we only store data that can be regenerated or refetched. Peko provides a `ResponseCache` utility for this with configurable item lifetime. The `cacher` middleware wraps it and provides drop in handler memoization and response caching for your routes.
+Peko apps are designed to boot from scratch at request time and disappear once the request is served. Therefore, storing data in memory between requests (stateful logic) is not reliable. Instead we should use stateless logic and store data within the client or external services.
-```js
-const cache = new Peko.ResponseCache({ lifetime: 5000 });
+This paradigm is often referred to as "serverless" or "edge computing" on cloud platforms, which offer code execution on shared server hardware. This is [much more resource efficient](https://developer.ibm.com/blogs/the-future-is-serverless/) than traditional server provisioning.
-server.addRoute("/do-stuff", Peko.cacher(cache), () => new Response(Date.now()));
-```
+Because our stateless apps cold-start it is important to keep their codebases small. The preact demo app only imports Peko and Preact as external dependencies and is very fast as a result - [https://peko.deno.dev](https://peko.deno.dev)!
-And that's it! Check out the API docs for deeper info. Otherwise happy coding 🤓
+Note: In reality a single app instance will serve multiple requests, we just can't guarantee it. This is why caching is still an effective optimization strategy but in-memory user sessions are not an effective authentication strategy.
Motivations
-The modern JS edge is great because the client-server gap practically disappears. We can have all of the SEO and UX benefits of SSR without any JavaScript transpilation or bundling. We can use modules and classes in the browser until users decide they want cloud compute. If we want TS source we can [emit](https://github.com/denoland/deno_emit) JS versions of code. This completely eliminates part of the traditional JavaScript toolchain, increasing project maintainability and simplicity, all while making our software even faster.
+The modern JavaScript edge rocks because the client-server gap practically disappears. We can share modules across the client and cloud. If we want TS source we can [emit](https://github.com/denoland/deno_emit) JS. This eliminates much of the bloat in traditional JS server-side systems, increasing project simplicity while making our software faster and more efficient.
-Better yet, Peko is not build for any specific frontend framework or library. You can use barebones HTML, React, Preact, Vue... you name it. Simply plug your app-rendering logic into the [Render](https://deno.land/x/peko@v1.0.0/handlers/ssr.ts?s=Render) function of an [ssrHandler](https://doc.deno.land/https://deno.land/x/peko/lib/handlers/ssr.ts).
+This is made possible by engines such as Deno that are built to the [ECMAScript](https://tc39.es/) specification (support for URL module imports is the secret sauce). UI libraries like [Preact](https://github.com/preactjs/preact) combined with [htm](https://github.com/developit/htm) offer lightning fast client-side hydration with a browser-friendly markup syntax. Deno also has native TypeScript support, a rich runtime API and loads of community tools for your back-end needs.
-This is all made possible by modern JavaScript runtimes. Deno is built to the [ECMAScript](https://tc39.es/) specification. This makes it compatible with browser JavaScript which elimates the need to generate separate client and server JavaScript bundles (the support for URL imports is the secret sauce). UI libraries like [Preact](https://github.com/preactjs/preact) combined with [htm](https://github.com/developit/htm) offer lightning fast client-side hydration with a browser-friendly markup syntax. On top of this Deno has native TypeScript support, a rich runtime API and loads of community tools for your back-end needs.
+If you are interested in contributing please submit a PR or get in contact ^^
-This project started out of excitement for the elegancy of Deno and the freedom it would bring to the JavaScript community. If you are interested in contributing please submit a PR or get in contact ^^
+Read `overview.md` for a more detailed guide on using Peko.
diff --git a/lib/server.ts b/lib/Server.ts
similarity index 100%
rename from lib/server.ts
rename to lib/Server.ts
diff --git a/lib/handlers/ssr.ts b/lib/handlers/ssr.ts
index 8945d265..2ec7a40f 100644
--- a/lib/handlers/ssr.ts
+++ b/lib/handlers/ssr.ts
@@ -1,4 +1,4 @@
-import { RequestContext } from "../server.ts"
+import { RequestContext } from "../Server.ts"
import { Handler, HandlerOptions } from "../types.ts"
import { Crypto } from "../utils/Crypto.ts"
import { mergeHeaders } from "../utils/helpers.ts"
diff --git a/lib/handlers/static.ts b/lib/handlers/static.ts
index 0d7683e7..297b99dd 100644
--- a/lib/handlers/static.ts
+++ b/lib/handlers/static.ts
@@ -1,6 +1,6 @@
import { contentType } from "https://deno.land/std@0.174.0/media_types/mod.ts";
import { fromFileUrl } from "https://deno.land/std@0.174.0/path/mod.ts"
-import { RequestContext } from "../server.ts"
+import { RequestContext } from "../Server.ts"
import { Handler, HandlerOptions } from "../types.ts"
import { Crypto } from "../utils/Crypto.ts"
import { mergeHeaders } from "../utils/helpers.ts"
diff --git a/lib/middleware/cacher.ts b/lib/middleware/cacher.ts
index cc5f3df6..035d0831 100644
--- a/lib/middleware/cacher.ts
+++ b/lib/middleware/cacher.ts
@@ -1,4 +1,4 @@
-import type { RequestContext } from "../server.ts";
+import type { RequestContext } from "../Server.ts";
import { Middleware } from "../types.ts";
import { ResponseCache } from "../utils/ResponseCache.ts";
diff --git a/lib/types.ts b/lib/types.ts
index 38d773b2..ba0e80b8 100644
--- a/lib/types.ts
+++ b/lib/types.ts
@@ -1,4 +1,4 @@
-import { RequestContext } from "./server.ts"
+import { RequestContext } from "./Server.ts"
export interface Route {
path: `/${string}`
diff --git a/lib/utils/Cascade.ts b/lib/utils/Cascade.ts
index a66787f7..6c09fc14 100644
--- a/lib/utils/Cascade.ts
+++ b/lib/utils/Cascade.ts
@@ -1,4 +1,4 @@
-import { RequestContext } from "../server.ts"
+import { RequestContext } from "../Server.ts"
import { Middleware, Result, Next, Route } from "../types.ts"
export type PromiseMiddleware = (ctx: RequestContext, next: Next) => Promise
diff --git a/lib/utils/Profiler.ts b/lib/utils/Profiler.ts
index 228d8701..c181f8d9 100644
--- a/lib/utils/Profiler.ts
+++ b/lib/utils/Profiler.ts
@@ -1,4 +1,4 @@
-import { Server } from "../server.ts"
+import { Server } from "../Server.ts"
import { Route } from "../types.ts"
type ProfileConfig = {
diff --git a/lib/utils/Router.ts b/lib/utils/Router.ts
index c874c30d..29a28cfd 100644
--- a/lib/utils/Router.ts
+++ b/lib/utils/Router.ts
@@ -23,62 +23,108 @@ export class Router {
* @param route: Route | Route["path"]
* @param arg2?: Partial | Middleware | Middleware[],
* @param arg3?: Handler
- * @returns number - Router.length
+ * @returns route: Route - added route object
*/
- addRoute(route: Route): number
- addRoute(route: Route["path"], data: Handler | Partial): number
- addRoute(route: Route["path"], middleware: Middleware | Middleware[], handler: Handler): number
- addRoute(
- arg1: Route | Route["path"],
- arg2?: Partial | Middleware | Middleware[],
- arg3?: Handler
- ): number {
- const routeObj: Partial = typeof arg1 !== "string"
- ? arg1
- : arguments.length === 2
- ? typeof arg2 === "function"
- ? { path: arg1, handler: arg2 as Handler }
- : { path: arg1, ...arg2 as Partial }
- : { path: arg1, middleware: arg2 as Middleware | Middleware[], handler: arg3 }
-
- if (this.routes.find(existing => existing.path === routeObj.path)) {
- throw new Error(`Route with path ${routeObj.path} already exists!`)
- }
-
- return this.routes.push(Router.applyDefaults(routeObj))
- }
-
- /**
- * Add Routes
- * @param routes: Route[] - middleware can be Middlewares or Middleware
- * @returns number - routes.length
- */
- addRoutes(routes: Route[]): number {
- routes.forEach(route => this.addRoute(route))
- return this.routes.length
- }
-
- /**
- * Remove Route from Peko server
- * @param route: Route["path"] of route to remove
- * @returns
- */
- removeRoute(route: Route["path"]): number {
- const routeToRemove = this.routes.find(r => r.path === route)
- if (routeToRemove) {
- this.routes.splice(this.routes.indexOf(routeToRemove), 1)
- }
-
- return this.routes.length
+ addRoute(route: Route): Route
+ addRoute(route: Route["path"], data: Handler | Partial): Route
+ addRoute(route: Route["path"], middleware: Middleware | Middleware[], handler: Handler): Route
+ addRoute(
+ arg1: Route | Route["path"],
+ arg2?: Partial | Middleware | Middleware[],
+ arg3?: Handler
+ ): Route {
+ const routeObj: Partial = typeof arg1 !== "string"
+ ? arg1
+ : arguments.length === 2
+ ? typeof arg2 === "function"
+ ? { path: arg1, handler: arg2 as Handler }
+ : { path: arg1, ...arg2 as Partial }
+ : { path: arg1, middleware: arg2 as Middleware | Middleware[], handler: arg3 }
+
+ if (this.routes.find(existing => existing.path === routeObj.path)) {
+ throw new Error(`Route with path ${routeObj.path} already exists!`)
}
-
- /**
- * Remove Routes
- * @param routes: Route["path"] of routes to remove
- * @returns
- */
- removeRoutes(routes: Route["path"][]): number {
- routes.forEach(route => this.removeRoute(route))
- return this.routes.length
+
+ const fullRoute = Router.applyDefaults(routeObj)
+ this.routes.push(fullRoute)
+
+ return fullRoute
+ }
+ /**
+ * Add Route with method "GET" (same as default addRoute behaviour)
+ * @returns route: Route - added route object
+ */
+ get: typeof this.addRoute = function() {
+ // @ts-ignore supply overload args
+ const newRoute = this.addRoute(...arguments)
+ newRoute.method = "GET"
+ return newRoute
+ }
+
+ /**
+ * Add Route with method "POST"
+ * @returns route: Route - added route object
+ */
+ post: typeof this.addRoute = function() {
+ // @ts-ignore supply overload args
+ const newRoute = this.addRoute(...arguments)
+ newRoute.method = "POST"
+ return newRoute
+ }
+
+ /**
+ * Add Route with method "PUT"
+ * @returns route: Route - added route object
+ */
+ put: typeof this.addRoute = function() {
+ // @ts-ignore supply overload args
+ const newRoute = this.addRoute(...arguments)
+ newRoute.method = "PUT"
+ return newRoute
+ }
+
+ /**
+ * Add Route with method "DELETE"
+ * @returns route: Route - added route object
+ */
+ delete: typeof this.addRoute = function() {
+ // @ts-ignore supply overload args
+ const newRoute = this.addRoute(...arguments)
+ newRoute.method = "DELETE"
+ return newRoute
+ }
+
+ /**
+ * Add Routes
+ * @param routes: Route[] - middleware can be Middlewares or Middleware
+ * @returns number - routes.length
+ */
+ addRoutes(routes: Route[]): number {
+ routes.forEach(route => this.addRoute(route))
+ return this.routes.length
+ }
+
+ /**
+ * Remove Route from Peko server
+ * @param route: Route["path"] of route to remove
+ * @returns
+ */
+ removeRoute(route: Route["path"]): number {
+ const routeToRemove = this.routes.find(r => r.path === route)
+ if (routeToRemove) {
+ this.routes.splice(this.routes.indexOf(routeToRemove), 1)
}
+
+ return this.routes.length
+ }
+
+ /**
+ * Remove Routes
+ * @param routes: Route["path"] of routes to remove
+ * @returns
+ */
+ removeRoutes(routes: Route["path"][]): number {
+ routes.forEach(route => this.removeRoute(route))
+ return this.routes.length
+ }
}
\ No newline at end of file
diff --git a/mod.ts b/mod.ts
index 0e1b393b..0aa295ad 100644
--- a/mod.ts
+++ b/mod.ts
@@ -3,7 +3,7 @@
*/
// Core classes, functions & types
-export * from "./lib/server.ts"
+export * from "./lib/Server.ts"
export * from "./lib/types.ts"
// Handlers
@@ -23,5 +23,5 @@ export * from "./lib/utils/ResponseCache.ts"
export * from "./lib/utils/Crypto.ts"
export * from "./lib/utils/helpers.ts"
-import { Server } from "./lib/server.ts"
+import { Server } from "./lib/Server.ts"
export default Server
\ No newline at end of file
diff --git a/overview.md b/overview.md
new file mode 100644
index 00000000..e7901e5b
--- /dev/null
+++ b/overview.md
@@ -0,0 +1,115 @@
+Peko library overview
+
+
+
+Server
+
+The TypeScript `server.ts` module describes a small framework for building HTTP servers on top of the Deno http/server module.
+
+Here are the main components:
+
+- **Server class**: which manages the HTTP server, the routes, and the middleware.
+- **RequestContext class:** holds information about the server, the request, and state to be shared between middleware.
+
+Main types (`types.ts`):
+
+- **Route**: an object with path, method, middleware, and handler properties.
+- **Middleware**: a function that receives a RequestContext and updates state or generates a response.
+- **Handler**: a function that handles requests by receiving a RequestContext and generating a response.
+
+The Server class has several methods for adding and removing routes and middleware, as well as starting the server and handling requests:
+
+- **use(middleware: Middleware | Middleware[] | Router)**: add global middleware or a router.
+- **addRoute(route: Route)**: adds a route to the server.
+- **addRoutes(routes: Route[])**: adds multiple routes to the server.
+- **removeRoute(route: string)**: removes a route from the server.
+- **removeRoutes(routes: string[])**: removes multiple routes from the server.
+- **listen(port?: number, onListen?: callback)**: starts listening to HTTP requests on the specified port.
+- **close()**: stops to HTTP listener process.
+
+```js
+import * as Peko from "https://deno.land/x/peko/mod.ts"; // or "../server.ts" for super featherweight
+
+const server = new Peko.Server();
+
+server.use(Peko.logger(console.log));
+
+server.addRoute("/hello", () => new Response("Hello world!"));
+
+server.listen(7777, () => console.log("Peko server started - let's go!"));
+```
+
+Routing
+
+Routes can be added to a Server instance directly or a Router instance. Below you can see the different ways routes can be added with `addRoute`.
+
+```js
+import * as Peko from "https://deno.land/x/peko/mod.ts"; // or "https://deno.land/x/peko/server.ts"
+
+const server = new Peko.Server()
+server.addRoute("/hello", () => new Response("Hello world!"))
+server.removeRoute("/hello");
+
+const router = new Peko.Router()
+
+router.addRoute("/shorthand-route", async (ctx, next) => { await next(); console.log(ctx.request.headers); }, () => new Response("Hello world!"));
+
+router.addRoute({
+ path: "/object-route",
+ middleware: async (ctx, next) => { await next(); console.log(ctx.request.headers); }, // can also be array of middleware
+ handler: () => new Response("Hello world!")
+})
+
+router.addRoutes([ /* array of route objects */ ])
+
+server.use(router)
+
+server.listen()
+```
+
+Request handling
+
+Each route must have a handler
function that generates a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response). Upon receiving a request the `Server` will construct a [RequestContext](https://deno.land/x/peko/server.ts?s=RequestContext) and cascade it through any global middleware, then route middleware and finally the route handler. Global and route middleware are invoked in the order they are added. If a response is returned by any middleware along the chain no subsequent middleware/handler will run.
+
+Peko comes with a library of utilities, middleware and handlers for common route use-cases, such as:
+- server-side-rendering
+- opening WebSockets
+- JWT signing/verifying & authentication
+- logging
+- caching
+
+See `handlers`, `mmiddleware` or `utils` for source, or dive into `examples` for demo implementations.
+
+The second argument to any middleware is the `next` fcn. This returns a promise that resolves to the first response returned by any subsequent middleware/handler. This is useful for error-handling as well as post-response operations such as logging. See the below snippet or `middleware/logger.ts` for examples.
+
+If no matching route is found for a request an empty 404 response is sent. If an error occurs in handling a request an empty 500 response is sent. Both of these behaviours can be overwritten with the following middleware:
+
+```js
+server.use(async (_, next) => {
+ const response = await next();
+ if (!response) return new Response("Would you look at that? Nothing's here!", { status: 404 });
+});
+```
+
+```js
+server.use(async (_, next) => {
+ try {
+ await next();
+ } catch(e) {
+ console.log(e);
+ return new Response("Oh no! An error occured :(", { status: 500 });
+ }
+});
+```
+
+Response caching
+
+In stateless computing, memory should only be used for source code and disposable cache data. Response caching ensures that we only store data that can be regenerated or refetched. Peko provides a `ResponseCache` utility for this with configurable item lifetime. The `cacher` middleware wraps it and provides drop in handler memoization and response caching for your routes.
+
+```js
+const cache = new Peko.ResponseCache({ lifetime: 5000 });
+
+server.addRoute("/do-stuff", Peko.cacher(cache), () => new Response(Date.now()));
+```
+
+And that's it! Check out the API docs for deeper info. Otherwise happy coding 🤓
diff --git a/tests/handlers/sse_test.ts b/tests/handlers/sse_test.ts
index 90df5ba0..e985aa0c 100644
--- a/tests/handlers/sse_test.ts
+++ b/tests/handlers/sse_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { sseHandler } from "../../lib/handlers/sse.ts"
Deno.test("HANDLER: Server-sent events", async (t) => {
diff --git a/tests/handlers/ssr_test.ts b/tests/handlers/ssr_test.ts
index 348b0364..ca355890 100644
--- a/tests/handlers/ssr_test.ts
+++ b/tests/handlers/ssr_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { ssrHandler } from "../../lib/handlers/ssr.ts"
Deno.test("HANDLER: Server-side render", async (t) => {
diff --git a/tests/handlers/static_test.ts b/tests/handlers/static_test.ts
index 542ffcb5..c6106106 100644
--- a/tests/handlers/static_test.ts
+++ b/tests/handlers/static_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { staticHandler } from "../../lib/handlers/static.ts"
Deno.test("HANDLER: Static", async (t) => {
diff --git a/tests/handlers/ws_test.ts b/tests/handlers/ws_test.ts
index 3429bc20..b5a63232 100644
--- a/tests/handlers/ws_test.ts
+++ b/tests/handlers/ws_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server } from "../../lib/server.ts"
+import { Server } from "../../lib/Server.ts"
import { wsHandler } from "../../lib/handlers/ws.ts"
Deno.test("HANDLER: WebSocket", async (t) => {
diff --git a/tests/middleware/authenticator_test.ts b/tests/middleware/authenticator_test.ts
index 9ae59a52..4d6612a4 100644
--- a/tests/middleware/authenticator_test.ts
+++ b/tests/middleware/authenticator_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { authenticator } from "../../lib/middleware/authenticator.ts"
import { Crypto } from "../../lib/utils/Crypto.ts"
diff --git a/tests/middleware/cacher_test.ts b/tests/middleware/cacher_test.ts
index ac557e1a..40cc6a82 100644
--- a/tests/middleware/cacher_test.ts
+++ b/tests/middleware/cacher_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { cacher } from "../../lib/middleware/cacher.ts"
import { testHandler } from "../mocks/middleware.ts"
import { ResponseCache } from "../../lib/utils/ResponseCache.ts"
diff --git a/tests/middleware/logger_test.ts b/tests/middleware/logger_test.ts
index 82161a13..57571009 100644
--- a/tests/middleware/logger_test.ts
+++ b/tests/middleware/logger_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { logger } from "../../lib/middleware/logger.ts"
Deno.test("MIDDLEWARE: Logger", async (t) => {
diff --git a/tests/scripts/profile.ts b/tests/scripts/profile.ts
index e8b7870c..c25b14f6 100644
--- a/tests/scripts/profile.ts
+++ b/tests/scripts/profile.ts
@@ -1,4 +1,4 @@
-import { Server } from "../../lib/server.ts"
+import { Server } from "../../lib/Server.ts"
import {
testMiddleware2,
testMiddleware3,
diff --git a/tests/server_test.ts b/tests/server_test.ts
index 81fe9a04..29756d21 100644
--- a/tests/server_test.ts
+++ b/tests/server_test.ts
@@ -1,4 +1,4 @@
-import { Server } from "../lib/server.ts"
+import { Server } from "../lib/Server.ts"
import {
testMiddleware2,
testMiddleware3,
@@ -15,9 +15,9 @@ Deno.test("SERVER", async (t) => {
server.addRoute({ path: "/route", handler: testHandler })
server.addRoute("/anotherRoute", { handler: testHandler })
server.addRoute("/anotherNotherRoute", testHandler)
- const routesLength = server.addRoute("/anotherNotherNotherRoute", testMiddleware2, testHandler)
+ server.addRoute("/anotherNotherNotherRoute", testMiddleware2, testHandler)
- assert(routesLength === 4 && server.routes.length === 4)
+ assert(server.routes.length === 4)
const request = new Request("http://localhost:7777/route")
const anotherRequest = new Request("http://localhost:7777/anotherRoute")
diff --git a/tests/utils/Cascade_test.ts b/tests/utils/Cascade_test.ts
index 48fb148d..d81bab3a 100644
--- a/tests/utils/Cascade_test.ts
+++ b/tests/utils/Cascade_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server, RequestContext } from "../../lib/server.ts"
+import { Server, RequestContext } from "../../lib/Server.ts"
import { Cascade } from "../../lib/utils/Cascade.ts"
import {
testMiddleware1,
diff --git a/tests/utils/Profiler_test.ts b/tests/utils/Profiler_test.ts
index fcc0f0db..788817e8 100644
--- a/tests/utils/Profiler_test.ts
+++ b/tests/utils/Profiler_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server } from "../../lib/server.ts"
+import { Server } from "../../lib/Server.ts"
import Profiler from "../../lib/utils/Profiler.ts"
Deno.test("UTIL: Profiler", async (t) => {
diff --git a/tests/router_test.ts b/tests/utils/Router_test.ts
similarity index 52%
rename from tests/router_test.ts
rename to tests/utils/Router_test.ts
index 4145d7c8..552457b2 100644
--- a/tests/router_test.ts
+++ b/tests/utils/Router_test.ts
@@ -1,21 +1,21 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server } from "../lib/server.ts"
-import { Router } from "../lib/utils/Router.ts"
+import { Server } from "../../lib/Server.ts"
+import { Router } from "../../lib/utils/Router.ts"
import {
testMiddleware1,
testHandler,
-} from "./mocks/middleware.ts"
+} from "../mocks/middleware.ts"
-Deno.test("SERVER", async (t) => {
+Deno.test("ROUTER", async (t) => {
const router = new Router()
await t.step("routes added with full route and string arg options", () => {
router.addRoute({ path: "/route", handler: testHandler })
router.addRoute("/anotherRoute", { handler: testHandler })
router.addRoute("/anotherNotherRoute", testHandler)
- const routesLength = router.addRoute("/anotherNotherNotherRoute", testMiddleware1, testHandler)
+ const finalRoute = router.addRoute("/anotherNotherNotherRoute", testMiddleware1, testHandler)
- assert(routesLength === 4 && router.routes.length === 4)
+ assert(finalRoute.path === "/anotherNotherNotherRoute" && router.routes.length === 4)
})
await t.step("routes removed", () => {
@@ -43,4 +43,31 @@ Deno.test("SERVER", async (t) => {
assert(!aRouter.routes.find(route => route.path === "/route"))
assert(aRouter.routes.length === 2)
})
+
+ await t.step ("http shorthand methods work correctly", () => {
+ const router = new Router()
+
+ const getRoute = router.get({
+ path: "/get",
+ handler: () => new Response("GET")
+ })
+ const postRoute = router.post({
+ path: "/post",
+ handler: () => new Response("POST")
+ })
+ const putRoute =router.put({
+ path: "/put",
+ handler: () => new Response("PUT")
+ })
+ const deleteRoute = router.delete({
+ path: "/delete",
+ handler: () => new Response("DELETE")
+ })
+
+ assert(router.routes.length === 4)
+ assert(getRoute.method === "GET")
+ assert(postRoute.method === "POST")
+ assert(putRoute.method === "PUT")
+ assert(deleteRoute.method === "DELETE")
+ })
})
diff --git a/tests/utils/helpers_test.ts b/tests/utils/helpers_test.ts
index b4da9956..968f8409 100644
--- a/tests/utils/helpers_test.ts
+++ b/tests/utils/helpers_test.ts
@@ -1,5 +1,5 @@
import { assert } from "https://deno.land/std@0.174.0/testing/asserts.ts"
-import { Server } from "../../lib/server.ts"
+import { Server } from "../../lib/Server.ts"
import {
mergeHeaders,
routesFromDir