or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser-setup.mdcli.mdgraphql-handlers.mdhttp-handlers.mdindex.mdnodejs-setup.mdreact-native-setup.mdresponse-creation.mdutilities.mdwebsocket-handlers.md

response-creation.mddocs/

0

# Response Creation

1

2

Response creation provides an enhanced Response class with convenience methods for creating various response types with proper headers and content handling.

3

4

## Capabilities

5

6

### HttpResponse Class

7

8

Enhanced Response class that extends the standard Response with additional features for mocking.

9

10

```typescript { .api }

11

/**

12

* Enhanced Response class with additional mocking features

13

* Drop-in replacement for standard Response with MSW-specific enhancements

14

*/

15

class HttpResponse<BodyType extends DefaultBodyType> extends Response {

16

/** Response body type marker for TypeScript */

17

readonly [bodyType]: BodyType;

18

19

/**

20

* Create an HttpResponse instance

21

* @param body - Response body content

22

* @param init - Response initialization options

23

*/

24

constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);

25

26

/** Create network error response */

27

static error(): HttpResponse<any>;

28

}

29

30

interface HttpResponseInit extends ResponseInit {

31

/** Response type (basic, cors, error, opaque, opaqueredirect) */

32

type?: ResponseType;

33

}

34

35

type DefaultBodyType =

36

| string

37

| number

38

| boolean

39

| null

40

| undefined

41

| ArrayBuffer

42

| Blob

43

| FormData

44

| ReadableStream;

45

```

46

47

**Usage Examples:**

48

49

```typescript

50

import { HttpResponse, http } from "msw";

51

52

// Basic HttpResponse with string body

53

http.get('/api/message', () => {

54

return new HttpResponse('Hello, world!', {

55

status: 200,

56

headers: {

57

'Content-Type': 'text/plain'

58

}

59

});

60

});

61

62

// HttpResponse with custom headers and status

63

http.post('/api/data', () => {

64

return new HttpResponse(JSON.stringify({ success: true }), {

65

status: 201,

66

statusText: 'Created',

67

headers: {

68

'Content-Type': 'application/json',

69

'X-Custom-Header': 'custom-value'

70

}

71

});

72

});

73

74

// Network error response

75

http.get('/api/network-error', () => {

76

return HttpResponse.error();

77

});

78

```

79

80

### Text Response Creation

81

82

Create text responses with proper Content-Type headers.

83

84

```typescript { .api }

85

/**

86

* Create a Response with Content-Type: "text/plain" body

87

* @param body - Text content for the response body

88

* @param init - Response initialization options

89

* @returns HttpResponse with text/plain content type

90

*/

91

static text<BodyType extends string>(

92

body?: NoInfer<BodyType> | null,

93

init?: HttpResponseInit

94

): HttpResponse<BodyType>;

95

```

96

97

**Usage Examples:**

98

99

```typescript

100

// Simple text response

101

http.get('/api/message', () => {

102

return HttpResponse.text('Hello, world!');

103

});

104

105

// Text response with custom status

106

http.get('/api/error-message', () => {

107

return HttpResponse.text('Something went wrong', {

108

status: 500

109

});

110

});

111

112

// Text response with custom headers

113

http.get('/api/plain-text', () => {

114

return HttpResponse.text('Plain text content', {

115

headers: {

116

'Cache-Control': 'no-cache',

117

'X-Source': 'mock'

118

}

119

});

120

});

121

122

// Empty text response

123

http.delete('/api/resource', () => {

124

return HttpResponse.text(null, { status: 204 });

125

});

126

127

// Multiline text response

128

http.get('/api/readme', () => {

129

return HttpResponse.text(`

130

# README

131

132

This is a multiline text response

133

with proper formatting.

134

135

## Features

136

- Feature 1

137

- Feature 2

138

`.trim());

139

});

140

```

141

142

### JSON Response Creation

143

144

Create JSON responses with proper Content-Type headers and automatic serialization.

145

146

```typescript { .api }

147

/**

148

* Create a Response with Content-Type: "application/json" body

149

* @param body - JavaScript object/array to serialize as JSON

150

* @param init - Response initialization options

151

* @returns HttpResponse with application/json content type

152

*/

153

static json<BodyType extends JsonBodyType>(

154

body?: NoInfer<BodyType> | null | undefined,

155

init?: HttpResponseInit

156

): HttpResponse<BodyType>;

157

158

type JsonBodyType = Record<string, any> | any[];

159

```

160

161

**Usage Examples:**

162

163

