Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hono

Package Overview
Dependencies
Maintainers
1
Versions
343
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hono - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0

2

dist/context.d.ts

@@ -6,3 +6,3 @@ /// <reference types="@cloudflare/workers-types" />

export declare type Env = Record<string, any>;
export declare class Context<RequestParamKeyType = string, E = Env> {
export declare class Context<RequestParamKeyType extends string = string, E = Env> {
req: Request<RequestParamKeyType>;

@@ -9,0 +9,0 @@ res: Response;

@@ -19,9 +19,27 @@ "use strict";

initRequest(req) {
req.header = (name) => {
return req.headers.get(name);
};
req.query = (key) => {
req.header = ((name) => {
if (name) {
return req.headers.get(name);
}
else {
const result = {};
for (const [key, value] of req.headers) {
result[key] = value;
}
return result;
}
});
req.query = ((key) => {
const url = new URL(req.url);
return url.searchParams.get(key);
};
if (key) {
return url.searchParams.get(key);
}
else {
const result = {};
for (const [key, value] of url.searchParams) {
result[key] = value;
}
return result;
}
});
return req;

@@ -28,0 +46,0 @@ }

@@ -5,11 +5,19 @@ /// <reference types="@cloudflare/workers-types" />

import type { Router } from './router';
import { METHOD_NAME_ALL_LOWERCASE } from './router';
declare global {
interface Request<ParamKeyType = string> {
param: (key: ParamKeyType) => string;
query: (key: string) => string;
header: (name: string) => string;
interface Request<ParamKeyType extends string = string> {
param: {
(key: ParamKeyType): string;
(): Record<ParamKeyType, string>;
};
query: {
(key: string): string;
(): Record<string, string>;
};
header: {
(name: string): string;
(): Record<string, string>;
};
}
}
export declare type Handler<RequestParamKeyType = string, E = Env> = (c: Context<RequestParamKeyType, E>, next: Next) => Response | Promise<Response> | void | Promise<void>;
export declare type Handler<RequestParamKeyType extends string = string, E = Env> = (c: Context<RequestParamKeyType, E>, next: Next) => Response | Promise<Response> | void | Promise<void>;
export declare type NotFoundHandler<E = Env> = (c: Context<string, E>) => Response;

@@ -27,25 +35,7 @@ export declare type ErrorHandler<E = Env> = (err: Error, c: Context<string, E>) => Response;

}
declare const methods: readonly ["get", "post", "put", "delete", "head", "options", "patch"];
declare type Methods = typeof methods[number] | typeof METHOD_NAME_ALL_LOWERCASE;
interface Routing<E extends Env> {
interface Route<E extends Env> {
path: string;
method: Methods;
method: string;
handler: Handler<string, E>;
}
declare const Route_base: new <E_1 extends Env, T extends string, U>() => {
delete: HandlerInterface<T, E_1, U>;
get: HandlerInterface<T, E_1, U>;
all: HandlerInterface<T, E_1, U>;
post: HandlerInterface<T, E_1, U>;
put: HandlerInterface<T, E_1, U>;
head: HandlerInterface<T, E_1, U>;
options: HandlerInterface<T, E_1, U>;
patch: HandlerInterface<T, E_1, U>;
};
export declare class Route<E = Env, P extends string = ''> extends Route_base<E, P, Route<E, P>> {
#private;
routes: Routing<E>[];
constructor();
private add;
}
declare const Hono_base: new <E_1 extends Env, T extends string, U>() => {

@@ -61,4 +51,3 @@ delete: HandlerInterface<T, E_1, U>;

};
export declare class Hono<E = Env, P extends string = ''> extends Hono_base<E, P, Hono<E, P>> {
#private;
export declare class Hono<E = Env, P extends string = '/'> extends Hono_base<E, P, Hono<E, P>> {
readonly routerClass: {

@@ -68,7 +57,10 @@ new (): Router<any>;

readonly strict: boolean;
private _router;
private _tempPath;
private path;
routes: Route<E>[];
constructor(init?: Partial<Pick<Hono, 'routerClass' | 'strict'>>);
private notFoundHandler;
private errorHandler;
route(path: string, route?: Route): Hono<E, P>;
route(path: string, app?: Hono<any>): Hono<E, P>;
use(path: string, ...middleware: Handler<string, E>[]): Hono<E, P>;

@@ -75,0 +67,0 @@ use(...middleware: Handler<string, E>[]): Hono<E, P>;

"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Route_path, _Hono_router, _Hono_tempPath;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Hono = exports.Route = void 0;
exports.Hono = void 0;
const compose_1 = require("./compose");

@@ -27,33 +15,2 @@ const context_1 = require("./context");

}
class Route extends defineDynamicClass() {
constructor() {
super();
this.routes = [];
_Route_path.set(this, '');
const allMethods = [...methods, router_2.METHOD_NAME_ALL_LOWERCASE];
allMethods.map((method) => {
this[method] = (args1, ...args) => {
if (typeof args1 === 'string') {
__classPrivateFieldSet(this, _Route_path, args1, "f");
}
else {
this.add(method, __classPrivateFieldGet(this, _Route_path, "f"), args1);
}
args.map((handler) => {
if (typeof handler !== 'string') {
this.add(method, __classPrivateFieldGet(this, _Route_path, "f"), handler);
}
});
return this;
};
});
}
add(method, path, handler) {
const r = { path: path, method: method, handler: handler };
this.routes.push(r);
return this;
}
}
exports.Route = Route;
_Route_path = new WeakMap();
class Hono extends defineDynamicClass() {

@@ -64,4 +21,4 @@ constructor(init = {}) {

this.strict = true; // strict routing - default is true
_Hono_router.set(this, void 0);
_Hono_tempPath.set(this, void 0);
this.path = '/';
this.routes = [];
this.notFoundHandler = (c) => {

@@ -94,15 +51,13 @@ const message = '404 Not Found';

Object.assign(this, init);
__classPrivateFieldSet(this, _Hono_router, new this.routerClass(), "f");
__classPrivateFieldSet(this, _Hono_tempPath, null, "f");
this._router = new this.routerClass();
this._tempPath = null;
}
route(path, route) {
const newHono = new Hono();
__classPrivateFieldSet(newHono, _Hono_tempPath, path, "f");
__classPrivateFieldSet(newHono, _Hono_router, __classPrivateFieldGet(this, _Hono_router, "f"), "f");
if (route) {
route.routes.map((r) => {
newHono.addRoute(r.method, r.path, r.handler);
route(path, app) {
this._tempPath = path;
if (app) {
app.routes.map((r) => {
this.addRoute(r.method, r.path, r.handler);
});
}
return newHono;
return this;
}

@@ -131,9 +86,11 @@ use(arg1, ...handlers) {

method = method.toUpperCase();
if (__classPrivateFieldGet(this, _Hono_tempPath, "f")) {
path = (0, url_1.mergePath)(__classPrivateFieldGet(this, _Hono_tempPath, "f"), path);
if (this._tempPath) {
path = (0, url_1.mergePath)(this._tempPath, path);
}
__classPrivateFieldGet(this, _Hono_router, "f").add(method, path, handler);
this._router.add(method, path, handler);
const r = { path: path, method: method, handler: handler };
this.routes.push(r);
}
async matchRoute(method, path) {
return __classPrivateFieldGet(this, _Hono_router, "f").match(method, path);
return this._router.match(method, path);
}

@@ -144,6 +101,12 @@ async dispatch(request, event, env) {

const result = await this.matchRoute(method, path);
request.param = (key) => {
if (result)
return result.params[key];
};
request.param = ((key) => {
if (result) {
if (key) {
return result.params[key];
}
else {
return result.params;
}
}
});
const handlers = result ? result.handlers : [this.notFoundHandler];

@@ -183,2 +146,1 @@ const c = new context_1.Context(request, { env: env, event: event, res: undefined });

exports.Hono = Hono;
_Hono_router = new WeakMap(), _Hono_tempPath = new WeakMap();

@@ -155,41 +155,68 @@ "use strict";

describe('param and query', () => {
const app = new hono_1.Hono();
app.get('/entry/:id', (c) => {
const id = c.req.param('id');
return c.text(`id is ${id}`);
const apps = {};
apps['get by name'] = (() => {
const app = new hono_1.Hono();
app.get('/entry/:id', (c) => {
const id = c.req.param('id');
return c.text(`id is ${id}`);
});
app.get('/date/:date{[0-9]+}', (c) => {
const date = c.req.param('date');
return c.text(`date is ${date}`);
});
app.get('/search', (c) => {
const name = c.req.query('name');
return c.text(`name is ${name}`);
});
app.get('/add-header', (c) => {
const bar = c.req.header('X-Foo');
return c.text(`foo is ${bar}`);
});
return app;
})();
apps['get all as an object'] = (() => {
const app = new hono_1.Hono();
app.get('/entry/:id', (c) => {
const { id } = c.req.param();
return c.text(`id is ${id}`);
});
app.get('/date/:date{[0-9]+}', (c) => {
const { date } = c.req.param();
return c.text(`date is ${date}`);
});
app.get('/search', (c) => {
const { name } = c.req.query();
return c.text(`name is ${name}`);
});
app.get('/add-header', (c) => {
const { 'x-foo': bar } = c.req.header();
return c.text(`foo is ${bar}`);
});
return app;
})();
describe.each(Object.keys(apps))('%s', (name) => {
const app = apps[name];
it('param of /entry/:id is found', async () => {
const res = await app.request('http://localhost/entry/123');
expect(res.status).toBe(200);
expect(await res.text()).toBe('id is 123');
});
it('param of /date/:date is found', async () => {
const res = await app.request('http://localhost/date/0401');
expect(res.status).toBe(200);
expect(await res.text()).toBe('date is 0401');
});
it('query of /search?name=sam is found', async () => {
const res = await app.request('http://localhost/search?name=sam');
expect(res.status).toBe(200);
expect(await res.text()).toBe('name is sam');
});
it('/add-header header - X-Foo is Bar', async () => {
const req = new Request('http://localhost/add-header');
req.headers.append('X-Foo', 'Bar');
const res = await app.request(req);
expect(res.status).toBe(200);
expect(await res.text()).toBe('foo is Bar');
});
});
app.get('/date/:date{[0-9]+}', (c) => {
const date = c.req.param('date');
return c.text(`date is ${date}`);
});
app.get('/search', (c) => {
const name = c.req.query('name');
return c.text(`name is ${name}`);
});
app.get('/add-header', (c) => {
const bar = c.req.header('X-Foo');
return c.text(`foo is ${bar}`);
});
it('param of /entry/:id is found', async () => {
const res = await app.request('http://localhost/entry/123');
expect(res.status).toBe(200);
expect(await res.text()).toBe('id is 123');
});
it('param of /date/:date is found', async () => {
const res = await app.request('http://localhost/date/0401');
expect(res.status).toBe(200);
expect(await res.text()).toBe('date is 0401');
});
it('query of /search?name=sam is found', async () => {
const res = await app.request('http://localhost/search?name=sam');
expect(res.status).toBe(200);
expect(await res.text()).toBe('name is sam');
});
it('/add-header header - X-Foo is Bar', async () => {
const req = new Request('http://localhost/add-header');
req.headers.append('X-Foo', 'Bar');
const res = await app.request(req);
expect(res.status).toBe(200);
expect(await res.text()).toBe('foo is Bar');
});
});

@@ -455,30 +482,53 @@ describe('Middleware', () => {

});
describe('`Route` with app.route', () => {
const app = new hono_1.Hono();
describe('Hono with `app.route`', () => {
describe('Basic', () => {
const route = new hono_1.Route();
route.get('/post', (c) => c.text('GET /POST'));
route.post('/post', (c) => c.text('POST /POST'));
app.route('/v1', route);
it('Should return 200 response - GET /v1/post', async () => {
const res = await app.request('http://localhost/v1/post');
expect(res.status).toBe(200);
expect(await res.text()).toBe('GET /POST');
const app = new hono_1.Hono();
const api = new hono_1.Hono();
const middleware = new hono_1.Hono();
api.get('/posts', (c) => c.text('List'));
api.post('/posts', (c) => c.text('Create'));
api.get('/posts/:id', (c) => c.text(`GET ${c.req.param('id')}`));
api.use('*', async (c, next) => {
await next();
c.res.headers.append('x-custom-a', 'a');
});
it('Should return 200 response - POST /v1/post', async () => {
const res = await app.request('http://localhost/v1/post', { method: 'POST' });
expect(res.status).toBe(200);
expect(await res.text()).toBe('POST /POST');
app.route('/api', api);
middleware.use('*', async (c, next) => {
await next();
c.res.headers.append('x-custom-b', 'b');
});
it('Should return 404 response - DELETE /v1/post', async () => {
const res = await app.request('http://localhost/v1/post', { method: 'DELETE' });
app.route('/api', middleware);
it('Should return not found response', async () => {
const res = await app.request('http://localhost/');
expect(res.status).toBe(404);
});
it('Should return 404 response - GET /post', async () => {
const res = await app.request('http://localhost/post');
it('Should return not found response', async () => {
const res = await app.request('http://localhost/posts');
expect(res.status).toBe(404);
});
test('GET /api/posts', async () => {
const res = await app.request('http://localhost/api/posts');
expect(res.status).toBe(200);
expect(await res.text()).toBe('List');
});
test('Custom header by middleware', async () => {
const res = await app.request('http://localhost/api/posts');
expect(res.status).toBe(200);
expect(res.headers.get('x-custom-a')).toBe('a');
expect(res.headers.get('x-custom-b')).toBe('b');
});
test('POST /api/posts', async () => {
const res = await app.request('http://localhost/api/posts', { method: 'POST' });
expect(res.status).toBe(200);
expect(await res.text()).toBe('Create');
});
test('GET /api/posts/123', async () => {
const res = await app.request('http://localhost/api/posts/123');
expect(res.status).toBe(200);
expect(await res.text()).toBe('GET 123');
});
});
describe('Chaining', () => {
const route = new hono_1.Route();
const app = new hono_1.Hono();
const route = new hono_1.Hono();
route.get('/post', (c) => c.text('GET /POST v2')).post((c) => c.text('POST /POST v2'));

@@ -501,18 +551,32 @@ app.route('/v2', route);

});
describe('Named parameter', () => {
const route = new hono_1.Route();
route.get('/post/:id', (c) => {
const id = c.req.param('id');
return c.text(`GET /post/${id} v3`);
describe('Nested', () => {
const app = new hono_1.Hono();
const api = new hono_1.Hono();
const book = new hono_1.Hono();
book.get('/', (c) => c.text('list books'));
book.get('/:id', (c) => c.text(`book ${c.req.param('id')}`));
api.get('/', (c) => c.text('this is API'));
api.route('/book', book);
app.get('/', (c) => c.text('root'));
app.route('/v2', api);
it('Should return 200 response - GET /', async () => {
const res = await app.request('http://localhost/');
expect(res.status).toBe(200);
expect(await res.text()).toBe('root');
});
app.route('/v3', route);
it('Should return 200 response - GET /v3/post/1', async () => {
const res = await app.request('http://localhost/v3/post/1');
it('Should return 200 response - GET /v2', async () => {
const res = await app.request('http://localhost/v2');
expect(res.status).toBe(200);
expect(await res.text()).toBe('GET /post/1 v3');
expect(await res.text()).toBe('this is API');
});
it('Should return 404 response - GET /v3/post', async () => {
const res = await app.request('http://localhost/v3/post/abc/def');
expect(res.status).toBe(404);
it('Should return 200 response - GET /v2/book', async () => {
const res = await app.request('http://localhost/v2/book');
expect(res.status).toBe(200);
expect(await res.text()).toBe('list books');
});
it('Should return 200 response - GET /v2/book/123', async () => {
const res = await app.request('http://localhost/v2/book/123');
expect(res.status).toBe(200);
expect(await res.text()).toBe('book 123');
});
});

@@ -519,0 +583,0 @@ });

@@ -1,4 +0,4 @@

export { Hono, Route } from './hono';
export { Hono } from './hono';
export type { Handler, Next } from './hono';
export { Context } from './context';
export type { Env } from './context';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Context = exports.Route = exports.Hono = void 0;
exports.Context = exports.Hono = void 0;
var hono_1 = require("./hono");
Object.defineProperty(exports, "Hono", { enumerable: true, get: function () { return hono_1.Hono; } });
Object.defineProperty(exports, "Route", { enumerable: true, get: function () { return hono_1.Route; } });
var context_1 = require("./context");
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });

@@ -5,3 +5,6 @@ import type { Context } from '../../context';

interface Request {
cookie: (name: string) => string;
cookie: {
(name: string): string;
(): Record<string, string>;
};
}

@@ -8,0 +11,0 @@ }

@@ -6,8 +6,13 @@ "use strict";

return async (c, next) => {
c.req.cookie = (name) => {
c.req.cookie = ((name) => {
const cookie = c.req.headers.get('Cookie');
const obj = parse(cookie);
const value = obj[name];
return value;
};
if (name) {
const value = obj[name];
return value;
}
else {
return obj;
}
});
c.cookie = (name, value, opt) => {

@@ -14,0 +19,0 @@ const cookie = serialize(name, value, opt);

@@ -6,50 +6,74 @@ "use strict";

describe('Cookie Middleware', () => {
const app = new hono_1.Hono();
app.use('/cookie', (0, _1.cookie)());
app.get('/cookie', (c) => {
const yummyCookie = c.req.cookie('yummy_cookie');
const tastyCookie = c.req.cookie('tasty_cookie');
const res = new Response('Good cookie');
res.headers.set('Yummy-Cookie', yummyCookie);
res.headers.set('Tasty-Cookie', tastyCookie);
return res;
describe('Parse cookie', () => {
const apps = {};
apps['get by name'] = (() => {
const app = new hono_1.Hono();
app.use('/cookie', (0, _1.cookie)());
app.get('/cookie', (c) => {
const yummyCookie = c.req.cookie('yummy_cookie');
const tastyCookie = c.req.cookie('tasty_cookie');
const res = new Response('Good cookie');
res.headers.set('Yummy-Cookie', yummyCookie);
res.headers.set('Tasty-Cookie', tastyCookie);
return res;
});
return app;
})();
apps['get all as an object'] = (() => {
const app = new hono_1.Hono();
app.use('/cookie', (0, _1.cookie)());
app.get('/cookie', (c) => {
const { yummy_cookie: yummyCookie, tasty_cookie: tastyCookie } = c.req.cookie();
const res = new Response('Good cookie');
res.headers.set('Yummy-Cookie', yummyCookie);
res.headers.set('Tasty-Cookie', tastyCookie);
return res;
});
return app;
})();
describe.each(Object.keys(apps))('%s', (name) => {
const app = apps[name];
it('Parse cookie on c.req.cookie', async () => {
const req = new Request('http://localhost/cookie');
const cookieString = 'yummy_cookie=choco; tasty_cookie = strawberry ';
req.headers.set('Cookie', cookieString);
const res = await app.request(req);
expect(res.headers.get('Yummy-Cookie')).toBe('choco');
expect(res.headers.get('Tasty-Cookie')).toBe('strawberry');
});
});
});
it('Parse cookie on c.req.cookie', async () => {
const req = new Request('http://localhost/cookie');
const cookieString = 'yummy_cookie=choco; tasty_cookie = strawberry ';
req.headers.set('Cookie', cookieString);
const res = await app.request(req);
expect(res.headers.get('Yummy-Cookie')).toBe('choco');
expect(res.headers.get('Tasty-Cookie')).toBe('strawberry');
});
app.use('/set-cookie', (0, _1.cookie)());
app.get('/set-cookie', (c) => {
c.cookie('delicious_cookie', 'macha');
return c.text('Give cookie');
});
it('Set cookie on c.cookie', async () => {
const res = await app.request('http://localhost/set-cookie');
expect(res.status).toBe(200);
const header = res.headers.get('Set-Cookie');
expect(header).toBe('delicious_cookie=macha');
});
app.use('/set-cookie-complex', (0, _1.cookie)());
app.get('/set-cookie-complex', (c) => {
c.cookie('great_cookie', 'banana', {
path: '/',
secure: true,
domain: 'example.com',
httpOnly: true,
maxAge: 1000,
expires: new Date(Date.UTC(2000, 11, 24, 10, 30, 59, 900)),
sameSite: 'Strict',
describe('Set cookie', () => {
const app = new hono_1.Hono();
app.use('/set-cookie', (0, _1.cookie)());
app.get('/set-cookie', (c) => {
c.cookie('delicious_cookie', 'macha');
return c.text('Give cookie');
});
return c.text('Give cookie');
it('Set cookie on c.cookie', async () => {
const res = await app.request('http://localhost/set-cookie');
expect(res.status).toBe(200);
const header = res.headers.get('Set-Cookie');
expect(header).toBe('delicious_cookie=macha');
});
app.use('/set-cookie-complex', (0, _1.cookie)());
app.get('/set-cookie-complex', (c) => {
c.cookie('great_cookie', 'banana', {
path: '/',
secure: true,
domain: 'example.com',
httpOnly: true,
maxAge: 1000,
expires: new Date(Date.UTC(2000, 11, 24, 10, 30, 59, 900)),
sameSite: 'Strict',
});
return c.text('Give cookie');
});
it('Complex pattern', async () => {
const res = await app.request('http://localhost/set-cookie-complex');
expect(res.status).toBe(200);
const header = res.headers.get('Set-Cookie');
expect(header).toBe('great_cookie=banana; Max-Age=1000; Domain=example.com; Path=/; Expires=Sun, 24 Dec 2000 10:30:59 GMT; HttpOnly; Secure; SameSite=Strict');
});
});
it('Complex pattern', async () => {
const res = await app.request('http://localhost/set-cookie-complex');
expect(res.status).toBe(200);
const header = res.headers.get('Set-Cookie');
expect(header).toBe('great_cookie=banana; Max-Age=1000; Domain=example.com; Path=/; Expires=Sun, 24 Dec 2000 10:30:59 GMT; HttpOnly; Secure; SameSite=Strict');
});
});

@@ -78,2 +78,6 @@ "use strict";

}
/* ['/', '/'] => `/` */
if (path === '/' && p === '') {
p = '/';
}
}

@@ -80,0 +84,0 @@ return p;

@@ -86,3 +86,12 @@ "use strict";

});
it('Should be `/book`', () => {
expect((0, url_1.mergePath)('/', 'book')).toBe('/book');
});
it('Should be `/book`', () => {
expect((0, url_1.mergePath)('/', '/book')).toBe('/book');
});
it('Should be `/`', () => {
expect((0, url_1.mergePath)('/', '/')).toBe('/');
});
});
});
{
"name": "hono",
"version": "1.2.2",
"version": "1.3.0",
"description": "Ultrafast web framework for Cloudflare Workers.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -55,3 +55,3 @@ <div align="center">

- **TrieRouter**(default) - Implemented with Trie tree structure.
- **RegExpRouter** - Match routes with one big Regex made before dispatching at once.
- **RegExpRouter** - Match the route with using one big Regex made before dispatch.

@@ -97,12 +97,10 @@ ## Hono in 1 minute

```ts
import { Hono, Route } from 'hono'
import { cors } from 'hono/cors'
import { Hono } from 'hono'
import { basicAuth } from 'hono/basic-auth'
const app = new Hono()
const v1 = new Route()
const v1 = new Hono()
v1.get('/posts', (c) => {
return c.text('list pots')
})
.post('/posts', cors(), (c) => {
.post(basicAuth({ username, password }), (c) => {
return c.text('created!', 201)

@@ -115,2 +113,3 @@ })

const app = new Hono()
app.route('/v1', v1)

@@ -146,3 +145,3 @@ ```

- app.**all**(\[path,\] handler|middleware...)
- app.**route**(path, \[Route\])
- app.**route**(path, \[app\])
- app.**use**(\[path,\] middleware)

@@ -163,2 +162,4 @@ - app.**notFound**(handler)

app.post('/', (c) => c.text('POST /'))
app.put('/', (c) => c.text('PUT /'))
app.delete('/', (c) => c.text('DELETE /'))

@@ -183,2 +184,11 @@ // Wildcard

or all parameters at once:
```ts
app.get('/posts/:id/comment/:comment_id', (c) => {
const { id, comment_id } = c.req.param()
...
})
```
### Regexp

@@ -188,4 +198,3 @@

app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
const date = c.req.param('date')
const title = c.req.param('title')
const { date, title } = c.req.param()
...

@@ -229,8 +238,8 @@ })

## Route
## Grouping
`Route` object enables Nested route.
Group the routes with `Hono` instance and add them to the main app with `route` method.
```ts
const book = new Route()
const book = new Hono()

@@ -245,2 +254,3 @@ book.get('/', (c) => c.text('List Books')) // GET /book

const app = new Hono()
app.route('/book', book)

@@ -350,2 +360,8 @@ ```

// Get all params at once
app.get('/search', (c) => {
const { q, limit, offset } = c.req.query()
...
})
// Captured params

@@ -440,4 +456,4 @@ app.get('/entry/:id', (c) => {

// Response object
app.use('/', (c, next) => {
next()
app.use('/', async (c, next) => {
await next()
c.res.headers.append('X-Debug', 'Debug message')

@@ -451,7 +467,7 @@ })

// FetchEvent object
app.use('*', async (c, next) => {
app.get('/foo', async (c) => {
c.event.waitUntil(
...
c.env.KV.put(key, data)
)
await next()
...
})

@@ -574,4 +590,59 @@ ```

## Examples
## Practical Example
How about writing web API with Hono?
```ts
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { basicAuth } from 'hono/basic-auth'
import { prettyJSON } from 'hono/pretty-json'
import { getPosts, getPosts, createPost } from './model'
const app = new Hono()
app.get('/', (c) => c.text('Pretty Blog API'))
app.use('*', prettyJSON())
app.notFound((c) => c.json({ message: 'Not Found', ok: false }, 404))
export interface Bindings {
USERNAME: string
PASSWORD: string
}
const api = new Hono<Bindings>()
api.get('/posts', (c) => {
const { limit, offset } = c.req.query()
const posts = getPosts({ limit, offset })
return c.json({ posts })
})
api.get('/posts/:id', (c) => {
const id = c.req.param('id')
const post = getPost({ id })
return c.json({ post })
})
api.post(
'/posts',
async (c, next) => {
const auth = basicAuth({ username: c.env.USERNAME, password: c.env.PASSWORD })
await auth(c, next)
},
async (c) => {
const post = await c.req.json<POST>()
const ok = createPost({ post })
return c.json({ ok })
}
)
app.use('/posts/*', cors())
app.route('/api', api)
export default app
```
## Other Examples
- Hono Examples - <https://github.com/honojs/examples>

@@ -578,0 +649,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc