{"id":13456297,"url":"https://github.com/fastify/light-my-request","last_synced_at":"2025-05-14T00:05:53.474Z","repository":{"id":25679800,"uuid":"105076677","full_name":"fastify/light-my-request","owner":"fastify","description":"Fake HTTP injection library","archived":false,"fork":false,"pushed_at":"2025-05-01T19:08:44.000Z","size":586,"stargazers_count":392,"open_issues_count":11,"forks_count":49,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-05-12T19:46:42.578Z","etag":null,"topics":["fastify-library","http","injection","nodejs"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/light-my-request","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fastify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"fastify","open_collective":"fastify"}},"created_at":"2017-09-27T22:40:55.000Z","updated_at":"2025-05-11T03:45:37.000Z","dependencies_parsed_at":"2024-03-07T11:48:44.548Z","dependency_job_id":"a1f5b12e-0a7d-4de8-b2d2-d1c18aef1935","html_url":"https://github.com/fastify/light-my-request","commit_stats":{"total_commits":504,"total_committers":79,"mean_commits":6.379746835443038,"dds":0.8452380952380952,"last_synced_commit":"b8201068c3b07d5eaa5b7afbf71ad351dfa47dd2"},"previous_names":[],"tags_count":75,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Flight-my-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Flight-my-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Flight-my-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Flight-my-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastify","download_url":"https://codeload.github.com/fastify/light-my-request/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254043418,"owners_count":22004949,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastify-library","http","injection","nodejs"],"created_at":"2024-07-31T08:01:19.444Z","updated_at":"2025-05-14T00:05:53.386Z","avatar_url":"https://github.com/fastify.png","language":"JavaScript","readme":"# Light my Request\n\n[![CI](https://github.com/fastify/light-my-request/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/light-my-request/actions/workflows/ci.yml)\n[![NPM version](https://img.shields.io/npm/v/light-my-request.svg?style=flat)](https://www.npmjs.com/package/light-my-request)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\nInjects a fake HTTP request/response into a node HTTP server for simulating server logic, writing tests, or debugging.\nDoes not use a socket connection so can be run against an inactive server (server not in listen mode).\n\n## Example\n\n```javascript\nconst http = require('node:http')\nconst inject = require('light-my-request')\n\nconst dispatch = function (req, res) {\n  const reply = 'Hello World'\n  res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': reply.length })\n  res.end(reply)\n}\n\nconst server = http.createServer(dispatch)\n\ninject(dispatch, { method: 'get', url: '/' }, (err, res) =\u003e {\n  console.log(res.payload)\n})\n```\nNote how `server.listen` is never called.\n\nAsync await and promises are supported as well!\n```javascript\n// promises\ninject(dispatch, { method: 'get', url: '/' })\n  .then(res =\u003e console.log(res.payload))\n  .catch(console.log)\n\n// async-await\ntry {\n  const res = await inject(dispatch, { method: 'get', url: '/' })\n  console.log(res.payload)\n} catch (err) {\n  console.log(err)\n}\n```\n\nYou can also use chaining methods if you do not pass the callback function. Check [here](#method-chaining) for details.\n\n```js\n// chaining methods\ninject(dispatch)\n  .get('/')                   // set the request method to GET, and request URL to '/'\n  .headers({ foo: 'bar' })    // set the request headers\n  .query({ foo: 'bar' })      // set the query parameters\n  .end((err, res) =\u003e {\n    console.log(res.payload)\n  })\n\ninject(dispatch)\n  .post('/')                  // set the request method to POST, and request URL to '/'\n  .payload('request payload') // set the request payload\n  .body('request body')       // alias for payload\n  .end((err, res) =\u003e {\n    console.log(res.payload)\n  })\n\n// async-await is also supported\ntry {\n  const chain = inject(dispatch).get('/')\n  const res = await chain.end()\n  console.log(res.payload)\n} catch (err) {\n  console.log(err)\n}\n```\n\nFile uploads (`multipart/form-data`) or form submit (`x-www-form-urlencoded`) can be achieved by using [form-auto-content](https://github.com/Eomm/form-auto-content) package as shown below:\n\n```js\nconst formAutoContent = require('form-auto-content')\nconst fs = require('node:fs')\n\ntry {\n  const form = formAutoContent({\n    myField: 'hello',\n    myFile: fs.createReadStream(`./path/to/file`)\n  })\n\n  const res = await inject(dispatch, {\n    method: 'post',\n    url: '/upload',\n    ...form\n  })\n  console.log(res.payload)\n} catch (err) {\n  console.log(err)\n}\n```\n\nThis module ships with a handwritten TypeScript declaration file for TS support. The declaration exports a single namespace `LightMyRequest`. You can import it one of two ways:\n```typescript\nimport * as LightMyRequest from 'light-my-request'\n\nconst dispatch: LightMyRequest.DispatchFunc = function (req, res) {\n  const reply = 'Hello World'\n  res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': reply.length })\n  res.end(reply)\n}\n\nLightMyRequest.inject(dispatch, { method: 'get', url: '/' }, (err, res) =\u003e {\n  console.log(res.payload)\n})\n\n// or\nimport { inject, DispatchFunc } from 'light-my-request'\n\nconst dispatch: DispatchFunc = function (req, res) {\n  const reply = 'Hello World'\n  res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': reply.length })\n  res.end(reply)\n}\n\ninject(dispatch, { method: 'get', url: '/' }, (err, res) =\u003e {\n  console.log(res.payload)\n})\n```\nThe declaration file exports types for the following parts of the API:\n- `inject` - standard light-my-request `inject` method\n- `DispatchFunc` - the fake HTTP dispatch function\n- `InjectPayload` - a union type for valid payload types\n- `isInjection` - standard light-my-request `isInjection` method\n- `InjectOptions` - options object for `inject` method\n- `Request` - custom light-my-request `request` object interface. Extends\n  Node.js `stream.Readable` type by default. This behavior can be changed by\n  setting the `Request` option in the `inject` method's options\n- `Response` - custom light-my-request `response` object interface. Extends Node.js `http.ServerResponse` type\n\n## API\n\n#### `inject(dispatchFunc[, options, callback])`\n\nInjects a fake request into an HTTP server.\n\n- `dispatchFunc` - listener function. The same as you would pass to `Http.createServer` when making a node HTTP server. Has the signature `function (req, res)` where:\n    - `req` - a simulated request object. Inherits from `Stream.Readable` by\n      default. Optionally inherits from another class, set in\n      `options.Request`\n    - `res` - a simulated response object. Inherits from node's `Http.ServerResponse`.\n- `options` - request options object where:\n  - `url` | `path` - a string specifying the request URL.\n  - `method` - a string specifying the HTTP request method, defaulting to `'GET'`.\n  - `authority` - a string specifying the HTTP HOST header value to be used if no header is provided, and the `url`\n    does not include an authority component. Defaults to `'localhost'`.\n  - `headers` - an optional object containing request headers.\n  - `cookies` - an optional object containing key-value pairs that will be encoded and added to `cookie` header. If the header is already set, the data will be appended.\n  - `remoteAddress` - an optional string specifying the client remote address. Defaults to `'127.0.0.1'`.\n  - `payload` - an optional request payload. Can be a string, Buffer, Stream, or object. If the payload is string, Buffer or Stream is used as is as the request payload. Otherwise, it is serialized with `JSON.stringify` forcing the request to have the `Content-type` equal to `application/json`\n  - `query` - an optional object or string containing query parameters.\n  - `body` - alias for payload.\n  - `simulate` - an object containing flags to simulate various conditions:\n    - `end` - indicates whether the request will fire an `end` event. Defaults to `undefined`, meaning an `end` event will fire.\n    - `split` - indicates whether the request payload will be split into chunks. Defaults to `undefined`, meaning payload will not be chunked.\n    - `error` - whether the request will emit an `error` event. Defaults to `undefined`, meaning no `error` event will be emitted. If set to `true`, the emitted error will have a message of `'Simulated'`.\n    - `close` - whether the request will emit a `close` event. Defaults to `undefined`, meaning no `close` event will be emitted.\n  - `validate` - Optional flag to validate this options object. Defaults to `true`.\n  - `server` - Optional http server. It is used for binding the `dispatchFunc`.\n  - `autoStart` - Automatically start the request as soon as the method\n    is called. It is only valid when not passing a callback. Defaults to `true`.\n  - `signal` - An `AbortSignal` that may be used to abort an ongoing request. Requires Node v16+.\n  - `Request` - Optional type from which the `request` object should inherit\n    instead of `stream.Readable`\n  - `payloadAsStream` - if set to `true`, the response will be streamed and not accumulated; in this case `res.payload`, `res.rawPayload` will be undefined.\n- `callback` - the callback function using the signature `function (err, res)` where:\n  - `err` - error object\n  - `res` - a response object where:\n    - `raw` - an object containing the raw request and response objects where:\n      - `req` - the simulated request object.\n      - `res` - the simulated response object.\n    - `headers` - an object containing the response headers.\n    - `statusCode` - the HTTP status code.\n    - `statusMessage` - the HTTP status message.\n    - `payload` - the payload as a UTF-8 encoded string.\n    - `body` - alias for payload.\n    - `rawPayload` - the raw payload as a Buffer.\n    - `trailers` - an object containing the response trailers.\n    - `json` - a function that parses a json response payload and returns an object.\n    - `stream` - a function that provides a `Readable` stream of the response payload.\n    - `cookies` - a getter that parses the `set-cookie` response header and returns an array with all the cookies and their metadata.\n\nNotes:\n\n- You can also pass a string in place of the `options` object as a shorthand\n  for `{url: string, method: 'GET'}`.\n- Beware when using the `Request` option. That might make _light-my-request_\n  slower. Sample benchmark result run on an i5-8600K CPU with `Request` set to\n  `http.IncomingMessage`:\n\n```\nRequest x 155,018 ops/sec ±0.47% (94 runs sampled)\nCustom Request x 30,373 ops/sec ±0.64% (90 runs sampled)\nRequest With Cookies x 125,696 ops/sec ±0.29% (96 runs sampled)\nRequest With Cookies n payload x 114,391 ops/sec ±0.33% (97 runs sampled)\nParseUrl x 255,790 ops/sec ±0.23% (99 runs sampled)\nParseUrl and query x 194,479 ops/sec ±0.16% (99 runs sampled)\n```\n\n#### `inject.isInjection(obj)`\n\nChecks if given object `obj` is a *light-my-request* `Request` object.\n\n#### Method chaining\n\nThe following methods can be used in chaining:\n- `delete`, `get`, `head`, `options`, `patch`, `post`, `put`, `trace`. They will set the HTTP request method and the request URL.\n- `body`, `headers`, `payload`, `query`, `cookies`. They can be used to set the request options object.\n\nAnd finally, you need to call `end`. It has the signature `function (callback)`.\nIf you invoke `end` without a callback function, the method will return a promise, thus you can:\n\n```js\nconst chain = inject(dispatch).get('/')\n\ntry {\n  const res = await chain.end()\n  console.log(res.payload)\n} catch (err) {\n  // handle error\n}\n\n// or\nchain.end()\n  .then(res =\u003e {\n    console.log(res.payload)\n  })\n  .catch(err =\u003e {\n    // handle error\n  })\n```\n\nBy the way, you can also use promises without calling `end`!\n\n```js\ninject(dispatch)\n  .get('/')\n  .then(res =\u003e {\n    console.log(res.payload)\n  })\n  .catch(err =\u003e {\n    // handle error\n  })\n```\n\nNote: The application would not respond multiple times. If you try to invoke any method after the application has responded, the application would throw an error.\n\n## Acknowledgments\nThis project has been forked from [`hapi/shot`](https://github.com/hapijs/shot) because we wanted to support *Node ≥ v4* and not only *Node ≥ v8*.\nAll credits prior to commit [00a2a82](https://github.com/fastify/light-my-request/commit/00a2a82eb773b765003b6085788cc3564cd08326) go to the `hapi/shot` project [contributors](https://github.com/hapijs/shot/graphs/contributors).\nSince commit [db8bced](https://github.com/fastify/light-my-request/commit/db8bced10b4367731688c8738621d42f39680efc) the project will be maintained by the Fastify team.\n\n## License\n\nLicensed under [BSD-3-Clause](./LICENSE).\n","funding_links":["https://github.com/sponsors/fastify","https://opencollective.com/fastify"],"categories":["JavaScript","Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Flight-my-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastify%2Flight-my-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Flight-my-request/lists"}