Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
sejori authored Apr 27, 2024
1 parent f57f1cc commit 621b388
Showing 1 changed file with 52 additions and 52 deletions.
104 changes: 52 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,35 @@
<p align="center">
<span>
&nbsp;
<a href="#Types">
Types
<a href="#overview">
Overview
</a>
&nbsp;
</span>
<span>
&nbsp;
<a href="#routing">
Routing
<a href="#recipes">
Recipes
</a>
&nbsp;
</span>
<span>
<span>
&nbsp;
<a href="#request-handling">
Request handling
<a href="#deployment">
Deployment
</a>
&nbsp;
</span>
<span>
&nbsp;
<a href="#response-caching">
Response caching
<a href="#motivations">
Motivations
</a>
&nbsp;
</span>
</p>

<h1>Overview</h1>
<h2 id="overview">Overview</h2>

Routes and middleware are added to a `Router` instance with `.use`, `.addRoute` or `.get/post/put/delete`.

Expand Down Expand Up @@ -82,42 +82,42 @@ Deno.serve((req) => router.handle(req))
<h2 id="types">Types</h2>

### [**Router**](https://deno.land/x/peko/mod.ts?s=Router)
The main class of Peko, provides `handle` method to generate `Response` from `Request` via configured routes and middleware.
The main class/entrypoint of Peko.

The `handle` method generates a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) from a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) argument via configured routes and middleware.

### [**Route**](https://deno.land/x/peko/mod.ts?s=Route)
Objects with `path`, `method`, `middleware`, and `handler` properties. Requests are matched to a regex generated from the given path. Dynamic parameters are supported in the `/users/:userid` syntax.
Routes are added to a `Router` and matched to a `Request` via their `path` property. Once matched, the route's `middleware` and `handlers` are invoked to process the `Request` (after global middleware on the `Router`).

Dynamic path parameters are supported in the `/users/:userid` syntax.

### [**RequestContext**](https://deno.land/x/peko/mod.ts?s=RequestContext)
An object containing `url`, `params` and `state` properties that is provided to all middleware and handler functions associated to a router or matched route.
An object containing request data that is passed into middleware and handlers in the `Request` process lifecycle.

The `state` property is an object designed to transfer information between middleware/handlers.

### [**Middleware**](https://deno.land/x/peko/mod.ts?s=Middleware)
Functions that receives a RequestContext and a next fcn. Should update `ctx.state`, perform side-effects or return a response.
Functions that receive `RequestContext` and `next`. They are designed to:
- Return a `Response` and end the `Request` processing lifecycle (e.g. returning a `401`)
- Call `await next()` to access the final response (e.g. logging)
- Edit the context's `state` (e.g. rendering geolocation to HTML)

### [**Handler**](https://deno.land/x/peko/mod.ts?s=Handler)
The final request handling function on a `Route`. Must generate and return a response using the provided request context.

<h2 id="request-handling">Request handling</h2>

Each route must have a `handler` function that returns/resolves to a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) and can optionally have `middleware` too.

### ctx: RequestContext
The final request handling function on a `Route`, receives `RequestContext` argument.

Upon receiving a request a `Router` will construct a [RequestContext](https://deno.land/x/peko/server.ts?s=RequestContext) and cascade it through global middleware, route middleware and the route handler.
Must return/resolve to a `Response` (e.g. Render HTML or return JSON payload).

Middleware are invoked in the order they are added. If a response is returned no subsequent middleware/handler will execute.
<h2 id="recipes">Recipes</h2>

Peko comes with a library of utilities, middleware and handlers for common route use-cases, such as:
- server-side rendering apps to HTML
- streaming server-sent events
- hashing and JWT authentication
### Library utilities
Check the [examples](https://github.com/sejori/peko/examples) to see implementations of:
- server-side rendering Preact to HTML
- streaming server-sent events to web client
- JWT authentication middleware
- logging requests
- caching responses

See `handlers`, `middleware` or `utils` for source, or dive into `examples` for demo implementations.

### `next: () => Promise<Response>`

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 editing headers or logging. See the below snippet or `middleware/logger.ts` for examples.
### Error handling

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:

Expand All @@ -139,15 +139,15 @@ router.use(async (_, next) => {
});
```

<h2 id="response-caching">Response caching</h2>
### 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. The configurable `cacher` middleware provides drop in handler memoization and response caching for your routes.

```js
router.addRoute("/get-time", Peko.cacher({ itemLifetime: 5000 }), () => new Response(Date.now()));
```

The cacher stores response items in memory by default, but it can be extended to use any key value storage by supplying the `store` options parameter.
The cacher stores response items in memory by default, but it can be extended to use any key value storage by supplying the `store` options parameter (e.g. Cloudflare Workers KV).

```js
import { Router, CacheItem, cacher } from "https://deno.land/x/peko/mod.ts"
Expand All @@ -169,46 +169,46 @@ router.addRoute("/get-time", {
})
```

And that's it! Check out the API docs for deeper info. Otherwise happy coding 🤓
<h2 id="deployment">Deployment</h2>

<h2>App showcase</h2>
- [Deno Deploy](https://dash.deno.com/projects) (fork and deploy the examples if you fancy 💖)
- Docker (coming soon...)

<h2 id="showcase">Showcase</h2>

PR to add your project 🙌

### [shineponics.org](https://shineponics.org) - smart-farming PaaS
### [shineponics.org](https://shineponics.org)
- **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)

### [peko-auth.deno.dev](https://peko-auth.deno.dev) - basic authentication demo
### [thesebsite.com](https://thesebsite.com)
- **Stack:** HTML5
- **Features:** JWT-based auth
- **Features:** UI TS scripts transpiled to JS and cached for browser
- [source](https://github.com/sebringrose/peko/blob/main/examples/auth/app.ts)

**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.

<h2>Deployment</h2>
<h2 id="motivations">Motivations</h2>

- [Deno Deploy](https://dash.deno.com/projects) (fork and deploy the examples if you fancy 💖)
- Docker (coming soon...)
### Apps on the edge

<h2>What does stateless mean?</h2>

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.
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.

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.
This is made possible by engines such as Deno that are built to the [ECMAScript](https://tc39.es/) specification</a> and can run TypeScript natively. 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.

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)!
If you are interested in contributing please submit a PR or get in contact ^^

<strong>Note:</strong> 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.
### What does stateless mean?

<h2 id="cool">Motivations</h2>
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.

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.
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.

This is made possible by engines such as Deno that are built to the [ECMAScript](https://tc39.es/) specification</a> and can run TypeScript natively. 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.
Because stateless apps can "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)!

If you are interested in contributing please submit a PR or get in contact ^^
<strong>Note:</strong> 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.

## Credits:
Chick logo from [Twemoji](https://github.com/twitter/twemoji)

1 comment on commit 621b388

@deno-deploy
Copy link

@deno-deploy deno-deploy bot commented on 621b388 Apr 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed to deploy:

Relative import path "esbuild" not prefixed with / or ./ or ../

Please sign in to comment.