{"id":19264726,"url":"https://github.com/noahsaso/snapper","last_synced_at":"2025-07-04T01:34:33.351Z","repository":{"id":219689644,"uuid":"749637329","full_name":"NoahSaso/snapper","owner":"NoahSaso","description":"API Caching Layer","archived":false,"fork":false,"pushed_at":"2025-06-17T01:39:20.000Z","size":542,"stargazers_count":7,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-17T02:35:10.739Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NoahSaso.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":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-01-29T04:50:36.000Z","updated_at":"2025-06-17T01:39:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"c492807c-f9d6-4b1c-9522-d927e1c2b366","html_url":"https://github.com/NoahSaso/snapper","commit_stats":null,"previous_names":["noahsaso/snapper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/NoahSaso/snapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoahSaso%2Fsnapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoahSaso%2Fsnapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoahSaso%2Fsnapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoahSaso%2Fsnapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NoahSaso","download_url":"https://codeload.github.com/NoahSaso/snapper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoahSaso%2Fsnapper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263431369,"owners_count":23465516,"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":[],"created_at":"2024-11-09T19:42:15.559Z","updated_at":"2025-07-04T01:34:33.343Z","avatar_url":"https://github.com/NoahSaso.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# snapper\n\nSnapper is an API caching layer built on Fastify and Redis in TypeScript. It\nmakes it easy to snapshot API requests and serve them from an intermediary\nserver to help reduce redundant API calls and navigate externally imposed rate\nlimits.\n\nIf a query does not exist in the cache, it will be fetched immediately, cached,\nand then returned in the same request. If a query has already been cached, the\ncached value will be returned immediately, regardless of how old it is. If this\nvalue is stale (based on the configured TTL), a background process will update\nits value for future requests, embodying the\n[stale-while-revalidate](https://web.dev/articles/stale-while-revalidate)\nideology. This ensures that Snapper balances responsiveness with freshness.\n\n## Setup\n\n1. Install [Redis](https://redis.io/docs/install/install-redis/).\n\n2. Install the server's packages:\n\n   ```sh\n   npm install\n   ```\n\n3. Copy .env.example to .env and configure the environment variables.\n\n   ```sh\n   cp .env.example .env\n   ```\n\n4. Build the server:\n\n   ```sh\n   npm run build\n   ```\n\n5. Generate a key pair:\n\n   ```sh\n   npm run generateKeyPair:default\n   ```\n\n### Configure server\n\nThe available environment variables and their defaults are shown below.\n\n```\n# set server host and port\nHOST=0.0.0.0\nPORT=3000\n\n# set redis connection URL\nREDIS_URL=redis://localhost:6379\n\n# set comma-separated regex CORS origins (optional)\n# if empty, all origins are allowed\nALLOWED_ORIGINS=http:\\/\\/localhost:\\d+\n\n# set background job admin dashboard password (viewable at /admin)\nADMIN_DASHBOARD_PASSWORD=admin\n\n# how many background jobs can process at once\nCONCURRENCY=50\n```\n\n## Queries\n\nAdd your own queries to the `src/server/queries` directory, and make sure to add\nthem to the `src/server/queries/index.ts` file.\n\n### Adding a new query\n\nAdding a new query is very simple. For a normal URL query, you just need to set\nits name, any parameters, URL, and cache TTL. A custom query is similar,\nrequiring an execute function instead of a URL. You can optionally configure\nqueries further, such as adding headers or transforming the response body. See\nthe type in the `src/types.ts` file for more details.\n\n#### All queries support:\n\n**`type`** is the type of the query (URL or Custom).\n\n**`name`** is the name of the query, which will be used in the query route and\nalso in the cache key.\n\n**`parameters`** are the query parameters that are required by the query. If a\nquery takes parameters, a separate response will be cached for each unique set\nof parameters. You likely want to use these parameters in the URL function.\n\n**`optionalParameters`** are optional query parameters used by the query. If a\nquery takes parameters, a separate response will be cached for each unique set\nof parameters. You likely want to use these parameters in the URL function.\n\n**`validate`** is an optional function that validates the parameters. If it\nthrows or returns an error, the query will not be fetched and the error will be\nreturned in the response. If it returns `false`, a generic error will be\nreturned.\n\n**`ttl`** is the cache TTL in seconds. If it's a function (instead of a number),\nit will be called with the query's parameters as arguments and the result will\nbe used.\n\n#### URL queries support:\n\n**`method`** is the optional HTTP method for the request. Defaults to `GET`.\n\n**`url`** is the URL for the request. If it's a function (instead of a string),\nit will be called with the query's parameters as arguments and the result will\nbe used.\n\n**`headers`** are the optional headers for the request. If it's a function\n(instead of an object), it will be called with the query's parameters as\narguments and the result will be used.\n\n**`transform`** is an optional function that transforms the query's response\nbody. Its second argument is the query's parameters.\n\n#### Custom queries support:\n\n**`execute`** is the function that will be called to execute the query. It will\nbe called with the query's parameters and a function that lets you get the\nresult of other queries. This is powerful, as it lets you compose other queries\ninto new queries.\n\n## Usage\n\nStart redis server:\n\n```sh\nredis-server\n```\n\nRun the node server:\n\n```sh\nnpm run serve\n\n### For hot reloading\nnpm run serve:dev\n```\n\nRun the revalidation processor:\n\n```sh\nnpm run process\n```\n\nPerform a query:\n\n```sh\ncurl -X GET 'http://localhost:3000/q/query_name?parameter=value'\n```\n\n### Development\n\nRun the server and revalidation processor via Docker:\n\n```sh\nnpm run start:dev\n```\n\nThe server is exposed on port 3030.\n\nView the admin dashboard at http://localhost:3030/admin\n\n### Production\n\nRun the server and revalidation processor with pm2 in production (daemon mode):\n\n```sh\nnpm run start:prod\n```\n\n## Testing\n\nRun the tests:\n\n```sh\nnpm run test\n```\n\n## Docker\n\nTo build the Docker image, run:\n\n```bash\nnpm run docker:build\n```\n\nTo tag and push to a container registry, run:\n\n```bash\ndocker tag snapper:latest your-registry/snapper:latest\ndocker push your-registry/snapper:latest\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoahsaso%2Fsnapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoahsaso%2Fsnapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoahsaso%2Fsnapper/lists"}