Skip to content

HTTP functions receive application/*+json bodies (e.g. JSON:API application/vnd.api+json) as a raw Buffer #809

Open

Description

@blackakula

Summary

An HTTP function receives a request body sent with a +json structured-syntax media type as a raw Buffer, while the same body sent as application/json arrives parsed. The most common case is JSON:API, whose spec says clients MUST send application/vnd.api+json (JSON:API media type), so a JSON:API-compliant client never gets a parsed body.

This was raised in #232 and closed as not reproducible. It reproduces on 5.0.5.

Environment

  • @google-cloud/functions-framework 5.0.5 (body-parser 2.3.0, express 5.2.1)
  • Node.js 24.15.0
  • Same behaviour deployed on Cloud Functions gen2

Reproduction

index.js:

exports.handler = (req, res) => {
  res.json({
    isBuffer: Buffer.isBuffer(req.body),
    body: Buffer.isBuffer(req.body) ? req.body.toString() : req.body,
  });
};
npx functions-framework --target=handler --port=8080

curl -s -H 'Content-Type: application/json' -d '{"data":{"type":"orders"}}' localhost:8080
# {"isBuffer":false,"body":{"data":{"type":"orders"}}}

curl -s -H 'Content-Type: application/vnd.api+json' -d '{"data":{"type":"orders"}}' localhost:8080
# {"isBuffer":true,"body":"{\"data\":{\"type\":\"orders\"}}"}

Expected

Both requests deliver the parsed object in req.body: a +json suffix means the payload is JSON (RFC 6839 §3.1).

Cause

src/server.ts registers the default JSON parser without a type, so body-parser falls back to its default of application/json only. Anything else falls through to the catch-all raw parser (type: '*/*'). body-parser deliberately keeps that default narrow and leaves widening it to the caller through the type option (expressjs/body-parser#131). The framework is the caller here, and user code has no way to pass that option.

Suggested fix

Widen the default JSON parser's type. The cloudevents parser is registered first, so application/cloudevents+json is still handled by it:

app.use(bodyParser.json({ ...defaultBodySavingOptions, type: ['application/json', 'application/*+json'] }));

Current workaround

Detect a Buffer body with a JSON media type in the handler and JSON.parse it there. This also means every function has to build its own error response for a malformed body. For application/json, that error never reaches the function at all (see #686).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions