prisma nested writes / updates not working

My prisma schema currently looks like this:
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model Exams {
id Int @default(autoincrement()) @id
name String
file String
subject String?
year Int
}

model Subjects {
id Int @default(autoincrement()) @id
name String
topics Topic[]
}

model Topic {
id Int @default(autoincrement()) @id
name String
subjectId Int
subject Subjects @relation(fields: [subjectId], references: [id])
@@index([subjectId])
}
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model Exams {
id Int @default(autoincrement()) @id
name String
file String
subject String?
year Int
}

model Subjects {
id Int @default(autoincrement()) @id
name String
topics Topic[]
}

model Topic {
id Int @default(autoincrement()) @id
name String
subjectId Int
subject Subjects @relation(fields: [subjectId], references: [id])
@@index([subjectId])
}
I want to make an API call which creates a topic specific to a subject. For example, if I specify that the subject is biology, it should make a new topic nested under biology. This is my current code which attempts that:
import { db } from "../../lib/db"
import type { NextApiRequest, NextApiResponse } from 'next';
import { SubjectsWhereUniqueInput } from './types';

export async function POST(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { name, subject } = req.body;
const subjectRecord = await db.subjects.findUnique({
where: { name: subject } as SubjectsWhereUniqueInput,
});

if (!subjectRecord) {
return res.status(404).json({ message: 'Subject not found' });
}

const topic = await db.topic.create({
data: {
name,
subject: { connect: { id: subjectRecord.id } },
},
});
res.status(201).json(topic);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
}
import { db } from "../../lib/db"
import type { NextApiRequest, NextApiResponse } from 'next';
import { SubjectsWhereUniqueInput } from './types';

export async function POST(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { name, subject } = req.body;
const subjectRecord = await db.subjects.findUnique({
where: { name: subject } as SubjectsWhereUniqueInput,
});

if (!subjectRecord) {
return res.status(404).json({ message: 'Subject not found' });
}

const topic = await db.topic.create({
data: {
name,
subject: { connect: { id: subjectRecord.id } },
},
});
res.status(201).json(topic);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
}
However when I try calling this API I get a 405 error, in addition to that I'm pretty sure the way I'm trying to do this is wrong as well. How would I be able to do this? Thanks
4 Replies
wlvz
wlvzOP2y ago
The idea is that on the website there should be a create topic button which I can click and create a topic for a specific subject
bruno!
bruno!2y ago
the subject name is not unique, so you can't use it with the "findUnique" in order to fix that you should either change the function to "findFirst" if you're okay on having duplicated names, or add @unique on the name field on the prisma schema you would see that the way you're running findUnique would be wrong if you didn't used the "as SubjectsWhereUniqueInput"
wlvz
wlvzOP2y ago
I managed to fix it but I ran into another issue Here is my new api call:
import { db } from "../../lib/db";
export async function GET() {
try {
const topic = await db.subjects.update({
where: {
id: 2,
},
data: {
topics: {
createMany: {
data: [{ name: "Topic 1" }, { name: "Topic 2"}],
},
},
},
include: {
topics: true,
},
});
return new Response(JSON.stringify(topic));
} catch (error) {
return new Response(null, { status: 500 });
}
}
import { db } from "../../lib/db";
export async function GET() {
try {
const topic = await db.subjects.update({
where: {
id: 2,
},
data: {
topics: {
createMany: {
data: [{ name: "Topic 1" }, { name: "Topic 2"}],
},
},
},
include: {
topics: true,
},
});
return new Response(JSON.stringify(topic));
} catch (error) {
return new Response(null, { status: 500 });
}
}
and here is my clientside code
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setCreatingTopic(true);
setError("");

try {
const response = await fetch("/api/addtopics", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ subject: lowercaseSubject, name: topicName }),
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}

const topic = await response.json();
setTopicName("");
setCreatingTopic(false);
setSuccessMessage(`Topic "${topic.name}" created successfully!`);
} catch (error) {
console.error(error);
setError((error as Error).message || "An error occurred");
setCreatingTopic(false);
}
};
/// some more code
return (
<div>
<h1>Exam: {capitalizedSubject}</h1>
<form onSubmit={handleSubmit}>
<label>
Topic name:
<input
type="text"
value={topicName}
onChange={(event) => setTopicName(event.target.value)}
/>
</label>
<button type="submit" disabled={creatingTopic}>
{creatingTopic ? "Creating..." : "Create topic"}
</button>
</form>
{error && <p>{error}</p>}
</div>
);
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setCreatingTopic(true);
setError("");

try {
const response = await fetch("/api/addtopics", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ subject: lowercaseSubject, name: topicName }),
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}

const topic = await response.json();
setTopicName("");
setCreatingTopic(false);
setSuccessMessage(`Topic "${topic.name}" created successfully!`);
} catch (error) {
console.error(error);
setError((error as Error).message || "An error occurred");
setCreatingTopic(false);
}
};
/// some more code
return (
<div>
<h1>Exam: {capitalizedSubject}</h1>
<form onSubmit={handleSubmit}>
<label>
Topic name:
<input
type="text"
value={topicName}
onChange={(event) => setTopicName(event.target.value)}
/>
</label>
<button type="submit" disabled={creatingTopic}>
{creatingTopic ? "Creating..." : "Create topic"}
</button>
</form>
{error && <p>{error}</p>}
</div>
);
how can I change the names in " data: [{ name: "Topic 1" }, { name: "Topic 2"}]," to the names inputed in the input text box on the client side?
bruno!
bruno!2y ago
just read the "name" that you're sending on the post request through the body also notice that with the current UI you're only getting 1 name at a time
Want results from more Discord servers?
Add your server