| icon | icons8:up-round |
|---|
h3 v2 includes some behavior and API changes that you need to consider applying when migrating.
Note
Currently v2 is in beta stage You can try with h3-nightly@2x
Note
This is an undergoing migration guide and is not finished yet.
H3 v2 is rewritten based on Web standard primitives (URL, Headers, Request, and Response).
event.node context is only available when running in Node.js runtime and event.web is available via event.request.
On Node.js runtime, h3 uses a two way proxy to sync Node.js API with Web standard API making it a seamless experience on Node.
Old utils for plain handler and web handler are removed to embrace web standards.
You should always explicitly return the response body.
If you were previously using methods below, you can replace them with return statements returning a text, JSON, stream, or web Response (h3 smartly detects and handles each):
send(event, value): Migrate toreturn <value>.sendError(event, <error>): Migrate tothrow createError(<error>).sendStream(event, <stream>): Migrate toreturn <stream>.sendWebResponse(event, <response>): Migrate toreturn <response>.
Other send utils that are renamed and need explicit return:
sendNoContent(event)/return null: Migrate toreturn noContent(event).sendIterable(event, <value>): Migrate toreturn iterable(event, <value>).sendRedirect(event, location, code): Migrate toreturn redirect(event, location, code).sendProxy(event, target): Migrate toreturn proxy(event, target).handleCors(event): Check return value (boolean) and earlyreturnif handled.serveStatic(event, content): Make sure to addreturnbefore.
Router functionality is now integrated into the h3 app core. Instead of createApp() and createRouter() you can use createH3().
New methods:
app.use(handler): Adds a global middleware.app.use(route, handler): Adds a routed middleware.app.on(method, handler)/app.all(handler)/app.[METHOD](handler): Adds a route handler.
Handlers will run in this order:
- All global middleware in the same order were registered
- All routed middleware from least specific to most specific paths (auto-sorted)
- Matched route handler
Any handler can return a response. If middleware don't return a response, next handlers will be tried and finally make a 404 if neither responses. Router handlers can return or not return any response, in this case, h3 will send a simple 200 with empty content.
h3 migrated to a brand new route-matching engine unjs/rou3. You might experience slight (but more intuitive) behavior changes for matching patterns.
Other changes from v1:
- Handlers registered with
app.use("/path", handler)only match/path(not/path/foo/bar). For matching all subpaths like before, it should be updated toapp.use("/path/**", handler). - The
event.pathreceived in each handler will have a full path without omitting the prefixes. usewithBase(base, handler)utility to make prefixed app. (example:withBase("/api", app.handler)). app.use(() => handler, { lazy: true })is no supported anymore. Instead you can useapp.use(defineLazyEventHandler(() => handler), { lazy: true }).app.use(["/path1", "/path2"], ...)andapp.use("/path", [handler1, handler2])are not supported anymore. Instead, use multipleapp.use()calls.- Custom
matchfunction forapp.useis not supported anymore (middleware can skip themselves). app.resolve(path) => { route, handler }changed toapp.resolve(method, path) => { method, route, handler }.router.use(path, handler)is deprecated. Userouter.all(path, handler)instead.router.add(path, method: Method | Method[]signature is changed torouter.add(method: Method, path)(important)
Most of request body utilities can now be replaced with event.request utils which is based on standard Request interface.
readBody(event) utility will use JSON.parse or URLSearchParams for parsing requests with application/x-www-form-urlencoded content-type.
- For text: Use event.request.text().
- For json: Use event.request.json().
- For formData: Use event.request.formData().
- For stream: Use event.request.body.
Behavior changes:
- Body utils won't throw an error if the incoming request has no body (or is a
GETmethod for example) but instead, return empty values. - Native
request.jsonandreadBodydoes not use unjs/destr anymore. You should always filter and sanitize data coming from user to avoid prototype-poisoning.
h3 migrated to leverage standard web Headers for all utils.
Header values are always a plain string now (no null or undefined or number or string[]).
For the Set-Cookie header, you can use headers.getSetCookie that always returns a string array.
h3 v2 deprecated some legacy and aliased utilities.
App and router:
createApp/createRouter: Migrate tocreateH3().
Handler:
eventHandler: Migrate todefineEventHandler(or remove it!).lazyEventHandler: Migrate todefineLazyEventHandler.toEventHandler/isEventHandler: (removed) Any function can be an event handler.useBase: Migrate towithbase.
Request:
getHeader/getRequestHeader: Migrate toevent.request.headers.get(name).getHeaders/getRequestHeaders: Migrate toObject.fromEntries(event.request.headers.entries()).getRequestPath: Migrate toevent.pathorevent.url.getMethod: Migrate toevent.method.
Response:
getResponseHeader/getResponseHeaders: Migrate toevent.response.headers.get(name)setHeader/setResponseHeader/setHeaders/setResponseHeaders: Migrate toevent.response.headers.set(name, value).appendHeader/appendResponseHeader/appendResponseHeaders: Migrate toevent.response.headers.append(name, value).removeResponseHeader/clearResponseHeaders: Migrate toevent.response.headers.delete(name)appendHeaders: Migrate toappendResponseHeaders.defaultContentType: Migrate toevent.response.headers.set("content-type", type)getResponseStatus/getResponseStatusText/setResponseStatus: Useevent.response.statusandevent.response.statusText.
Node.js:
defineNodeListener: Migrate todefineNodeHandler.fromNodeMiddleware: Migrate tofromNodeHandler.toNodeListener: Migrate totoNodeHandler.createEvent: (removed): Use Node.js adapter (toNodeHandler(app)).fromNodeRequest: (removed): Use Node.js adapter (toNodeHandler(app)).promisifyNodeListener(removed).callNodeListener: (removed).
Web:
fromPlainHandler: (removed) Migrate to Web API.toPlainHandler: (removed) Migrate to Web API.fromPlainRequest(removed) Migrate to Web API or usemockEventutil for testing.callWithPlainRequest(removed) Migrate to Web API.fromWebRequest: (removed) Migrate to Web API.callWithWebRequest: (removed).
Body:
readRawBody: Migrate toevent.request.text()orevent.request.arrayBuffer().getBodyStream/getRequestWebStream: Migrate toevent.request.body.readFormData/readMultipartFormData/readFormDataBody: Migrate toevent.request.formData().
Utils:
isStream: Migrate toinstanceof ReadableStream.isWebResponse: Migrate toinstanceof Response.splitCookiesString: UsesplitSetCookieStringfrom cookie-es.MIMES: (removed).
Types:
App: Migrate toH3.AppOptions: Migrate toH3Config._RequestMiddleware: Migrate toRequestMiddleware._ResponseMiddleware: Migrate toResponseMiddleware.NodeListener: Migrate toNodeHandler.TypedHeaders: Migrate toRequestHeadersandResponseHeaders.HTTPHeaderName: Migrate toRequestHeaderNameandResponseHeaderName.H3Headers: Migrate to nativeHeaders.H3Response: Migrate to nativeResponse.MultiPartData: Migrate to nativeFormData.RouteNode: Migrate toRouterEntry.CreateRouterOptions: Migrate toRouterOptions.
Removed type exports: WebEventContext, NodeEventContext, NodePromisifiedHandler, AppUse, Stack, InputLayer, InputStack, Layer, Matcher, PlainHandler, PlainRequest, PlainResponse, WebHandler.