Routes
At their core, routes describe how a request for a given path should be handled, and what the response should be. To do this, routes have two main parts: the handler, and the component. A route can have either one, or both, but never neither.
The handler is a function that is called for every request to the route. It
needs to return a response that is then sent to the client. The response could
be anything: a plain text string, a JSON object, an HTML page, a WebSocket
connection, a streaming file, or pretty much anything else. The handler is
passed a render
function that it can call to invoke rendering a component.
The component is the template for a page. It is a JSX element that is rendered
on the server. The page component gets passed props that can be used by it to
determine exactly what should be rendered. By default components receives props
consisting of: the request URL, the matches from the URL pattern match, and any
data passed to the handler's render
function.
Handler route
Let's look at a basic route that returns a plain text string:
// routes/plain.tsx
import { HandlerContext, Handlers } from "$fresh/server.ts";
export const handler: Handlers = {
GET(_req: Request, _ctx: HandlerContext) {
return new Response("Hello World");
},
};
To define a handler, one needs to export a handler
function or object from the
route module. If the handler is an object, each key in the object is the name of
the HTTP method that the handler should be called for. For example the GET
handler above is called for GET
requests. If the handler is a function, it is
called for all requests regardless of the method. If an HTTP method does not
have a corresponding handler, a 405 HTTP error is returned.
Component route
Now, let's render some HTML using the route component:
// routes/html.tsx
import { PageProps } from "$fresh/server.ts";
export default function Page(props: PageProps) {
return <div>You are on the page '{props.url.href}'.</div>;
}
The page component needs to be the default export of the route module. It is passed props that can be used to render the page.
As you can see in the second example, if no handler is explicitly defined a default handler is used that just renders out the page component if present. You can also override the default handler though to modify how exactly rendering should work.
Mixed handler and component route
In the below example, a custom handler is used to add a custom header to the response after rendering the page component.
// routes/html.tsx
import { HandlerContext, Handlers, PageProps } from "$fresh/server.ts";
export const handler: Handlers = {
async GET(_req: Request, ctx: HandlerContext) {
const resp = await ctx.render();
resp.headers.set("X-Custom-Header", "Hello World");
return resp;
},
};
export default function Page(props: PageProps) {
return <div>You are on the page '{props.url.href}'.</div>;
}