{"id":21497162,"url":"https://github.com/financial-times/n-express","last_synced_at":"2025-12-17T17:33:30.644Z","repository":{"id":24537211,"uuid":"27943640","full_name":"Financial-Times/n-express","owner":"Financial-Times","description":"Slightly enhanced Express.","archived":false,"fork":false,"pushed_at":"2024-04-09T15:52:08.000Z","size":2370,"stargazers_count":8,"open_issues_count":6,"forks_count":3,"subscribers_count":86,"default_branch":"main","last_synced_at":"2024-04-10T04:14:05.759Z","etag":null,"topics":["component","customer-products","platforms-customer-products"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@financial-times/n-express","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"caskroom/homebrew-fonts","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Financial-Times.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2014-12-13T00:18:33.000Z","updated_at":"2024-05-17T15:00:22.904Z","dependencies_parsed_at":"2023-10-03T14:50:30.285Z","dependency_job_id":"c2286eee-bd83-4a1e-8a19-da05159b5836","html_url":"https://github.com/Financial-Times/n-express","commit_stats":null,"previous_names":[],"tags_count":616,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Financial-Times%2Fn-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Financial-Times%2Fn-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Financial-Times%2Fn-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Financial-Times%2Fn-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Financial-Times","download_url":"https://codeload.github.com/Financial-Times/n-express/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226065661,"owners_count":17568249,"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":["component","customer-products","platforms-customer-products"],"created_at":"2024-11-23T16:21:55.159Z","updated_at":"2025-12-17T17:33:30.554Z","avatar_url":"https://github.com/Financial-Times.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# n-express\n\n[Express](https://expressjs.com/), slightly enhanced with extra functions and common middleware for FT.com apps.\n\n```\nnpm install -S @financial-times/n-express\n```\n\n# Usage\n\nImport `n-express`, and initialise it with some [options](#app-init-options):\n\n```js\nconst nExpress = require('@financial-times/n-express');\n\nconst app = nExpress({\n\t// options\n});\n```\n\nThe `nExpress` function returns an [Express `app` object](https://expressjs.com/en/4x/api.html#app).\n\n## App init options\n\nPassed in to `nExpress`, these (Booleans defaulting to false unless otherwise stated) turn on various optional features\n\n### Mandatory\n\n- `systemCode` - allows the application to communicate its [Biz Ops](https://biz-ops.in.ft.com/) code to other services.\n\n### Optional\n\n- `withBackendAuthentication` - Boolean, defaults to `true` - if there is a `FT_NEXT_BACKEND_KEY[_OLD]` env variable, the app will expect requests to have an equivalent `FT-Next-Backend-Key[-Old]` header; this turns off that functionality. Backend authentication is required for applications serving traffic that should only come via the Fastly -\u003e Preflight -\u003e Router request routing. An example of why is the Next Article application, if this didn't have backend authentication enabled you would be able to view articles via the heroku application url as it wouldn't be protected by barriers which are handled within Fastly and Preflight.\n- `withFlags` - decorates each request with [flags](https://github.com/Financial-Times/n-flags-client) as `res.locals.flags`\n- `withConsent` - decorates each request with the user's consent preferences as `res.locals.consent`\n- `withAnonMiddleware`- adds middleware that converts headers related to logged in status in to a `res.locals.anon` model\n- `healthChecks` Array - an array of healthchecks to serve on the `/__health` path (see 'Healthchecks' section below)\n- `healthChecksAppName` String - the name of the application, output in the `/__health` JSON. This defaults to `Next FT.com \u003cappname\u003e in \u003cregion\u003e`.\n\n## Static properties and methods\n- `Router` - `express.Router`\n- `static` - `express.static` middleware\n- `flags` - `n-flags-client` instance\n- `getAppContainer()` - returns an object:\n\t- `app`: the express app instance\n\t- `meta`: object containing the name, description and directory of the app\n\t- `addInitPromise()`: function for adding additional promises to wait for before allowing the app to accept traffic\n\n\n## Cache control\nSeveral useful cache control header values are available as constants on responses:\n```\n\tres.FT_NO_CACHE = 'max-age=0, no-cache, must-revalidate';\n\tres.FT_NO_CACHE_PRIVATE = 'max-age=0, no-cache, no-store, must-revalidate, private';\n\tres.FT_SHORT_CACHE = 'max-age=600, stale-while-revalidate=60, stale-if-error=86400';\n\tres.FT_HOUR_CACHE = 'max-age=3600, stale-while-revalidate=60, stale-if-error=86400';\n\tres.FT_DAY_CACHE = 'max-age=86400, stale-while-revalidate=60, stale-if-error=86400';\n\tres.FT_WEEK_CACHE = 'max-age=604800, stale-while-revalidate=60, stale-if-error=259200';\n\tres.FT_LONG_CACHE = 'max-age=86400, stale-while-revalidate=60, stale-if-error=259200';\n```\n\n## Cache varying\nVarious vary headers are set by default (ft-flags, ft-anonymous-user, ft-edition, Accept-Encoding as of Apr 2016 ) as they are required for most responses - the user experience will break if they are not. To control these a few additional methods are provided\n- `res.unvary('My-Header')` - use if your response definitely doesn't need to vary on one of the standard vary headers e.g. .rss probably doesn't need to vary on ft-edition\n- `res.unvaryAll('wrapper')` removes all headers included by default for use by the usual next page layout... ideal for serving html fragments, json etc.\n- `res.unvaryAll()` - remove all vary headers. *Do not use lightly!!!*\n- `res.vary('My-Header')` - add to the list of vary headers\n\n\n\n# Health checks\n\nFor an example set of health check results, see [ft-next-health-eu.herokuapp.com/__health](https://ft-next-health-eu.herokuapp.com/__health) and [ft-next-health-us.herokuapp.com/__health](https://ft-next-health-us.herokuapp.com/__health). For testing health checks, the [Health Status Formatter extension for Google Chrome](https://github.com/triblondon/health-status-formatter) is recommended.\n\nHealth checks can be tested for failures of a specific degree of severity by appending the severity number to the health check URL. This is particularly useful for setting up fine-grained alerting. For example, if on next.ft.com a severity level 2 health check were failing:\n\nhttps://ft-next-health-eu.herokuapp.com/__health.1 would return HTTP status 200\nhttps://ft-next-health-eu.herokuapp.com/__health.2 would return HTTP status 500\nhttps://ft-next-health-eu.herokuapp.com/__health.3 would return HTTP status 500\n\nEach health check must have a getStatus() property, which returns an object meeting the specifications of the [FT Health Check Standard](https://docs.google.com/document/d/18hefJjImF5IFp9WvPAm9Iq5_GmWzI9ahlKSzShpQl1s/edit) and the [FT Check Standard] (https://docs.google.com/document/edit?id=1ftlkDj1SUXvKvKJGvoMoF1GnSUInCNPnNGomqTpJaFk#). This might look roughly like the following example:\n\nNote also that it is now required for the JSON returned at the `/__health` endpoint to contain the system code. To ensure that this happens, please ensure that the `systemCode` property of the express app init options has been supplied. See the 'App init options' section above.\n\n```js\nvar exampleHealthCheck = {\n\tgetStatus: () =\u003e {\n\t\treturn {\n\t\t\tname: 'Some health check',\n\t\t\tok: true,\n\t\t\tcheckOutput: 'Everything is fine',\n\t\t\tlastUpdated: new Date(),\n\t\t\tpanicGuide: 'Don\\'t panic',\n\t\t\tseverity: 3,\n\t\t\tbusinessImpact: \"Some specific feature will fail\",\n\t\t\ttechnicalSummary: \"Doesn\\'t actually check anything, just an example\"\n\t\t};\n\t}\n}\n```\n\n# Troubleshooting\n\n## Testing with flags\n\nIf you’re using flags and testing with mocha, you’ll need to expose listen in your app:\n\n```\nmodule.exports.listen = app.listen(port);\n```\n\nAnd in your tests, add this:\n\n```\nbefore(function() {\n\treturn app.listen;\n});\n```\n\nThis’ll make sure your tests wait for flags to be ready.\n\n## Writing tests with n-express in other apps \nIf you're including n-express in your integration tests, you can add this:\n\n```\nafter(() =\u003e {\n  app.close()\n})\n```\n\nto stop the tests from hanging from scheduled healthchecks \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinancial-times%2Fn-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffinancial-times%2Fn-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinancial-times%2Fn-express/lists"}