7

I'm building a custom endpoint on Strapi. For this endpoint, I need to have the raw body content. Is it possible to obtain it from the ctx variable?

stripe : async(ctx) => {
    // Handle the event
    const sig = ctx.request.headers['stripe-signature']
    
    let event = null
    try {
      // ctx.request.body needs to be the original raw body
      event = stripe.webhooks.constructEvent(ctx.request.body,sig, endpointSecret)
    }catch (e) {
      ctx.badRequest(null,e)
      return
    }
Rui Figueiredo
  • 110
  • 1
  • 5

4 Answers4

8

Create a middleware (/config/middleware.js) and update it to the following

module.exports = {
  settings: {
    cors: {
      enabled: true,
    },
    parser: {
      enabled: true,
      multipart: true,
      includeUnparsed: true,
    },
  },
};

In the controller (/api/<model>/controllers/<model>.js):

const unparsed = require("koa-body/unparsed.js");
const unparsedBody = ctx.request.body[unparsed];
Abhishek E H
  • 479
  • 2
  • 7
  • 14
1

The official koa-bodyparser package actually does this out of the box. See: https://github.com/koajs/bodyparser#raw-body

Here is a small example:

import Koa from 'koa';
import KoaRouter from '@koa/router';
import koaBodyParser from 'koa-bodyparser';

const app = new Koa();
const router = new KoaRouter();

const stripeCheckout = (ctx, next) => {
  const sig = ctx.request.header['stripe-signature'];
  
  let event;
  
  if (!process.env.STRIPE_ENDPOINT_SECRET) {
    throw new Error('Missing Stripe endpoint secret.');
  }
  
  try {
    event = stripe.webhooks.constructEvent(
      ctx.request.rawBody,
      sig,
      endpointSecret: process.env.STRIPE_ENDPOINT_SECRET
    );
  } catch (err) {
    logger('error', err);
    
    ctx.status = 400;
    ctx.body = `Webhook Error: ${err.message}`;
    
    return next();
  }
  
  // ... do something with the event
  
  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    
    // ... do something with the checkout session
  }
  
  // return a response to acknowledge receipt of the event
  ctx.status = 200;
  ctx.body = { received: true };
  
  return next();
};

// POST
router.post('/stripe-checkout', stripeCheckout);

app.use(koaBodyParser());

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(port, () => {
  logger('log', `✅  Done! Server is listening on http://localhost:${port}`);
});
Zino Hofmann
  • 145
  • 1
  • 9
0

I'm not sure to understand your needs.

ctx.request.body contains the original body of your request.

After that if you want to send event as response body you can do this like that. ctx.body = event;

And a warning in your code. You wrote define a const for event and you assign event withe the result of your strapi webhook. You have to define a let variable.

Jim LAURIE
  • 3,859
  • 1
  • 11
  • 14
0

It actually works by switching on "includingUnparsed" in the request environment configuration (config/environments/development/request.json -> parser.includedUnparsed: true).

You can access the unparsed body using the koa-body built-in feature for that:

Some applications require crytopgraphic verification of request bodies, for example webhooks from slack or stripe. The unparsed body can be accessed if includeUnparsed is true in koa-body's options. When enabled, import the symbol for accessing the request body from unparsed = require('koa-body/unparsed.js'), or define your own accessor using unparsed = Symbol.for('unparsedBody'). Then the unparsed body is available using ctx.request.body[unparsed].

koa-body docs

Blaubaer
  • 3
  • 2