Params and Search Params
Another use case for Tempeh is to have typesafe parameters for your routes. This is useful when you want to pass parameters to your routes and you want to make sure that the parameters are of the correct type.
Tempeh extends the Route configuration to provide type to the native
useSearchParams
and useParams
hooks provided by next/router.
Let's see this in action
Example
Suppose you have a workspaces page in Next.js and it may take multiple parameters like projectId
. You can define the types for these parameters in the route configuration.
Similarly it may also take a query parameter like sortBy
, limit
, query
etc to sort workspace activities or filter them.
---
SearchParams:
projectId: number
sortBy: string
limit: number
query: string
Params:
projectId: string
---
File Structure
├── root
| |
| ├── app
| | ├── layout.tsx
| | ├── page.tsx
| | |
| | ├── workspaces
| | | ├── [projectId]
| | | | ├── page.tsx
| | | | ├── route.info.ts
| |
| |
| ├── package.json
| ├── next.config.mjs
As you can see we are just extending the route configuration to each page level here so that we have a single source of truth for all the parameters and query parameters attributed to a single route. this way managing the routes and parameters becomes easy.
workspaces/route.info.ts
import * as z from "zod";
import { routeBuilder } from "tempeh";
// Ideally this must be in the route.config.ts, but for the sake of example, we have shown it here
const { createRoute } = routeBuilder({
additionalBaseUrls: {
APP: "https://app.example.com",
API: "https://api.example.com",
},
defaultBaseUrl: "/",
}).getInstance();
// we will create our route config here
const paramSchema = z.object({
projectId: z.string(),
});
const searchParamSchema = z.object({
sortBy: z.enum(["asc", "desc"]).optional().default("asc"),
limit: z.string().pipe(z.coerce.number()).optional(),
query: z.string().optional(),
});
const WorkspaceRoute = createRoute({
name: "WorkspaceRoute",
fn: ({ projectId }) => `/workspaces/${projectId}`,
paramsSchema: paramSchema,
searchParamsSchema: searchParamSchema,
});
export default WorkspaceRoute;
Usage
Now you can use the WorkspaceRoute
in your components to link to the workspace page. From any page in the application you can link to the workspace page by passing the projectId
and other search params. This way you will never have to worry about the type of the parameters and query parameters.
Suppose inside a filter component you want to access to the workspace link with the query parameters sortBy
, limit
and query
.
Note: It only works in the client components as it uses the next/router hooks internally.
"use client";
import WorkspaceRoute from "../../route.info";
export const Filter = () => {
const { projectId } = WorkspaceRoute.useParams();
const { sortBy, limit, query } = WorkspaceRoute.useSearchParams();
return (
<div>
{/** using the values of search params here*/}
<Activities sort={sortBy} limit={limit} query={query} />
</div>
);
};
export default Filter;
Note: useParams
and useSearchParams
throw if the params and searchParams extracted by the hooks do not pass the validation check imposed by the schema.
Safe Usage
Sometimes we do care about errors thrown by the useParams
and useSearchParams
. In such situations, useParams
and useSearchParams
take a boolean flag as option - safe
. When turned on, the hooks return an object with two properties - value
and error
. The value
property contains the extracted params and searchParams, and the error
property contains the error thrown by the schema validation. Both of these values will be seperated out by the tag success
making it easy to pass in pattern matching or conditional logic.
success -> true :: value will be returned
success -> false :: error will be returned
Things to note:
- The fact that we are using zod here, we can always define in our schema to transform the values to the desired type. In the above example we are coercing the
limit
to a number. - This is only available in the client side components as it uses the next/router hooks internally.
- The tempeh also provides a
params
andsearchParams
property from the builtrouteConfig
but there are caviats to it:- It is solely made to infer type so you can't access the values directly from it.
This is how you can use the params and search params to infer types in your Next.js server components with Tempeh.
parseParams & parseSearchParams
Apart from hooks, createRoute also exposes two functions parseParams
and parseSearchParams
which can be used to parse the params and searchParams from the URL. These functions are useful when you want to parse the params and searchParams in a function or a utility file.
A great use case of this is to parse params returned by Next.js Page
import WorkspaceRoute from "../../route.info";
const WorkspacePage = ({ params }: { params: unknown }) => {
// Will throw error
const { workspaceId } = WorkspaceRoute.parseParams(params);
// Will not throw error
const safeParams = WorkspaceRoute.parseParams(params, { safe: true });
// use returned value pass in the props or render conditionally
return (
<div>
{/** using the values of search params here*/}
<Activities projectId = {projectId} />
</div>
);
};