Routes
Routes are the entry point for all requests to your application. They map a specific URL pattern to a specific file or route handler function.
In Hyperspan, routes can live in two main places:
app/routes
directory (file-based routes)app/server.ts
file (custom route handlers)
File-Based Routing
To make things easier, Hyperspan uses file-based routing. This means that you can create a
file in the app/routes
directory and it will be automatically picked up by the
framework and added to your routing table.
Here are some examples of how files in the app/routes
directory map to URL
patterns:
File Path | URL Pattern |
---|---|
app/routes/index.ts |
/ |
app/routes/about.ts |
/about |
app/routes/posts/index.ts |
/posts |
app/routes/posts/[id].ts |
/posts/:id |
app/routes/auth/[...authPath].ts |
/auth/* |
Route and query params can be accessed from the Hono Request object by name.
// File: app/routes/posts/[id].ts
import { createRoute } from '@hyperspan/framework';
import { fetchPostById } from '@/src/entities/posts'; // whatever your data layer is
export default createRoute(async (c) => {
const id = c.req.param('id');
const post = await fetchPostById(id);
return html`<main>
<h1>${post.title}</h1>
<div>${post.content}</div>
</main>`;
});
The createRoute
Function
File-based routes are created by default exporting the results of calling the
createRoute
function.
The most basic route is a function that returns a string of HTML.
import { createRoute } from '@hyperspan/framework';
export default createRoute(() => html`<div>Hello, world!</div>`);
Using Plain Functions
You can define a route with a plain function, but you won't have the proper types included by default, or other helpful APIs like limiting the route to a specific HTTP method, adding route-specific middleware, etc.
import { Context } from 'hono';
export default function (c: Context) {
return html`<div>Hello, ${c.req.param('name')}!</div>`;
}
createRoute
.
Route Parameters
The createRoute
function has a
Hono Context parameter that can be used to
access information from the request, like
parameters from the route path, query string parameters, headers, cookies, etc.
import { createRoute } from '@hyperspan/framework';
export default createRoute((c) => {
return html`<div>Hello, ${c.req.param('name')}!</div>`;
});
Custom Route Paths
If you need to use a custom path for a file-based route, you can import any file-based route and make it accessible with any custom path or URL pattern you need.
Just import createRouteFromModule
from @hyperspan/framework
and
pass in the imported module.
import { createServer, createRouteFromModule } from '@hyperspan/framework';
import PostPageRoute from '@/app/routes/posts/[id].ts';
const app = await createServer({
appDir: './app',
staticFileRoot: './public',
});
// Post page route is now accessible at /articles/:id in addition to /posts/:id
app.get('/articles/:id', createRouteFromModule(PostPageRoute));
export default app;
This is similar to how rewrites work in Next.js, only this is more direct and flexible instead of limited toa config file.
Custom Route Handlers
If you need more control over routing or need to do something that doesn't fit within
file-based routing, you can create a custom route handler function in
app/server.ts
. The createServer
function will return a
Hono instance that you can use to add custom
Hono Routes or
Hono Middleware.
import { createServer } from '@hyperspan/framework';
const app = await createServer({
appDir: './app',
staticFileRoot: './public',
});
// Custom Hono Route
app.get('/my-custom-route', (c) => c.html('<div>Hello, world!</div>'));
export default app;
If you need to add routes before the file-based routes are processed, you can do so
by using the beforeRoutesAdded
hook in createServer
.
import { createServer } from '@hyperspan/framework';
const app = await createServer({
appDir: './app',
staticFileRoot: './public',
beforeRoutesAdded: (app) => {
app.get('/custom-route-before-file-routes', (c) => c.html('<div>Hello, world!</div>'));
},
});
export default app;
Custom Middleware
You can also add custom middleware to the Hono server in app/server.ts
. This is
useful for things like authentication, logging, etc.
import { createServer } from '@hyperspan/framework';
import { trimTrailingSlash } from 'hono/trailing-slash';
const app = await createServer({
appDir: './app',
staticFileRoot: './public',
});
// Custom Hono Middleware
app.use(trimTrailingSlash());
export default app;
If you are unfamiliar with middleware, you can read more about it in the Hono Middleware documentation.