{"id":18011260,"url":"https://github.com/cabinjs/parse-request","last_synced_at":"2025-03-26T15:32:42.397Z","repository":{"id":33953766,"uuid":"138442213","full_name":"cabinjs/parse-request","owner":"cabinjs","description":"Parse requests in the Browser and Node (with added support for multer and passport). Made for Cabin.","archived":false,"fork":false,"pushed_at":"2024-06-25T19:05:20.000Z","size":970,"stargazers_count":9,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-09-28T03:52:37.018Z","etag":null,"topics":["arraybuffer","buffer","express","javascript","koa","logger","logging","middleware","multer","node","parse","parser","passport","req","request","requests","route","stream","utility"],"latest_commit_sha":null,"homepage":"https://cabinjs.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cabinjs.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}},"created_at":"2018-06-24T00:23:36.000Z","updated_at":"2024-06-25T19:05:23.000Z","dependencies_parsed_at":"2024-06-18T18:35:33.968Z","dependency_job_id":"cbd6e4f9-3f29-4ef8-aedc-6ba0d637718e","html_url":"https://github.com/cabinjs/parse-request","commit_stats":{"total_commits":104,"total_committers":4,"mean_commits":26.0,"dds":"0.28846153846153844","last_synced_commit":"1eb47ddd2cb019fb4c9546a4f345539d4b117e01"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabinjs%2Fparse-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabinjs%2Fparse-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabinjs%2Fparse-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cabinjs%2Fparse-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cabinjs","download_url":"https://codeload.github.com/cabinjs/parse-request/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222155809,"owners_count":16940424,"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":["arraybuffer","buffer","express","javascript","koa","logger","logging","middleware","multer","node","parse","parser","passport","req","request","requests","route","stream","utility"],"created_at":"2024-10-30T03:08:37.031Z","updated_at":"2024-10-30T03:08:37.700Z","avatar_url":"https://github.com/cabinjs.png","language":"JavaScript","readme":"# parse-request\n\n[![build status](https://github.com/cabinjs/parse-request/actions/workflows/ci.yml/badge.svg)](https://github.com/cabinjs/parse-request/actions/workflows/ci.yml)\n[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)\n[![license](https://img.shields.io/github/license/cabinjs/parse-request.svg)](LICENSE)\n\n\u003e Parse requests in the Browser and Node (with added support for [multer][] and [passport][]). Made for [Cabin][].\n\n\n## Table of Contents\n\n* [Install](#install)\n* [How does it work](#how-does-it-work)\n  * [Credit Card Masking](#credit-card-masking)\n  * [Sensitive Field Names Automatically Masked](#sensitive-field-names-automatically-masked)\n  * [Sensitive Header Names Automatically Masked](#sensitive-header-names-automatically-masked)\n* [Usage](#usage)\n  * [VanillaJS](#vanillajs)\n  * [Koa](#koa)\n  * [Express](#express)\n* [Contributors](#contributors)\n* [License](#license)\n\n\n## Install\n\n[npm][]:\n\n```sh\nnpm install parse-request\n```\n\n\n## How does it work\n\n\u003e **This package is used internally by Cabin's middleware, and we highly recommend you to simply use [Cabin][] instead of this package in particular.**\n\nThis package exports a function that accepts an Object `options` argument:\n\n* `options` (Object) - a configuration object\n  * `req` (Object) - an Express/Connect request object (defaults to `false`) (you must either pass this option or `ctx` option, but not both)\n  * `ctx` (Object) - a Koa context object (defaults to `false`) (you must either pass this option or `req` option, but not both)\n  * `responseHeaders` (String or Object) - we highly recommend that you pass `res._headers` (see [Cabin][]'s middleware logic if you need an example of this)\n  * `userFields` (Array) - defaults to `[ 'id', 'email', 'full_name', 'ip_address' ]`, list of fields to cherry-pick from the user object parsed out of `req.user`\n  * `sanitizeFields` (Array) - defaults to the list of Strings provided under [Sensitive Field Names Automatically Masked](#sensitive-field-names-automatically-masked) below\n  * `sanitizeHeaders` (Array) - defaults to the list of Strings provided under [Sensitive Header Names Automatically Masked](#sensitive-header-names-automatically-masked) below (case insensitive)\n  * `maskCreditCards` (Boolean) - defaults to `true`, and specifies whether or not credit card numbers are masked\n  * `maskBuffers` (Boolean) - defaults to `true`, and will rewrite `Buffer`'s, `ArrayBuffer`'s, and `SharedArrayBuffer`'s recursively as an object of `{ type: \u003cString\u003e, byteLength: \u003cNumber\u003e }`.  Note that this will save you on disk log storage size as logs will not output verbose stringified buffers – e.g. imagine a 10MB file image upload sent across the request body as a Buffer!)\n  * `maskStreams` (Boolean) - defauls to `true`, and will rewrite `Stream`'s to `{ type: 'Stream' }` (this is useful for those using multer v2.x (streams version), or those that have streams in `req.body`, `req.file`, or `req.files`)\n  * `checkId` (Boolean) - defaults to `true`, and prevents Strings that closely resemble primary key ID's from being masked (e.g. properties named `_id`, `id`, `ID`, `product_id`, `product-id`, `productId`, `productID`, and `product[id]` won't get masked or show as a false-positive for a credit card check)\n  * `checkCuid` (Boolean) - defaults to `true`, and prevents [cuid][] values from being masked\n  * `checkObjectId` (Boolean) - defaults to `true`, and prevents [MongoDB BSON ObjectId][bson-objectid] from being masked\n  * `checkUUID` (Boolean) - defaults to `true`, and prevents [uuid][] values from being masked\n  * `rfdc` (Object) - defaults to `{ proto: false, circles: false }` (you should not need to customize this, but if necessary refer to [rfdc][] documentation)\n  * `parseBody` (Boolean) - defaults to `true`, if you set to `false` we will not parse nor clone the request `body` property (this overrides all other parsing settings related)\n  * `parseQuery` (Boolean) - defaults to `true`, if you set to `false` we will not parse nor clone the request `query` property (this overrides all other parsing settings related)\n  * `parseFiles` (Boolean) - defaults to `true`, if you set to `false` we will not parse nor clone the request `file` nor `files` properties (this overrides all other parsing settings related)\n\nIt automatically detects whether the request is from the Browser, Koa, or Express, and returns a parsed object with populated properties.\n\nHere's an example object parsed:\n\n```js\n{\n  \"id\": \"5d126d86160cea56950f80a9\",\n  \"timestamp\": \"2019-06-25T18:52:54.000Z\",\n  \"is_http\": true,\n  \"request\": {\n    \"method\": \"POST\",\n    \"query\": {\n      \"foo\": \"bar\",\n      \"beep\": \"boop\"\n    },\n    \"headers\": {\n      \"host\": \"127.0.0.1:59746\",\n      \"accept-encoding\": \"gzip, deflate\",\n      \"user-agent\": \"node-superagent/3.8.3\",\n      \"authorization\": \"Basic ********************\",\n      \"accept\": \"application/json\",\n      \"cookie\": \"foo=bar;beep=boop\",\n      \"content-type\": \"multipart/form-data; boundary=--------------------------104476455118209968089794\",\n      \"content-length\": \"1599\",\n      \"connection\": \"close\"\n    },\n    \"cookies\": {\n      \"foo\": \"bar\",\n      \"beep\": \"boop\"\n    },\n    \"url\": \"/?foo=bar\u0026beep=boop\",\n    \"body\": \"{\\\"product_id\\\":\\\"5d0350ef2ca74d11ee6e4f00\\\",\\\"name\\\":\\\"nifty\\\",\\\"surname\\\":\\\"lettuce\\\",\\\"bank_account_number\\\":\\\"1234567890\\\",\\\"card\\\":{\\\"number\\\":\\\"****-****-****-****\\\"},\\\"stripe_token\\\":\\\"***************\\\",\\\"favorite_color\\\":\\\"green\\\"}\",\n    \"timestamp\": \"2019-06-25T18:52:54.589Z\",\n    \"id\": \"fbbce5d4-02d9-4a81-9a70-909631317e7d\",\n    \"http_version\": \"1.1\",\n    \"files\": \"{\\\"avatar\\\":[{\\\"fieldname\\\":\\\"avatar\\\",\\\"originalname\\\":\\\"avatar.png\\\",\\\"encoding\\\":\\\"7bit\\\",\\\"mimetype\\\":\\\"image/png\\\",\\\"buffer\\\":{\\\"type\\\":\\\"Buffer\\\",\\\"byteLength\\\":216},\\\"size\\\":216}],\\\"boop\\\":[{\\\"fieldname\\\":\\\"boop\\\",\\\"originalname\\\":\\\"boop-1.txt\\\",\\\"encoding\\\":\\\"7bit\\\",\\\"mimetype\\\":\\\"text/plain\\\",\\\"buffer\\\":{\\\"type\\\":\\\"Buffer\\\",\\\"byteLength\\\":7},\\\"size\\\":7},{\\\"fieldname\\\":\\\"boop\\\",\\\"originalname\\\":\\\"boop-2.txt\\\",\\\"encoding\\\":\\\"7bit\\\",\\\"mimetype\\\":\\\"text/plain\\\",\\\"buffer\\\":{\\\"type\\\":\\\"Buffer\\\",\\\"byteLength\\\":7},\\\"size\\\":7}]}\"\n  },\n  \"user\": {\n    \"ip_address\": \"::ffff:127.0.0.1\"\n  },\n  \"response\": {\n    \"headers\": {\n      \"x-powered-by\": \"Express\",\n      \"x-request-id\": \"fbbce5d4-02d9-4a81-9a70-909631317e7d\",\n      \"content-security-policy\": \"default-src 'none'\",\n      \"x-content-type-options\": \"nosniff\",\n      \"content-type\": \"text/html; charset=utf-8\",\n      \"content-length\": \"1213\",\n      \"x-response-time\": \"48.658ms\",\n      \"date\": \"Tue, 25 Jun 2019 18:52:54 GMT\",\n      \"connection\": \"close\"\n    },\n    \"http_version\": \"1.1\",\n    \"status_code\": 200,\n    \"reason_phrase\": \"OK\",\n    \"timestamp\": \"2019-06-25T18:52:54.000Z\",\n    \"duration\": 48.658\n  },\n  \"duration\": 1.350323,\n  \"app\": {\n    \"name\": \"parse-request\",\n    \"version\": \"1.0.11\",\n    \"node\": \"v10.15.3\",\n    \"hash\": \"f99bb8f28be5c6dc76bed76f6dd8984accc5c5fa\",\n    \"environment\": \"test\",\n    \"hostname\": \"users-MacBook-Pro.local\",\n    \"pid\": 22165\n  }\n}\n```\n\nA few extra details about the above parsed properties:\n\n* `id` (String) - is a newly created BSON ObjectId used to uniquely identify this log\n* `timestamp` (String) - is the [ISO-8601][] date time string parsed from the `id` (thanks to MongoDB BSON `ObjectID.getTimestamp` method)\n* `is_http` (Boolean) - defaults to `true` to indicate that this was a parsed HTTP request\n* `duration` (Number) - is the number of milliseconds that `parseRequest` took to parse the request object (note that this uses `process.hrtime` which this package polyfills thanks to [browser-process-hrtime][])\n* `user` (Object) - is parsed from the user object on `req.user` automatically (e.g. you are using [passport][]):\n  * `ip_address` (String) - IP address parsed\n  * `...` - additional fields are optionally parsed from `req.user`\n* `request` (Object) - request object information parsed from `options.req`:\n  * `id` (String) - is conditionally added if `req.id` is a String (we highly recommend that you use [express-request-id][] in your project, which will automatically add this property if `X-Request-Id` if it is set, otherwise it will generate it as a new UUID)\n  * `file` (Object) - is conditionally added if you have a `req.file` property (e.g. if you're using [multer][])\n  * `files` (Array) - is conditionally added if you have a `req.files` property (e.g. if you're using [multer][])\n  * `http_version` (String) - is parsed from `req.httpVersion` or `req.httpVersionMajor` and `req.httpVersionMinor`\n  * `timesamp` (String) - is the [ISO-8601][] date time string parsed from when the request was received (we highly recommend that you use [request-received][] for this to be parsed as accurately as possible, although we do support a few widely-used fallback approaches)\n  * `headers` (Object) - the raw request headers (lowercased)\n* `response` (Object) - response object information parsed from `options.responseHeaders` (we use [http-headers][] to parse this information):\n  * `http_version` (String) - is parsed from the response HTTP headers major and minor HTTP version\n  * `timestamp` (String) - is the [ISO-8601][] date time string parsed from the response's `Date` header\n  * `duration` (Number) - is the number of milliseconds parsed from the `X-Response-Time` HTTP header (we highly recommend that you use [response-time][] and [request-received][])\n  * `headers` (Object) - the raw response headers (lowercased)\n  * `status_code` (Number) - the response's status code (see RFC spec on [Status Code and Reason Phrase][rfc-spec])\n  * `reason_phrase` (String) - the response's reason phrase (see RFC spec on [Status Code and Reason Phrase][rfc-spec])\n\nPlease see [Credit Card Masking](#credit-card-masking) and [Sensitive Field Names Automatically Masked](#sensitive-field-names-automatically-masked) below for more information about how `request.body`, `request.file`, and `request.files` are parsed and conditionally masked for security.\n\n### Credit Card Masking\n\nWe also have built-in credit-card number detection and masking using the [credit-card-type][] library.\n\nThis means that credit card numbers (or fields that are very similar to a credit card) will be automatically masked.  If you'd like to turn this off, pass `false` to `maskCreditCards`\\*\\*\n\n### Sensitive Field Names Automatically Masked\n\nSee [sensitive-fields][] for the complete list.\n\n### Sensitive Header Names Automatically Masked\n\nThe `Authorization` HTTP header has its `\u003ccredentials\u003e` portion automatically masked.\n\nThis means that if you are using BasicAuth or JSON Web Tokens (\"JWT\"), then your tokens will be hidden.\n\n\n## Usage\n\nWe highly recommend to simply use [Cabin][] as this package is built-in!\n\n### VanillaJS\n\nThe example below uses [xhook][] which is used to intercept HTTP requests made in the browser.\n\n```html\n\u003cscript src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=performance,WeakRef\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/xhook\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/parse-request\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\"\u003e\n  (function() {\n    xhook.after(function(req, res) {\n      var req = parseRequest({ req });\n      console.log('req', req);\n      // ...\n    });\n  })();\n\u003c/script\u003e\n```\n\n#### Required Browser Features\n\nWe recommend using \u003chttps://cdnjs.cloudflare.com/polyfill\u003e (specifically with the bundle mentioned in [VanillaJS](#vanillajs) above):\n\n```html\n\u003cscript src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=performance,WeakRef\"\u003e\u003c/script\u003e\n```\n\n* performance.now() is not supported in op\\_mini all\n* WeakRef is not supported in Opera 91\n\n### Koa\n\n```js\nconst parseRequest = require('parse-request');\n\n// ...\n\napp.get('/', (ctx, next) =\u003e {\n  const req = parseRequest({ req: ctx });\n  console.log('req', req);\n  // ...\n});\n```\n\n### Express\n\n```js\nconst parseRequest = require('parse-request');\n\n// ...\n\napp.get('/', (req, res, next) =\u003e {\n  const req = parseRequest({ req });\n  console.log('req', req);\n  // ...\n});\n```\n\n#### If you override req.body and need to preserve original in logs\n\nSometimes developers overwrite `req.body` or `req.body` properties – therefore if you want to preserve the original request, you can add `req._originalBody = req.body` (or `ctx.request._originalBody = ctx.request.body` if you're using Koa) at the top of your route middleware (or as a global route middleware).\n\n#### If you want to disable body parsing just for a specific route (e.g. prevent log output from showing the body)\n\nIf you're using Express:\n\n```js\nconst disableBodyParsing = Symbol.for('parse-request.disableBodyParsing');\n\n// ...\n\napp.get('/', (req, res, next) =\u003e {\n  req[disableBodyParsing] = true;\n  next();\n});\n```\n\nIf you're using Koa:\n\n```js\nconst disableBodyParsing = Symbol.for('parse-request.disableBodyParsing');\n\n// ...\n\napp.get('/', (ctx, next) =\u003e {\n  ctx.req[disableBodyParsing] = true;\n  next();\n});\n```\n\n#### If you want to disable file parsing just for a specific route (e.g. prevent log output from showing the file(s))\n\nIf you're using Express:\n\n```js\nconst disableFileParsing = Symbol.for('parse-request.disableFileParsing');\n\n// ...\n\napp.get('/', (req, res, next) =\u003e {\n  req[disableFileParsing] = true;\n  next();\n});\n```\n\nIf you're using Koa:\n\n```js\nconst disableFileParsing = Symbol.for('parse-request.disableFileParsing');\n\n// ...\n\napp.get('/', (ctx, next) =\u003e {\n  ctx.req[disableFileParsing] = true;\n  next();\n});\n```\n\n\n## Contributors\n\n| Name           | Website                    |\n| -------------- | -------------------------- |\n| **Nick Baugh** | \u003chttp://niftylettuce.com/\u003e |\n\n\n## License\n\n[MIT](LICENSE) © [Nick Baugh](http://niftylettuce.com/)\n\n\n##\n\n[npm]: https://www.npmjs.com/\n\n[passport]: http://www.passportjs.org/\n\n[cabin]: https://cabinjs.com\n\n[xhook]: https://github.com/jpillora/xhook\n\n[credit-card-type]: https://github.com/braintree/credit-card-type\n\n[sensitive-fields]: https://github.com/cabinjs/sensitive-fields\n\n[cuid]: https://github.com/ericelliott/cuid\n\n[bson-objectid]: https://docs.mongodb.com/manual/reference/method/ObjectId/\n\n[uuid]: https://github.com/kelektiv/node-uuid#uuid-\n\n[multer]: https://github.com/expressjs/multer\n\n[rfdc]: https://github.com/davidmarkclements/rfdc\n\n[request-received]: https://github.com/cabinjs/request-received\n\n[express-request-id]: https://github.com/floatdrop/express-request-id\n\n[browser-process-hrtime]: https://github.com/kumavis/browser-process-hrtime/\n\n[iso-8601]: https://en.wikipedia.org/wiki/ISO_8601\n\n[response-time]: https://github.com/expressjs/response-time\n\n[http-headers]: https://github.com/watson/http-headers\n\n[rfc-spec]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcabinjs%2Fparse-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcabinjs%2Fparse-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcabinjs%2Fparse-request/lists"}