Client Can't Infer Error When Using OnError
Resolving Client-Side Type Inference Issues with onError in Hono
When working with APIs, it's essential to ensure that client-side type inference works correctly, especially when handling errors. In this article, we'll explore the issue of type inference not working as expected when using the onError
middleware in Hono, and provide a solution to resolve this problem.
Understanding the Issue
In the example code, we have a Hono application with multiple routes, each returning a JSON response when successful or throwing an error. We're using the onError
middleware to catch and handle errors in the application. However, when we try to infer the type of the response on the client-side, it doesn't work as expected when an error is thrown.
import { Hono } from "hono"
const app = new Hono().get("/", (c) => {
if(!c.env){
throw new Error("Something wrong happened")
}
const result = {message: "foo"}
return c.text(result, 201)
})
export default app
import { onError } from "stoker/middlewares"
import { Hono } from "hono"
const app = new Hono()
.route("/orders", orders)
.onError(onError)
The Problem with onError
The issue arises because the onError
middleware doesn't return a JSON response with an error code (e.g., 400 or 500). Instead, it catches and handles the error internally. This means that when we try to infer the type of the response on the client-side, it doesn't work as expected when an error is thrown.
export async function createOrder() {
try {
const client = hcWithType(import.meta.env.VITE_BASE_API_URL)
const response = await client.orders.$post( )
if (!response.ok) {
// This returns the type I get when successful, I want the type when an error is thrown
const data = await response.json()
throw new Error(data)
}
return await response.json()
} catch (error) {
console.error("Order creation error:", error)
throw error
}
}
Resolving the Issue
To resolve this issue, we need to modify the onError
middleware to return a JSON response with an error code when an error is thrown. We can achieve this by using the c.error
method provided by Hono.
import { onError } from "stoker/middlewares"
import { Hono } from "hono"
const app = new Hono()
.route("/orders", orders)
.onError((c, err) => {
return c.error(500, { message: "Internal Server Error" })
})
In this modified version, when an error is thrown, the onError
middleware catches it and returns a JSON response with a 500 error code and a message.
Client-Side Type Inference
With this modification, the client-side type inference should now work correctly when an error is thrown. We can modify the createOrder
function to handle the error response correctly.
export async function createOrder() {
try {
const client = hcWithType(import.meta.env.VITE_BASE_API_URL)
const response = await client.orders.$post( )
if (!response.ok) {
// This returns the type I get when an error is thrown
const data = await response.json()
throw new Error(data)
}
return await response.json()
} catch (error) {
console.error("Order creation error:", error)
if (error instanceof Error && error.message.startsWith("Internal Server Error")) {
// Handle the error response correctly
console.error("Error message:", error.message)
} else {
throw error
}
}
}
In this modified version, when an error is thrown, we can handle the error response correctly by checking if the error message starts with "Internal Server Error". If it does, we can handle the error response accordingly.
Conclusion
In this article, we've explored the issue of type inference not working as expected when using the onError
middleware in Hono. We've modified the onError
middleware to return a JSON response with an error code when an error is thrown, and modified the client-side code to handle the error response correctly. With this modification, the client-side type inference should now work correctly when an error is thrown.
Frequently Asked Questions: Resolving Client-Side Type Inference Issues with onError in Hono
In our previous article, we explored the issue of type inference not working as expected when using the onError
middleware in Hono. We also provided a solution to resolve this problem by modifying the onError
middleware to return a JSON response with an error code when an error is thrown. In this article, we'll answer some frequently asked questions related to this topic.
Q: Why is type inference not working as expected when using onError?
A: Type inference is not working as expected when using onError
because the middleware doesn't return a JSON response with an error code. Instead, it catches and handles the error internally. This means that when we try to infer the type of the response on the client-side, it doesn't work as expected when an error is thrown.
Q: How can I modify the onError middleware to return a JSON response with an error code?
A: You can modify the onError
middleware to return a JSON response with an error code by using the c.error
method provided by Hono. For example:
import { onError } from "stoker/middlewares"
import { Hono } from "hono"
const app = new Hono()
.route("/orders", orders)
.onError((c, err) => {
return c.error(500, { message: "Internal Server Error" })
})
Q: What is the difference between c.error and c.json?
A: c.error
and c.json
are both methods provided by Hono for returning a response. However, c.error
is used to return an error response with a specific status code, while c.json
is used to return a JSON response with a default status code of 200.
Q: How can I handle the error response correctly on the client-side?
A: You can handle the error response correctly on the client-side by checking if the error message starts with "Internal Server Error". If it does, you can handle the error response accordingly. For example:
export async function createOrder() {
try {
const client = hcWithType(import.meta.env.VITE_BASE_API_URL)
const response = await client.orders.$post( )
if (!response.ok) {
// This returns the type I get when an error is thrown
const data = await response.json()
throw new Error(data)
}
return await response.json()
} catch (error) {
console.error("Order creation error:", error)
if (error instanceof Error && error.message.startsWith("Internal Server Error")) {
// Handle the error response correctly
console.error("Error message:", error.message)
} else {
throw error
}
}
}
Q: Can I use c.error with a custom status code?
A: Yes, you can use c.error
with a custom status code. For example:
import { onError } from "stoker/middlewares"
import { Hono } from "hono"
const app = new Hono()
.route("/orders", orders)
.onError((c, err) => {
return c.error(422, { message: "Validation failed" })
})
In this example, we're using c.error
with a custom status code of 422, which is typically used for validation errors.
Q: How can I log the error message on the client-side?
A: You can log the error message on the client-side by using the console.error
method. For example:
export async function createOrder() {
try {
const client = hcWithType(import.meta.env.VITE_BASE_API_URL)
const response = await client.orders.$post( )
if (!response.ok) {
// This returns the type I get when an error is thrown
const data = await response.json()
throw new Error(data)
}
return await response.json()
} catch (error) {
console.error("Order creation error:", error)
if (error instanceof Error && error.message.startsWith("Internal Server Error")) {
// Log the error message
console.error("Error message:", error.message)
} else {
throw error
}
}
}
In this example, we're logging the error message using console.error
.
Conclusion
In this article, we've answered some frequently asked questions related to resolving client-side type inference issues with onError
in Hono. We've provided examples and code snippets to help you understand how to modify the onError
middleware to return a JSON response with an error code, handle the error response correctly on the client-side, and log the error message.