lool
lool

Reputation: 665

How to access request body in nextjs 13.2 route handler

I was trying to send a post request to my api. However trying to access the request body in the route handler causes the error below:

Code:

export async function POST(request: Request) {
  const postBody: postProps = JSON.parse(request.body) // 👈 Error here on request.body
  ...
}

Error: Argument of type 'ReadableStream' is not assignable to parameter of type 'string'.

Any help would be appreciated

Upvotes: 30

Views: 38168

Answers (4)

zEELz
zEELz

Reputation: 391

After battling with this issue for an hour, I had to comment output prop in next.config.js to get request.json() to deliver the request's body.

const nextConfig = {
    // "output": "export",
    "distDir": "build",
    experimental: {
        serverActions: true
    }
}

I'm still trying to understand the connection. Shouldn't I be able to build my client components to a dir?

Upvotes: 1

SwiftDeveloper
SwiftDeveloper

Reputation: 31

I was having trouble getting a Stripe webhook to work using App Router. The following worked for me (using Kyle's method of getting the raw body).

import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2023-08-16',
});

import { NextRequest, NextResponse } from 'next/server';

const WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET;

export async function POST(req: NextRequest) {
  const rawBody = await req.text(); // gets the raw body from the request
  const sig = req.headers.get('stripe-signature');

  let event;
  let result = 'Webhook called.';

  try {
    event = stripe.webhooks.constructEvent(rawBody, sig!, WEBHOOK_SECRET!);
  } catch (err: any) {
    console.error(err);
    return NextResponse.json({ error: err.message }, { status: 400 });
  }

  // Handle the event
  switch (event.type) {
    case 'payment_intent.created':
      console.log('Payment Intent Created.');
      break;
    case 'payment_intent.payment_failed':
      console.log('Payment Failed.');
      break;
    case 'payment_intent.processing':
      console.log('Payment processing...');
      break;
    case 'payment_intent.succeeded':
      const paymentIntent = event.data.object;
      console.log('paymentIntent: ', paymentIntent);
      console.log(`Payment Succeeded`);
      break;
    // ... handle other event types
    default:
      console.warn(`Unhandled event type ${event.type}`);
  }
  return NextResponse.json({ received: true, status: result });
}

Also, you cannot call both req.json() and req.text(). You will get a body consumed error.

Upvotes: 3

Kyle Davis
Kyle Davis

Reputation: 106

I was having issues Verifying the webhook from Clerk in Next.js using App Router.

The following worked for me.

import { Webhook } from "svix";

export async function POST(req: NextRequest) {
  const svix_id = req.headers.get("svix-id") ?? '';
  const svix_timestamp = req.headers.get("svix-timestamp") ?? '';
  const svix_signature = req.headers.get("svix-signature") ?? '';
  
  const body = await req.text(); // This get's the raw body as a string
  
  const sivx =  new Webhook("your_secret_key_here")

  const payload = sivx.verify(body, {
    "svix-id": svix_id,
    "svix-timestamp": svix_timestamp,
    "svix-signature": svix_signature,

  });

  // The payload is the json.
  console.log(payload);

  // The rest of your code

  return NextResponse.json(null, { status: 200 })

}


For reference:

https://developer.mozilla.org/en-US/docs/Web/API/Response/text

Upvotes: 6

Michael
Michael

Reputation: 6899

You need to call json() on the Request object.

export async function POST(request: Request) {
  const res = await request.json() // res now contains body
}

Upvotes: 65

Related Questions