{"id":18858229,"url":"https://github.com/mahendrahegde/node-idempotency","last_synced_at":"2025-04-14T11:53:31.528Z","repository":{"id":229731549,"uuid":"770129429","full_name":"mahendraHegde/node-idempotency","owner":"mahendraHegde","description":"makes any request idempotent across nodejs frameworks like nestjs, express, fastify","archived":false,"fork":false,"pushed_at":"2024-08-12T20:40:55.000Z","size":654,"stargazers_count":6,"open_issues_count":8,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T01:03:40.906Z","etag":null,"topics":["deduplicate","express","fastify","fastify-plugin","idempotency","idempotency-key","idempotent","idempotent-requests","nestjs","nestjs-idempotency","nodejs","request-deduplication","rest","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/mahendraHegde.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":"Contributing.md","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":"2024-03-11T01:14:32.000Z","updated_at":"2025-03-11T02:29:51.000Z","dependencies_parsed_at":"2024-04-28T00:22:17.507Z","dependency_job_id":"7b610002-92ef-459c-af7c-dd94cd4452c0","html_url":"https://github.com/mahendraHegde/node-idempotency","commit_stats":null,"previous_names":["mahendrahegde/node-idempotency"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mahendraHegde%2Fnode-idempotency","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mahendraHegde%2Fnode-idempotency/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mahendraHegde%2Fnode-idempotency/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mahendraHegde%2Fnode-idempotency/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mahendraHegde","download_url":"https://codeload.github.com/mahendraHegde/node-idempotency/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248877982,"owners_count":21176241,"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":["deduplicate","express","fastify","fastify-plugin","idempotency","idempotency-key","idempotent","idempotent-requests","nestjs","nestjs-idempotency","nodejs","request-deduplication","rest","typescript"],"created_at":"2024-11-08T04:11:05.474Z","updated_at":"2025-04-14T11:53:31.476Z","avatar_url":"https://github.com/mahendraHegde.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch3\u003e Node-Idempotency \u003c/h3\u003e\n\u003ci\u003emakes any request idempotent.\u003c/i\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n#### Why?\n\n---\n\nNetwork requests are unpredictable; clients/proxies may send duplicate or concurrent requests due to retries or network issues. To ensure smooth operation, servers must process each request only once. \u003ci\u003e**This package detects and handles duplicates, preventing issues like double charging the customer**\u003c/i\u003e. It's:\n\n- \u003ci\u003eRace Condition free: \u003c/i\u003e Ensures consistent behavior even during concurrent requests.\n- \u003ci\u003eModular:\u003c/i\u003e Easily integrates with your storage or existing implementation.\n- \u003ci\u003eCustomizable:\u003c/i\u003e options to tweak the library as per your need.\n- \u003ci\u003e[RFC](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/) compliant: \u003c/i\u003e Adheres to standards for compatibility with other systems/clients.\n\nand powers,\n\n- [`@node-idempotency/nestjs`](https://www.npmjs.com/package/@node-idempotency/nestjs) - Plug and Play `nestjs` wrapper for `@node-idempotency/core`\n\n- [`@node-idempotency/express`](https://www.npmjs.com/package/@node-idempotency/express) - Plug and Play `express` middleware for `@node-idempotency/core`\n\n- [`@node-idempotency/fastify`](https://www.npmjs.com/package/@node-idempotency/fastify) - Plug and Play `fastify` plugin for `@node-idempotency/core`\n\n---\n\n#### How?\n\n![No Image](flow.png)\n\n---\n\n#### @node-idempotency/core\n\n---\n\nif above packages dont meet your needs, you can utilise the core package directly to tweek it as per your needs.\n\n##### install\n\n```bash\nnpm i @node-idempotency/core\n```\n\n##### usage\n\nThe flow for idempotency is simple, you call the `onRequest` handler, when you receieve the request from clients before it reaches your business logic/controller.\n\n`onRequest` handler validates request for conflicts, figerprint missmatch, no idempotency-key(when idempotency is enforced) and gives back the response if the key is already seen, you typically give back the \"cached\" response to the client.\n\nif its a new request, it marks the request as progress generates fingerprint using `body` (so that it can validate conflicts for duplicate requests and figure out fingerprint missmatch), and returns undefined, you are responsible here to pass the request to your controller/business logic.\n\n`onResponse` handler is called by you when your business logic completes for the first time, so that the response can be stored and the request can be marked as complete.\n\n```ts\nimport { Idempotency } from \"@node-idempotency/core\";\nimport { MemoryStorageAdapter } from \"@node-idempotency/storage-adapter-memory\";\n\n// Create an Idempotency instance using a MemoryStorageAdapter\nconst idempotency = new Idempotency(new MemoryStorageAdapter(), {\n  ...idempotencyOptions,\n});\n\n// On receiving a request, call `onRequest` to validate idempotency\ntry {\n  const response = await idempotency.onRequest({\n    method: \"POST\",\n    headers: { \"idempotency-key\": \"123\" },\n    body: { pay: 100 },\n    path: \"/charge\",\n    options: { ...idempotencyOptions }, // Optional request-level overrides\n  });\n\n  if (!response) {\n    // New request, allow it to proceed\n    return;\n  }\n\n  // Duplicate request, return previous response\n  // Example: res.status(response.additional.status).send(response.body)\n} catch (err) {\n  // Handle idempotency errors (conflict, in-progress, fingerprint mismatch, etc.)\n  // Refer to API documentation for specific error codes\n}\n\n// Intercept response to complete the idempotency cycle\nconst response = await idempotency.onResponse(\n  {\n    method: \"POST\",\n    headers: { \"idempotency-key\": \"123\" },\n    body: { pay: 100 },\n    path: \"/charge\",\n    options: { ...idempotencyOptions }, // Optional request-level overrides\n  },\n  {\n    body: { charge: \"success\" }, // or error: your_error\n    additional: { status: 201 },\n  },\n);\n```\n\ncheck details about the api [here](./packages/core/docs/classes/Idempotency.md)\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\nOther packages in the monorepo are, click on the links to read detailed uses of each repo.\n\n1. [`@node-idempotency/storage`](packages/storage/Readme.md) - `Storage` adapater interface that dictate the storage interface for the `core`.\n\n2. [`@node-idempotency/storage-adapter-memory`](https://github.com/mahendraHegde/node-idempotency/tree/main/packages/storage-adapter-memory) - `In-memory` implementation of `Storage` interface.\n\n3. [`@node-idempotency/storage-adapter-redis`](packages/storage-adapter-redis/Readme.md) - `Redis` implementation of `Storage` interface.\n\n---\n\n#### Contributing\n\nRead more [here](./Contributing.md)\n\n---\n\n#### Release\n\n1. pnpm changeset\n2. commit changes\n3. pnpm prepare:publish\n4. pnpm publish -r --filter=\\!node-idempotency\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmahendrahegde%2Fnode-idempotency","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmahendrahegde%2Fnode-idempotency","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmahendrahegde%2Fnode-idempotency/lists"}