diff --git a/@types/index.d.ts b/@types/index.d.ts index 2374801f6..f68dd28e2 100644 --- a/@types/index.d.ts +++ b/@types/index.d.ts @@ -196,6 +196,7 @@ export class Response extends BodyMixin { static error(): Response; static redirect(url: string, status?: number): Response; + static json(data: any, init?: ResponseInit): Response; } export class FetchError extends Error { diff --git a/@types/index.test-d.ts b/@types/index.test-d.ts index 627766599..3272a0e7c 100644 --- a/@types/index.test-d.ts +++ b/@types/index.test-d.ts @@ -93,6 +93,11 @@ async function run() { expectType(Response.redirect('https://google.com')); expectType(Response.redirect('https://google.com', 301)); + + expectType(Response.json({foo: 'bar'})); + expectType(Response.json({foo: 'bar'}, { + status: 301 + })); } run().finally(() => { diff --git a/src/response.js b/src/response.js index 63af26711..9806c0cba 100644 --- a/src/response.js +++ b/src/response.js @@ -124,6 +124,25 @@ export default class Response extends Body { return response; } + static json(data = undefined, init = {}) { + const body = JSON.stringify(data); + + if (body === undefined) { + throw new TypeError('data is not JSON serializable'); + } + + const headers = new Headers(init && init.headers); + + if (!headers.has('content-type')) { + headers.set('content-type', 'application/json'); + } + + return new Response(body, { + ...init, + headers + }); + } + get [Symbol.toStringTag]() { return 'Response'; } diff --git a/test/main.js b/test/main.js index ec58f8285..93e0cee19 100644 --- a/test/main.js +++ b/test/main.js @@ -2281,6 +2281,33 @@ describe('node-fetch', () => { const res = await fetch(url); expect(res.url).to.equal(`${base}m%C3%B6bius`); }); + + it('static Response.json should work', async () => { + const response = Response.json({foo: 'bar'}); + expect(response.status).to.equal(200); + expect(response.headers.get('content-type')).to.equal('application/json'); + expect(await response.text()).to.equal(JSON.stringify({foo: 'bar'})); + + const response1 = Response.json(null, { + status: 301, + statusText: 'node-fetch', + headers: { + 'Content-Type': 'text/plain' + } + }); + + expect(response1.headers.get('content-type')).to.equal('text/plain'); + expect(response1.status).to.equal(301); + expect(response1.statusText).to.equal('node-fetch'); + + const response2 = Response.json(null, { + headers: { + 'CoNtEnT-TypE': 'text/plain' + } + }); + + expect(response2.headers.get('content-type')).to.equal('text/plain'); + }); }); describe('node-fetch using IPv6', () => {