Using bodies
Bodies are used to send data in a request and receive data in a response. Request bodies are commonly used to include a payload of data that the server will process, whereas response bodies may contain the result returned by the server. A body can contain various types of data, such as JSON, XML, and binary data such as images and files.
@zimic/interceptor
automatically parses request and response bodies based on their content-type
header.
content-type | Default parsed type |
---|---|
application/json | JSON |
application/xml | String |
application/x-www-form-urlencoded | HttpSearchParams |
application/* (others) | Blob |
multipart/form-data | HttpFormData |
multipart/* (others) | Blob |
text/* | String |
image/* | Blob |
audio/* | Blob |
font/* | Blob |
video/* | Blob |
*/* (others) | JSON if possible, otherwise String |
Using request bodies
Request bodies can be declared in your schema using the request.body
property.
Then, they will be available in the body
property, such as in
handler.with()
,
computed responses, and
handler.requests
.
JSON request body
JSON bodies are one of the most common ways to send data in requests. To use a JSON body in a request, declare its type in your schema.
import { HttpSchema } from '@zimic/http';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
POST: {
request: {
body: { username: string };
};
response: {
201: { body: User };
};
};
};
}>;
- Local interceptor
- Remote interceptor
interceptor
.post('/users')
.with({
body: { username: 'me' },
})
.respond({
status: 201,
body: user,
})
.times(1);
await interceptor
.post('/users')
.with({
body: { username: 'me' },
})
.respond({
status: 201,
body: user,
})
.times(1);
content-type
header inference@zimic/http
automatically infers the type of the content-type
header as application/json
if the request body is a
JSON type. You can override this behavior by explicitly setting a different type in your schema.
type Schema = HttpSchema<{
'/users': {
POST: {
request: {
headers: {
'content-type': 'application/json; charset=utf-8';
};
body: { username: string };
};
response: {
201: { body: User };
};
};
};
}>;
FormData
request body
FormData
is a special type of body to construct a set of
key-value pairs with variable types of data. A common use case is to upload files to a server.
To send a FormData
body, declare its type in your schema. Use the
HttpFormData
to indicate that the body is a FormData
type.
import { HttpFormData, HttpSchema } from '@zimic/http';
interface AvatarFormDataSchema {
image: File;
}
type Schema = HttpSchema<{
'/users/:userId/avatar': {
PUT: {
request: {
headers?: { 'content-type'?: 'multipart/form-data' };
body: HttpFormData<AvatarFormDataSchema>;
};
response: {
200: { body: { url: string } };
};
};
};
}>;
- Local interceptor
- Remote interceptor
import { HttpFormData } from '@zimic/http';
// Getting an uploaded file from an input element
const imageInput = document.querySelector<HTMLInputElement>('input[type="file"]');
const imageFile = imageInput!.files![0];
const formData = new HttpFormData<AvatarFormDataSchema>();
formData.append('image', imageFile);
interceptor
.post('/users')
.with({
body: formData,
})
.respond({
status: 201,
body: { url: `https://example.com/${user.id}/avatar.png` },
})
.times(1);
import { HttpFormData } from '@zimic/http';
// Getting an uploaded file from an input element
const imageInput = document.querySelector<HTMLInputElement>('input[type="file"]');
const imageFile = imageInput!.files![0];
const formData = new HttpFormData<AvatarFormDataSchema>();
formData.append('image', imageFile);
await interceptor
.post('/users')
.with({
body: formData,
})
.respond({
status: 201,
body: { url: `https://example.com/${user.id}/avatar.png` },
})
.times(1);
Binary request body
Binary bodies are used to send raw binary data in requests. To send a binary body, declare its type in your
schema. Blob
,
ArrayBuffer
, and
ReadableStream
are frequently used types for binary data.
import { HttpSchema } from '@zimic/http';
interface Video {
id: string;
url: string;
}
type Schema = HttpSchema<{
'/upload': {
POST: {
request: {
headers?: { 'content-type'?: string };
body: Blob;
};
};
response: {
201: { body: Video };
};
};
}>;
- Local interceptor
- Remote interceptor
import fs from 'fs';
// Getting a file from the file system
const videoBuffer = await fs.promises.readFile('video.mp4');
const videoFile = new File([videoBuffer], 'video.mp4');
interceptor
.post('/upload')
.with({
body: videoFile,
})
.respond({
status: 201,
body: video,
})
.times(1);
import fs from 'fs';
// Getting a file from the file system
const videoBuffer = await fs.promises.readFile('video.mp4');
const videoFile = new File([videoBuffer], 'video.mp4');
await interceptor
.post('/upload')
.with({
body: videoFile,
})
.respond({
status: 201,
body: video,
})
.times(1);
Plain-text request body
Plain-text bodies can be declared as a string.
import { HttpSchema } from '@zimic/http';
type Schema = HttpSchema<{
'/content': {
POST: {
request: {
body: string;
};
response: {
201: {};
};
};
};
}>;
- Local interceptor
- Remote interceptor
interceptor
.post('/context')
.with({
body: 'text',
})
.respond({
status: 201,
})
.times(1);
await interceptor
.post('/context')
.with({
body: 'text',
})
.respond({
status: 201,
})
.times(1);
URL-encoded request body
Bodies with URL-encoded data can be declared with HttpSearchParams
.
import { HttpSchema, HttpSearchParams } from '@zimic/http';
interface UserCreationSearchParams {
username: string;
}
type Schema = HttpSchema<{
'/users': {
POST: {
request: {
headers?: { 'content-type'?: 'application/x-www-form-urlencoded' };
body: HttpSearchParams<UserCreationSearchParams>;
};
};
};
}>;
- Local interceptor
- Remote interceptor
import { HttpSearchParams } from '@zimic/http';
const searchParams = new HttpSearchParams<UserCreationSearchParams>({
username: 'me',
});
interceptor
.post('/users')
.with({
body: searchParams,
})
.respond({
status: 201,
body: user,
})
.times(1);
import { HttpSearchParams } from '@zimic/http';
const searchParams = new HttpSearchParams<UserCreationSearchParams>({
username: 'me',
});
await interceptor
.post('/users')
.with({
body: searchParams,
})
.respond({
status: 201,
body: user,
})
.times(1);
Using response bodies
Response bodies are declared in your schema using the response.<status>.body
property.
Then, they will be available in the body
property, such as in
handler.respond()
.
JSON response body
To use a JSON response body, declare its type in your schema.
import { HttpSchema } from '@zimic/http';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
response: {
200: {
body: User[];
};
};
};
};
}>;
- Local interceptor
- Remote interceptor
interceptor
.get('/users')
.respond({
status: 200,
body: users,
})
.times(1);
await interceptor
.get('/users')
.respond({
status: 200,
body: users,
})
.times(1);
FormData
response body
To use a FormData
response body, declare its type in your schema using the
HttpFormData
.
import { HttpFormData, HttpSchema } from '@zimic/http';
interface AvatarFormDataSchema {
image: File;
}
type Schema = HttpSchema<{
'/users/:userId/avatar': {
GET: {
response: {
200: {
headers?: { 'content-type'?: 'multipart/form-data' };
body: HttpFormData<AvatarFormDataSchema>;
};
};
};
};
}>;
- Local interceptor
- Remote interceptor
import { HttpFormData } from '@zimic/http';
const formData = new HttpFormData<AvatarFormDataSchema>();
formData.append('image', new File([''], 'avatar.png'));
interceptor
.get(`/users/${user.id}/avatar`)
.respond({
status: 200,
body: formData,
})
.times(1);
import { HttpFormData } from '@zimic/http';
const formData = new HttpFormData<AvatarFormDataSchema>();
formData.append('image', new File([''], 'avatar.png'));
await interceptor
.get(`/users/${user.id}/avatar`)
.respond({
status: 200,
body: formData,
})
.times(1);
Binary response body
Binary response bodies can be declared with types such as Blob
,
ArrayBuffer
, and
ReadableStream
.
import { HttpSchema } from '@zimic/http';
interface Video {
id: string;
url: string;
}
type Schema = HttpSchema<{
'/videos/:videoId': {
GET: {
response: {
200: {
headers?: { 'content-type'?: string };
body: Blob;
};
};
};
};
}>;
- Local interceptor
- Remote interceptor
import fs from 'fs';
import { HttpFormData } from '@zimic/http';
// Getting a file from the file system
const videoBuffer = await fs.promises.readFile('video.mp4');
const videoFile = new Blob([videoBuffer], { type: 'video/mp4' });
interceptor
.get(`/videos/${video.id}`)
.respond({
status: 200,
body: videoFile,
})
.times(1);
import fs from 'fs';
import { HttpFormData } from '@zimic/http';
// Getting a file from the file system
const videoBuffer = await fs.promises.readFile('video.mp4');
const videoFile = new Blob([videoBuffer], { type: 'video/mp4' });
await interceptor
.get(`/videos/${video.id}`)
.respond({
status: 200,
body: videoFile,
})
.times(1);
Plain-text response body
Plain-text response bodies can be declared as a string.
import { HttpSchema } from '@zimic/http';
type Schema = HttpSchema<{
'/content': {
GET: {
response: {
200: {
body: string;
};
};
};
};
}>;
- Local interceptor
- Remote interceptor
interceptor
.get('/content')
.respond({
status: 200,
body: 'text',
})
.times(1);
await interceptor
.get('/content')
.respond({
status: 200,
body: 'text',
})
.times(1);
URL-encoded response body
URL-encoded response bodies can be declared with HttpSearchParams
.
import { HttpSchema, HttpSearchParams } from '@zimic/http';
interface UserCreationSearchParams {
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
response: {
200: {
headers?: { 'content-type'?: 'application/x-www-form-urlencoded' };
body: HttpSearchParams<UserCreationSearchParams>;
};
};
};
};
}>;
- Local interceptor
- Remote interceptor
import { HttpSearchParams } from '@zimic/http';
const searchParams = new HttpSearchParams<UserCreationSearchParams>({
username: 'me',
});
interceptor
.get('/users')
.respond({
status: 200,
body: searchParams,
})
.times(1);
import { HttpSearchParams } from '@zimic/http';
const searchParams = new HttpSearchParams<UserCreationSearchParams>({
username: 'me',
});
await interceptor
.get('/users')
.respond({
status: 200,
body: searchParams,
})
.times(1);