diff --git a/packages/next/server/web/spec-extension/response.ts b/packages/next/server/web/spec-extension/response.ts index dabf3827d4ef21f..dff46ef005c5afa 100644 --- a/packages/next/server/web/spec-extension/response.ts +++ b/packages/next/server/web/spec-extension/response.ts @@ -63,6 +63,12 @@ export class NextResponse extends Response { return this.cookie(name, '', { expires: new Date(1), path: '/', ...opts }) } + static json(body: any) { + return new NextResponse(JSON.stringify(body), { + headers: { 'content-type': 'application/json' }, + }) + } + static redirect(url: string | NextURL, status = 302) { if (!REDIRECTS.has(status)) { throw new RangeError( diff --git a/test/unit/web-runtime/next-response.test.ts b/test/unit/web-runtime/next-response.test.ts new file mode 100644 index 000000000000000..f56ff68c88c166a --- /dev/null +++ b/test/unit/web-runtime/next-response.test.ts @@ -0,0 +1,54 @@ +/* eslint-env jest */ + +import { Blob, File, FormData } from 'next/dist/compiled/formdata-node' +import { Crypto } from 'next/dist/server/web/sandbox/polyfills' +import { Response } from 'next/dist/server/web/spec-compliant/response' +import { Headers } from 'next/dist/server/web/spec-compliant/headers' +import * as streams from 'web-streams-polyfill/ponyfill' + +beforeAll(() => { + global['Blob'] = Blob + global['crypto'] = new Crypto() + global['File'] = File + global['FormData'] = FormData + global['Headers'] = Headers + global['ReadableStream'] = streams.ReadableStream + global['TransformStream'] = streams.TransformStream + global['Response'] = Response +}) + +afterAll(() => { + delete global['Blob'] + delete global['crypto'] + delete global['File'] + delete global['Headers'] + delete global['FormData'] + delete global['ReadableStream'] + delete global['TransformStream'] +}) + +const toJSON = async (response) => ({ + body: await response.json(), + contentType: response.headers.get('content-type'), +}) + +it('automatically parses and formats JSON', async () => { + const { NextResponse } = await import( + 'next/dist/server/web/spec-extension/response' + ) + + expect(await toJSON(NextResponse.json({ message: 'hello!' }))).toMatchObject({ + contentType: 'application/json', + body: { message: 'hello!' }, + }) + + expect(await toJSON(NextResponse.json(null))).toMatchObject({ + contentType: 'application/json', + body: null, + }) + + expect(await toJSON(NextResponse.json(''))).toMatchObject({ + contentType: 'application/json', + body: '', + }) +})