Seamless REST/GraphQL API mocking library for browser and Node.js.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Response creation provides an enhanced Response class with convenience methods for creating various response types with proper headers and content handling.
Enhanced Response class that extends the standard Response with additional features for mocking.
/**
* Enhanced Response class with additional mocking features
* Drop-in replacement for standard Response with MSW-specific enhancements
*/
class HttpResponse<BodyType extends DefaultBodyType> extends Response {
/** Response body type marker for TypeScript */
readonly [bodyType]: BodyType;
/**
* Create an HttpResponse instance
* @param body - Response body content
* @param init - Response initialization options
*/
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
/** Create network error response */
static error(): HttpResponse<any>;
}
interface HttpResponseInit extends ResponseInit {
/** Response type (basic, cors, error, opaque, opaqueredirect) */
type?: ResponseType;
}
type DefaultBodyType =
| string
| number
| boolean
| null
| undefined
| ArrayBuffer
| Blob
| FormData
| ReadableStream;Usage Examples:
import { HttpResponse, http } from "msw";
// Basic HttpResponse with string body
http.get('/api/message', () => {
return new HttpResponse('Hello, world!', {
status: 200,
headers: {
'Content-Type': 'text/plain'
}
});
});
// HttpResponse with custom headers and status
http.post('/api/data', () => {
return new HttpResponse(JSON.stringify({ success: true }), {
status: 201,
statusText: 'Created',
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'custom-value'
}
});
});
// Network error response
http.get('/api/network-error', () => {
return HttpResponse.error();
});Create text responses with proper Content-Type headers.
/**
* Create a Response with Content-Type: "text/plain" body
* @param body - Text content for the response body
* @param init - Response initialization options
* @returns HttpResponse with text/plain content type
*/
static text<BodyType extends string>(
body?: NoInfer<BodyType> | null,
init?: HttpResponseInit
): HttpResponse<BodyType>;Usage Examples:
// Simple text response
http.get('/api/message', () => {
return HttpResponse.text('Hello, world!');
});
// Text response with custom status
http.get('/api/error-message', () => {
return HttpResponse.text('Something went wrong', {
status: 500
});
});
// Text response with custom headers
http.get('/api/plain-text', () => {
return HttpResponse.text('Plain text content', {
headers: {
'Cache-Control': 'no-cache',
'X-Source': 'mock'
}
});
});
// Empty text response
http.delete('/api/resource', () => {
return HttpResponse.text(null, { status: 204 });
});
// Multiline text response
http.get('/api/readme', () => {
return HttpResponse.text(`
# README
This is a multiline text response
with proper formatting.
## Features
- Feature 1
- Feature 2
`.trim());
});Create JSON responses with proper Content-Type headers and automatic serialization.
/**
* Create a Response with Content-Type: "application/json" body
* @param body - JavaScript object/array to serialize as JSON
* @param init - Response initialization options
* @returns HttpResponse with application/json content type
*/
static json<BodyType extends JsonBodyType>(
body?: NoInfer<BodyType> | null | undefined,
init?: HttpResponseInit
): HttpResponse<BodyType>;
type JsonBodyType = Record<string, any> | any[];Usage Examples:
// Simple JSON object response
http.get('/api/user', () => {
return HttpResponse.json({
id: 1,
name: 'John Doe',
email: 'john@example.com'
});
});
// JSON array response
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' }
]);
});
// JSON response with custom status
http.post('/api/users', () => {
return HttpResponse.json(
{ id: 3, name: 'New User', created: true },
{ status: 201 }
);
});
// Error JSON response
http.get('/api/protected', () => {
return HttpResponse.json(
{
error: 'Unauthorized',
code: 'AUTH_REQUIRED',
message: 'Please provide valid authentication'
},
{ status: 401 }
);
});
// Complex nested JSON
http.get('/api/dashboard', () => {
return HttpResponse.json({
user: {
id: 1,
profile: { name: 'John', avatar: 'avatar.jpg' }
},
stats: {
views: 1234,
likes: 567,
comments: 89
},
posts: [
{ id: 1, title: 'First Post', published: true },
{ id: 2, title: 'Second Post', published: false }
]
});
});
// Empty JSON response
http.delete('/api/user/1', () => {
return HttpResponse.json(null, { status: 204 });
});
// JSON response with custom headers
http.get('/api/data', () => {
return HttpResponse.json(
{ data: 'example' },
{
headers: {
'X-Total-Count': '1',
'Cache-Control': 'max-age=300'
}
}
);
});Create XML responses with proper Content-Type headers.
/**
* Create a Response with Content-Type: "application/xml" body
* @param body - XML string content
* @param init - Response initialization options
* @returns HttpResponse with text/xml content type
*/
static xml<BodyType extends string>(
body?: BodyType | null,
init?: HttpResponseInit
): HttpResponse<BodyType>;Usage Examples:
// Simple XML response
http.get('/api/data.xml', () => {
return HttpResponse.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<user>
<id>1</id>
<name>John Doe</name>
<email>john@example.com</email>
</user>
`);
});
// XML response with custom status
http.post('/api/soap', () => {
return HttpResponse.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<response>Success</response>
</soap:Body>
</soap:Envelope>
`, { status: 201 });
});
// RSS feed response
http.get('/api/feed', () => {
return HttpResponse.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>My Blog</title>
<description>Latest posts</description>
<item>
<title>First Post</title>
<description>Content of first post</description>
</item>
</channel>
</rss>
`);
});
// XML error response
http.get('/api/error.xml', () => {
return HttpResponse.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<error>
<code>404</code>
<message>Resource not found</message>
</error>
`, { status: 404 });
});Create HTML responses with proper Content-Type headers.
/**
* Create a Response with Content-Type: "text/html" body
* @param body - HTML string content
* @param init - Response initialization options
* @returns HttpResponse with text/html content type
*/
static html<BodyType extends string>(
body?: BodyType | null,
init?: HttpResponseInit
): HttpResponse<BodyType>;Usage Examples:
// Simple HTML page
http.get('/login', () => {
return HttpResponse.html(`
<!DOCTYPE html>
<html>
<head><title>Login</title></head>
<body>
<form>
<input type="text" placeholder="Username" />
<input type="password" placeholder="Password" />
<button type="submit">Login</button>
</form>
</body>
</html>
`);
});
// HTML fragment
http.get('/api/widget', () => {
return HttpResponse.html(`
<div class="widget">
<h3>Dynamic Widget</h3>
<p>This content was generated by MSW</p>
</div>
`);
});
// HTML error page
http.get('/not-found', () => {
return HttpResponse.html(`
<!DOCTYPE html>
<html>
<head><title>404 - Not Found</title></head>
<body>
<h1>Page Not Found</h1>
<p>The requested page could not be found.</p>
</body>
</html>
`, { status: 404 });
});
// Server-side rendered component
http.get('/ssr-component', () => {
return HttpResponse.html(`
<div id="app">
<header>
<h1>Server Rendered</h1>
</header>
<main>
<p>This HTML was "rendered" by MSW</p>
</main>
</div>
`);
});Create responses with binary data using ArrayBuffer.
/**
* Create a Response with an ArrayBuffer body
* @param body - ArrayBuffer or SharedArrayBuffer content
* @param init - Response initialization options
* @returns HttpResponse with application/octet-stream content type
*/
static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(
body?: BodyType,
init?: HttpResponseInit
): HttpResponse<BodyType>;Usage Examples:
// Binary file response
http.get('/api/file.bin', () => {
const buffer = new ArrayBuffer(16);
const view = new Uint8Array(buffer);
// Fill with sample binary data
for (let i = 0; i < view.length; i++) {
view[i] = i * 2;
}
return HttpResponse.arrayBuffer(buffer);
});
// Image response (simulated)
http.get('/api/image.png', () => {
// Create a minimal PNG-like binary structure
const buffer = new ArrayBuffer(100);
const view = new Uint8Array(buffer);
// PNG signature (not a real PNG, just for demo)
view.set([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
return HttpResponse.arrayBuffer(buffer, {
headers: {
'Content-Type': 'image/png'
}
});
});
// Binary data with custom content type
http.get('/api/data.custom', () => {
const buffer = new ArrayBuffer(64);
const view = new Float32Array(buffer);
// Fill with float data
for (let i = 0; i < view.length; i++) {
view[i] = Math.random();
}
return HttpResponse.arrayBuffer(buffer, {
headers: {
'Content-Type': 'application/x-custom-binary'
}
});
});
// Download response
http.get('/api/download/:filename', ({ params }) => {
const buffer = new ArrayBuffer(1024);
// ... fill buffer with file content
return HttpResponse.arrayBuffer(buffer, {
headers: {
'Content-Disposition': `attachment; filename="${params.filename}"`,
'Content-Type': 'application/octet-stream'
}
});
});Create responses with FormData bodies.
/**
* Create a Response with a FormData body
* @param body - FormData instance
* @param init - Response initialization options
* @returns HttpResponse with FormData body
*/
static formData(
body?: FormData,
init?: HttpResponseInit
): HttpResponse<FormData>;Usage Examples:
// Form data response
http.get('/api/form-data', () => {
const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('email', 'john@example.com');
formData.append('age', '30');
return HttpResponse.formData(formData);
});
// File upload simulation
http.post('/api/upload', () => {
const formData = new FormData();
formData.append('status', 'success');
formData.append('fileId', '12345');
formData.append('filename', 'uploaded-file.txt');
return HttpResponse.formData(formData, {
status: 201
});
});
// Multi-part response with files
http.get('/api/export', () => {
const formData = new FormData();
// Simulate file content
const blob = new Blob(['CSV data content'], { type: 'text/csv' });
formData.append('file', blob, 'export.csv');
formData.append('format', 'csv');
formData.append('records', '1000');
return HttpResponse.formData(formData);
});Set custom headers for enhanced response simulation.
// Response with caching headers
http.get('/api/cached-data', () => {
return HttpResponse.json(
{ data: 'cached content' },
{
headers: {
'Cache-Control': 'public, max-age=3600',
'ETag': '"abc123"',
'Last-Modified': 'Wed, 21 Oct 2015 07:28:00 GMT'
}
}
);
});
// CORS headers
http.options('/api/cors-endpoint', () => {
return new HttpResponse(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400'
}
});
});
// Security headers
http.get('/api/secure-data', () => {
return HttpResponse.json(
{ sensitiveData: 'protected' },
{
headers: {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Strict-Transport-Security': 'max-age=31536000'
}
}
);
});
// Custom API headers
http.get('/api/data', () => {
return HttpResponse.json(
{ results: [] },
{
headers: {
'X-Total-Count': '0',
'X-Page': '1',
'X-Per-Page': '20',
'X-Rate-Limit-Remaining': '99'
}
}
);
});Handle various HTTP status codes appropriately.
// Success responses
http.get('/api/data', () => {
return HttpResponse.json({ data: 'ok' }); // 200 OK (default)
});
http.post('/api/resource', () => {
return HttpResponse.json(
{ id: 1, created: true },
{ status: 201 } // 201 Created
);
});
http.put('/api/resource/1', () => {
return HttpResponse.json(
{ id: 1, updated: true },
{ status: 200 } // 200 OK for updates
);
});
http.delete('/api/resource/1', () => {
return new HttpResponse(null, { status: 204 }); // 204 No Content
});
// Client error responses
http.get('/api/unauthorized', () => {
return HttpResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
});
http.get('/api/forbidden', () => {
return HttpResponse.json(
{ error: 'Forbidden' },
{ status: 403 }
);
});
http.get('/api/not-found', () => {
return HttpResponse.json(
{ error: 'Not found' },
{ status: 404 }
);
});
http.post('/api/invalid-data', () => {
return HttpResponse.json(
{
error: 'Validation failed',
details: { name: 'Required field' }
},
{ status: 422 }
);
});
// Server error responses
http.get('/api/server-error', () => {
return HttpResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
});
http.get('/api/service-unavailable', () => {
return HttpResponse.json(
{ error: 'Service temporarily unavailable' },
{ status: 503 }
);
});
// Redirect responses
http.get('/api/redirect', () => {
return new HttpResponse(null, {
status: 302,
headers: {
'Location': '/api/new-location'
}
});
});// Response class types
class HttpResponse<BodyType extends DefaultBodyType> extends Response {
readonly [bodyType]: BodyType;
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
static error(): HttpResponse<any>;
static text<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;
static json<T extends JsonBodyType>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;
static xml<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;
static html<T extends string>(body?: T | null, init?: HttpResponseInit): HttpResponse<T>;
static arrayBuffer<T extends ArrayBuffer | SharedArrayBuffer>(body?: T, init?: HttpResponseInit): HttpResponse<T>;
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
}
// Body types
type DefaultBodyType =
| string
| number
| boolean
| null
| undefined
| ArrayBuffer
| Blob
| FormData
| ReadableStream;
type JsonBodyType = Record<string, any> | any[];
// Response initialization
interface HttpResponseInit extends ResponseInit {
status?: number;
statusText?: string;
headers?: HeadersInit;
type?: ResponseType;
}
// Utility types
type NoInfer<T> = [T][T extends any ? 0 : never];
// Symbol for body type tracking
declare const bodyType: unique symbol;