@edgefirst-dev/crud-routes - v1.0.0

React Router CRUD Helper

A helper to define CRUD routes in a React Router application using routes.ts.

Inspired by Rails resource routing.

bun add @edgefirst-dev/crud-routes

Import the crud helper in your app/routes.ts file.

import { crud } from "@edgefirst-dev/crud-routes";

Then you can use to to define routes in the exported array.

export default [...crud("users")] satisfies RouteConfig;

This will generate the following routes:

Path File ID Used to
- ./views/users/_layout.tsx users.layout Layout of every users route
/users ./views/users/index.tsx users.index Display a list of all users
/users/new ./views/users/new.tsx users.new Form to create a new user
/users/:userId ./views/users/show.tsx users.show Display the details of a user
/users/:userId/edit ./views/users/edit.tsx users.edit Form to edit a user
/users/:userId/destroy ./views/users/destroy.tsx users.destroy Action to delete a user

You can also define a custom ID prefix for the generated routes.

export default [...crud("users", { idPrefix: "admin" })] satisfies RouteConfig;

This will generate the following routes:

Path File ID Used to
- ./views/users/_layout.tsx admin.layout Layout of every users route
/users ./views/users/index.tsx admin.index Display a list of all users
/users/new ./views/users/new.tsx admin.new Form to create a new user
/users/:userId ./views/users/show.tsx admin.show Display the details of a user
/users/:userId/edit ./views/users/edit.tsx admin.edit Form to edit a user
/users/:userId/destroy ./views/users/destroy.tsx admin.destroy Action to delete a user

You can also define nested routes using the React Router built-in helpers.

import { crud } from "@edgefirst-dev/crud-routes";
import { route } from "@react-router/dev/routes";

export default [
...crud("users", () => [
// /users/profile
route("profile", "./views/users/profile.tsx", { id: "users.profile" }),
]),
] satisfies RouteConfig;

This will generate the following routes:

Path File ID Used to
- ./views/users/_layout.tsx users.layout Layout of every users route
/users ./views/users/index.tsx users.index Display a list of all users
/users/new ./views/users/new.tsx users.new Form to create a new user
/users/:userId ./views/users/show.tsx users.show Display the details of a user
/users/:userId/edit ./views/users/edit.tsx users.edit Form to edit a user
/users/:userId/destroy ./views/users/destroy.tsx users.destroy Action to delete a user
/users/profile ./views/users/profile.tsx users.profile Display the profile of a user

The nested route will be added to the layout of the CRUD.

A member route is a route attached to a specific resource. For example, in the resource users a member can be nested inside /users/:userId.

import { crud, route } from "@edgefirst-dev/crud-routes";

export default [
...crud("users", () => [
route("profile", "./views/users/profile.tsx", {
id: "users.profile",
on: "member",
}),
]),
] satisfies RouteConfig;

Here we're using the route helper exported by this package to define a new route. The on option is used to define the type of route. In this case, it's a member route.

A member route could also be another CRUD

import { crud } from "@edgefirst-dev/crud-routes";

export default [
...crud("users", () => [
...crud("posts", { on: "member" }), // /users/:userId/posts and other CRUD routes
]),
] satisfies RouteConfig;

A collection route is a route attached to a specific resource. For example, in the resource users a collection can be nested inside /users.

import { crud, route } from "@edgefirst-dev/crud-routes";

export default [
...crud("users", () => [
route("profile", "./views/users/profile.tsx", {
id: "users.profile",
on: "member",
}),
]),
] satisfies RouteConfig;

Here we're using the route helper exported by this package to define a new route. The on option is used to define the type of route. In this case, it's a collection route.

A collection route could also be another CRUD

import { crud } from "@edgefirst-dev/crud-routes";

export default [
...crud("users", () => [
...crud("posts", { on: "collection" }), // /users/posts and other CRUD routes
]),
] satisfies RouteConfig;

Shallow routes allows you to nest a resource inside another resource, but limiting it to only the index and new routes. While the show, edit, and destroy routes are not nested, and with the same layout for both nested and non-nested routes.

import { crud } from "@edgefirst-dev/crud-routes";

export default [
...crud("users", () => [...crud("posts", { on: "shallow" })]),
] satisfies RouteConfig;

This will generate the following routes:

Path File ID Used to
- ./views/users/_layout.tsx users.layout Layout of every users route
/users ./views/users/index.tsx users.index Display a list of all users
/users/new ./views/users/new.tsx users.new Form to create a new user
/users/:userId ./views/users/show.tsx users.show Display the details of a user
/users/:userId/edit ./views/users/edit.tsx users.edit Form to edit a user
/users/:userId/destroy ./views/users/destroy.tsx users.destroy Action to delete a user
/users/:userId/posts ./views/posts/index.tsx users.posts Display a list of all posts
/users/:userId/posts/new ./views/posts/new.tsx users.posts.new Form to create a new post
/posts/:postId ./views/posts/show.tsx posts.show Display the details of a post
/posts/:postId/edit ./views/posts/edit.tsx posts.edit Form to edit a post
/posts/:postId/destroy ./views/posts/destroy.tsx posts.destroy Action to delete a post

Note that shallow routes will not include a layout for the nested resource. This is because the layout is shared with the parent resource.