How Do I Pass Plain Text As My Request Body Using NestJS?
Solution 1:
I see that this question is pretty old, but it is listed in google among first, so I want to add answer here.
If you don't want to add body-parser
middleware (for example, you want plain text only in single controller method), you can use raw-body
(which is already exists in your node_modules), something like this:
import * as rawbody from 'raw-body';
import { Controller, Post, Body, Req } from '@nestjs/common';
@Controller('/')
export class IndexController {
@Post()
async index(@Body() data, @Req() req) {
// we have to check req.readable because of raw-body issue #57
// https://github.com/stream-utils/raw-body/issues/57
if (req.readable) {
// body is ignored by NestJS -> get raw body from request
const raw = await rawbody(req);
const text = raw.toString().trim();
console.log('body:', text);
} else {
// body is parsed by NestJS
console.log('data:', data);
}
// ...
}
}
you could also create new parameter decorator
import * as rawbody from 'raw-body';
import { createParamDecorator, HttpException, HttpStatus } from '@nestjs/common';
export const PlainBody = createParamDecorator(async (data, req) => {
if (req.readable) {
return (await rawbody(req)).toString().trim();
}
throw new HttpException('Body aint text/plain', HttpStatus.INTERNAL_SERVER_ERROR);
});
and use it like
@Post()
async index(@PlainBody() text: string) {
// ...
(I didn't check decorator code, wrote it right here in comment)
Solution 2:
Adding on @yumaa's post above
Here's the working decorator with NestJS v7.0.8:
import { createParamDecorator, ExecutionContext, BadRequestException } from '@nestjs/common';
import * as rawBody from "raw-body";
export const PlainBody = createParamDecorator(async (_, context: ExecutionContext) => {
const req = context.switchToHttp().getRequest<import("express").Request>();
if (!req.readable) { throw new BadRequestException("Invalid body"); }
const body = (await rawBody(req)).toString("utf8").trim();
return body;
})
Solution 3:
The semantics of a post request are determined by the header that indicates the content type. Try making sure the request header has the type 'text/plain' and see of this helps.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
Solution 4:
Nest is not compatible with plain/text and you must pass a bodyparser to your express app instead. Try something like this:
import * as bodyParser from 'body-parser';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(bodyparser({ ...options })) // for plain/text bodies
await app.listen(3000)
}
bootstrap();
where options is created from https://www.npmjs.com/package/body-parser
Solution 5:
Old question but none of the above worked for me but the following did:
The above decorator or controller-method approaches did not work for me as the request body buffer had always already been read.
I was able to get it working using the following middleware. (Note in my case I needed to validate a Xero webhook so the example is geared towards that)
cache-raw-body-on-request.ts:
import { json } from 'body-parser';
import * as cloneBuffer from 'clone-buffer';
export const cachedRawBodyRequestKey = 'rawBodyBuffer';
/**
* Clones the request buffer and stores it on the request object for reading later
*/
export const cacheRawBodyOnRequest = json({
verify: (req: any, res, buf, encoding) => {
// only clone the buffer if we're receiving a Xero webhook request
if (req.headers['x-xero-signature'] && Buffer.isBuffer(buf)) {
req[cachedRawBodyRequestKey] = cloneBuffer(buf);
}
return true;
},
});
main.ts:
app.use(cacheRawBodyOnRequest);
controller:
const textBody = req[cachedRawBodyRequestKey].toString('utf-8');
Post a Comment for "How Do I Pass Plain Text As My Request Body Using NestJS?"