{"id":16431838,"url":"https://github.com/coreybutler/common-api","last_synced_at":"2025-03-23T08:31:41.833Z","repository":{"id":42933713,"uuid":"192791592","full_name":"coreybutler/common-api","owner":"coreybutler","description":"A collection of utility methods for producing API's.","archived":false,"fork":false,"pushed_at":"2023-01-06T01:31:07.000Z","size":553,"stargazers_count":11,"open_issues_count":11,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-17T22:24:49.658Z","etag":null,"topics":["api","atob","express","middleware","nodejs","request","response","utility"],"latest_commit_sha":null,"homepage":null,"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/coreybutler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["coreybutler"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2019-06-19T19:23:42.000Z","updated_at":"2024-03-14T14:03:04.000Z","dependencies_parsed_at":"2023-02-05T01:30:51.476Z","dependency_job_id":null,"html_url":"https://github.com/coreybutler/common-api","commit_stats":null,"previous_names":["butlerlogic/common-api","ecorventures/common-api"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreybutler%2Fcommon-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreybutler%2Fcommon-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreybutler%2Fcommon-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreybutler%2Fcommon-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coreybutler","download_url":"https://codeload.github.com/coreybutler/common-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245078067,"owners_count":20557274,"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":["api","atob","express","middleware","nodejs","request","response","utility"],"created_at":"2024-10-11T08:32:57.169Z","updated_at":"2025-03-23T08:31:41.461Z","avatar_url":"https://github.com/coreybutler.png","language":"JavaScript","funding_links":["https://github.com/sponsors/coreybutler"],"categories":[],"sub_categories":[],"readme":"# Common API Utilities\n\nLike this project? Let people know with a [tweet](https://twitter.com/intent/tweet?hashtags=nodejs,expressjs\u0026original_referer=http%3A%2F%2F127.0.0.1%3A91%2F\u0026text=Check%20out%20@butlerlogic%2fcommon-api%20for%20simplifying%20API%20development%20with%20Express!\u0026tw_p=tweetbutton\u0026url=http%3A%2F%2Fgithub.com%2Fbutlerlogic%2Fcommon-api\u0026via=goldglovecb). \n\nThis is a lightweight library containing a few commonly used methods for creating API's with Express.js. It is ideally suited for prototyping API's.\n\n![common-api](https://qph.fs.quoracdn.net/main-qimg-f993f1bf76edc43fc5844d812f2f0c4b)\n\n_There's a short walk-thru/guide/example available on [Quora](https://qr.ae/TW4E4R)_\n\n## Installation:\n\n`npm install @butlerlogic/common-api -S`\n\n## Usage\n\n```javascript\nconst express = require('express')\nconst API = require('@butlerlogic/common-api')\nconst app = express()\n\napp.post('/endpoint', API.validateJsonBody(), (req, res) =\u003e { ... })\n\nconst server = app.listen(() =\u003e console.log('Server is running.'))\n```\n\n## Shortcuts\n\n### [Request Middleware](#Middleware)\n- [log()](#log)\n- [logRequestHeaders()](#logRequestHeaders)\n- [logRedirects([bool])](#logRedirectsbool)\n- [litmusTest([message])](#litmustestmessage))\n- [validateJsonBody](#validateJsonBody)\n- [validNumericId](#validNumericId)\n- [validId](#validId)\n- [validResult(res, callback)](#validresultres-callback)\n- [basicauth(user, password)](#basicauthuser-password)\n- [bearer(token)](#bearertoken)\n- [applyCommonConfiguration(app, [autolog])](#applycommonconfigurationapp-autolog)\n- [applySimpleCORS(app, host='*')](#applysimplecorsapp-host)\n- [allowHeaders('Origin', 'X-Requested-With')](#allowheadersorigin-x-requested-with)\n- [allowMethods('GET', 'POST', 'OPTIONS')](#allowmethodsget-post-options)\n- [allowOrigins('a.domain.com', 'b.domain.com')](#alloworiginsadomaincom-bdomaincom)\n- [allowPreflight()](#allowpreflight)\n- [allowAll('host')](#allowallhost)\n\n### [Responses](#Responses)\n- [200](#200)\n- [OK](#OK)\n- [201](#201)\n- [CREATED](#CREATED)\n- [401](#401)\n- [UNAUTHORIZED](#UNAUTHORIZED)\n- [404](#404)\n- [NOT_FOUND](#NOT_FOUND)\n- [501](#501)\n- [NOT_IMPLEMENTED](#NOT_IMPLEMENTED)\n- [Other HTTP Status Codes](#OTHER_STATUS_CODES)\n- [redirect(url, [permanent, moved])](#redirecturl-permanent-moved)\n- [reply(anything)](#replyanything)\n- [replyWithError(res, [status, message]|error)](#replywitherrorres-status-messageerror)\n- [replyWithMaskedError(res, [status, message]|error)](#replywithmaskederrorres-status-messageerror)\n\n### [Utilities](#Utilities)\n- [createUUID](#createUUID)\n- [atob(value)](#atob(value))\n- [applyBaseUrl (req, route = '/' [, forceTLS = false])](#applybaseurl-req-route---forcetls--false)\n- [applyRelativeUrl (req, route = '/' [, forceTLS = false])](#applyrelativeurl-req-route---forcetls--false)\n- [errorType](#errorType)\n- [commonHeaders](#commonHeaders)\n- [httpMethods](#httpMethods)\n\n## Middleware\n\nThe following static methods are available:\n\n### log\n\nConfigures a simple console logging utility (with colorized output). This can be used as middleware for all requests or individual requests.\n\n```javascript\napp.use(API.log)\n```\n\n```javascript\napp.post('/endpoint', API.log, ...)\n```\n\n### logRequestHeaders\n\nConfigures a simple console logging utility (with colorized output), which will log the request headers of the request. This can be used as middleware for all requests or individual requests.\n\n```javascript\napp.use(API.logRequestHeaders)\n```\n\n```javascript\napp.post('/endpoint', API.logRequestHeaders, ...)\n```\n\n### logRedirects([bool])\n\nToggle redirect logging. This is _not middleware_. It is just a function to determine whether redirected requests should be logged to the console or not.\n\n```javascript\nAPI.logRedirects() // Defaults to `true`\nAPI.logRedirects(true)\nAPI.logRedirects(false)\n```\n\nWhen active, this will log a message like:\n\n```sh\nRedirect GET /redirect → http://domain.com/endpoint\n```\n\n### litmusTest([message])\n\nThis pass-thru middleware component is useful for determining whether a route or responder is reachable or not. A message (`LITMUS TEST` by default) is logged to the console/stdout, without affecting the network request/response.\n\n```javascript\napp.use('/endpoint', API.litmusTest('endpoint reachable'), ...)\n```\n\n### validateJsonBody\n\n```javascript\napp.post('/endpoint', API.validateJsonBody(), ...)\n```\n\nValidates a request body exists and consists of valid JSON.\n\nIt is also possible to verify that the JSON body contains specific \"top level\" attributes (i.e. nesting is _not_ supported).\n\nFor example, \n\n```javascript\napp.post('/endpoint', API.validateJsonBody('a', 'b', 'c'), ...)\n```\nThe code above will verify that the request body is valid JSON containing attributes `a`, `b`, and `c`.\n\n_Valid JSON_\n\n```json\n{\n  \"a\": \"text\",\n  \"b\": \"text\",\n  \"c\": \"text\",\n  \"d\": \"extra is ok\"\n}\n```\n\n_Invalid JSON_\n\n```json\n{\n  \"a\": \"text\",\n  \"c\": \"text\",\n  \"d\": \"extra is ok\"\n}\n```\n\n_Produces:_\n```sh\n400 - Missing parameters: b\n```\n\n### validNumericId\n\n```javascript\napp.post('/endpoint/:id', API.validNumericId(), ...)\n```\n\nAssures `:id` is a valid numeric value. This also supports a query parameter, such as `/endpoint?id=12345`. This will add an attribute to the `request` object (`req.id`).\n\nAn alternative argument name can be provided, such as:\n\n```javascript\napp.post('/endpoint/:userid', API.validNumericId('userid'), ...)\n```\n\n### validId\n\n```javascript\napp.post('/endpoint/:id', API.validId(), ...)\n```\n\nAssures `:id` exists, as a string. This also supports a query parameter, such as `/endpoint?id=some_id`. This will add an attribute to the `request` object (`req.id`).\n\nAn alternative argument name can be provided, such as:\n\n```javascript\napp.post('/endpoint/:userid', API.validId('userid'), ...)\n```\n\n### validResult(res, callback)\n\nInspects the result and returns a function that will throw an error or return results.\n\n```javascript\nlet checkResult = API.validResult(res, results =\u003e res.send(results))\n\napp.get('/endpoint', (req, res) =\u003e { ...processing... }, checkResult)\n```\n\n### basicauth(user, password)\n\nThis method will perform basic authentication.\nIt will compare the authentication header credentials\nwith the username and password.\n\nFor example, `basicauth('user', 'passwd')` would compare the\nuser-submitted username/password to `user` and `passwd`. If\nthey do not match, a 401 (Not Authorized) response is sent.\nIf authentication is successful, a `user` attribute will be \nappended to the request (i.e. `req.user`).\n\n```javascript\napp.get('/secure', API.basicauth('user', 'passwd'), (req, res) =\u003e ...)\n// req.user would be set \"user\" when authentication succeeds.\n```\n\nIt is also possible to perform a more advanced authentication\nusing a custom function. For example:\n\n```javascript\napp.get('/secure', API.basicauth(function (username, password, grantedFn, deniedFn) {\n  if (confirmWithDatabase(username, password)) {\n    grantedFn()\n  } else {\n    deniedFn()\n  }\n}))\n```\n\nThe `username`/`password` will be supplied in plain text. The\n`grantedFn()` should be run when user authentication succeeds,\nand the `deniedFn()` should be run when it fails. Any downstream\nmiddleware or other handlers will be able to access the username\nby referencing `req.user`.\n\n### bearer(token)\n\nThis method looks for a bearer token in the `Authorization` request header. If the token does not match, a `401 (Unauthorized)` status is returned.\n\n```javascript\napp.get('/secure/path', API.bearer('mytoken'), API.reply('authenticated'))\n```\n\nThe code above would succeed for requests which contain the following request header:\n\n```sh\nAuthorization: Bearer mytoken\n```\n\n\u003e The case-insensitive keyword \"bearer\" is required for this to work.\n\nIt is also possible to use a custom function to evaluate the request token. The function must by synchronous and return a boolean value (`true` or `false`).\n\n```javascript\napp.get('/secure/path', API.bearer(function (token) {\n  return isValidToken(token)\n}), API.reply('authenticated'))\n```\n\nTokens do not necessarily represent a unique user, but they are often used\nto lookup a user. To facilitate this, the `req.user` attribute is set to the\nvalue of the token so downstream middleware can perform lookups or further\nvalidate the token.\n\n### applyCommonConfiguration(app, [autolog])\n\n```javascript\nconst express = require('express')\nconst app = express()\nconst API = require('@butlerlogic/common-api')\n\nAPI.applyCommonConfiguration(app)\n```\n\nThis helper method is designed to rapidly implement common endpoints. This can be used throughout the testing phase or in production.\n\nThe common configuration consists of 3 basic endpoints:\n\n- `/ping`: A simple responder that returns a `200 (OK)` response.\n- `/version`: Responds with a plaintext body containing the version of the API, as determined by the `version` attribute found in the `package.json` file of the server.\n- `/info`: Responds with a JSON payload containing 3 attributes:\n    - `runningSince`: The timestamp when the API server was launched.\n    - `version`: Same as `/version` above.\n    - `routes`: An array of all known routes/endpoints of the API.\n\nThis also disables the `x-powered-by` header used in Express.\n\nBy default, this method enables logging (using the log method). This can be turned off by passing `false` as a second argument:\n\n```javascript\nAPI.applyCommonConfiguration(app, false)\n```\n\n### applySimpleCORS(app, host='*')\n\n```javascript\nconst express = require('express')\nconst app = express()\nconst API = require('@butlerlogic/common-api')\n\nAPI.applySimpleCORS(app)\n// API.applySimpleCORS(app, 'localhost')\n```\n\nImplementing [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) support while prototyping/developing an API can consume more time than most people anticipate. This method applies a simple CORS configuration so you can \"continue coding\". It is unlikely this configuration will be used in production environments unless the API is behind a secure gateway, but it helps temporarily resolve the most common challenges of _developing_ with CORS.\n\nThis method applies 3 response headers to all responses:\n\n- `Access-Control-Allow-Origin`: By default, this is set to `*`, but the host can be modified by passing an optional 2nd argument to the function.\n- `Access-Control-Allow-Headers`: Set to `'Origin, X-Requested-With, Content-Type, Accept'`\n- `Access-Control-Allow-Methods`: Set to `GET, POST, PUT, PATCH, DELETE, OPTIONS`\n\n## allowHeaders('Origin', 'X-Requested-With')\n\nThis [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) middleware feature can be used to specify/override which HTTP headers are allowed to be sent with requests to the server (by endpoint). This automatically handles setting the appopriate `Access-Control-Allow-Headers` HTTP header.\n\n```javascript\nconst express = require('express')\nconst app = express()\nconst API = require('@butlerlogic/common-api')\n\nAPI.applySimpleCORS(app)\n\napp.get('/special/endpoint, API.allowOrigins('a.domain.com', 'b.domain.com'), (req, res) =\u003e {...})\n```\n\nThis can also be applied to all requests:\n\n```javascript\napp.use(API.allowOrigins('a.domain.com', 'b.domain.com'))\n```\n\n## allowMethods('GET', 'POST', 'OPTIONS')\n\nThis [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) middleware feature can be used to specify/override which methods are allowed to be used when making HTTP requests to a specific endpoint/route. This automatically handles setting the appopriate `Access-Control-Allow-Methods` HTTP header.\n\n```javascript\nconst express = require('express')\nconst app = express()\nconst API = require('@butlerlogic/common-api')\n\nAPI.applySimpleCORS(app)\n\napp.get('/special/endpoint, API.allowMethods('PATCH', 'POST'), (req, res) =\u003e {...})\n```\n\nThis can also be applied to all requests:\n\n```javascript\napp.use(API.allowMethods('GET'))\n```\n\n## allowOrigins('a.domain.com', 'b.domain.com')\n\nThis [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) middleware feature can be used to specify/override which hosts are allowed to send requests to the server (by endpoint). This automatically handles setting the appopriate `Access-Control-Allow-Origin` HTTP header.\n\n```javascript\nconst express = require('express')\nconst app = express()\nconst API = require('@butlerlogic/common-api')\n\nAPI.applySimpleCORS(app)\n\napp.get('/special/endpoint, API.allowOrigins('a.domain.com', 'b.domain.com'), (req, res) =\u003e {...})\n```\n\nThis can also be applied to all requests:\n\n```javascript\napp.use(API.allowOrigins('a.domain.com', 'b.domain.com'))\n```\n\n## allowPreflight()\n\nThis middleware responds to `OPTIONS` requests with a `200 OK` response. This method is useful because it automatically applies the appropriate CORS configurations to support any request headers submitted to the endpoint.\n\n```javascript\napp.use(API.allowPreflight())\n\n// or\n\napp.any('/path', API.allowPreflight(), (req, res) =\u003e { ... })\n```\n\n## allowAll(host)\n\nThis middleware uses CORS, allowing any request from the specified host(s). This should not be considered a secure or insecure method. Used appropriately, it can provide proper security at large scale. Used inappropriately, it can be insecure at any scale. Use with caution. Remember, this method is primarily useful for developing functional API's before locking them down with tighter security restrictions.\n\n```javascript\n// Allow anything from any domain (insecure)\napp.use(API.allowAll('*'))\napp.use(API.allowAll()) // Equivalent of above\n\n// Allow anything from my domain (semi-secure, limited to 1 domain)\napp.use(API.allowAll('mydomain.com'))\n\n// Applied to a specific endpoint (semi-secure, limited to 1 path on 1 domain)\napp.get('/endpoint', this.allowAll('mydomain.com'), (req, res) =\u003e { ... })\n\n// Applied to a specific endpoint for multiple sources\napp.get('/endpoint', this.allowAll('mydomain.com', 'mypartner.com'), (req, res) =\u003e { ... })\n```\n\n---\n\n## Responses\n\n### 200\n\n```javascript\napp.post('/endpoint', API.200)\n```\n\nSends a status code `200` response.\n\n### OK\n\n```javascript\napp.post('/endpoint', API.OK)\n```\n\nSends a status code `200` response.\n\n### 201\n\n```javascript\napp.post('/endpoint', API.201)\n```\n\nSends a status code `201` response.\n\n### CREATED\n\n```javascript\napp.post('/endpoint', API.CREATED)\n```\n\nSends a status code `201` response.\n\n### 401\n\n```javascript\napp.post('/endpoint', API.401)\n```\n\nSends a status code `401` response.\n\n### UNAUTHORIZED\n\n```javascript\napp.post('/endpoint', API.UNAUTHORIZED)\n```\n\nSends a status code `401` response.\n\n### 404\n\n```javascript\napp.post('/endpoint', API.404)\n```\n\nSends a status code `404` response.\n\n### NOT_FOUND\n\n```javascript\napp.post('/endpoint', API.NOT_FOUND)\n```\n\nSends a status code `404` response.\n\n### 501\n\n```javascript\napp.post('/endpoint', API.501)\n```\n\nSends a status code `501` response.\n\n### NOT_IMPLEMENTED\n\n```javascript\napp.post('/endpoint', API.NOT_IMPLEMENTED)\n```\n\nSends a status code `501` response.\n\n### OTHER_STATUS_CODES\n\nAll of the standard status codes have shortcut methods available. Each HTTP status code has two methods associated with it: `HTTP###` and a method named by replacing spaces and hyphens in the the status message with underscores, removing special characters, and converting the whole message to upper case.\n\nFor example, HTTP status 304 (Not Modified) would have a method `HTTP304` and `NOT_MODIFIED`.\n\nThe [joke status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418), 418 (I'm a Teapot) illustrates how special characters are removed.\n\n- `HTTP418()`\n- `IM_A_TEAPOT()`\n\n### redirect(url, [permanent, moved])\n\nA helper method for redirecting requests to another location. This is not a proxy, it does not actually forward requests. It tells the client the URL being requested is outdated and/or has been moved permanently/temporarily.\n\nThis method exists since redirects have been used incorrectly in the past (by the entire industry). The redirect HTTP status codes changed in [RFC 7231](https://tools.ietf.org/html/rfc7231) (2014), but are still commonly disregarded. This method supplies the appropriate HTTP status codes without having to remember which code is proper for each circumstance.\n\n```javascript\napp.get('/path', API.redirect('https://elsewhere.com')) // 307\n// ^ equivalent of: app.get('/path', API.redirect('https://elsewhere.com', false, false))\n\napp.get('/path', API.redirect('https://elsewhere.com', true, false)) // 308\napp.get('/path', API.redirect('https://elsewhere.com', true, true)) // 301\napp.get('/path', API.redirect('https://elsewhere.com', false, true)) // 303\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eHTTP Status Codes\u003c/summary\u003e\n\n| Code | Purpose | Description |\n| - | - |- |\n|301|Moved Permanently|This and all future requests should be directed to the given URI.|\n|303|See Other|The response to the request can be found under another URI using the GET method. When received in response to a POST (or PUT/DELETE), the client should presume that the server has received the data and should issue a new GET request to the given URI.|\n|307|Temporary Redirect|In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For example, a POST request should be repeated using another POST request.|\n|308|Permanent Redirect|The request and all future requests should be repeated using another URI. 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. So, for example, submitting a form to a permanently redirected resource may continue smoothly.|\n\n\u003e **302** (Found) is not a valid redirect code.\n\u003e\n\u003e Tells the client to look at (browse to) another URL. 302 has been superseded by 303 and 307. This is an example of industry practice contradicting the standard. The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was \"Moved Temporarily\"),[21] but popular browsers implemented 302 with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours.[22] However, some Web applications and frameworks use the 302 status code as if it were the 303.\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eFrom the API docs\u003c/summary\u003e\n\n```javascript\n/**\n * Redirect the request to another location.\n * @param {string} url\n * The location to redirect to.\n * @param {boolean} [permanent=false]\n * Instruct the client that the redirect is permanent,\n * suggesting all future requests should be made directly\n * to the new location. When this is `false`, a HTTP `307`\n * code is returned. When `true`, a HTTP `308` is returned.\n * @param {boolean} [moved=false]\n * Inform the client that the destination has been moved.\n * When _moved_ is `true` and _permanent_ is `false`, an\n * HTTP `303` (Found) status is returned, informing the\n * client the request has been received and a `GET` request\n * should be issued to the new location to retrieve it. When\n * _permanent_ is `true`, a HTTP `301` is returned,\n * indicating all future requests should be made directly to\n * the new location.\n */\n```\n\n\u003c/details\u003e\n\n### reply(anything)\n\nA helper method to send objects as a JSON response, or to send plain text. This function attempts to automatically determine the appropriate response header type.\n\n_Example:_\n\n```javascript\napp.get('/path', API.reply(myJsonObject))\n```\n\n### replyWithError(res, [status, message]|error)\n\nSend an HTTP error response. This function accepts two different kinds of arguments. The response is always the first argument. The method will also accept a custom HTTP status code and/or a custom plaintext message, as shown here:\n\n```javascript\napp.get('/myendpoint', (req, res) =\u003e {\n  if (problem === true) {\n    API.replyWithError(res, 400, 'There is a problem.')\n  }\n})\n```\n\nBy default, an HTTP status code of `500` (Server Error) is used.\n\nAnother option it to pass a JavaScript error as the last argument.\n\n```javascript\napp.get('/myendpoint', (req, res) =\u003e {\n  someFunction((err, data) =\u003e {\n    API.replyWithError(res, err)\n  })\n})\n\n// A custom HTTP status code can be used\napp.get('/myendpoint', (req, res) =\u003e {\n  someFunction((err, data) =\u003e {\n    API.replyWithError(res, 404, err)\n  })\n})\n```\n\nIn the first example, an error is passed as the last argument. Using this approach, the response will have a `400` status and the message will be auto-extracted from the JavaScript error. The second example will do the same thing, but it will send a `404` status code instead of the default.\n\n### replyWithMaskedError(res, [status, message]|error)\n\nThis functions very similarly to `replyWithError`, but a non-descript error message is sent to the client with a reference ID. The message/error is written to the console, making it possible to lookup actual error in the server logs.\n\nFor example:\n\n```javascript\napp.get('/myendpoint', (req, res) =\u003e {\n  if (problem === true) {\n    API.replyWithMaskedError(res, 400, 'There is a problem connecting to the database.')\n  }\n})\n```\n\nThe response _sent in the reply_ will actually look like:\n\n```\n400 An error occurred. Reference: eaac53bc-8b95-4e81-bc29-dead2a14c2ea\n```\n\nThe logs would look like:\n\n```\n[ERROR:eaac53bc-8b95-4e81-bc29-dead2a14c2ea] (400) There was a problem connecting to the database.\n```\n\n---\n\n## Utilities\n\n### createUUID\n\nThis utility method helps generate unique ID's. This is used to generate the transaction ID for masked error output (`replyWithMaskedError` method).\n\n### atob(value)\n\n_ASCII to Binary_:\nThis mimics the window.atob function. It is commonly used to extract username/password from a request.\n\n### applyBaseUrl (req, route = '/', forceTLS = false)\n\nApply the base URL to the specified route. If `forceTLS` is set to `true`, the response will always use the `https` protocol.\n\n```javascript\napp.get('/my/path', (req, res) =\u003e {\n  res.json({\n    id: API.applyBaseURL(req, 'myid')\n  })\n})\n```\n\nIf a request was made to `http://domain.com/my/path`, this would return:\n\n```json\n{\n  \"id\": \"http://domain.com/myid\"\n}\n```\n\n\n\n### applyRelativeUrl (req, route = '/', forceTLS = false)\n\nApply the relative URL to the specified route. If `forceTLS` is set to `true`, the response will always use the `https` protocol.\n\n```javascript\napp.get('/my/path', (req, res) =\u003e {\n  res.json({\n    id: API.applyBaseURL(req, 'myid')\n  })\n})\n```\n\nIf a request was made to `http://domain.com/my/path`, this would return:\n\n```json\n{\n  \"id\": \"http://domain.com/my/path/myid\"\n}\n```\n\n### errorType\n\nBy default, using replyWithError or replyWithMaskedError will produce standard text-based error reponses, such as `401 (Unauthorized)`.\n\nIt is possible to produce JSON instead, resulting in:\n\n```json\n{\n  \"status\": 401,\n  \"message\": \"Unauthorized\"\n}\n```\n\nIf JSON is needed, set the errorType to `json`.\n\n```javascript\nAPI.errorType = 'json'\n```\n\n### commonHeaders\n\nThis is an array of the most common request headers used by HTTP clients. This is useful when constructing your own list of CORS headers using the `allowHeaders` method.\n\n```javascript\nconsole.log(API.commonHeaders)\n```\n\nHeaders include: `Origin`, `X-Requested-With`, `Content-Type`, and `Accept`. This list may be updated from time to time.\n\n### httpMethods\n\nAn array of the official HTTP methods.\n\n```javascript\nconsole.log(API.httpMethods)\n```\n\nIncludes:\n\n- `GET`\n- `HEAD`\n- `POST`\n- `PUT`\n- `DELETE`\n- `CONNECT`\n- `OPTIONS`\n- `TRACE`\n- `PATCH`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoreybutler%2Fcommon-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoreybutler%2Fcommon-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoreybutler%2Fcommon-api/lists"}