A simple server framework (written in TypeScript).
npm install kauai
-
.use()
- Add aMiddleware/Router
to the stack
import { Kauai } from "kauai";
const app = new Kauai().use(middleware1).use(router2);
app.use("/path", middleware2, router2);
app.use(new RegExp("path"), router3, middleware1);
-
.off()
- remove aMiddleware/Router
form the stack
import { Kauai } from "kauai";
const app = new Kauai()
.use("/path", middleware1)
.use(middleware2)
.off("/path", middleware1);
-
.createServer()
- create a server (HTTP)
import { Kauai } from "kauai";
const app = new Kauai()
.use(new RegExp("path"), middleware)
.use("/path2", router);
const server = app.createServer();
-
.createSecureServer()
- create a server (HTTPS)
import { Kauai } from "kauai";
const app = new Kauai().use("/path", middleware).use("/path2", router);
const secureServer = app.createSecureServer({ key, cert });
-
.log
- get the logger (see@kauai/logger
)
const { log } = context;
log.info("Hello World", { data: 100 });
-
.setHeader()
- Set a response header
const name = "X-HEADER";
const value = ["value1", "value2"];
context.setHeader(name, value);
-
.status()
- set the response status
context.status(401);
-
.request
- get the original request object (instanceof KauaiRequest
)
const { request } = context;
-
.response
- get the original response object (instanceof KauaiResponse
)
const { response } = context;
-
.id
- getid
of the context (generated by the randomUUID() function and logged astrace_id
by thecontext.log
)
const { id } = context;
.done
class MyMiddleware extends Middleware {
public run(context: Context): void {
context.done = true; // Stop passing the `context` to other middlewares
}
}
-
.url
- parsedURL
object
const {
log,
url: { search },
} = context;
log.trace("url search string", { search });
-
.send()
- executecontext.response.send()
and setcontext.done
totrue
await context.send(data);
// or
await context.response.send(data);
context.done = true;
-
.json()
- executecontext.response.json()
and setcontext.done
totrue
const json = { message: "Hello World!" };
await context.json(json);
// or
await context.response.json(json);
context.done = true;
-
.text()
- executecontext.response.text()
and setcontext.done
totrue
const text = "Hello World!";
await context.text(text);
// or
await context.response.text(text);
context.done = true;
-
.html()
- executecontext.response.html()
and setcontext.done
totrue
const html = "<html></html>";
await context.html(html);
// or
await context.response.html(html);
context.done = true;
-
.form()
- executecontext.response.form()
and setcontext.done
totrue
const form = new URLSearchParams({ a: "1" });
await context.form(form);
// or
await context.response.form(form);
context.done = true;
-
.sendFile()
- executecontext.response.sendFile()
and setcontext.done
totrue
const path = "<path to file>";
await context.sendFile(path);
// or
await context.response.sendFile(path);
context.done = true;
-
.throw()
- throwKauaiError
context.throw(402, { json: { error: "Payment Required" }, expose: true });
Any middleware should be extended from the abstract Middleware
class and implement the .run()
method
import { randomInt } from "crypto";
import { Middleware, Context } from "kauai";
export class MyMiddleware extends Middleware {
public async run(context: Context): Promise<void> {
const randomNumber = await new Promise((resolve, reject) => {
randomInt(1, 100, (error, n) => {
if (error) {
reject(error);
} else {
resolve(n);
}
});
});
if (randomNumber <= 50) {
context.throw(400, {
message: "Generated number is less than or equal to 50",
expose: true,
});
}
return context.json({ message: "Generated number is greater than 50" });
}
}
-
.disabled
- One can disable a middleware at any time
import { Middleware, Context } from "kauai";
export class MyMiddleware1 extends Middleware {
public run(context: Context): Promise<void> {
return context.json({ message: "Hello World" });
}
}
const mm1 = new MyMiddleware1({ disabled: true });
export class MyMiddleware2 extends Middleware {
public async run(): Promise<void> {
// Disable `mm1` every hour
setInterval(() => {
mm1.disabled = !mm1.disabled;
}, 1000 * 60 * 60);
}
}
-
.ignore_errors
- ignore errors fromawait this.run(context)
import { Middleware, Context } from "kauai";
export class MyMiddleware1 extends Middleware {
public run(context: Context): Promise<void> {
if (this.ignore_errors) {
return context.json({ message: "Hello World" });
}
context.throw(400);
}
}
const mm1 = new MyMiddleware1({ ignore_errors: true });
export class MyMiddleware2 extends Middleware {
public async run(): Promise<void> {
// Throw errors from `mm1.run()` every minute
setInterval(() => {
mm1.ignore_errors = !mm1.ignore_errors;
}, 1000 * 60);
}
}
KauaiError
represents an HTTP error
import { Middleware, Context, KauaiError } from "kauai";
export class MyMiddleware extends Middleware {
public run(context: Context): Promise<void> {
const { length } = context.request.cookies;
if (!length) {
const status = 401;
const expose = true;
const message =
"Text message to send (when `expose === true` and `json === null`)";
const json = {
error:
"Send `json` as application/json (when `expose === true`) instead of `message`",
};
throw new KauaiError(status, { expose, message, json });
}
return context.json({ message: `Received ${length} cookies` });
}
}
Simple usage with http
import { createServer } from "http";
import { KauaiRequest } from "kauai";
server = createServer({ IncomingMessage: KauaiRequest });
-
.header()
- get a header by name
const rawHeader = request.header("X-Header");
-
.id
- get the request id
const { id } = request;
-
.protocol
- respects the Forwarded header:
const { protocol } = request;
if (protocol !== "https:") {
console.error("The connection is not secure");
}
-
.secure
- same asrequest.protocol === "https:"
const { secure } = request;
if (!secure) {
console.error("The connection is not secure");
}
-
.query
- A copy ofURL.search
parsed by thequerystring.parse()
method
const { query } = request;
// same as
const query = { ...parse(this.URL.search.substring(1)) };
Simple usage with http
import { createServer } from "http";
import { KauaiResponse } from "kauai";
server = createServer({ ServerResponse: KauaiResponse });
-
.cookies
- The.send()
method will add cookies to the response
import { randomUUID } from "crypto";
import { Cookie } from "kauai";
const key = "__Secure-Random-UUID";
const value = randomUUID();
const cookie = new Cookie({ key, value });
response.cookies.add(cookie);
await response.send("Check the `Set-Cookie` header for a random UUID");
-
.status()
- Set the status code of the response
await response.status(400).send();
-
.set()
- Set the headers
const headers = {
"X-AMOUNT": "100.02 USD",
"X-MONTHS": ["jan", "feb"],
};
await response.status(402).set(headers).send("Payment is required");
-
.send()
- send data
await response.send(
"Could be `number` | `string` | `Buffer` | `Readable` | `bigint` | `undefined`"
);
-
.json()
- send an object asapplication/json
usingJSON.stringify()
const json = { k: "v", k1: 1, m: "message", f: false };
await response.json(json);
-
.text()
- send text asplain/text
const text = "Hello World!";
await response.text(text);
-
.html()
- send text astext/html
const html = "<html></html>";
await response.html(html);
-
.form()
- sendURLSearchParams
;
const form = new URLSearchParams({ a: "1", b: ["a", "c"] });
await response.form(form);
-
.sendFile()
- Send a file. Respects the following headers
const path = "<path to file>";
await response.sendFile(path);
import { AcceptEncoding } from "kauai";
const encodings = AcceptEncoding.fromString(request.headers["accept-encoding"]);
// or using KauaiRequest
const { accept_encoding } = request;
import { Authorization } from "kauai";
const authorization = AcceptEncoding.fromString(
request.headers["Authorization"]
);
// or using KauaiRequest
const { authorization } = request;
import { ContentEncoding } from "kauai";
const encodings = ContentEncoding.fromString(
request.headers["content-encoding"]
);
// or using KauaiRequest
const { content_encoding } = request;
import { ContentRange } from "kauai";
const cr = new ContentRange({ start: 0, end: 499, size: 1000 });
response.setHeader("Content-Range", cr.toString());
import { ContentType } from "kauai";
const type = ContentType.fromString(request.headers["content-type"]);
// or using KauaiRequest
const { content_type } = request;
import { Cookie } from "kauai";
const cookies = Cookie.fromString(request.headers["cookie"]);
// or using KauaiRequest
const { cookies } = request;
// or using KauaiResponse
const cookie1 = new Cookie({
key: "__Secure-K1",
value: "v1",
http_only: false,
});
const cookie2 = new Cookie({
key: "K2",
value: "v2",
same_site: "None",
max_age: 1000,
});
response.cookies.add(cookie1).add(cookie2);
import { Forwarded } from "kauai";
const forwarded = Forwarded.fromString(request.headers["forwarded"]);
// or using KauaiRequest
const { forwarded } = request;
import { IfModifiedSince } from "kauai";
const if_modified_since = IfModifiedSince.fromString(
request.headers["if-modified-since"]
);
// or using KauaiRequest
const { if_modified_since } = request;
import { Range } from "kauai";
const range = Range.fromString(request.headers.range);
// or using KauaiRequest
const { range } = request;
npm run test:ci