{"id":13406175,"url":"https://github.com/hodgef/apiker","last_synced_at":"2025-04-09T22:10:13.242Z","repository":{"id":37249517,"uuid":"424450122","full_name":"hodgef/apiker","owner":"hodgef","description":"🔼 Create Serverless APIs with Cloudflare Workers, Durable Objects \u0026 Wrangler","archived":false,"fork":false,"pushed_at":"2025-02-14T03:53:33.000Z","size":3096,"stargazers_count":121,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T21:02:53.055Z","etag":null,"topics":["api","cloudflare-workers","durable-objects","jwt","wrangler"],"latest_commit_sha":null,"homepage":"http://hodgef.com/apiker","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/hodgef.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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},"funding":{"buy_me_a_coffee":"hodgef"}},"created_at":"2021-11-04T02:40:33.000Z","updated_at":"2025-03-18T03:37:32.000Z","dependencies_parsed_at":"2024-01-17T01:48:39.411Z","dependency_job_id":"b1f5e8ec-f7ee-444c-8cf3-5395d7a20d65","html_url":"https://github.com/hodgef/apiker","commit_stats":{"total_commits":302,"total_committers":2,"mean_commits":151.0,"dds":0.2814569536423841,"last_synced_commit":"2196e406124f2797841f25c88b4cbd8507e0593d"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hodgef%2Fapiker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hodgef%2Fapiker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hodgef%2Fapiker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hodgef%2Fapiker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hodgef","download_url":"https://codeload.github.com/hodgef/apiker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248119294,"owners_count":21050755,"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","cloudflare-workers","durable-objects","jwt","wrangler"],"created_at":"2024-07-30T19:02:23.237Z","updated_at":"2025-04-09T22:10:13.221Z","avatar_url":"https://github.com/hodgef.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/hodgef"],"categories":["TypeScript"],"sub_categories":[],"readme":" \u003cdiv\u003e\n \u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/hodgef/apiker\" title=\"View Documentation\"\u003e\u003cimg width=\"110\" src=\"https://user-images.githubusercontent.com/25509135/142580530-07c335a7-5a11-47dd-8acc-b45842e8da32.png\" /\u003e\u003c/a\u003e\n \u003c/p\u003e\n \n \u003cdiv align=\"center\"\u003e\n  \u003cp\u003eCreate Serverless APIs using Cloudflare Workers, Durable Objects \u0026 Wrangler\u003c/p\u003e\n\n \u003ca href=\"https://www.npmjs.com/package/apiker\"\u003e\u003cimg src=\"https://badgen.net/npm/v/apiker\" alt=\"npm version\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/hodgef/apiker\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/hodgef/apiker\" alt=\"latest commit\"\u003e\u003c/a\u003e \u003ca href=\"https://discord.com/invite/SJexsCG\"\u003e\u003cimg src=\"https://img.shields.io/discord/498978399801573396.svg?label=\u0026logo=discord\u0026logoColor=ffffff\u0026color=7389D8\u0026labelColor=6A7EC2\" alt=\"join our chat\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n \n\u003c/div\u003e\n\n## 📦 Installation \u0026 Usage\n\nWith Apiker, you can create an API in only 3 lines of code\n```js\nimport { apiker, res } from \"apiker\";\nconst routes = { \"/users/:id/hello\": () =\u003e res(\"Hello World!\") };\n\napiker.init({ routes, exports, objects: [\"Common\"] });\n\n```\n\u003e ➡️ GET /users/my-user/hello\n```\n{ \"message\": \"Hello World!\" }\n```\n\nCheck out the **[Getting Started](https://hodgef.com/apiker/)** page to begin.\n\n\nNote: To run Apiker, you need a Cloudflare account with [Durable Objects access](https://developers.cloudflare.com/workers/platform/pricing#durable-objects).\n\n\n## ⭐ Features\n\n- 📕 Routing and State management\n- 🔑 Auth, JWT-based (Register, Login, Refresh token, Delete user, Forgot user, Verify user email)\n- ✅ OAuth handlers (GitHub)\n- ⚡️Automatically updates [Durable Object](https://developers.cloudflare.com/workers/learning/using-durable-objects) migrations, classes and bindings so you don't have to.\n- 🛑 Rate Limiting / Flooding mitigation\n- 🛡️ Firewall support (IP bans with Cloudflare Firewall)\n- 📧 Email support (with [Brevo](https://www.brevo.com/products/transactional-email/))\n- ⚙️ Simple Admin panel\n- 👤 Geolocation handlers\n- 📝 Logging handlers\n\n## 📕 Examples\n\n### 1. Route example\n```js\nimport { res, res_400 } from \"apiker\";\n\nexport const myRouteHandler = async ({\n  request, // https://developers.cloudflare.com/workers/runtime-apis/request/\n  body, // The body of your request, such as form params or plaintext, depending on request content-type\n  headers, // Request headers. Response headers are located at `apiker.responseHeaders`\n  matches, // Your query params and route parts\n  state // The state method used to interact with permanent storage (check the examples below \u0026 docs for more info)\n}) =\u003e {\n  // If we want to allow POST only, we explicitly check for it :\n  if(request.method !== \"POST\"){\n     // returns 400 Bad Request error. You can also use `res(\"Invalid Method\", 405)`\n     // https://github.com/hodgef/apiker/blob/master/src/components/Response/Response.ts#L10\n     return res_400();\n  }\n\n  // We'll return the request body passed, for example POST form parameters\n  // `res` and `res_000` functions respond with JSON. To respond with raw text you can use `resRaw`\n  // https://github.com/hodgef/apiker/blob/master/src/components/Response/Response.ts#L23\n  return res({ body });\n};\n```\n```js\nconst routes = {\n  \"/users/myroute\": myRouteHandler\n};\n```\nDiscuss: https://github.com/hodgef/apiker/issues/133\n\n### 2. State: Save value to `Common` object (shared by all visitors)\n```js\nimport { res } from \"apiker\";\n\nexport const example1_saveValueCommon = async ({ state }) =\u003e {\n  // Using `state` with no parameters will default to the Common object\n  const count = ((await state().get(\"count\")) || 0) + 1;\n  await state().put({ count });\n  return res({ count });\n};\n```\n\u003e ➡️ GET /example1\n```\n{ \"count\": 1 }\n```\n[View Source](https://github.com/hodgef/apiker-examples/blob/master/src/controllers/example1_saveValueCommon.ts) | [View Demo](https://apiker-examples.volted.co/example1)\n\n### 3. State: Save value to a different object, and use one object instance per visitor\n```js\nimport { res } from \"apiker\";\n\nexport const example2_saveValueDiffObject = async ({ state }) =\u003e {\n  const count = (await state(\"Example2\").get(\"count\") || 0) + 1;\n  await state(\"Example2\").put({ count });\n  return res({ count });\n};\n\n// In index.js ...\napiker.init({\n ...\n objectStateMapping: {\n    // One object instance per user IP\n    Example2: OBMT.SIGNEDIP\n  }\n});\n```\n\u003e ➡️ GET /example2\n```\n{ \"count\": 1 }\n```\n[View Source](https://github.com/hodgef/apiker-examples/blob/master/src/controllers/example2_saveValueDiffObject.ts) | [View Demo](https://apiker-examples.volted.co/example2)\n\n### 4. State: Use one object instance per route parameter value\n```js\nimport { res } from \"apiker\";\n\nexport const example3_instancePerRouteParam = async ({ state, matches }) =\u003e {\n  // Get username from route (/example3/:username)\n  const username = matches.params.username;\n  const acceptedUsernames = [\"bob\", \"rob\", \"todd\"];\n\n  if (acceptedUsernames.includes(username)) {\n    const { name = username, count = 0 } = (await state(\"Example3\").get(\"username\")) || {};\n    const payload = {\n      username: {\n        name,\n        count: count + 1\n      }\n    };\n\n    await state(\"Example3\").put(payload);\n    return res(payload);\n  } else {\n    return res({ acceptedUsernames });\n  }\n};\n\n\n// In index.js ...\napiker.init({\n ...\n objectStateMapping: {\n    // Mapped to the parameter `username` in the route\n    Example3: \"username\"\n  }\n});\n```\n\u003e ➡️ GET /example3/bob\n```\n{\n    \"username\": {\n        \"name\": \"bob\",\n        \"count\": 1\n    }\n}\n```\n[View Source](https://github.com/hodgef/apiker-examples/blob/master/src/controllers/example3_instancePerRouteParam.ts) | [View Demo](https://apiker-examples.volted.co/example3/bob)\n\n\u003e For more details and examples, check out the **[Documentation](https://hodgef.com/apiker/)**.\n\n## ✅ Contributing \n\nPRs and issues are welcome. Feel free to submit any issues you have at:\n[https://github.com/hodgef/Apiker/issues](https://github.com/hodgef/Apiker/issues)\n\n### Questions? Join the chat\n\n\u003ca href=\"https://discordapp.com/invite/SJexsCG\" title=\"Join our Discord chat\" target=\"_blank\"\u003e\u003cimg src=\"https://discordapp.com/api/guilds/498978399801573396/widget.png?style=banner2\" align=\"center\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhodgef%2Fapiker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhodgef%2Fapiker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhodgef%2Fapiker/lists"}