node-request-interceptor
Version:
Low-level HTTP/HTTPS/XHR request interception library for NodeJS
171 lines (116 loc) • 6.22 kB
Markdown
[](https://www.npmjs.com/package/node-request-interceptor)
[](https://app.circleci.com/pipelines/github/mswjs/node-request-interceptor)
# `node-request-interceptor`
Low-level HTTP/HTTPS/XHR request interception library for NodeJS.
**Intercepts any requests issued by:**
- `http.get`/`http.request`
- `https.get`/`https.request`
- `fetch`
- `XMLHttpRequest`
- Any third-party libraries that utilize the modules above (i.e. `request`, `node-fetch`, etc.)
## Motivation
While there are a lot of network communication mocking libraries, they tend to use request interception as an implementation detail, exposing you a high-level API that includes request matching, timeouts, retries, and so forth.
This library is a strip-to-bone implementation that provides as little abstraction as possible to execute arbitrary logic upon any request in NodeJS. It's primarily designed as an underlying component for a high-level API mocking solutions.
### How is this library different?
As interception is often combined with request route matching, some libraries can determine whether a request should be mocked _before_ it actually happens. This approach is not suitable for this library, as it rather _intercepts all requests_ and then let's you decide which ones should be mocked. This affects the level at which interception happens, and also the way mocked/original response is constructed, in comparison to other solutions.
### Why XMLHttpRequest?
Although NodeJS has no `XMLHttpRequest` implementation, this library covers it for the sake of processes that still run in NodeJS, but emulate a browser-like environment (i.e. `jsdom` when running tests in Jest).
## What this library does
This library monkey-patches the following native modules:
- `http.get`/`http.request`
- `https.get`/`https.request`
- `XMLHttpRequest`
Once patched, it provides an interface to execute an arbitrary logic upon any outgoing request using a request middleware function.
- Bypasses all requests by default, so your network channel is not affected.
- Handles an abstract response object returned from the request middleware as an actual response for the occurred request (taking into account the difference in constructing a response for different clients).
## What this library doesn't do
- Does **not** provide any request matching logic.
- Does **not** decide how to handle requests.
- Does **not** run in a browser (although supports `jsdom`).
## Getting started
```bash
npm install node-request-interceptor
```
## API
### `RequestInterceptor(interceptors: Interceptor[])`
```js
import { RequestInterceptor } from 'node-request-interceptor'
import withDefaultInterceptors from 'node-request-interceptor/presets/default'
const interceptor = new RequestInterceptor(withDefaultInterceptors)
```
> Using the `/presets/default` interceptors preset is the recommended way to ensure all requests get intercepted, regardless of their origin.
### Interceptors
This library utilizes a concept of an _interceptor_–a module that performs necessary patching, handles a mocked response, and restores patched instances.
**The list of interceptors:**
- `/interceptors/ClientRequest`
- `/interceptors/XMLHttpRequest`
To use one, or multiple interceptors, import and provide them to the `RequestInterceptor` constructor.
```js
import { RequestInterceptors } from 'node-request-interceptor'
import { interceptXMLHttpRequest } from 'node-request-interceptor/interceptors/XMLHttpRequest'
// This `interceptor` instance would handle only XMLHttpRequest,
// ignoring requests issued via `http`/`https` modules.
const interceptor = new RequestInterceptors([interceptXMLHttpRequest])
```
> Interceptors are crucial in leveraging environment-specific module overrides. Certain environments (i.e. React Native) do not have access to native NodeJS modules (like `http`). Importing such modules raises an exception, and must be avoided.
### Methods
#### `.use(middleware: (req: InterceptedRequest, ref: IncomingMessage | XMLHttpRequest) => MockedResponse): void`
Applies a given middleware function to an intercepted request. May return a [`MockedResponse`](#MockedResponse) object that is going to be used to respond to an intercepted request.
##### Requests monitoring
```js
interceptor.use((req) => {
// Will print to stdout any outgoing requests
// without affecting their responses
console.log('%s %s', req.method, req.url.href)
})
```
##### Response mocking
When a request middleware returns a [`MockedResponse`](#MockedResponse) object, it will be returned as the response to the intercepted request. This library automatically creates a proper response instance according to the request issuing module (`http`/`XMLHttpRequest`).
```js
interceptor.use((req) => {
if (['https://google.com'].includes(req.url.origin)) {
// Will return a mocked response for any request
// that is issued from the "https://google.com" origin.
return {
status: 301,
headers: {
'x-powered-by': 'node-request-interceptor',
},
body: JSON.stringify({
message: 'Hey, I am a mocked response',
}),
}
}
})
```
#### `.restore(): void`
Restores all patched modules and stops the interception of any future requests.
```js
interceptor.restore()
```
---
### `InterceptedRequest`
```ts
interface InterceptedRequest {
url: URL
method: string
headers?: http.OutgoingHttpHeaders
body?: string
}
```
---
### `MockedResponse`
Whenever a `MockedResponse` object is returned from the request middleware function, it's being used to constructs a relevant response for the intercepted request.
```ts
interface MockedResponse {
status?: number
statusText?: string
headers?: Record<string, string | string[]>
body?: string
}
```
## Special mention
The following libraries were used as an inspiration to write this low-level API:
- [`node`](https://github.com/nodejs/node)
- [`nock`](https://github.com/nock/nock)
- [`mock-xmlhttprequest`](https://github.com/berniegp/mock-xmlhttprequest)