honojs / hono Goto Github PK
View Code? Open in Web Editor NEWWeb framework built on Web Standards
Home Page: https://hono.dev
License: MIT License
Web framework built on Web Standards
Home Page: https://hono.dev
License: MIT License
I'm trying to see Hono works on Deno. Even if I can, the project files, etc. will maybe get more complicated. So finding a better way. I will give up if it is not found.
Traditionally using express I would have this file structure:
── routes
├── index.js
├── users.route.js
── index.js
And then in users.route.js
I would define all my routes relating to users e.g.
const router = express.Router();
router
.route('/')
.post(auth('manageUsers'), validate(userValidation.createUser), userController.createUser)
.get(auth('getUsers'), validate(userValidation.getUsers), userController.getUsers);
router
.route('/:userId')
.get(auth('getUsers'), validate(userValidation.getUser), userController.getUser)
.patch(auth('manageUsers'), validate(userValidation.updateUser), userController.updateUser)
.delete(auth('manageUsers'), validate(userValidation.deleteUser), userController.deleteUser);
module.exports = router;
In routes/index.js
I would apply the base urls to all my defined routes and then in the top level index.js
I would import and enable them:
// v1 api routes
app.use('/v1', routes);
What is the recommended way of doing this in Hono?
I'd love to see an official example with Miniflare with live reloading for development mode.
I've put together my own project that was working with Miniflare 2.0.0 and Hono 0.0.13. However, if I update Miniflare to 2.2.0, it no longer works. Miniflare shows this on the durable object example:
[mf:err] GET /api/: TypeError: Failed to parse URL from [object Object]
at new Request (/Users/jn/Apps/project-api/node_modules/undici/lib/fetch/request.js:83:23)
at new Request (/Users/jn/Apps/project-api/node_modules/miniflare/node_modules/@miniflare/core/src/standards/http.ts:398:13)
at EventTarget.dispatchFetch (/Users/jn/Apps/project-api/node_modules/miniflare/node_modules/@miniflare/core/src/index.ts:999:51)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Server.<anonymous> (/Users/jn/Apps/project-api/node_modules/@miniflare/http-server/src/index.ts:167:20)
Currently, hono
depends on @types/service-worker-mock
to run unit test, there're some interfaces missing and I think it would not be fixed since it's no longer maintained. https://github.com/zackargyle/service-workers
For example the reqest.formData()
is not supported currently, which block some unit test for hono
.
Write a document on how to handle Environment variables for Cloudflare Workers. Like this:
app.post('/posts', async (c, next) => {
const auth = basicAuth({ username: c.env.NAME, password: c.env.PASS })
await auth(c, next)
})
For data sharing.
const app = new Hono()
app.use('*', async (c, next) => {
c.set('name', 'foo')
await next()
})
app.get('/', (c) => {
const foo = c.get('name')
return c.text(`Hello ${foo}!`)
})
Since hono is using wrangler@beta, so we can not use the official action wrangler-action since it is still in version 1.x.x.
And I tried with script,
name: workers
on:
push:
branches:
- production
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16.7.0
- name: publish
run: |
cd api;
npx wrangler@beta publish index.js;
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
It complains with error log,
cd api;
npx wrangler@beta publish index.js;
shell: /usr/bin/bash -e {0}
env:
CF_API_TOKEN: ***
npm WARN exec The following package was not found and will be installed: wrangler@beta
Using "CF_API_TOKEN" environment variable. This is deprecated. Please use "CLOUDFLARE_API_TOKEN", instead.
⛅️ wrangler 0.0.2[7](https://github.com/gikiapp/giki.api/runs/6211614457?check_suite_focus=true#step:4:7)
--------------------
No account id found, quitting...
If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new.
Error: Process completed with exit code 1.
Any idea to solve this?
I want a project logo image! A cool image for Hono! Is there anyone who can design and draw it?
The current handler and middleware design of Hono is great, and I am thinking the possibility to make it a little simpler and cleaner.
hono.use
const middleware = async (ctx, next) => {
// middleware functionality code
await next()
}
const handler = async (ctx) => {
ctx.body = 'hello world'
}
Then we can apply them with chained style,
new Hono().use(middleware).use(handler)
or compose style,
new Hono().use(middleware, handler)
Hono's routers (TrieRouter and RegExpRouter) are so cool with high performance as we see in Hono currently, to better support hono.use
mentioned above, we can extend it a little bit to be like,
const router = new TrieRouter()
router
.get('/', (ctx) => ctx.body = 'ok')
.post('/', (ctx) => ctx.body = {'status': 'created'})
...
Then Hono can just apply it likem
hono.use(router.routes())
Does this sound like an idea worth discussing?
In Cloudflare Worker, we can set environment variables in wrangler.toml, but I found that it's not accessible when we use Hono in Service Worker mode (app.fire()
).
Module Worker mode like following works well.
export default {
fetch(request, env, event) {
return app.fetch(request, env, event)
},
}
I am thinking if we can make environment variables works in app.fire()
, it'd be great.
We want to have "Logger" middleware as a builtin middleware. We have to write middleware with no dependency on any other npm modules. To know how to write middleware, see Powered By
middleware:
const poweredBy = async (c, next) => {
await next()
await c.res.headers.append('X-Powered-By', 'Hono')
}
After we wrote middleware, add the method to Middleware
object:
Middleware.poweredBy = poweredBy
And then, we can use middleware like this:
const { Hono, Middleware } = require('hono')
...
app.use('*', Middleware.poweredBy)
Add Hono's starter template to cloudflare/templates
https://github.com/cloudflare/templates
Enable app.get('/foo', ()=>{}).post(() => {})
It's would be great if we can apply middlewares like,
app.use('/path', m1, m2, ...)
or
app.use('/path', m1)
.use(m2)
.use(m3)
Webpack 4 that is used in current version wrangler has polyfills for Node.js like Buffer
or crypto
. But, Webpack 5 polyfill are not included. Then, basic-auth
middleware is not working in other environments such as wrangler 2.0 default settings.
One of the ways is basic-auth
middleware imports Buffer
and crypto
. In mustache middleware, it imports mustache
dynamically like this: https://github.com/yusukebe/hono/blob/d3a6f2cdf79deeff6e147d14353971425e74ecbf/src/middleware/mustache/mustache.ts#L11
If users want to use basic-auth
middleware, they should install Buffer
and crypto
.
wrangler init
has been removed. Use this command:
npm init cloudflare my-app https://github.com/honojs/hono-minimal
Throw the errros about crypto
on Node v18.x
FAIL src/utils/jwt/jwt.test.ts
● JWT › HS256 sign & verify & decode
TypeError: Value of "this" must be of type SubtleCrypto
73 | alg: AlgorithmTypes = AlgorithmTypes.HS256
74 | ): Promise<ArrayBuffer> => {
> 75 | const cryptoKey = await crypto.subtle.importKey(
| ^
76 | CryptoKeyFormat.RAW,
77 | utf8ToUint8Array(secret),
78 | param(alg),
at signing (src/utils/jwt/jwt.ts:75:41)
at Object.sign (src/utils/jwt/jwt.ts:95:64)
at Object.<anonymous> (src/utils/jwt/jwt.test.ts:74:17)
...
I've noticed that we don't have a smart API for the application with a large structure. It's related to #200
So, I propose yet another way for routing. That is stacking routes and using these as middleware.
import { Hono, Route } from 'hono'
const app = new Hono()
const route = new Route()
route.get('/entry', handler, handler).post(handler, handler)
app.use('/v1', route)
app.fire()
The routers TrieRouter
and RegExpRouter
do not have routes like a stack but tree. So, we can't use the ways directly, and we have to make the object to stack routes. Route
object is for stacking in the above code.
It's just the idea. If you have comments, please tell me.
Say I wanted to validate the parameters for a post request using middleware but not affect the other methods like get etc, I would like to be able to do:
const route = app.route('/users')
route.post('/', validate(userValidation.createUser), userController.createUser)
But that isn't possible, the only way I can see to do it currently is:
const route = app.route('/users')
app.user('/users', validate(userValidation.createUser))
route.post('/', userController.createUser)
But this does it for all methods in the /users
route, I could check in the middleware for the route method but this isn't ideal. Is there a way to do this that I am missing?
Just like what koa
logger does https://github.com/koajs/logger/blob/master/index.js#L135
My english is poor 😥 please write documents in better English. For examples:
src/middleware/powered-by/README.md
examples/basic/README.md
I know you can access all the parameters in a url, www.url.com/?param1=hey¶m2=three
, by doing:
c.req.query('param1')
c.req.query('param2')
But is there anyway of just accessing an object for all the available parameters without having to know their names in advance?
RegExpRouter
as default?app.get('/', (c) => 'Hello Hono!')
c.stash
?405 method not allowed
c.render
with other middlewarechained route
and c.route
??TypeError: c.req.header is not a function
pretty
option on c.json
#150types.ts
cf-static
serve-static
#76mustache
#72React
waituntil
?parsedBody
as any?graphql
any
all
d.ts
edge-mock
#18c.json()
files
field in package.jsonc.redirect
#36c.notFound
c.text('not found', 404)
c.json({}, 200, {'x-custom-header': 'value'})
#34FetchEvent
instance as c.req.event
c.notFound()
?const res = c.text('a'); res.headers.set()
is good way? #62Middleware
Most features of Hono work on Fastly Compute@Edge. Here is example:
https://github.com/yusukebe/hono/tree/master/example/compute-at-edge
That's great Hono supports both Cloudflare Workers and Compute@Edge. But, basic-auth middleware does not work on Compute@Edge because it does not provides crypto
.
The code I tried is here:
app.use('/auth', Middleware.basicAuth({ username: 'user', password: 'pass' }))
Can basic-auth middleware support Fastly Compute@Edge? We can do it with polyfill
? Using digest.hash_sha256
in C@E? If it is difficult to support C@E without dependencies, let us give up. Because, Hono must not depends any modules.
If anyone knows, let me know.
Hono package became too fat because including builtin middleware. So, we should detach middleware from Hone main package. We can use exports in package.json
. For example :
"exports": {
".": "./dist/index.js",
"./powered-by": "./dist/middleware/powered-by/powered-by.js"
}
import { Hono } from 'hono'
import { poweredBy } from 'hono/poweredBy'
...
app.use('*', poweredBy())
I don't know it will be well. We should try it.
reg-exp-router
HonoRequest
/ Response => HonoResponse
Next
typetypes.ts
v28.0.0 has been released!
I notice that calculating Content-Length
makes returning a response slowly.
let length = 0
if (data) {
if (data instanceof ArrayBuffer) {
length = data.byteLength
} else if (typeof data == 'string') {
const Encoder = new TextEncoder()
length = Encoder.encode(data).byteLength || 0
}
}
Wrangler, Miniflare, or Cloudflare calculate Content-Length
and add to a header automatically. So, we do not have to do it by ourselves. So, how about removing this section?
If we remove it, logger
middleware can not show Content-Length
.
Now Hono is developed in yusukebe/hono
. But:
So, It is a good idea to make the organization for Hono. And transfer this project under the organization.
RegExpRouter is disabled in the build for a feature development, will enable it before merge develop
to master
https://github.com/honojs/hono/pull/198/files#diff-3ae20d611c1c7263a9c1bce0449291ebfea1c5d578b3fcdbb596353ad885db25R8
To make that Response supports the shortcuts such as c.req.param
, c.req.query
, and c.req.header
, we use declare global
.
declare global {
interface Request<ParamKeyType = string> {
param: (key: ParamKeyType) => string
query: (key: string) => string
header: (name: string) => string
}
}
This is good, but not better. We can use these methods in the Hono app, but in other environments, a Request
object does not have params
, query
, and header
, naturally.
So, I'm planning to make HonoRequest
extending Request
object. It is not necessary to make HonoResponse
.
TS tells the following error:
Argument of type "Handler" is not assignable to parameter of type "Handler"
Types of parameters 'string' and 'never' are incompatible. ts(2345)
in
examples/blog/src/index.ts
for all routes (get,post,,put,delete) like:
app.get('/', Controller.root)
Is there any way to create a default or wildcard route? For example, if I want to build a custom 404 handler, I can't seem to be able to do it.
Example I thought would work:
app.get("/api/abc", handleAbcRoute);
app.get("/api/*", handleCustom404);
However, the last wildcard route always takes precedence. There seems to be no way for the first route to be handled appropriately and all other routes use the handleCustom404
function.
I think I can help on this you think it's ok.
It seems like the builtin middlewares not included correctly in release package (version 0.5.1)
import { Hono } from 'hono'
import { basicAuth } from 'hono/basicAuth'
const app = new Hono()
app.use('/api/talks', basicAuth())
app.get('/', (c) => {c.json({})})
./index.js
Module not found: Error: Can't resolve 'hono/basicAuth' in '/Users/minhuang/Development/Projects/giki.api/services/talks/create'
resolve 'hono/basicAuth' in '/Users/minhuang/Development/Projects/giki.api/services/talks/create'
Parsed request is a module
Support Module Workers for Cloudflare Workers: Migrating to module Workers · Cloudflare Workers docs
Such like this, we should modify Context
object.
const app = new Hono()
app.get('/', (c) => {
// c.waitUntil()
// c.env => Env
return c.text('From hono!')
})
export default {
fetch: (req, env, ctx) => app.fetch(req, env, ctx),
}
Is there a best way to set Cors in Hono?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.