```typescript

164

// Simple JSON object response

165

http.get('/api/user', () => {

166

return HttpResponse.json({

167

id: 1,

168

name: 'John Doe',

169

email: 'john@example.com'

170

});

171

});

172

173

// JSON array response

174

http.get('/api/users', () => {

175

return HttpResponse.json([

176

{ id: 1, name: 'John Doe' },

177

{ id: 2, name: 'Jane Smith' }

178

]);

179

});

180

181

// JSON response with custom status

182

http.post('/api/users', () => {

183

return HttpResponse.json(

184

{ id: 3, name: 'New User', created: true },

185

{ status: 201 }

186

);

187

});

188

189

// Error JSON response

190

http.get('/api/protected', () => {

191

return HttpResponse.json(

192

{

193

error: 'Unauthorized',

194

code: 'AUTH_REQUIRED',

195

message: 'Please provide valid authentication'

196

},

197

{ status: 401 }

198

);

199

});

200

201

// Complex nested JSON

202

http.get('/api/dashboard', () => {

203

return HttpResponse.json({

204

user: {

205

id: 1,

206

profile: { name: 'John', avatar: 'avatar.jpg' }

207

},

208

stats: {

209

views: 1234,

210

likes: 567,

211

comments: 89

212

},

213

posts: [

214

{ id: 1, title: 'First Post', published: true },

215

{ id: 2, title: 'Second Post', published: false }

216

]

217

});

218

});

219

220

// Empty JSON response

221

http.delete('/api/user/1', () => {

222

return HttpResponse.json(null, { status: 204 });

223

});

224

225

// JSON response with custom headers

226

http.get('/api/data', () => {

227

return HttpResponse.json(

228

{ data: 'example' },

229

{

230

headers: {

231

'X-Total-Count': '1',

232

'Cache-Control': 'max-age=300'

233

}

234

}

235

);

236

});

237

```

238

239

### XML Response Creation

240

241

Create XML responses with proper Content-Type headers.

242

243

```typescript { .api }

244

/**

245

* Create a Response with Content-Type: "application/xml" body

246

* @param body - XML string content

247

* @param init - Response initialization options

248

* @returns HttpResponse with text/xml content type

249

*/

250

static xml<BodyType extends string>(

251

body?: BodyType | null,

252

init?: HttpResponseInit

253

): HttpResponse<BodyType>;

254

```

255

256

**Usage Examples:**

257

258

```typescript

259

// Simple XML response

260

http.get('/api/data.xml', () => {

261

return HttpResponse.xml(`

262

<?xml version="1.0" encoding="UTF-8"?>

263

<user>

264

<id>1</id>

265

<name>John Doe</name>

266

<email>john@example.com</email>

267

</user>

268

`);

269

});

270

271

// XML response with custom status

272

http.post('/api/soap', () => {

273

return HttpResponse.xml(`

274

<?xml version="1.0" encoding="UTF-8"?>

275

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

276

<soap:Body>

277

<response>Success</response>

278

</soap:Body>

279

</soap:Envelope>

280

`, { status: 201 });

281

});

282

283

// RSS feed response

284

http.get('/api/feed', () => {

285

return HttpResponse.xml(`

286

<?xml version="1.0" encoding="UTF-8"?>

287

<rss version="2.0">

288

<channel>

289

<title>My Blog</title>

290

<description>Latest posts</description>

291

<item>

292

<title>First Post</title>

293

<description>Content of first post</description>

294

</item>

295

</channel>

296

</rss>

297

`);

298

});

299

300

// XML error response

301

http.get('/api/error.xml', () => {

302

return HttpResponse.xml(`

303

<?xml version="1.0" encoding="UTF-8"?>

304

<error>

305

<code>404</code>

306

<message>Resource not found</message>

307

</error>

308

`, { status: 404 });

309

});

310

```

311

312

### HTML Response Creation

313

314

Create HTML responses with proper Content-Type headers.

315

316

```typescript { .api }

317

/**

318

* Create a Response with Content-Type: "text/html" body

319

* @param body - HTML string content

320

* @param init - Response initialization options

321

* @returns HttpResponse with text/html content type

322

*/

323

static html<BodyType extends string>(

324

body?: BodyType | null,

325

init?: HttpResponseInit

326

): HttpResponse<BodyType>;

327

```

328

329

**Usage Examples:**

330

331

```typescript

332

// Simple HTML page

333

http.get('/login', () => {

334

return HttpResponse.html(`

335

<!DOCTYPE html>

336

<html>

337

<head><title>Login</title></head>

338

<body>

339

<form>

340

<input type="text" placeholder="Username" />

341

<input type="password" placeholder="Password" />

342

<button type="submit">Login</button>

343

</form>

344

</body>

345

</html>

346

`);

347

});

348

349

// HTML fragment

350

http.get('/api/widget', () => {

351

return HttpResponse.html(`

352

<div class="widget">

353

<h3>Dynamic Widget</h3>

354

<p>This content was generated by MSW</p>

355

</div>

356

