in-process-request
Version:
A node.js library that executes a http handler function in the current process without having to start a local http server.
382 lines (307 loc) • 10.3 kB
Markdown
# in-process-request
A node.js library that executes a http handler function in the current process without having to start a local http server.
[](https://travis-ci.org/janaz/in-process-request)
It supports the following frameworks
* Express.js v3
* Express.js v4
* Express.js v5
* Apollo Server v2
* Apollo Server v3
* Hapi v19
* Hapi v20
* NestJS v7
* Connect v3
* Koa v2
* Polka
* Fastify v3
* More to come...
It has been tested with the following node versions
* v10
* v12
* v14
* v15
## Usage
```sh
$ npm install in-process-request
```
```javascript
const inProcessRequest = require('in-process-request');
const handler = inProcessRequest(app);
handler(requestOptions)
.then((response) => {
console.log(response);
// do something with the response
});
```
`requestOptions` is an object with the following properties
* `path` (**mandatory**) - The request path with optional query string, for example `'/my/resource/123?full=true'`
* `method` - request method, the default is `'GET'`
* `body` - request body, `string` or `Buffer`
* `headers` - request headers object, for example: `{'conent-type': 'application/json'}`
* `remoteAddress` - IP address of the client making the request
* `remotePort` - IP port of the client connection
* `ssl` - Set to `true` to pretend that SSL connection is used. Defaults to `false`
`response` is an object with the following properties
* `statusCode` - status code of the response
* `statusMessage` - status message of the response
* `headers` - object with response headers
* `body` - `Buffer` containing the body
* `isUTF8` - set to `true` if the response is a utf-8 string. In that case `response.body.toString()` can be used to extract the utf-8 string
### Express.js example
```javascript
const inProcessRequest = require('in-process-request')
const express = require('express');
const myApp = express();
myApp.get('/test', (req, res) => {
res.json({ok: true, a: req.query.a});
});
const myAppHandler = inProcessRequest(myApp);
const requestOptions = {
path: '/test',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
```
### Koa example
```javascript
const inProcessRequest = require('in-process-request')
const Koa = require('koa');
const serve = require('koa-static');
const mount = require('koa-mount');
const Router = require('koa-router');
const koa = new Koa();
const router = new Router();
router.get('/test', ctx => {
ctx.body = "Hello"
});
koa.use(router.routes());
// koa.callback() returns the requestListener functions
const myApp = koa.callback();
const myAppHandler = inProcessRequest(myApp);
const requestOptions = {
path: '/test',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
```
### Hapi example
In order to get access to the `requestListener` function in Hapi we need to use custom `listener` object. The `in-process-request` module comes with a helper class `HapiListener` that makes it easy. An instance of this class is used as the listener and the `handler` property of that instance provides the request listener function.
```javascript
const inProcessRequest = require('in-process-request')
const Hapi = require('@hapi/hapi');
// create custom listener for Hapi
const myListener = new inProcessRequest.HapiListener()
// Pass the custom listener to Hapi.server
const server = Hapi.server({
listener: myListener
});
server.route({
method: 'GET',
path: '/',
handler: (_request: any, _h: any) => {
return 'Hello World!';
}
});
const waitForServer = async () => {
//wait for the server to initialize
await server.start()
// return the request listener function
return myListener.handler
}
waitForServer().then((myApp) => {
// The server is initialized and we have access to the request handler - myApp
const myAppHandler = inProcessRequest(myApp);
const requestOptions = {
path: '/',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
})
```
### NestJS example
This library provides a handy adapter for retrieving the underlying Express instance, which is needed for using this library to send requests to NestJS app.
```typescript
import inProcessRequest from 'in-process-request'
import { NestFactory } from '@nestjs/core';
import { Module, Get, Controller } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
@Controller()
class AppController {
@Get()
render() {
return { hello: 'world' };
}
}
@Module({
imports: [],
controllers: [AppController],
})
class AppModule {}
const getApp = async () => {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
return await inProcessRequest.nestHandler(app);
}
getApp().then((myApp) => {
// The server is initialized and we have access to the request handler - myApp
const myAppHandler = inProcessRequest(myApp);
const requestOptions = {
path: '/',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
})
```
### Fastify example
This library provides an adapter for retrieving the underlying NodeJS server handler
```javascript
const fastify = require('fastify');
const inProcessRequest = require('in-process-request')
const build = (options) => {
const app = fastify(options)
app.get('/', async (_request, reply) => {
return { hello: 'world' }
})
return app;
}
const fastifyOpts = {logger: false};
inProcessRequest.fastifyHandler(build)(fastifyOpts).then((myApp) => {
// The server is initialized and we have access to the request handler - myApp
const myAppHandler = inProcessRequest(myApp);
const requestOptions = {
path: '/',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
})
```
### Polka example
```javascript
const inProcessRequest = require('in-process-request')
const polka = require('polka');
const myApp = polka();
myApp.get('/test', (req, res) => {
res.json({ok: true, a: req.query.a});
});
const myAppHandler = inProcessRequest(myApp.handler.bind(myApp));
const requestOptions = {
path: '/test',
method: 'GET',
}
myAppHandler(requestOptions).then(response => {
console.log('Body', response.body);
console.log('Headers', response.headers);
console.log('Status Code', response.statusCode);
console.log('Status Message', response.statusMessage);
console.log('Is UTF8 body?', response.isUTF8);
})
```
## Usage in integration tests
### Mocha / Chai
```javascript
const { expect } = require('chai');
const inProcessRequest = require('in-process-request')
const express = require('express');
const app = express();
app.get('/test', (req, res) => {
res.set('X-Hello', 'world');
res.json({ok: true, a: req.query.a})
});
describe('handler', () => {
it('responds with 200, custom header and query param in JSON body', () => {
const reqOptions = {
path: '/test?a=xyz',
method: 'GET',
}
return inProcessRequest(app)(reqOptions).then(response => {
const json = JSON.parse(response.body.toString())
expect(json).to.deep.equal({ok: true, a: 'xyz'});
expect(response.headers['x-hello']).to.equal('world');
expect(response.statusCode).to.equal(200);
expect(response.isUTF8).to.be.true;
});
});
it('responds with 200, custom header and query param in JSON body', (done) => {
const reqOptions = {
path: '/test?a=xyz',
method: 'GET',
}
inProcessRequest(app)(reqOptions).then(response => {
const json = JSON.parse(response.body.toString())
expect(json).to.deep.equal({ok: true, a: 'xyz'});
expect(response.headers['x-hello']).to.equal('world');
expect(response.statusCode).to.equal(200);
expect(response.isUTF8).to.be.true;
done();
});
});
})
```
### Jest
```javascript
const inProcessRequest = require('in-process-request')
const express = require('express');
const app = express();
app.get('/test', (req, res) => {
res.set('X-Hello', 'world');
res.json({ok: true, a: req.query.a})
});
describe('handler', () => {
it('responds with 200, custom header and query param in JSON body', () => {
const reqOptions = {
path: '/test?a=xyz',
method: 'GET',
}
return inProcessRequest(app)(reqOptions).then(response => {
const json = JSON.parse(response.body.toString())
expect(json).toEqual({ok: true, a: 'xyz'});
expect(response.headers['x-hello']).toEequal('world');
expect(response.statusCode).toEequal(200);
expect(response.isUTF8).to.be.true;
});
});
it('responds with 200, custom header and query param in JSON body', (done) => {
const reqOptions = {
path: '/test?a=xyz',
method: 'GET',
}
inProcessRequest(app)(reqOptions).then(response => {
const json = JSON.parse(response.body.toString())
expect(json).toEqual({ok: true, a: 'xyz'});
expect(response.headers['x-hello']).toEequal('world');
expect(response.statusCode).toEequal(200);
expect(response.isUTF8).toBeTrue();
done();
});
});
})
```