Handling Update Operations with a Custom PATCH API in Payload CMS 3.0

With Payload CMS 3.0, the platform no longer provides built-in support for PATCH operations through the GraphQL or REST API. This can be limiting when you want to partially update a document without overwriting the entire object (which is typically what PUT or POST operations do).

To address this, you’ve created a custom API route in your Next.js app that:

  • Accepts only POST or PUT methods.
  • Internally converts those requests into PATCH operations by:
  • Extracting the id of the document to update.
  • Forwarding the update payload to a constructed PATCH endpoint:
  • https://your-domain.com/api/[collection]/[id]
  • Using fetch() to call the Payload API directly with method "PATCH".
  • Includes necessary headers like Authorization and Content-Type.

This workaround helps you simulate PATCH functionality while using methods still allowed by your client logic (POST or PUT), ensuring only changed fields are updated.

import type { NextApiRequest, NextApiResponse } from "next";
import { GRAPHQL_API_URL } from "@/_api/shared";


export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const {
    method,
    body,
    query: { collection }
  } = req;


  // Allow only POST or PUT
  if (method !== "POST" && method !== "PUT") {
    res.setHeader("Allow", ["POST", "PUT"]);
    return res.status(405).json({ success: false, message: `Method ${method} Not Allowed` });
  }


  const { id, ...updateData } = body;


  if (!id || typeof updateData !== "object" || typeof collection !== "string") {
    return res.status(400).json({
      success: false,
      message: "Missing 'id', 'collection', or invalid update payload"
    });
  }


  const patchUrl = `${GRAPHQL_API_URL}/api/${collection}/${id}`;


  try {
    const response = await fetch(patchUrl, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.PAYLOAD_API_KEY || ""}`
      },
      body: JSON.stringify(updateData)
    });


    const result = await response.json();


    if (!response.ok) {
      throw new Error(result.message || "PATCH failed");
    }


    return res.status(200).json({
      success: true,
      message: `Updated '${collection}' record.`,
      data: result
    });
  } catch (err: any) {
    console.error("PATCH error:", err);
    return res.status(500).json({
      success: false,
      message: err.message || "Server Error"
    });
  }
}


Leave a comment

Your email address will not be published. Required fields are marked *