Coder Social home page Coder Social logo

h3's Introduction

H3

npm version npm downloads

H3 (pronounced as /eɪtʃθriː/, like h-3) is a minimal h(ttp) framework built for high performance and portability.

👉 Documentation

Contribution

Local development
  • Clone this repository
  • Install the latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Run tests using pnpm dev or pnpm test

License

Published under the MIT license. Made by @pi0 and community 💛


🤖 auto updated with automd

h3's People

Contributors

aareksio avatar antfu avatar atinux avatar autofix-ci[bot] avatar barbapapazes avatar changjoo-park avatar damianglowala avatar danielroe avatar dargmuesli avatar enkot avatar farnabaz avatar galactichypernova avatar harlan-zw avatar hebilicious avatar iainsproat avatar mannil avatar maou-shonen avatar nozomuikuta avatar pi0 avatar renovate[bot] avatar seho-dev avatar shahriar-rahi avatar shyam-chen avatar sisou avatar stafyniaksacha avatar tobiasdiez avatar torstendittmann avatar wobsoriano avatar ytjmt avatar zhiyuanzmj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h3's Issues

question. How `setImmediate` improve performance?

Hello @pi0 . I can not find for place to question. So I leave my question here.

I saw yesterday your commit. I understood early return (break to return) is nice pattern in the upper diff src/app.ts.
but, I didn't understand to use setImmediate. All of request already asynchronous. Why need Promise with setImmediate ?

I tried to benchmark before / after setImmediate . I got almost same result.

useBody doesn't resolve Promise on local call when body is empty

I tested with an api endpoint on a Nuxt3 project but you can probably reproduce with any local call I guess.

server/api/user.ts

export default async (req: IncomingMessage, res: ServerResponse) => {
    const body = await useBody(req)
}

Using ohmyfetch to call the api locally with default GET method (and without body)

await $fetch('/api/user')

The Promise in the useRawBody function never gets resolved because the req.on is never called

h3/src/utils/body.ts

Lines 29 to 41 in 25a6195

return new Promise<string>((resolve, reject) => {
const bodyData: any[] = []
req
.on('error', (err) => { reject(err) })
.on('data', (chunk) => { bodyData.push(chunk) })
.on('end', () => {
// @ts-ignore
req[RawBodySymbol] = Buffer.concat(bodyData)
// @ts-ignore
resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol])
})
})
}

I guess it's tied to unenv fetch setting the req.body to null
https://github.com/unjs/unenv/blob/909d75e48667ce0732ce0fa8b6a2af4895f54d8e/src/runtime/fetch/call.ts#L31

req.body = context.body || null

I don't know if it's something that needs to be fixed here or in unenv.

As solution in h3 could be using this syntax (Node.js v10 + only) :

const bodyData = [];

for await (const chunk of req) {
    bodyData.push(chunk);
}

req[RawBodySymbol] = Buffer.concat(bodyData) 
resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol]) 

router issue with query params

@pi0 Hello, Thank you very much createRouter for solving my problem. I used the add function to successfully add a route for a get request, and it works normally, but if I add a query parameter after the URL, such as /a?title=a, Such a route will fail to match;

Originally posted by @1018715564 in #76 (comment)

ERROR: Cannot set headers after they are sent to the client : Cannot set headers after they are sent to the client

Hello I made nuxt-nitro demo clone without nitro. URL is here. https://nuxt-without-nitro-demo.vercel.app/

I try with /api/hello made with h3, It failed after deploy. When I test on local, It make error.

 ERROR  Cannot set headers after they are sent to the client                                                                                                              20:39:12

  at ServerResponse.setHeader (_http_outgoing.js:518:11)
  at sendError (node_modules/h3/dist/index.js:502:7)
  at node_modules/h3/dist/index.js:514:14

My server middleware is https://github.com/ChangJoo-Park/nuxt-without-nitro-demo/blob/main/server/hello.js#L4-L8.
I tested with remove res.setHeader('Access-Control-Allow-Origin', '*') . but it fails too.

