In-Process HTTP Request Executor

raw JSON →
0.3.1 verified Thu Apr 23 auth: no javascript

in-process-request is a lightweight Node.js library designed to execute HTTP handler functions directly within the current process, bypassing the need to start and manage a local HTTP server. This makes it ideal for integration testing of API routes or for internal service-to-service communication within the same application without network overhead. The library provides a unified interface for interacting with handlers from popular web frameworks including Express.js (v3, v4, v5), Koa (v2), Hapi (v19, v20), NestJS (v7), Fastify (v3), Connect (v3), Polka, and Apollo Server (v2, v3). Its current stable version is 0.3.1, with releases typically focusing on bug fixes, dependency updates, and ensuring compatibility with newer versions of supported frameworks. It differentiates itself by offering a robust mocking layer for HTTP requests and responses, allowing for precise control over the input and examination of the output.

error Error: The 'path' property is mandatory in requestOptions.
cause The `path` property was omitted or provided as an empty string in the `requestOptions` object passed to the handler.
fix
Ensure that requestOptions includes a non-empty path string, e.g., handler({ path: '/api/resource', method: 'GET' }).
error TypeError: app.callback is not a function
cause When integrating with Koa.js, the `inProcessRequest` function expects the raw request listener, not the Koa application instance itself.
fix
Pass koaApp.callback() to inProcessRequest, not koaApp. Correct usage: const handler = inProcessRequest(koaApp.callback());
error TypeError: listener is not an instance of Server
cause When integrating with Hapi, the Hapi server needs a specific custom listener provided by `in-process-request` to expose its request handler.
fix
Use the HapiListener helper class. Create an instance of HapiListener, pass it to Hapi.server({ listener: myListener }), and then use myListener.handler with inProcessRequest. Example: const myListener = new HapiListener(); const server = Hapi.server({ listener: myListener }); const handler = inProcessRequest(myListener.handler);
gotcha Ensure the target web framework version is explicitly supported by `in-process-request`. While the library aims for broad compatibility, changes in framework internals can lead to unexpected behavior or require updates. Refer to the package's README for the list of officially tested and supported framework versions.
fix Check the `in-process-request` README for specific framework version compatibility. Upgrade `in-process-request` or adjust your framework version if conflicts arise.
gotcha The `requestOptions.path` property is mandatory for every request. Omitting or providing an empty string for `path` will result in an error, as the library cannot determine which route to match.
fix Always provide a valid non-empty `path` string in the `requestOptions` object, e.g., `{ path: '/my-endpoint?query=value' }`.
gotcha The request and response objects provided to and returned from the handler are mocks, not actual `http.IncomingMessage` and `http.ServerResponse` instances. While they replicate essential properties and methods, deep reliance on specific Node.js HTTP stream or socket properties that are not explicitly mocked may lead to issues.
fix Limit interactions with the request and response objects to standard HTTP methods, headers, body, and status codes. Avoid relying on low-level `socket` properties or stream events unless explicitly documented as supported by `in-process-request`'s mocks.
npm install in-process-request
yarn add in-process-request
pnpm add in-process-request

This quickstart demonstrates how to set up an Express.js application and use `in-process-request` to execute both GET and POST requests against its handler, capturing the response details.

import inProcessRequest from 'in-process-request';
import express from 'express';

// Create a basic Express application
const myApp = express();
myApp.use(express.json()); // Enable JSON body parsing

myApp.get('/api/test', (req, res) => {
  res.json({ message: 'Hello from API!', query: req.query });
});

myApp.post('/api/data', (req, res) => {
  if (!req.body || Object.keys(req.body).length === 0) {
    return res.status(400).json({ error: 'Request body is empty' });
  }
  res.status(201).json({ received: req.body, timestamp: new Date().toISOString() });
});

// Create an in-process handler for the Express app
const myAppHandler = inProcessRequest(myApp);

async function runTests() {
  // Test a GET request
  const getResponse = await myAppHandler({
    path: '/api/test?param1=value1&param2=value2',
    method: 'GET',
    headers: { 'Accept': 'application/json' }
  });

  console.log('--- GET Request Result ---');
  console.log('Status Code:', getResponse.statusCode);
  if (getResponse.isUTF8) {
    const body = getResponse.body.toString('utf8');
    console.log('Body:', body);
    console.log('Parsed JSON:', JSON.parse(body));
  }

  // Test a POST request with a JSON body
  const postResponse = await myAppHandler({
    path: '/api/data',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ item: 'sample', quantity: 10 })
  });

  console.log('\n--- POST Request Result ---');
  console.log('Status Code:', postResponse.statusCode);
  if (postResponse.isUTF8) {
    const body = postResponse.body.toString('utf8');
    console.log('Body:', body);
    console.log('Parsed JSON:', JSON.parse(body));
  }
}

runTests();