| icon | fluent:target-24-regular |
|---|
Event handler define application logic.
After creating an app instance, you can start defining your application logic using event handlers.
An event handler is a function that receive an Event instance and returns a response. You can compare it to controllers in other frameworks.
You can define event handlers using defineEventHandler or [eventHandler utilities:
Note
You can use defineEventHandler and eventHandler interchangeably. They are aliases. You can use the one you prefer but stick to it for consistency.
import { defineEventHandler } from "h3";
defineEventHandler((event) => {
return "Response";
});The callback function can be sync or async:
defineEventHandler(async (event) => {
return "Response";
});You can use an object syntax in defineEventHandler for more flexible options.
defineEventHandler({
onRequest: [],
onBeforeResponse: []
handler: (event) => {
return "Response";
},
})Values returned from event handlers are automatically converted to responses. It can be:
- JSON serializable value. If returning a JSON object or serializable value, it will be stringified and sent with default
application/jsoncontent-type. string: Sent as-is using defaultapplication/htmlcontent-type.null: h3 with end response with204 - No Contentstatus code.- Web
ReadableStreamor nodeReadable - Web
ArrayBufferor nodeBuffer - Web Fetch Response
Errorinstance. It's supported but recommended to throw errors instead of returning them usingcreateErrorutility.
Any of above values could also be wrapped in a Promise. This means that you can return a Promise from your event handler and h3 will wait for it to resolve before sending the response.
Example: Send HTML response:
app.use(defineEventHandler(async (event) => "<h1>Hello world!</h1>"));Example: Send JSON response:
app.use(
"/api",
defineEventHandler(async (event) => ({ url: event.node.req.url })),
);Example: Send a promise:
app.use(defineEventHandlers(async (event) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ url: event.node.req.url });
}, 1000);
});
}));You can easily control the error returned by using the createError utility.
import { createError, defineEventHandler } from "h3";
app.use(
"/hello",
defineEventHandler((event) => {
throw createError({
status: 400,
message: "An error occured",
});
}),
);This will end the request with 400 - Bad Request status code and the following JSON response:
{
"status": 400,
"message": "An error occured"
}If during calling an event handler an error with new Error() will be thrown (without create Error), h3 will automatically catch as a 500 - Internal Server Error status response considering it an unhandled error.
app.use(
"/hello",
defineEventHandler((event) => {
// Do NOT do this and use createError()!
throw new Error("Something went wrong");
}),
);You can define lazy event handlers using defineLazyEventHandler or lazyEventHandler utilities. This allow you to define some one-time logic that will be executed only once when the first request matching the route is received.
A lazy event handler must return an event handler:
import { defineLazyEventHandler } from "h3";
app.use(defineLazyEventHandler(() => {
console.log("This will be executed only once");
// This will be executed only once
return defineEventHandler((event) => {
// This will be executed on every request
return "Response";
});
}));This is useful to define some one-time logic such as configuration, class initialization, heavy computation, etc.
Event handlers that don't return any value act as middleware. They can be used to add side effects to your application such as logging, caching, etc or to modify the request or response.
Tip
Middleware pattern is not recommanded for h3 in general. Side effects can affect global application performance and make tracing logic harder. Instead use h3 composables and object syntax hooks.
Similar to normal event handlers, you can define middleware using defineEventHandler or eventHandler utilities:
defineEventHandler((event) => {
console.log(`Middleware. Path: ${event.path}`);
});Important
Middleware must not return any value or directly return a response for event.
If you return a response, it will act as a normal event handler!
Then, you can register middleware to app instance using the use method:
app.use(defineEventHandler((event) => {
console.log("Middleware 1");
}));
app.use(defineEventHandler((event) => {
console.log("Middleware 2");
}));
app.use(defineEventHandler((event) => {
return "Response";
}));You can define as much middleware as you need. They will be called in order of registration.
There are situations that you might want to convert an event handler or utility made for Node.js or another framework to h3. There are built-in utils to do this.!
If you have a legacy request handler with (req, res) => {} syntax made for Node.js, you can use fromNodeListener to convert it to an h3 event handler.
import { createApp, fromNodeMiddleware } from "h3";
import exampleMiddleware from "example-node-middleware";
export const app = createApp();
app.use(fromNodeListener(exampleMiddleware()));Tip
For example, this will help you to use Vite Middleware mode with h3 apps.
You can convert a fetch-like function (with Request => Response signuture) into an h3 event handler using fromWebHandler util.
import { webHandler } from "web-handler"; // This package doesn't exist, it's just an example
import { createApp, fromWebHandler } from "h3";
export const app = createApp();
app.use(fromWebHandler(webHandler));