{"id":19405202,"url":"https://github.com/outofsyncstudios/request-utils","last_synced_at":"2026-05-08T03:32:35.226Z","repository":{"id":28534986,"uuid":"118663663","full_name":"OutOfSyncStudios/request-utils","owner":"OutOfSyncStudios","description":"A simple utility framework library for processing common HTTP requests and parameter handling","archived":false,"fork":false,"pushed_at":"2023-03-06T02:24:28.000Z","size":406,"stargazers_count":1,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-28T16:05:36.786Z","etag":null,"topics":["framework","http-client","nodejs","npm","open-source"],"latest_commit_sha":null,"homepage":"","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/OutOfSyncStudios.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}},"created_at":"2018-01-23T20:12:49.000Z","updated_at":"2023-03-30T18:02:05.000Z","dependencies_parsed_at":"2023-07-18T00:53:18.451Z","dependency_job_id":null,"html_url":"https://github.com/OutOfSyncStudios/request-utils","commit_stats":{"total_commits":27,"total_committers":2,"mean_commits":13.5,"dds":0.03703703703703709,"last_synced_commit":"6bc3a2d3d58b23b4a8ebc29b0211537680c34bf8"},"previous_names":["mediaxpost/request-utils"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutOfSyncStudios%2Frequest-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutOfSyncStudios%2Frequest-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutOfSyncStudios%2Frequest-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutOfSyncStudios%2Frequest-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OutOfSyncStudios","download_url":"https://codeload.github.com/OutOfSyncStudios/request-utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240582044,"owners_count":19824145,"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":["framework","http-client","nodejs","npm","open-source"],"created_at":"2024-11-10T11:37:24.620Z","updated_at":"2026-05-08T03:32:35.161Z","avatar_url":"https://github.com/OutOfSyncStudios.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# request-utils\n\n[![NPM](https://nodei.co/npm/@outofsync/request-utils.png?downloads=true)](https://nodei.co/npm/@outofsync/request-utils/)\n\n[![Actual version published on npm](http://img.shields.io/npm/v/@outofsync/request-utils.svg)](https://www.npmjs.org/package/@outofsync/request-utils)\n[![Build and Test Master](https://github.com/OutOfSyncStudios/request-utils/actions/workflows/build-master.yml/badge.svg)](https://github.com/OutOfSyncStudios/request-utils/actions/workflows/build-master.yml)\n[![Total npm module downloads](http://img.shields.io/npm/dt/@outofsync/request-utils.svg)](https://www.npmjs.org/package/@outofsync/request-utils)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/062776002e3942a198f19da955bf1ac9)](https://www.codacy.com/gh/OutOfSyncStudios/request-utils/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=OutOfSyncStudios/request-utils\u0026amp;utm_campaign=Badge_Grade)\n[![Codacy Coverage Badge](https://app.codacy.com/project/badge/Coverage/062776002e3942a198f19da955bf1ac9)](https://www.codacy.com/gh/OutOfSyncStudios/request-utils/dashboard?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=OutOfSyncStudios/request-utils\u0026utm_campaign=Badge_Coverage)\n[![Dependencies badge](https://david-dm.org/OutOfSyncStudios/request-utils/status.svg)](https://david-dm.org/OutOfSyncStudios/request-utils?view=list)\n\n\n`request-utils` is simple framework designed to simplify HTTP Request handling and parameters parsing by abstracting commonly reused processing patterns. It can be used with any framework that creates and uses HTTPRequest objects.\n\n# [Installation](#installation)\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n\n```shell\nnpm install @outofsync/request-utils\n```\n\n# [Usage](#usage)\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n```js\nconst ReqUtils = require('@outofsync/request-utils');\nconst reqUtils = new ReqUtils();\n\n// Example Express.js handler and controller functions\nfunction handler(locals, req, res, next) {\n  console.log(locals.dataVal1);\n  console.log(locals.dataVal2);\n  next();\n}\n\nasync function controller(req, res, next) {\n  await reqUtils.handleRequest(\n    {\n      params: {\n        dataVal1: {\n          type: 'string',\n          source: ['body', 'headers', 'query'],\n          required: true\n        },\n        dataVal2: {\n          type: 'string',\n          source: ['body', 'headers', 'query'],\n          required: true\n        }\n      },\n      authContext: { super: true, server: true }\n    },\n    handler, \n    req, \n    res, \n    next\n  );\n}\n```\n\n# [Upgrading from v3 to v4](#upgrade)\nIf you are upgrading from v3 to v4 you need to be aware of the following breaking changes: \n* The `ctor` ReqUtils is no longer allows invoked with the `req` (HttpRequest) object as a parameter. \n* All methods are now stateless and require the `req` (HttpRequest) to be passed as the first parameter. Reordering parameters to the beginning of the function signature and now being required.\n* The handleRequest and handleRequestAsync methods have been renamed to reflect a more promise-based design. \n  * The old `handleRequestAsync` is now just `handleRequest`.\n  * The old `handleRequest` is now `handleRequestSync`.\n* The handleRequest methods have had their parameters reordered so that they follow typical ordering in other libraries -- `req, res, next`\n* The handler function signature for passed handler to the handleRequest methods all now have a function signature of `(locals, req, res, next)` where locals are the loaded variabls.\n* The following paramters passed as a part of handleRequest methods have been changed:\n  * `security` parameter option that previously performed rudimentary context checking of a request has been renamed `authContext`.\n  * `secure` parameter option that previously performed a TLS protocol check, is now named `forceTls`.\n* The `skipAuth` and `setSkipAuth` methods have been removed.\n* New options have been added for \n\n***Existing codebases will need to be refactored to account for these changes.***\n\n# [API Reference](#api)\n\u003ca name=\"api\"\u003e\u003c/a\u003e\n\n## new ReqUtils([params]) \u0026#x27fe; instanceof ReqUtils\nCreate an instance of ReqUtils. Additional configuration parameters may be passed in `params` map as follows:\n\n| Param | Type | Default | Description |\n| ----- | ---- | ------- | ----------- |\n| checkPermissions | Function(HTTPRequest) \u0026#x27fe; bool | `() =\u003e { return true; }` | A function to perform additional permission check which returns a boolean if the check passes |\n| customErrorResponseCodes | [CustomCodes](#types-custom-codes) | See Below | A `CustomCodes` object to be used with handleCustomErrors, which checks an error message for the message and sets the appropriate code |\n| customResponseMessages | [CustomMessages](#types-custom-messages) | See Below | A `CustomMessages` object which defines the error message details and status codes for various error codes |\n| defaultAuthContext | [AuthContext](#types-auth-context) | `{ super: false, signed: false, server: false, client: false }` | A `AuthContext` object which defines the default AuthContext state |\n| defaultLang | string | `'en'` | Language definition to use when looking up CustomCodes and CustomMessages string |\n| debug | boolean | `false` | Enable debugging output |\n| enableAuthContextCheck | boolean | `true` | handleRequest methods will check AuthContext provided when enabled |\n| enableForceTlsCheck | boolean | `true` | handleRequest methods will check if request is over TLS when enabled |\n| enablePermissionsCheck | boolean | `true` | handleRequest methods will run the permissions check function when enabled |\n\n**Defaults**:\n```js\n  // These are the default options\n  {\n    checkPermissions: ((req) =\u003e {\n      return true;\n    ),\n    customErrorResponseCodes: {},\n    customResponseMessages: {\n      [200000]: { summary: 'OK', message: '', status: 200 },\n      [400000]: { summary: 'Bad Request', message: 'The request is malformed.', status: 400 },\n      [400001]: { summary: 'Non-Existent Record', message: 'The record requested does not exist.', status: 400 },    \n      [400002]: { summary: 'Missing Parameters', message: 'The request is missing required parameters.', status: 400 },\n      [401000]: { summary: 'Unauthorized', message: 'This request is not authorized.', status: 401 },    \n      [403000]: {\n        summary: 'Forbidden',\n        message: 'The credentials provided are not authorized for this request',\n        status: 403\n      },\n      [403001]: { summary: 'Forbidden', message: 'Secure endpoints can only be accessed via HTTPS.', status: 403 },\n      [404000]: {\n        summary: 'Not Found',\n        message: 'The requested resource does not exist or you are not authorized to access it.',\n        status: 404\n      },    \n      [408000]: { summary: 'Timed Out', message: 'The request timed out.', status: 408 },\n      [429000]: { summary: 'Rate Limit', message: 'Rate limit has been exceeded', status: 429 },    \n      [500000]: { summary: 'Could Not Connect', message: 'The server connection timed out', status: 500 },\n      [500001]: { summary: 'General Server Error', message: 'A fatal error has occurred on the server.', status: 500 }\n    },\n    defaultAuthContext: { super: false, signed: false, server: false, client: false }\n  }\n```\n\n## Request Handling\n\n### .handleRequest(params, handler, req, res, next) \u0026#x27fe; Promise\u003cvoid|Error\u003e\n### .handleRequestSync(params, handler, req, res, next) \u0026#x27fe; void / Error\nUsing the `params` provides, performs the following, so long as the `req` has not already been processed.\n1. When enabled, checks the current request AuthContext (as updated by the `setAuthContext` or `updateAuthContext` methods) of the request against `params.authContext`. Sets `403000` response code on failure.\n2. When enabled, checks the TLS Protocol requirement (`params.forceTls`) of the request. (Was this request made over HTTPS when `req.secure === true`?). Sets `403001` response code on failure.\n3. Retrieves all request parameters configured (`params.params`) from the request.\n4. Checks for required HTTP Request parameters. Sets `400001` reponse code on failure.\n5. Sets default values for optional request parameters that are unset\n6. Validates that all request parameters are set to the expected data types. Sets `400002` response code on failure.\n7. When enabled, runs `checkPermission`. Sets `403000` response code on failure.\n8. If none of the above generates an error, then runs the `handler` function provided. If the handler throws an Exception, it then sets a `500001` error.\n\n* `req` is the HTTP Request object.\n* `res` is the HTTP Response object.\n* `next` is the asynchronous handler used by [ExpressJS](), [SailsJS](), and other similar frameworks to continue execution or return errors. `res` is the HTTP Response object for the request. `req` is the HTTPRequest object.\n* `params` are outlined in the [Request Handler Parameters](#type-handler-params) below.\n* `handler` is a function with a function signature as follow:\n```js\n  (locals, req, res, next) =\u003e {\n    // Do something ... \n    // locals stores the parameters that have been parsed \n    // from the request as passed to the handleRequest\n    // method in `params.params`.\n  }\n```\n\n**Example Usage**:\n```js\nfunction handler(locals, req, res, next) {\n  console.log(locals);\n  next()\n}\n\nreqUtils.handleRequestSync({\n    params: { },\n    authContext: {\n      super: true,    // Only accessible by super-users\n      server: true,   // Only accessible from a sever-based context\n      client: false\n    },\n    forceTls: false\n  },\n  handler, \n  req, \n  res, \n  next\n);\n```\n\n## Error Handling\n\n### .getResponseMessage(code, lang, customMessages) \u0026#x27fe; [ResponseMessage](#types-reponse-message) / null\nChecks the `code` for a match in the merged `ReqUtils.customResponseMessages` dictionary for the given `lang`. If the language dictionary is found and a match exists, then the corresponding response message is returned. If no matching message is found for the language specified or the language can't be found, then the custom messsages are used to reconcile the message code.\n\n### .handleCustomErrors(req, err, customCodes, customMessages) \u0026#x27fe; object\n`req` is the HTTP Request object. Checks `err.name` for a match in the merged `ReqUtils.customErrorResponseCodes` and `customCodes`. If a match is found, then the found code is looked up in the merged `ReqUtils.customResponseMessages` and `customMessages` for a summary message.  If no code is found, then the code is set to 500001. If no summary is found, then the summary message is set to 'An unexpected error has occurred -- {err.name}'. The code and error are then returned in a objects. If `err` is null, then the object returned contains a `null` message. If `err.name` is null, then it defaults to 'No details'.\n\n```js\n  // { msg: 'Something went wrong', code: 500001 }\n```\n\n## Utility\n\n### .setTimedout(req)\nSet the `req.timedout` flag to true and sets the `req.respCode` to 429000.\n\n### .setError(req, code)\nSet the `req.hasError` flag to true and sets the `req.respCode` to `code` provided.\n\n### .setData(req, data)\nSet the `req.hasData` flag to true and sets `req.data` to `data` provided, so that it can be processed downstream.\n\n### .hasResponse(req) \u0026#x27fe; boolean\nTest the `req` to see if the `hasData`, `hasError` or `timedout` flags have been set\n\n### .setAuthContext(req, authContext)\nSet the `req.authContext` flags with fills from the `defaultAuthContext`.\n\n### .updateAuthContext(req, authContext)\nMerge `authContext` values into `req.authContext` values, overwriting any values currently set in `req.authContext`.\n\n### .checkAuthContext(req, options) \u0026#x27fe; boolean\nCompares the `options` values against the `req.authContext` ensuring that any option set true is also true in the\n`req.authContext`.  Any value set false in the options is ignored. Returns false if any option is true, but the\nauthContext is false.\n\n### .checkPermissions(req) \u0026#x27fe; boolean\nRuns the configured `checkPermissions` function configured as a part of the initialization options for ReqUtils.\n\n## Parameter Binding\n\n### .retrieveParams(req, params)\nSets the `req.handler` from the `params` provided, then gathers, parses, and converts these values from the request and\nplaces the values into both `req.handler.[key].value` `req.locals.[key]`.\n\n### .compileRequiredParams(params) \u0026#x27fe; object\nAnalyzes the `params` configured and creates a dictionary of required and optional parameters. This is used to validate\nthe request in the `handleRequest` method.\n\n```js\n  // { required: reqParams, optional: optParams }\n```\n\n### .hasRequiredParams(requiredParams) \u0026#x27fe; array\nAnalyzes the key values in the `requiredParams` and checks that each of them have a value. Each key name with a missing\nvalue is returned in an array. With an empty array being returned if there are no missing values. `requiredParams` is\nthe `.required` key from the object returned from `.compileRequiredParams`\n\n### .handleDefaults(req, optionalParams)\nReviews the `optionalParameter` key values set and compares the keys with the values set in `req.locals`. If any\nvalue is missing, then the `default` value is assigned to the key. `optionalParams` is the `.options` key from the\nobject returned from `.compileRequiredParams`\n\n### .validateParams(params)\nValidates all values in `req.locals` against the `type` specified for that key. Returns an array of field names where\nthe key value does not match the given type specified in the `params`.\n\n# [Types](#types)\n\u003ca name=\"types\"\u003e\u003c/a\u003e\n\n## Auth Context\n\u003ca name=\"types-auth-context\"\u003e\u003c/a\u003e\nAuth Context is an object hash which contains key and boolean value pairs. It is left up to the system designer what\neach of these contexts indicate.  For example, in one system `client` could mean that the request originated in such a\nway that it is interpreted to be having come from a browser or mobile device, and `server` could mean the request\noriginated from another server. Any custom keys and specific logic is left to the system designer to implement.\n\n```js\n{\n  super: false,\n  signed: false,\n  server: false,\n  client: false\n}\n```\n\n## Request Parameter\n\u003ca name=\"types-request-parameter\"\u003e\u003c/a\u003e\nA Request Parameter provides a definition for values that may be sent as a part of the incoming request, where to parse\nthem from, their data type, whether they are required, a default value if they are missing, and optional validation\nparameters.\n\n```js\ndataVal1: {\n  type: 'string',\n  required: true,\n  source: ['body', 'headers', 'query'],\n  default: (v) =\u003e { return(v); },\n  options: {}\n}\n\n```\n| Key | Type | Description | Required |\n| --- | ---- | ----------- | -------- |\n| type | string | The data type for this parameter. See below. | Y |\n| required | boolean | Whether the parameter is required. | Y |\n| source | array(string) | The locations to search for the parameters. Sources are searched in the order provided and the first source to find the value is the one used.  See below. | Y |\n| default | value or function | The default value to use when the value can not be found. When passing a function, the existing value (including null and undefined) is passed into the function and the value returned is used as the default. | N |\n| options | object | Additional validator.js options for the data type. See below. | N |\n\n### Data Types and Validation options\nThe following data types are supported for parsing: `int`, `float`, `bool`, `email`, `currency`, `uuid`, `url`, `fqdn`, `apikey`, `string`, `any`. For more information, please see the [validation-helper README](https://www.npmjs.com/package/@outofsync/validation-helper#api)\n\n### Sources\nThe following request sources are available:\n\n| Source | Description |\n| ------ | ----------- |\n| `'params'` | Searched the request route parameters for the key. This is only supported in frameworks that perform route parameter binding to `req.params`. |\n| `'header'` | Searches the request headers (lowercase) for the key. |\n| `'body'` | Searches the form body (x-www-form-urlencoded) values for the key. |\n| `'query'` | Searches the url query variables for the key. |\n\nAdditionally, all requests will search for a JSON string passed to `body.params`, and parse that object into the appropriate data fields.\n\n## Request Parameter Collection\nA collection of [Request Parameters](#types-request-parameter) in Key / Request Parameter pairs\n\u003ca name=\"types-request-parameter-collection\"\u003e\u003c/a\u003e\n```js\nconst params = {\n  ['Test1']: {\n    type: 'int',\n    source: ['body'],\n    required: false\n  },\n  ['Test2']: {\n    type: 'int',\n    source: ['body'],\n    required: false\n  }\n};\n```\n\n## Request Handler Parameters\n\u003ca name=\"types-hanlder-params\"\u003e\u003c/a\u003e\n\n```js\n{\n  params: {\n    ['Test1']: {\n      type: 'int',\n      source: ['body'],\n      required: false\n    }\n  },\n  security: {\n\n  },\n  forceTls: false\n}\n```\n\n| Key | Type | Description | Required |\n| --- | ---- | ----------- | -------- |\n| params | [Request Parameter Collection](#types-request-parameter-collection) | The request parameters for this handler. | Y |\n| security | [Auth Context](#) | The required Auth Context for this request | N |\n| forceTls | boolean | Whether this request is required to be made over HTTPS. Default: `false`. | N |\n\n## CustomCodes\n\u003ca name=\"types-custom-codes\"\u003e\u003c/a\u003e\nCustomCodes are a collection of named key and integer value pairs representing the response code to use when a specific `err.name` matches a given key.\n\n```js\n{\n  ['SequelizeUniqueConstraintError']: 400006,\n  ['SequelizeDatabaseError']: 400103,\n  ['SequelizeConnectionRefusedError']: 500002\n}\n```\n\n## ResponseMessage\n\u003ca name=\"types-response-message\"\u003e\u003c/a\u003e\n\n```js\n  { summary: 'OK', message: '', status: 200 },\n```\n\n| Key | Type | Description | Required |\n| --- | ---- | ----------- | -------- |\n| summary | string | The response summary for the specific response code | Y |\n| message | string | The response message for detailed error information | Y |\n| status | int | The HTTP Response status code | Y |\n\n## CustomMessages\n\u003ca name=\"types-custom-messages\"\u003e\u003c/a\u003e\nA collection of [ResponseMessage](#types-reponse-message) objects, with a matching response code key.\n\n```js\n{\n  [200000]: { summary: 'OK', message: '', status: 200 },\n  [400000]: { summary: 'Bad Request', message: 'The request is malformed.', status: 400 },\n  [400001]: { summary: 'Missing Parameters', message: 'The request is missing required parameters.', status: 400 }\n}\n```\n\n# [License](#license)\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n\nCopyright (c) 2018, 2019 Jay Reardon\nCopyright (c) 2019-2022 Out of Sync Studios LLC  -- Licensed under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foutofsyncstudios%2Frequest-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foutofsyncstudios%2Frequest-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foutofsyncstudios%2Frequest-utils/lists"}