{"id":13411365,"url":"https://github.com/jkyberneees/fastify-gateway","last_synced_at":"2025-05-09T00:03:37.295Z","repository":{"id":52289909,"uuid":"144907486","full_name":"jkyberneees/fastify-gateway","owner":"jkyberneees","description":"A Node.js API gateway that just works!","archived":false,"fork":false,"pushed_at":"2023-06-03T19:48:30.000Z","size":663,"stargazers_count":108,"open_issues_count":7,"forks_count":14,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-09T00:03:03.025Z","etag":null,"topics":["api-gateway","fastify","http-proxy","http-router","nodejs"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/k-fastify-gateway","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/jkyberneees.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-08-15T21:58:42.000Z","updated_at":"2025-04-09T06:11:07.000Z","dependencies_parsed_at":"2024-05-15T16:03:20.526Z","dependency_job_id":"0a0d1a43-f1e0-42e2-a59c-126f39243ee7","html_url":"https://github.com/jkyberneees/fastify-gateway","commit_stats":{"total_commits":153,"total_committers":7,"mean_commits":"21.857142857142858","dds":"0.33333333333333337","last_synced_commit":"fcb4e936a607473ab3b1039bda3c881eb6461bb0"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkyberneees%2Ffastify-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkyberneees%2Ffastify-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkyberneees%2Ffastify-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkyberneees%2Ffastify-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jkyberneees","download_url":"https://codeload.github.com/jkyberneees/fastify-gateway/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253166502,"owners_count":21864475,"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-gateway","fastify","http-proxy","http-router","nodejs"],"created_at":"2024-07-30T20:01:13.165Z","updated_at":"2025-05-09T00:03:37.226Z","avatar_url":"https://github.com/jkyberneees.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Web Development"],"sub_categories":["Javascript"],"readme":"# k-fastify-gateway\nA Node.js API gateway that just works!\n\n[![Build Status](https://travis-ci.org/jkyberneees/fastify-gateway.svg?branch=master)](https://travis-ci.org/jkyberneees/fastify-gateway)\n[![NPM version](https://img.shields.io/npm/v/k-fastify-gateway.svg?style=flat)](https://www.npmjs.com/package/k-fastify-gateway) [![Greenkeeper badge](https://badges.greenkeeper.io/jkyberneees/fastify-gateway.svg)](https://greenkeeper.io/)\n\n- There is also a faster, non-fastify dependent clone: https://github.com/jkyberneees/fast-gateway\n\n## Get started in two steps\n\nInstall required dependencies:\n```bash\nnpm i fastify k-fastify-gateway\n```\n\u003e NOTE: From v2.x, `fastify-reply-from` is a direct dependency.\n\nLaunch your gateway 🔥:\n```js\nconst fastify = require('fastify')({})\n\n// required plugin for HTTP requests proxy\nfastify.register(require('fastify-reply-from'))\n\n// gateway plugin\nfastify.register(require('k-fastify-gateway'), {\n\n  middlewares: [\n    require('cors')()\n  ],\n\n  routes: [{\n    prefix: '/public',\n    prefixRewrite: '',\n    target: 'http://localhost:3000',\n    middlewares: [],\n    hooks: {\n      // async onRequest (req, reply) {},\n      // onResponse (req, reply, res) { reply.send(res) }\n    }\n  }, {\n    prefix: '/admin',\n    target: 'http://localhost:3001',\n    middlewares: [\n      require('basic-auth-connect')('admin', 's3cr3t-pass')\n    ]\n  }, {\n    prefix: '/user',\n    target: 'http://localhost:3001'\n  }]\n})\n\n// start the gateway HTTP server\nfastify.listen(8080).then((address) =\u003e {\n  console.log(`API Gateway listening on ${address}`)\n})\n```\n\n## Introduction\n\nNode.js API Gateway plugin for the [fastify](https://fastify.io) [ecosystem](https://www.fastify.io/ecosystem/), a low footprint implementation that uses the [fastify-reply-from](https://github.com/fastify/fastify-reply-from) HTTP proxy library.  \n\nYeap, this is a super fast gateway implementation!\n\n### Motivation\n\nCreating fine grained REST microservices in Node.js is the [easy part](https://thenewstack.io/introducing-fastify-speedy-node-js-web-framework/), difficult is to correctly integrate them as one single solution afterwards!  \n\nThis gateway implementation is not only a classic HTTP proxy router, it is also a Node.js friendly `cross-cutting concerns` management solution. You don't have to:\n - repeat in/out middleware logic anymore (cors, authentication, authorization, caching, ...)\n - blame Node.js because the asynchronous post processing of proxied requests was hard to implement...\n - ...\n - or just learn Lua to extend nginx ;)\n\n## Configuration options explained\n\n```js\n{\n  // Optional global middlewares (https://www.fastify.io/docs/latest/Middlewares/). Default value: []\n  middlewares: [],\n  // Optional global value for routes \"pathRegex\". Default value: '/*'\n  pathRegex: '/*',\n\n  // HTTP proxy\n  routes: [{\n    // Optional path matching regex. Default value: '/*'\n    // In order to disable the 'pathRegex' at all, you can use an empty string: ''\n    pathRegex: '/*',\n    // route prefix\n    prefix: '/public',\n    // Optional \"prefix rewrite\" before request is forwarded. Default value: ''\n    prefixRewrite: '',\n    // Optional body limit setting for fastify JSON body parser. Default value: 1048576 (1 MiB)\n    bodyLimit: 1048576,\n    // remote HTTP server URL to forward the request\n    target: 'http://localhost:3000',\n    // optional HTTP methods to limit the requests proxy to certain verbs only\n    methods: ['GET', 'POST', ...], // any of supported HTTP methods: https://github.com/fastify/fastify/blob/master/docs/Routes.md#full-declaration\n    // Optional route level middlewares. Default value: []\n    middlewares: [],\n    // Optional proxy lifecycle hooks. Default value: {}\n    hooks: {\n      async onRequest (req, reply) {\n      //   // we can optionally reply from here if required\n      //   reply.send('Hello World!')\n      //\n      //   return true // truthy value returned will abort the request forwarding\n      },\n      onResponse (req, reply, res) {  \n        // do some post-processing here\n        // ...\n        // forward response to origin client once finished\n        reply.send(res)\n      }\n\n      // other options allowed https://github.com/fastify/fastify-reply-from#replyfromsource-opts\n    }\n  }]\n}\n```\n## Gateway level caching\n### Why?\n\u003e Because `caching` is the last mile for low latency distributed systems!  \n\nEnabling proper caching strategies at gateway level will drastically reduce the latency of your system,\nas it reduces network round-trips and remote services processing.  \nWe are talking here about improvements in response times from `X ms` to `~2ms`, as an example.  \n\n###  Setting up gateway cache\n#### Single node cache (memory):\n```js\n// cache plugin setup\nconst gateway = require('fastify')({})\ngateway.register(require('k-fastify-gateway/src/plugins/cache'), {})\n```\n\u003e Recommended if there is only one gateway instance\n\n#### Multi nodes cache (redis):\n```js\n// redis setup\nconst CacheManager = require('cache-manager')\nconst redisStore = require('cache-manager-ioredis')\nconst redisCache = CacheManager.caching({\n  store: redisStore,\n  db: 0,\n  host: 'localhost',\n  port: 6379,\n  ttl: 30\n})\n\n// cache plugin setup\nconst gateway = require('fastify')({})\ngateway.register(require('k-fastify-gateway/src/plugins/cache'), {\n  stores: [redisCache]\n})\n```\n\u003e Required if there are more than one gateway instances\n\n### Enabling cache for service endpoints\nAlthough API Gateway level cache aims as a centralized cache for all services behind the wall, are the services\nthe ones who indicate the responses to be cached and for how long.  \n\nCache entries will be created for all remote responses coming with the `x-cache-timeout` header:\n```js\nres.setHeader('x-cache-timeout', '1 hour')\n```\n\u003e Here we use the [`ms`](`https://www.npmjs.com/package/ms`) package to convert timeout to seconds. Please note that `millisecond` unit is not supported!  \n\nExample on remote service using `restana`:\n```js\nservice.get('/numbers', (req, res) =\u003e {\n  res.setHeader('x-cache-timeout', '1 hour')\n\n  res.send([\n    1, 2, 3\n  ])\n})\n```\n\n### Invalidating cache\n\u003e Let's face it, gateway level cache invalidation was complex..., until now!  \n\nRemote services can also expire cache entries on demand, i.e: when the data state changes. Here we use the `x-cache-expire` header to indicate the gateway cache entries to expire using a matching pattern:\n```js\nres.setHeader('x-cache-expire', '*/numbers')\n```\n\u003e Here we use the [`matcher`](`https://www.npmjs.com/package/matcher`) package for matching patterns evaluation.\n\nExample on remote service using `restana`:\n```js\nservice.patch('/numbers', (req, res) =\u003e {\n  res.setHeader('x-cache-expire', '*/numbers')\n\n  // ...\n  res.send(200)\n})\n```\n\n### Custom cache keys\nCache keys are generated using: `req.method + req.url`, however, for indexing/segmenting requirements it makes sense to allow cache keys extensions.  \nUnfortunately, this feature can't be implemented at remote service level, because the gateway needs to know the entire lookup key when a request\nreaches the gateway.  \n\nFor doing this, we simply recommend using middlewares on the service configuration:\n```js\nroutes: [{\n  prefix: '/users',\n  target: 'http://localhost:3000',\n  middlewares: [(req, res, next) =\u003e {\n    req.cacheAppendKey = (req) =\u003e req.user.id // here cache key will be: req.method + req.url + req.user.id\n    return next()\n  }]\n}]\n```\n\u003e In this example we also distinguish cache entries by `user.id`, very common case!\n\n### Disable cache for custom endpoints\nYou can also disable cache checks for certain requests programmatically:\n```js\nroutes: [{\n  prefix: '/users',\n  target: 'http://localhost:3000',\n  middlewares: [(req, res, next) =\u003e {\n    req.cacheDisabled = true\n    return next()\n  }]\n}]\n```\n\n## Breaking changes\nIn `v2.x` the `hooks.onResponse` signature has changed from:\n```js\nonResponse (res, reply)\n```\nto:\n```js\nonResponse (req, reply, res)\n```\n\u003e More details: https://github.com/fastify/fastify-reply-from/pull/43\n\n## Benchmarks\n`Version`: 2.0.1  \n`Node`: 10.15.3  \n`Machine`: MacBook Pro 2016, 2,7 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3  \n`Gateway processes`: 1  \n`Service processes`: 1\n\n```bash\nRunning 30s test @ http://127.0.0.1:8080/service/hi\n  8 threads and 8 connections\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency   841.58us  662.17us  35.22ms   98.66%\n    Req/Sec     1.23k   130.62     1.29k    95.02%\n  293897 requests in 30.10s, 42.60MB read\nRequests/sec:   9763.61\nTransfer/sec:      1.42MB\n```\n\n## Want to contribute?\nThis is your repo ;)  \n\n\u003e Note: We aim to be 100% code coverage, please consider it on your pull requests.\n\n## Related projects\n- middleware-if-unless (https://www.npmjs.com/package/middleware-if-unless)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkyberneees%2Ffastify-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjkyberneees%2Ffastify-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkyberneees%2Ffastify-gateway/lists"}