`);

357

});

358

359

// HTML error page

360

http.get('/not-found', () => {

361

return HttpResponse.html(`

362

<!DOCTYPE html>

363

<html>

364

<head><title>404 - Not Found</title></head>

365

<body>

366

<h1>Page Not Found</h1>

367

<p>The requested page could not be found.</p>

368

</body>

369

</html>

370

`, { status: 404 });

371

});

372

373

// Server-side rendered component

374

http.get('/ssr-component', () => {

375

return HttpResponse.html(`

376

<div id="app">

377

<header>

378

<h1>Server Rendered</h1>

379

</header>

380

<main>

381

<p>This HTML was "rendered" by MSW</p>

382

</main>

383

</div>

384

`);

385

});

386

```

387

388

### Binary Response Creation

389

390

Create responses with binary data using ArrayBuffer.

391

392

```typescript { .api }

393

/**

394

* Create a Response with an ArrayBuffer body

395

* @param body - ArrayBuffer or SharedArrayBuffer content

396

* @param init - Response initialization options

397

* @returns HttpResponse with application/octet-stream content type

398

*/

399

static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(

400

body?: BodyType,

401

init?: HttpResponseInit

402

): HttpResponse<BodyType>;

403

```

404

405

**Usage Examples:**

406

407

```typescript

408

// Binary file response

409

http.get('/api/file.bin', () => {

410

const buffer = new ArrayBuffer(16);

411

const view = new Uint8Array(buffer);

412

413

// Fill with sample binary data

414

for (let i = 0; i < view.length; i++) {

415

view[i] = i * 2;

416

}

417

418

return HttpResponse.arrayBuffer(buffer);

419

});

420

421

// Image response (simulated)

422

http.get('/api/image.png', () => {

423

// Create a minimal PNG-like binary structure

424

const buffer = new ArrayBuffer(100);

425

const view = new Uint8Array(buffer);

426

427

// PNG signature (not a real PNG, just for demo)

428

view.set([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);

429

430

return HttpResponse.arrayBuffer(buffer, {

431

headers: {

432

'Content-Type': 'image/png'

433

}

434

});

435

});

436

437

// Binary data with custom content type

438

http.get('/api/data.custom', () => {

439

const buffer = new ArrayBuffer(64);

440

const view = new Float32Array(buffer);

441

442

// Fill with float data

443

for (let i = 0; i < view.length; i++) {

444

view[i] = Math.random();

445

}

446

447

return HttpResponse.arrayBuffer(buffer, {

448

headers: {

449

'Content-Type': 'application/x-custom-binary'

450

}

451

});

452

});

453

454

// Download response

455

http.get('/api/download/:filename', ({ params }) => {

456

const buffer = new ArrayBuffer(1024);

457

// ... fill buffer with file content

458

459

return HttpResponse.arrayBuffer(buffer, {

460

headers: {

461

'Content-Disposition': `attachment; filename="${params.filename}"`,

462

'Content-Type': 'application/octet-stream'

463

}

464

});

465

});

466

```

467

468

### Form Data Response Creation

469

470

Create responses with FormData bodies.

471

472

```typescript { .api }

473

/**

474

* Create a Response with a FormData body

475

* @param body - FormData instance

476

* @param init - Response initialization options

477

* @returns HttpResponse with FormData body

478

*/

479

static formData(

480

body?: FormData,

481

init?: HttpResponseInit

482

): HttpResponse<FormData>;

483

```

484

485

**Usage Examples:**

486

487

```typescript

488

// Form data response

489

http.get('/api/form-data', () => {

490

const formData = new FormData();

491

formData.append('name', 'John Doe');

492

formData.append('email', 'john@example.com');

493

formData.append('age', '30');

494

495

return HttpResponse.formData(formData);

496

});

497

498

// File upload simulation

499

http.post('/api/upload', () => {

500

const formData = new FormData();

501

formData.append('status', 'success');

502

formData.append('fileId', '12345');

503

formData.append('filename', 'uploaded-file.txt');

504

505

return HttpResponse.formData(formData, {

506

status: 201

507

});

508

});

509

510

// Multi-part response with files

511

http.get('/api/export', () => {

512

const formData = new FormData();

513

514

// Simulate file content

515

const blob = new Blob(['CSV data content'], { type: 'text/csv' });

516

formData.append('file', blob, 'export.csv');

517

formData.append('format', 'csv');

518

formData.append('records', '1000');

519

520

return HttpResponse.formData(formData);

521

});

522

```

523

524

### Custom Response Headers

525

526

Set custom headers for enhanced response simulation.

527

528

