Resource Routes are not part of your application UI, but are still part of your application. They can send any kind of Response.
Most routes in Remix are UI Routes, or routes that actually render a component. But routes don't always have to render components. There are a handful of cases where you want to use route as a general purpose endpoint to your website. Here are a few examples:
If a route doesn't export a default component, it can be used as a Resource Route. If called with GET
, the loader's response is returned and none of the parent route loaders are called either (because those are needed for the UI, but this is not the UI). If called with POST
, the action's response is called.
For example, consider a UI Route that renders a report, note the link:
export function loader({ params }) {
return getReport(params.id);
}
export default function Report() {
let report = useLoaderData();
return (
<div>
<h1>{report.name}</h1>
<Link to="pdf" reloadDocument>
View as PDF
</Link>
{/* ... */}
</div>
);
}
It's linking to a PDF version of the page. To make this work we can create a Resource Route below it. Notice that it has no component: that makes it a Resource Route.
export function loader({ params }) {
let report = await getReport(params.id);
let pdf = await generateReportPDF(report);
return new Response(pdf, {
status: 200,
headers: {
"Content-Type": "application/pdf"
}
});
}
When the user clicks the link from the UI route, they will navigate to the PDF.
reloadDocument
on any Links to Resource Routes
There's a subtle detail to be aware of when linking to resource routes. You need to link to it with <Link reloadDocument>
or a plain <a href>
. If you link to it with a normal <Link to="pdf">
without reloadDocument
, then the resource route will be treated as a UI route. Remix will try to get the data with fetch
and render the component. Don't sweat it too much, you'll get a helpful error message if you make this mistake.
You'll probably want to add a file extension to your resource routes. This is tricky because one of Remix's route file naming conventions is that .
becomes /
so you can nest the URL without nesting the UI.
To add a .
to a route's path, use the []
escape characters. Our PDF route file name would change like so:
# original
# /reports/123/pdf
app/routes/reports/$id/pdf.ts
# with a file extension
# /reports/123.pdf
app/routes/reports/$id/[.pdf].ts
# or like this, the resulting URL is the same
app/routes/reports/$id.[.pdf].ts