Home > OS >  How to use express.json and express.raw together?
How to use express.json and express.raw together?

Time:11-13

I am building a web application with a login form and stripe subscription functionality.

In order to receive JSON data I am using express.json as

app.use(express.json());

When I was using the above middleware to receive stripe webhook secret the server could not receive it.

So I had to add the express.raw

My middleware looked like this:

app.use(express.raw({ type: "application/json" }));
app.use(express.json());

But now I am unable to receive form JSON data.

Here is my stripe logic:

export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => {
    let data;
    let eventType;
    let event = req.body;
    const webhookSecret = "web hook secret provided by stripe";
    if (webhookSecret) {
        let signature = req.headers["stripe-signature"];

        try {
            event = stripe.webhooks.constructEvent(req.body, signature , webhookSecret);
        } catch (err) {
            console.log(`⚠️  Webhook signature verification failed.`);  //This part is throwing the error
            return res.sendStatus(400);
        }
        
        data = event.data;
        eventType = event.type;
    } else {
       
       
        data = req.body.data;
        eventType = req.body.type;
    }
    let subscription;

    switch (eventType) {
         
       // Here webhook events are managed

    }

    res.sendStatus(200);
};

Here is the index.js code:


app.use(express.raw({ type: "application/json" }));
app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.post("/webhooks", postStripeWebhook);

Updated code-------------------------

index.js:

app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.post("/webhooks", postStripeWebhook);

Middleware code:

export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => {
    let data;
    let eventType;
    let event = req.body;
    const webhookSecret = "web hook secret provided by stripe";
    if (webhookSecret) {
        let signature = req.headers["stripe-signature"];

        try {
            event = stripe.webhooks.constructEvent(JSON.stringify(req.body), signature , webhookSecret);     //updated this line
        } catch (err) {
            console.log(`⚠️  Webhook signature verification failed.`);  //This part is throwing the error
            return res.sendStatus(400);
        }
        
        data = event.data;
        eventType = event.type;
    } else {
       
       
        data = req.body.data;
        eventType = req.body.type;
    }
    let subscription;

    switch (eventType) {
         
       // Here webhook events are managed

    }

    res.sendStatus(200);
};

I updated the code but still, but the problem persists.

Please guide me on how to modify my middleware to receive both types of data.

CodePudding user response:

It depends on your needs

you can add the bodyParser.json() as a middleware in your api

For example: app.post('/some/special/route/accepts_as_json', bodyParser.json() , (req,res)=>{} )

Then leave the app.use(express.raw({ type: "application/json" })); on your index, if you don't mention the middleware it will be raw, if you do mention is you will receive the jsons

CodePudding user response:

You don't need express.raw, only express.json. This parses JSON requests and stores the resulting Javascript object in req.body. However, if you want to send this object to stripe.webhooks.constructEvent, you must stringify it again:

stripe.webhooks.constructEvent(JSON.stringify(req.body), sig, endpointSecret)

Without the JSON.stringify, you would send [object Object], which is not understood by Stripe and leads to the observed error.

express.raw({type: "application/json"}) writes the JSON to req.body as a string, but this is not useful except for your special case, therefore I would not use it. However, if the Stripe signature depends on the exact string format of the JSON payload (which I would find strange), then you cannot avoid this. In this case, you should follow Ibrahim shamma's suggestion but put the Stripe middleware before the express.json():

app.post("/webhooks", express.raw({type: "application/json"}), postStripeWebhook);
app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());

This ensures that the "raw parsing" happens only for POST /webhooks requests, all others can still be parsed as normal JSON.

  • Related