Handling Relation Fields in Prisma Body Requests
One of the most powerful features of Arkos is its ability to automatically transform JSON data with nested relations into the appropriate Prisma operations. This eliminates the need to manually structure complex nested creates, updates, and connections.
When working with related entities in REST APIs or form submissions, the data structure you receive is typically flat or hierarchical JSON, not the nested operation structure Prisma expects. The handleRelationFieldsInBody
utility bridges this gap by intelligently converting your API request data.
The handleRelationFieldsInBody
is only used internally by Arkos and not exported to external usage, because let's be sincere you now how to handle this prisma stuff if not read about in https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries.
Input And Output Example
Input JSON (from client)
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"category": {
"id": 5
},
"attributes": [
{ "name": "Color", "value": "Red" },
{ "name": "Size", "value": "Medium" }
],
"tags": [{ "id": 1 }, { "id": 2 }],
"images": [
{ "url": "image1.jpg", "isPrimary": true },
{ "id": 123, "isPrimary": false, "altText": "Updated alt text" },
{ "id": 456, "apiAction": "delete" }
]
}
Output (for Prisma)
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"category": {
"connect": { "id": 5 }
},
"attributes": {
"create": [
{ "name": "Color", "value": "Red" },
{ "name": "Size", "value": "Medium" }
]
},
"tags": {
"connect": [
{ "id": 1 },
{ "id": 2 }
]
},
"images": {
"create": [
{ "url": "image1.jpg", "isPrimary": true }
],
"update": [
{ "where": { "id": 123 }, "data": { "isPrimary": false, "altText": "Updated alt text" } }
],
"deleteMany": {
"id": { "in": [456] }
}
}
}
Even though Arkos have it's own helper function for hanlding relational fields data on request, you can write the it on your own as if your where sending a pure JSON for prisma adding connect, create, delete, update or ther features that prisma supports, and Arkos automatically notice and not try to apply nothing on it's own.
Bear in mind that if you implement your own logic for prisma relation fields operations as stated on the tip above, Arkos will not handle the nested fields inside the nested field (deeply nested) that you handled by yourself on the first level.
❌ Arkos Will Not Handle Deeply Nested Fields For subCategory Automatically
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"subCategory": {
"create": {
{ "name": "New Sub Category", "category": { "id": 3 } }
}
},
}
// Where a new sub category must be created and be
// connected to a existing category with id 3
Here Arkos will not handle the connection of the sub category to the category you must pass this on your own as raw prisma data field, because prisma will throw an error writing like this. To assess this you must write the field entirely as an raw prisma data like the following example:
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"subCategory": {
"create": {
{ "name": "New Sub Category", "category": { "connect": { "id": 3 } } }
}
},
}
// Where a new sub category must be created and be
// connected to a existing category with id 3
You read more about nested fields operations on Prisma Official documenation clicking here.
✅ Arkos Will Handle Nested Fields For subCategory Automatically
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"subCategory": {
"name": "New Sub Category",
"category": { "id": 3 }
}
}
// Where a new sub category must be created and be
// connected to a existing category with id 3.
Here Arkos will scan the nested fields on subCategory to handle this for you and automaticlly transform this to a valid prisma raw data like below:
{
"name": "New Product",
"price": 29.99,
"description": "A fantastic product",
"subCategory": {
"create": {
{ "name": "New Sub Category", "category": { "connect": { "id": 3 } } }
}
},
}
// Where a new sub category must be created and be
// connected to a existing category with id 3
How Operations Are Determined
The utility handleRelationFieldsInBody
function examines the structure of each relation field to determine the appropriate Prisma operation:
JSON Structure | Resulting Prisma Operation | Observation |
---|---|---|
{ "fieldName": { "id": 5 } } | { "fieldName": { "connect": { "id": 5 } } } | You can also pass a @unique field in order to connect. |
{ "fieldName": { "email": "user@example.com" } } | { "fieldName": { "connect": { "email": "user@example.com" } } } | email must be defined as @unique on your schema or it will be marked as data to create instead. |
{ "fieldName": { "name": "New Item" } } | { "fieldName": { "create": { "name": "New Item" } } } | name must NOT be @unique otherwise Arkos will try to connect with this. |
{ "fieldName": { "id": 5, "name": "Updated" } } | { "fieldName": { "update": { "where": {"id": 5 }, "data": { "name": "Updated" } } } } | you could pass also pass another @unique field instead of id and Arkos will try to update with it. |
{ "fieldName": { "id": 5, "apiAction": "delete" } } | { "fieldName": { "delete" : { "where" : { "id" : 5 } } } } or deleteMany for arrays | It can also be done through a @unique field and the apiAction to delete in order to delete the nested data. |
{ "fieldName": { "id": 5, "apiAction": "disconnect" } } | { "fieldName": { "disconnect": { "where" : { "id": 5 } } } } | It can also be done through a @unique field and the apiAction to disconnect in order to disconnect the nested data. |
Bear in mind that to connect you can use any field that is @unique under your model schema or otherwise Arkos will try to create by default.
By default when you want to update nested relation fields Arkos will automatically look for an id
on the nested data if not found then a @unique field will be searched if not found also Arkos will judge it as a data to be created.
Common JSON Patterns and Their Transformations
Creating a New Entity with Relations
// Input JSON
{
"title": "New Blog Post",
"content": "This is the content",
"author": { "id": 123 },
"tags": [
{ "name": "Technology" },
{ "name": "Programming" }
]
}
// Transformed for Prisma
{
"title": "New Blog Post",
"content": "This is the content",
"author": {
"connect": { "id": 123 }
},
"tags": {
"create": [
{ "name": "Technology" },
{ "name": "Programming" }
]
}
}
Updating an Entity with Mixed Relation Operations
// Input JSON
{
"id": 456,
"title": "Updated Blog Post",
"comments": [
{ "id": 1, "text": "Updated comment" },
{ "content": "New comment" },
{ "id": 3, "apiAction": "delete" }
]
}
// Transformed for Prisma
{
"id": 456,
"title": "Updated Blog Post",
"comments": {
"update": [
{ "where": { "id": 1 }, "data": { "text": "Updated comment" } }
],
"create": [
{ "content": "New comment" }
],
"deleteMany": {
"id": { "in": [3] }
}
}
}
Connecting by Unique Fields
// Input JSON
{
"name": "New Order",
"customer": { "email": "customer@example.com" },
"products": [
{ "sku": "PROD-123" },
{ "sku": "PROD-456" }
]
}
// Transformed for Prisma (assuming email and sku are unique fields)
{
"name": "New Order",
"customer": {
"connect": { "email": "customer@example.com" }
},
"products": {
"connect": [
{ "sku": "PROD-123" },
{ "sku": "PROD-456" }
]
}
}
Note that this behavior is handled on the service layer of Arkos request handling pipeline for each prisma model, you can read more about the Request Handling Pipeline clicking here.
The apiAction
Property
You can include an apiAction
property to explicitly specify the operation:
{
"items": [
{ "id": 1, "quantity": 3, "apiAction": "update" },
{ "productId": 42, "quantity": 1 },
{ "id": 3, "apiAction": "delete" },
{ "id": 4, "apiAction": "disconnect" },
{ "id": 5, "apiAction": "connect" }
]
}
Valid apiAction
values:
"connect"
: Force connect operation even with additional fields"update"
: Explicitly mark for update"delete"
: Remove relation (usesdeleteMany
for arrays automatically)"disconnect"
: Disconnect without deleting
Integration with Arkos
This utility is automatically integrated into Arkos' base controllers. If you're using the framework's default controllers, the relation handling happens automatically:
import { BaseController } from "arkos/controllers";
export class ProductController extends BaseController {
constructor() {
super("product"); // Automatically handles relations for Product model
}
// Custom methods can use the utility directly
async createBundle(req, res) {
const bundleData = handleRelationFieldsInBody(
req.body,
getPrismaModelRelations("ProductBundle")
);
// Use processed data with Prisma
const bundle = await this.prisma.productBundle.create({
data: bundleData,
});
res.status(201).json({ data: bundle });
}
}
Best Practices
- Document API Structure: Ensure your frontend developers understand the expected structure
- Validate Input: Always validate input data before passing to relation handlers
- Consider Depth: For very deep nesting, consider separate API endpoints
- Use Explicit Actions: When the default behavior isn't sufficient, use
apiAction
- Handling Files: For relations that include file uploads, process uploads first then add file references to your data