Hey guys thanks in advance! I’m using react-admin@5.3.0
in nextjs@14.2.14
. My src/app/admin/App.tsx
looks like this:
// src/app/admin/App.tsx
const dataProvider = simpleRestProvider("/api");
const App = () => {
return (
<Admin dataProvider={dataProvider}>
{/* ... */}
<Resource
name="units"
list={UnitList}
create={UnitCreate}
edit={UnitEdit}
recordRepresentation={(record) => `${record.section.name} - ${record.name}`}
/>
{/* ... */}
</Admin>
);
};
It will go to src/app/api/(admin)/units/route.ts
// src/app/api/(admin)/units/route.ts
import { auth } from "@/auth";
import { db } from "@/db";
import { units } from "@/db/schema";
import { asc } from "drizzle-orm";
import { NextResponse } from "next/server";
export const GET = async () => {
const session = await auth();
if (!session) {
return new NextResponse("Unauthorized", { status: 401 }); // User not signed in
}
if (!session.user || session.user.role !== "admin") {
return new NextResponse("Forbidden", { status: 403 }); // User signed in but not admin
}
const data = await db.query.units.findMany({
orderBy: [asc(units.order)],
with: { section: true },
});
const totalCount = data.length;
const headers = new Headers();
headers.set("Access-Control-Allow-Origin", "*");
headers.set(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS",
);
headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
headers.set("Access-Control-Expose-Headers", "Content-Range");
headers.set("Content-Range", `units 0-${totalCount}/${totalCount}`);
return NextResponse.json(data, { headers });
};
export const POST = async (req: Request) => {
const session = await auth();
if (!session) {
return new NextResponse("Unauthorized", { status: 401 }); // User not signed in
}
if (!session.user || session.user.role !== "admin") {
return new NextResponse("Forbidden", { status: 403 }); // User signed in but not admin
}
const body = await req.json();
console.log(body);
const data = await db
.insert(units)
.values({
...body,
})
.returning();
return NextResponse.json(data[0]);
};
This is the type of the object being returned from this route:
const data: {
name: string;
order: number;
id: number;
description: string;
sectionId: number;
section: {
name: string;
id: number;
description: string;
courseId: number;
};
}[]
I get the error when I create a record using react-admin create functionality and if I refresh the page the error goes away. What’s weird is if i set the record representation to recordRepresentation="name"
there is no error. Which could mean that the error only appears when i set the recordrepresentation to a nested object.
Am I doing something wrong?
I tried reading the react-admin docs I found nothing.
I also tried adding a hidden field for section.name
the UnitList.tsx
i thought it will reference it but it didnt do anything:
import {
Datagrid,
List,
NumberField,
ReferenceField,
TextField,
} from "react-admin";
export const UnitList = () => (
<List filter={{ order: true }}>
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<TextField source="description" />
<NumberField source="order" />
<ReferenceField source="sectionId" reference="sections" />
<TextField source="section.name" label={false} hidden /> // <- this line
</Datagrid>
</List>
);
I figured it out. The issue was when react-admin creates a resource, it sends a POST
request to api/<resource>
in my case api/(admin)/units
and it will expect you to return the object you just created which I did in my API route:
// ...
export const POST = async (req: Request) => {
// ...
const body = await req.json();
console.log(body);
const data = await db
.insert(units)
.values({
...body,
})
.returning();
return NextResponse.json(data[0]);
};
The problem is the data[0]
has no sections
property which my App.tsx
uses as a recordRepresentation
for my units resource
// src/app/admin/App.tsx
const dataProvider = simpleRestProvider("/api");
const App = () => {
return (
<Admin dataProvider={dataProvider}>
{/* ... */}
<Resource
name="units"
list={UnitList}
create={UnitCreate}
edit={UnitEdit}
recordRepresentation={(record) => `${record.section.name} - ${record.name}`}
/>
{/* ... */}
</Admin>
);
};
To fix this I went and queried the data with the id
returned from the data[0]
object.
// ...
export const POST = async (req: Request) => {
// ...
const body = await req.json();
console.log(body);
const data = await db
.insert(units)
.values({
...body,
})
.returning();
const dataWithSection = await db.query.units.findFirst({
where: eq(units.id, data[0].id),
with: { section: true },
});
return NextResponse.json(dataWithSection);
};
Note that i'm doing another db call so its inefficient but it works. Maybe someone knows how to optimize this with drizzle or postgres please teach me thanks.