```typescript

529

// Response with caching headers

530

http.get('/api/cached-data', () => {

531

return HttpResponse.json(

532

{ data: 'cached content' },

533

{

534

headers: {

535

'Cache-Control': 'public, max-age=3600',

536

'ETag': '"abc123"',

537

'Last-Modified': 'Wed, 21 Oct 2015 07:28:00 GMT'

538

}

539

}

540

);

541

});

542

543

// CORS headers

544

http.options('/api/cors-endpoint', () => {

545

return new HttpResponse(null, {

546

status: 204,

547

headers: {

548

'Access-Control-Allow-Origin': '*',

549

'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',

550

'Access-Control-Allow-Headers': 'Content-Type, Authorization',

551

'Access-Control-Max-Age': '86400'

552

}

553

});

554

});

555

556

// Security headers

557

http.get('/api/secure-data', () => {

558

return HttpResponse.json(

559

{ sensitiveData: 'protected' },

560

{

561

headers: {

562

'X-Content-Type-Options': 'nosniff',

563

'X-Frame-Options': 'DENY',

564

'X-XSS-Protection': '1; mode=block',

565

'Strict-Transport-Security': 'max-age=31536000'

566

}

567

}

568

);

569

});

570

571

// Custom API headers

572

http.get('/api/data', () => {

573

return HttpResponse.json(

574

{ results: [] },

575

{

576

headers: {

577

'X-Total-Count': '0',

578

'X-Page': '1',

579

'X-Per-Page': '20',

580

'X-Rate-Limit-Remaining': '99'

581

}

582

}

583

);

584

});

585

```

586

587

### Response Status Codes

588

589

Handle various HTTP status codes appropriately.

590

591

```typescript

592

// Success responses

593

http.get('/api/data', () => {

594

return HttpResponse.json({ data: 'ok' }); // 200 OK (default)

595

});

596

597

http.post('/api/resource', () => {

598

return HttpResponse.json(

599

{ id: 1, created: true },

600

{ status: 201 } // 201 Created

601

);

602

});

603

604

http.put('/api/resource/1', () => {

605

return HttpResponse.json(

606

{ id: 1, updated: true },

607

{ status: 200 } // 200 OK for updates

608

);

609

});

610

611

http.delete('/api/resource/1', () => {

612

return new HttpResponse(null, { status: 204 }); // 204 No Content

613

});

614

615

// Client error responses

616

http.get('/api/unauthorized', () => {

617

return HttpResponse.json(

618

{ error: 'Unauthorized' },

619

{ status: 401 }

620

);

621

});

622

623

http.get('/api/forbidden', () => {

624

return HttpResponse.json(

625

{ error: 'Forbidden' },

626

{ status: 403 }

627

);

628

});

629

630

http.get('/api/not-found', () => {

631

return HttpResponse.json(

632

{ error: 'Not found' },

633

{ status: 404 }

634

);

635

});

636

637

http.post('/api/invalid-data', () => {

638

return HttpResponse.json(

639

{

640

error: 'Validation failed',

641

details: { name: 'Required field' }

642

},

643

{ status: 422 }

644

);

645

});

646

647

// Server error responses

648

http.get('/api/server-error', () => {

649

return HttpResponse.json(

650

{ error: 'Internal server error' },

651

{ status: 500 }

652

);

653

});

654

655

http.get('/api/service-unavailable', () => {

656

return HttpResponse.json(

657

{ error: 'Service temporarily unavailable' },

658

{ status: 503 }

659

);

660

});

661

662

// Redirect responses

663

http.get('/api/redirect', () => {

664

return new HttpResponse(null, {

665

status: 302,

666

headers: {

667

'Location': '/api/new-location'

668

}

669

});

670

});

671

```

672

673

## Types

674

675

```typescript { .api }

676

// Response class types

677

class HttpResponse<BodyType extends DefaultBodyType> extends Response {

678

readonly [bodyType]: BodyType;

679

constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);

680

681

static error(): HttpResponse<any>;

682

static text<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;

683

static json<T extends JsonBodyType>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;

684

static xml<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;

685

static html<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;

686

static arrayBuffer<T extends ArrayBuffer | SharedArrayBuffer>(body?: T, init?: HttpResponseInit): HttpResponse<T>;

687

static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;

688

}

689

690

// Body types

691

type DefaultBodyType =

692

| string

693

| number

694

| boolean

695

| null

696

| undefined

697

| ArrayBuffer

698

| Blob

699

| FormData

700

| ReadableStream;

701

702

type JsonBodyType = Record<string, any> | any[];

703

704

// Response initialization

705

interface HttpResponseInit extends ResponseInit {

706

status?: number;

707

statusText?: string;

708

headers?: HeadersInit;

709

type?: ResponseType;

710

}

711

712

// Utility types

713

type NoInfer<T> = [T][T extends any ? 0 : never];

714

715

// Symbol for body type tracking

716

declare const bodyType: unique symbol;

717

```