[TS][TypeError] JSONValue doesn't accept optional keys

https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgFIGUDyA5TAjAKwgTGQG8BYAKGVuQG0APALmQGcwpQBzAXVYw4AanAA2AVwgBuagF9qoSLEQpB2AIJQocAJ7IIjSCAAmbZJu06APGpESIAPnJzqYHQAdVWbHcnIAvOycPMgAPsgg4gC2eNBhyHgA9omiEHAg8Wr4RCSZ3ha6MlQK4NDwSMhROujQAG7ASABKEGzuiSBsEAAiLQhc7mDA7c40yCxBXCDc1LQ6APysHJPTVPJUbp6V1XUNEM2t7Z0BI7QgcFEQi8FTM8jGvf2D7QtbNVD1TS1tHd0PwANDEAuYpUGDiEAkQFbABi4IQAAoAJQCby+FCUUYIQ6kKrqADucGAkGM+2+nVYVTeHz2X0OKECGLoEXOl2QAHJIBw2QAaW60e5sPr-J4gViMpljVgclpgHl8ug6Vjg+4wUAQYzyta0Na3KAQMDiKAZXEEonq0l0uRAA

I am trying to use h3 to return some responses from a service (in my case, it's contentful). Of course some values from the service can be undefined, because in the CMS they are not required, but JSONValue (more specifically, JSONObject) doesn't accept undefined values.

interface JSONObject {
    [x: symbol]: JSONValue;
}

This fixes errors, but I'm not sure it's correct.

@antfu cc

is it necessary?

image

  1. Have been confirmed type is object
  2. In my opinion,val !== void 0 is not necessary

There are other applications for this part of the code ?

Pray for god's guidance~~~

useQuery(req) return all DOM page.. 0.7.1 + nuxt3

in template vue


    const data = await useAsyncData("blogitem", () =>
      $fetch("/api/news-item?", {
        method: "GET",
        params: {
          query: "slug",
          slug: route.params.id,
        },
      })
    ).then((res) => {
      return res.data;
    });

in server api

let query = useQuery(req)
console.log(query)

return this.. before woks fine.
Снимок экрана 2022-04-08 в 12 34 50

matchParams() utility

A match factory utility to match params (/[user]/[foo?]/) and populate req.params

how to use match option in h3

In my program, there are nested routes, such as /api/a and /api/a/detail, but due to fast prefix matching, when I access /api/a/detail, the trigger is still /api/a's callback function, what should I do now?

server hangs if a handler returns undefined

with automatic promisifying, if a handler returns undefined, the promise never resolves and the server hangs...

Is there a reason we don't immediately resolve(undefined) if the handler does?

Respond with a stream of data

Hello!

Is there a way already to respond a request with a stream of data?

I am planning specifically to use puppeteer page.createPDFStream, as Firebase Functions don't give us much initial memory, and I only found a way to increase it via regular cloud function, and not using nuxt /server/api folder.

So, probably in this case, stream the data would be a good fit.
Thanks a lot!

Handle cases?

Example: /api/moduleLists will not work, we need to set it lowercase.

useBody doesn't work in middleware

when i use useBody (h3 version 0.3.8) in the context of a middleware, the request doesn't fulfill. Removing the method call solves the issue.

How can i get the request body in the context of a middleware so i can use it for logging ? it seems calling useBody results in the next handler to not be invoked...

Here is my demo code:

import { useBody } from "h3";

export default async function (req, res, next) {
  const { statusCode } = res;

  if(["POST", "PUT", "DELETE"].includes(req.method)) {
    req.body = await useBody(req);
  }

  if (process.$winstonLog) {
    process.$winstonLog(req, statusCode);
  }

  next();
}

async handle did not wait for closing

Found while experimenting with nuxt3.

In my nuxt app, h3 will use a lazy/promisify/async middleware handle, which will eventually be invoked in callHandle:

h3/src/handle.ts

Lines 18 to 21 in 2805d4c

try {
const returned = handle(req, res, next)
if (returned !== undefined) {
resolve(returned)

But async function will return a promise instance, if async handler does not send/close the response before they return, callHandle resolve immediately.

The following patch is helpful on my case:

--- a/node_modules/h3/dist/index.mjs
+++ b/node_modules/h3/dist/index.mjs
@@ -109,7 +109,7 @@ function callHandle(handle, req, res) {
     const next = (err) => err ? reject(err) : resolve(void 0);
     try {
       const returned = handle(req, res, next);
-      if (returned !== void 0) {
+      if (returned !== void 0 && !(returned instanceof Promise)) {
         resolve(returned);
       } else {
         res.once("close", next);

Suspect it is root cause of #21.

document utils

  • Adding JSDoc
  • Find a hosted solution to render JSDocs (deno does this for example for registered modules but we might have another solution)

H3Event Class

Related to #73

The current approach for universal compatibility is to take node req and res as references and emulate them with unenv. With the new Event interface, we can move towards the native web events.

  • New H3Event class wrapping req and res and implementing FetchEvent interface (minimal)
  • Create new H3EventRequest class wrapping H3Event and implimenting Request interface (minimal)
  • New test suite for event interface

[bug] large file upload cause crashes

i'm trying to upload file from client and save it locally on the server...
for the server side i' using busboy.... and it work correctly only with small files.... with large file i get an error:

 ERROR  [h3] write EPIPE                                                                                                                                     17:21:55

  at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:94:16

Is FormData supported?

Hi, it turns out I'm passing a blob through FormData and useBody isn't picking it up right. Is it supported?

Available request methods?

Does h3 support all request methods? The examples only showcase get -- tried looking through the code to see if I could glean any additional information but came up empty.

  • get
  • post
  • put
  • patch
  • delete
  • ...

Custom API server middleware with nuxt collides with other API

Hello, I have a nuxt app with a proxy middleware and server middleware using h3.

nuxt.config.js

  axios: {
    proxy: true,
  },

  proxy: {
    '/api/': {
      target: process.env.MYTOKEN,
      pathRewrite: { '^/api/': '' },
      logLevel: 'debug',
      onProxyReq: (proxyReq: any) => {
        proxyReq.path += '?api_key_token=' + process.env.MYTOKEN;
      },
    },
  },

  serverMiddleware: [
    { path: '/api', handler: '~/server/api.ts' }
  ],

api.ts

import { createApp } from 'h3';

const app = createApp();

app.use('/hello', () => {
  return {
    hello: 'world'
  }
});

export default app;

All other /api routes in the proxy returns 404. Only the /api/hello custom server middleware works.

When using express, everything works fine. I also tried to have 2 custom server middlewares using h3:

nuxt.config.js

  serverMiddleware: [
    { path: '/api', handler: '~/server/api.ts' }
    { path: '/api', handler: '~/server/api-two.ts' }
  ],

api.ts

import { createApp } from 'h3';

const app = createApp();

app.use('/hello', () => {
  return {
    hello: 'world'
  }
});

export default app;

api-two.ts

import { createApp } from 'h3';

const app = createApp();

app.use('/hi', () => {
  return {
    hi: 'world'
  }
});

export default app;

The first one works but api-two.ts returns 404. Do I need to setup something here? Thank you!

Documentation/example of how to run h3 in a worker environment

I'm trying to get started with h3 in a Cloudflare worker - are there any examples of how to get started with h3 in workers?

import { createApp } from 'h3'

const app = createApp()
app.use('/', () => 'Hello world')

addEventListener('fetch', (e) => {
  // ???
})

useBody with `application/x-www-form-urlencoded`

Hello, when using useBody I get a string instead of an object. Something like this field=value&another=value. Is there an option to make this an object? What I currently do is this:

let body = await useBody(req)
body = Object.fromEntries(new URLSearchParams(body))

thanks

https support?

Hi! Very interested on this. I can get express and the core http server to serve over HTTPS quite easily, but I... don't know enough about h3 to do that with your library? Is there documentation on the topic?

Migrating to Events API

h3 was born with the idea of being a platform-agnostic server framework for all JavaScript environments and backward compatibility with legacy server middleware format for Node.js and Express compatibility.

Initially, we started with the most backward-compatible format (req, res) and improved it by async support async (req, res) and also directly returning a response for a pleasant experience with (req, res) => 'Hello World' format.

unjs/unenv provides a createCall and mocks of Node.js HTTP built-ins. Thanks to this mocking framework, h3 is able to work nicely on almost any serverless or Worker platform.

However, this kind of setup keeps h3 to be away from natively supporting non Node.js environments with the cost of unenv overhead for any code not using Node.js.

Additionally, (req, res) format is not even suitable to extend h3 supporting Node.js features like http2 without compatibility API and ws support.

Migration to (event) format will be progressive and backward compatibility wherever necessary however we potentially have to introduce breaking changes as semver-minor until reaching [email protected].

Progress

  • opt-in using event format using defineEventHandler (#74)
  • use Event api with utils with compatibility layer (#75)
  • Event class (#81)
  • Make node-js handlers opt-in and drop (req, res) implicit conversion (#178)
  • Make event.req and event.res optional and adopt more of event native (#231)
  • Mock (with warning) for req, res (#472)
  • Migrate all leftover utils

sort stack

automatically sort by layer.route.length to avoid ordering issues (with an AppOption to disable)

Alternative: sort(app) | app.sort()

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Edited/Blocked

These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

bun
docs/package.json
  • undocs ^0.2.21
github-actions
.github/workflows/autofix.yml
  • actions/checkout v4
  • actions/setup-node v4
  • autofix-ci/action ea32e3a12414e6d3183163c3424a7d7a8631ad84
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-node v4
  • codecov/codecov-action v4
npm
package.json
  • cookie-es ^1.1.0
  • crossws ^0.2.4
  • defu ^6.1.4
  • destr ^2.0.3
  • iron-webcrypto ^1.1.1
  • ohash ^1.1.3
  • radix3 ^1.1.2
  • ufo ^1.5.3
  • uncrypto ^0.1.3
  • unenv ^1.9.0
  • 0x ^5.7.0
  • @types/express ^4.17.21
  • @types/node ^20.12.7
  • @types/supertest ^6.0.2
  • @vitest/coverage-v8 ^1.5.2
  • autocannon ^7.15.0
  • automd ^0.3.7
  • changelogen ^0.5.5
  • connect ^3.7.0
  • eslint ^9.1.1
  • eslint-config-unjs ^0.3.0-rc.6
  • express ^4.19.2
  • get-port ^7.1.0
  • jiti ^1.21.0
  • listhen ^1.7.2
  • node-fetch-native ^1.6.4
  • prettier ^3.2.5
  • react ^18.3.1
  • react-dom ^18.3.1
  • supertest ^6.3.4
  • typescript ^5.4.5
  • unbuild ^2.0.0
  • vitest ^1.5.2
  • zod ^3.23.4
  • pnpm 9.0.6
playground/package.json

  • Check this box to trigger a request for Renovate to run again on this repository

http method filtering

Supporting http methods could be a nice DX addition but it implicitly adds runtime overhead if implemented using a wrapper function (#14). We might support a built-in filter similar to the filter we use for quick prefix matching.

Overall downside of this feature is that we will loose lazy loading on handles based on their acceptance method which might be important for serverless environments so i think might worth waiting to use h3 more in realistic projects before making decision.

Request: Dockerized H3 API example

Hello @pi0,
I know you are very busy with Nuxt 3 development, so I don't expect you would be able to fulfil this request anytime soon. Maybe this could be put on the back burner. Or maybe someone else can help me here.

What I'm looking for is for a starter template to get me started with using Node + H3 + Docker + Testing.

I'll be making a series of mini-applications with somewhat different API's. Some will support only one endpoint. Some will support a few endpoints. Some need to support POST and PUT on top of GET endpoints. Some of these endpoints will share functions. I've been using the /server directory in Nuxt 3 and I feel like H3 would be a better choice for what I need instead of going with Express as seen in this example: https://github.com/petkivim/nodejs-rest-api-example

There is no frontend needed in these mini-apps. But what I would like is a good testing framework for the endpoints and utility functions.

I would love if each of my mini-apps had a structure that looked more or less like this:

/api
/api/endpoint1.js
/api/entity/endpoint2.js
/utils
/utils/function1.js
/tests
/tests/testFunction1.js
/tests/endpoint1.js
package.json
Dockerfile

And if I ran docker compose up from this repo, I would be able to access localhost:3000/api/endpoint and localhost:3000/api/entity/endpoint2. I would also love to be able to run yarn test and get my test suite to run all my tests.

I'm just very curious of the most minimal and ideal approach to setting this up. Any sort of guidance on best practice to accomplishing something close to what I want here would be very much appreciated :)

Accept File upload!

How do I use h3 to get files from client/browser for file upload?
I am coming from ExpressJs, where I can install a package called express-fileupload.
Link:
Express Fileupload

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload())
Then 
app.post ('/someApi' , (req, res) =>{
   console.log(req.files)
})

How do I achieve this?

0.5.4 problems with nuxt3

/.output/server/chunks/nitro/server.mjs:69
const hasReqHeader = (req, header, includes) => req.headers[header] && req.headers[header].toLowerCase().includes(includes);
^

TypeError: Cannot read properties of undefined (reading 'accept')
at hasReqHeader (file:///home/garant/admin/.output/server/chunks/nitro/server.mjs:69:60)
at Object.handleError [as onError] (file:///home/garant/admin/.output/server/chunks/nitro/server.mjs:71:25)
at nodeHandler (file:///home/garant/admin/.output/server/node_modules/h3/dist/index.mjs:319:23)

How to stream files

Hi, I am trying to stream files from local disc (for a reason it's not served as static).

I tried to use sendStream or send it directly to pipe but each time I get 404. Documentation is not mentioning too much how to use streams. How to use it correctly with h3?

export default defineEventHandler((event) -> 
     const stream = fs.createReadStream(path);
     stream.pipe(event.res);
)

or

const stream = fs.createReadStream(path);
      sendStream(event, stream);

Cannot read property 'length' of undefined

I'm getting an error when I try to use nuxi and @nuxt/bridge-edge to run a server; the error appears to be on layer.handle.length if layer.handle is undefined

using
"@nuxt/bridge": "@nuxt/[email protected]",
node v14.18.0

 FATAL  Cannot read property 'length' of undefined

at normalizeLayer ([app]/node_modules/h3/dist/index.mjs:625:36)
at use ([app]/node_modules/h3/dist/index.mjs:580:20)
at Function.app.use ([app]/node_modules/h3/dist/index.mjs:567:35)
at createDevServer ([app]/node_modules/@nuxt/nitro/dist/index.mjs:1796:7)
at createNuxt2DevServer ([app]/node_modules/@nuxt/bridge-edge/dist/chunks/module.mjs:269:18)
at setupNitroBridge ([app]/node_modules/@nuxt/bridge-edge/dist/chunks/module.mjs:163:19)
at setup ([app]/node_modules/@nuxt/bridge-edge/dist/chunks/module.mjs:1054:13)
at ModuleContainer.normalizedModule ([app]/node_modules/@nuxt/kit/dist/index.mjs:501:29)
// file ([app]/node_modules/h3/dist/index.mjs:625:36)

function normalizeLayer(layer) {
  if (layer.promisify === void 0) {
    layer.promisify = layer.handle.length > 2;
  }
  return {
    route: withoutTrailingSlash(layer.route),
    match: layer.match,
    handle: layer.lazy ? lazyHandle(layer.handle, layer.promisify) : layer.promisify ? promisifyHandle(layer.handle) : layer.handle
  };
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.