{"id":29828074,"url":"https://github.com/ditzdev/rakta","last_synced_at":"2025-10-10T20:33:31.771Z","repository":{"id":304697687,"uuid":"1019653401","full_name":"DitzDev/Rakta","owner":"DitzDev","description":"Express.js Like, Powerful, Fast, and Minimalist web Framework for Nim. Focus on your Backend.","archived":false,"fork":false,"pushed_at":"2025-07-20T12:08:35.000Z","size":849,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-29T07:37:48.381Z","etag":null,"topics":["nim","web-framework"],"latest_commit_sha":null,"homepage":"","language":"Nim","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/DitzDev.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,"zenodo":null}},"created_at":"2025-07-14T16:55:56.000Z","updated_at":"2025-07-24T14:55:48.000Z","dependencies_parsed_at":"2025-07-14T21:35:02.398Z","dependency_job_id":"f92628d4-2d0f-4867-8d15-f1e70ebd7a0b","html_url":"https://github.com/DitzDev/Rakta","commit_stats":null,"previous_names":["ditzdev/rakta"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/DitzDev/Rakta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DitzDev%2FRakta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DitzDev%2FRakta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DitzDev%2FRakta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DitzDev%2FRakta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DitzDev","download_url":"https://codeload.github.com/DitzDev/Rakta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DitzDev%2FRakta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005272,"owners_count":26083863,"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","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["nim","web-framework"],"created_at":"2025-07-29T07:16:11.423Z","updated_at":"2025-10-10T20:33:31.741Z","avatar_url":"https://github.com/DitzDev.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\r\n  \u003cimg src=\"assets/rakta_logo.png\" alt=\"Rakta Logo\" height=\"100\"\u003e\r\n\u003c/p\u003e\r\n\r\n\u003ch1 align=\"center\"\u003eRakta\u003c/h1\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003cb\u003eExpress.js like, Powerful, Fast, and Minimalist Web Framework for Nim\u003c/b\u003e  \r\n  \u003cbr\u003e\r\n  \u003ci\u003eFocus on your backend.\u003c/i\u003e\r\n\u003c/p\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003ca href=\"https://github.com/DitzDev/Rakta/blob/main/LICENSE\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/github/license/DitzDev/rakta?color=blue\" alt=\"License\"\u003e\r\n  \u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n## Features\r\n\r\n- **Fast \u0026 Efficient**: Built with Nim's performance in mind\r\n- **Minimalist Design**: Clean API with essential features\r\n- **Middleware Support**: Flexible middleware system\r\n- **Static File Serving**: Built-in static file serving with caching\r\n- **CORS Support**: Easy cross-origin resource sharing setup\r\n- **Route Parameters**: Support for dynamic route parameters\r\n- **JSON Support**: Built-in JSON request/response handling\r\n- **Cookie Management**: Easy cookie setting and retrieval\r\n- **File Upload**: Support for file uploads and downloads\r\n- **WebSocket (Experimental, need zlib)**: Rakta supports native WebSocket without any third-party dependencies.\r\n- **Frontend Hot-Reload (Experimental, Need to refresh browser to see changes)**: Simplify the development process.\r\n\r\n## Installation\r\n1. Add `Rakta` to your .nimble file:\r\n```bash\r\nnimble add Rakta\r\n```\r\n\r\n2. Install Rakta:\r\n```bash\r\nnimble install Rakta\r\n```\r\n\r\n## Quick Start\r\n\r\n```nim\r\nimport asyncdispatch, json\r\nimport Rakta\r\n\r\nlet app = newApp()\r\n\r\n# Add CORS middleware\r\napp.use(corsMiddleware())\r\n\r\n# Serve static files\r\napp.use(app.serveStatic(\"public\"))\r\n\r\n# Basic route\r\napp.get(\"/\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.send(\"Hello, Rakta!\")\r\n)\r\n\r\n# JSON API endpoint\r\napp.get(\"/api/status\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.json(%*{\r\n    \"status\": \"success\",\r\n    \"framework\": \"Rakta\",\r\n    \"version\": \"0.1.0\"\r\n  })\r\n)\r\n\r\n# Route with parameters\r\napp.get(\"/users/:id\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userId = ctx.getParam(\"id\")\r\n  await ctx.json(%*{\r\n    \"userId\": userId,\r\n    \"name\": \"User \" \u0026 userId\r\n  })\r\n)\r\n\r\n# Start server\r\nwaitFor app.listen(3000, proc() =\r\n  echo \"🚀 Server running at http://localhost:3000\"\r\n)\r\n```\r\n\r\n## Documentation\r\n\r\n### Application Setup\r\n\r\n#### Creating an App\r\n\r\n```nim\r\nlet app = newApp()\r\n```\r\n\r\nCreates a new Rakta application instance with default configuration.\r\n\r\n#### Starting the Server\r\n\r\n```nim\r\nwaitFor app.listen(3000, proc() =\r\n  echo \"Server started on port 3000\"\r\n)\r\n```\r\n\r\nStarts the HTTP server on the specified port with an optional callback.\r\n\r\n### Routing\r\n\r\n#### Basic Routes\r\n\r\n```nim\r\n# GET route\r\napp.get(\"/\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.send(\"Hello World\")\r\n)\r\n\r\n# POST route\r\napp.post(\"/api/users\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userData = ctx.jsonBody()\r\n  await ctx.json(%*{\"created\": userData})\r\n)\r\n\r\n# PUT route\r\napp.put(\"/api/users/:id\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userId = ctx.getParam(\"id\")\r\n  let userData = ctx.jsonBody()\r\n  await ctx.json(%*{\"updated\": userId, \"data\": userData})\r\n)\r\n\r\n# DELETE route\r\napp.delete(\"/api/users/:id\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userId = ctx.getParam(\"id\")\r\n  await ctx.json(%*{\"deleted\": userId})\r\n)\r\n```\r\n\r\n#### Route Parameters\r\n\r\n```nim\r\n# Single parameter\r\napp.get(\"/users/:id\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userId = ctx.getParam(\"id\")\r\n  await ctx.json(%*{\"userId\": userId})\r\n)\r\n\r\n# Multiple parameters\r\napp.get(\"/posts/:category/:slug\", proc(ctx: Context): Future[void] {.async.} =\r\n  let category = ctx.getParam(\"category\")\r\n  let slug = ctx.getParam(\"slug\")\r\n  await ctx.json(%*{\"category\": category, \"slug\": slug})\r\n)\r\n```\r\n\r\n### Middleware\r\n\r\n#### Using Middleware\r\n\r\n```nim\r\n# Built-in CORS middleware\r\napp.use(corsMiddleware())\r\n\r\n# Custom middleware\r\napp.use(proc(ctx: Context): Future[void] {.async.} =\r\n  echo \"Request to \", ctx.req.path\r\n  await ctx.next()\r\n)\r\n\r\n# Static file serving\r\napp.use(app.serveStatic(\"public\"))\r\n```\r\n\r\n#### CORS Configuration\r\n\r\n```nim\r\n# Allow all origins\r\napp.use(corsMiddleware())\r\n\r\n# Allow specific origin\r\napp.use(corsMiddleware(\"https://myapp.com\"))\r\n\r\n# Custom configuration\r\napp.use(corsMiddleware(\r\n  allowOrigin = \"https://myapp.com\",\r\n  allowMethods = \"GET,POST,PUT,DELETE\",\r\n  allowHeaders = \"Content-Type,Authorization\"\r\n))\r\n```\r\n\r\n### Request Handling\r\n\r\n#### Query Parameters\r\n\r\n```nim\r\napp.get(\"/search\", proc(ctx: Context): Future[void] {.async.} =\r\n  let query = ctx.getQuery(\"q\")\r\n  let page = ctx.getQuery(\"page\")\r\n  await ctx.json(%*{\"query\": query, \"page\": page})\r\n)\r\n```\r\n\r\n#### JSON Request Body\r\n\r\n```nim\r\napp.post(\"/api/data\", proc(ctx: Context): Future[void] {.async.} =\r\n  let jsonData = ctx.jsonBody()\r\n  await ctx.json(%*{\"received\": jsonData})\r\n)\r\n```\r\n\r\n#### Cookies\r\n\r\n```nim\r\n# Set cookie\r\napp.get(\"/login\", proc(ctx: Context): Future[void] {.async.} =\r\n  discard ctx.setCookie(\"session\", \"abc123\", httpOnly = true)\r\n  await ctx.json(%*{\"message\": \"Logged in\"})\r\n)\r\n\r\n# Get cookie\r\napp.get(\"/profile\", proc(ctx: Context): Future[void] {.async.} =\r\n  let sessionId = ctx.getCookie(\"session\")\r\n  if sessionId != \"\":\r\n    await ctx.json(%*{\"sessionId\": sessionId})\r\n  else:\r\n    await ctx.json(%*{\"error\": \"Not authenticated\"})\r\n)\r\n```\r\n\r\n### Response Handling\r\n\r\n#### Plain Text Response\r\n\r\n```nim\r\napp.get(\"/text\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.send(\"Plain text response\")\r\n)\r\n```\r\n\r\n#### JSON Response\r\n\r\n```nim\r\napp.get(\"/json\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.json(%*{\"message\": \"JSON response\"})\r\n)\r\n```\r\n\r\n#### Custom Headers\r\n\r\n```nim\r\napp.get(\"/custom\", proc(ctx: Context): Future[void] {.async.} =\r\n  discard ctx.setHeader(\"X-Custom-Header\", \"Custom Value\")\r\n  await ctx.send(\"Response with custom header\")\r\n)\r\n```\r\n\r\n#### Status Codes\r\n\r\n```nim\r\napp.get(\"/error\", proc(ctx: Context): Future[void] {.async.} =\r\n  discard ctx.status(Http400)\r\n  await ctx.json(%*{\"error\": \"Bad Request\"})\r\n)\r\n```\r\n\r\n### File Handling\r\n\r\n#### Serving Files\r\n\r\n```nim\r\n# Basic file serving\r\napp.get(\"/download\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.sendFile(\"files/document.pdf\")\r\n)\r\n\r\n# With custom headers\r\napp.get(\"/download/pdf\", proc(ctx: Context): Future[void] {.async.} =\r\n  let headers = {\r\n    \"Content-Disposition\": \"attachment; filename=document.pdf\"\r\n  }.toTable()\r\n  await ctx.sendFile(\"files/document.pdf\", headers)\r\n)\r\n```\r\n\r\n#### Static Files\r\n\r\n```nim\r\n# Serve from public directory\r\napp.use(app.serveStatic(\"public\"))\r\n\r\n# Serve with URL prefix\r\napp.use(app.serveStatic(\"assets\", \"/static\"))\r\n```\r\n\r\n### Error Handling\r\n\r\n```nim\r\napp.get(\"/api/error\", proc(ctx: Context): Future[void] {.async.} =\r\n  try:\r\n    # Some operation that might fail\r\n    raise newException(ValueError, \"Something went wrong\")\r\n  except ValueError as e:\r\n    discard ctx.status(Http400)\r\n    await ctx.json(%*{\"error\": e.msg})\r\n)\r\n```\r\n\r\n## API Reference\r\n\r\n### App Methods\r\n\r\n- `newApp()`: Creates a new application instance\r\n- `get(pattern, handler)`: Registers GET route\r\n- `post(pattern, handler)`: Registers POST route\r\n- `put(pattern, handler)`: Registers PUT route\r\n- `delete(pattern, handler)`: Registers DELETE route\r\n- `use(middleware)`: Adds middleware\r\n- `serveStatic(dir, prefix)`: Creates static file middleware\r\n- `listen(port, callback)`: Starts the server\r\n\r\n### Context Methods\r\n\r\n- `getParam(name)`: Gets route parameter value\r\n- `getQuery(name)`: Gets query parameter value\r\n- `getCookie(name)`: Gets cookie value\r\n- `jsonBody()`: Parses request body as JSON\r\n- `send(content)`: Sends plain text response\r\n- `json(data)`: Sends JSON response\r\n- `sendFile(path, options)`: Sends file response\r\n- `status(code)`: Sets response status code\r\n- `setHeader(name, value)`: Sets response header\r\n- `setCookie(name, value, options)`: Sets cookie\r\n- `next()`: Continues to next middleware\r\n\r\n### Middleware\r\n\r\n- `corsMiddleware(origin, methods, headers)`: CORS middleware\r\n- `serveStatic(dir, prefix)`: Static file serving middleware\r\n\r\n## Examples\r\n\r\n### Complete API Server\r\n\r\n```nim\r\nimport asyncdispatch, json, os, times, tables\r\nimport Rakta\r\n\r\nlet app = newApp()\r\n\r\n# Middleware\r\napp.use(corsMiddleware())\r\napp.use(app.serveStatic(\"public\"))\r\n\r\n# Logging middleware\r\napp.use(proc(ctx: Context): Future[void] {.async.} =\r\n  echo \"Incoming request to \", ctx.req.path\r\n  await ctx.next()\r\n)\r\n\r\n# API routes\r\napp.get(\"/api/status\", proc(ctx: Context): Future[void] {.async.} =\r\n  await ctx.json(%*{\r\n    \"status\": \"success\",\r\n    \"framework\": \"Rakta\",\r\n    \"version\": \"0.1.0\",\r\n    \"timestamp\": $now()\r\n  })\r\n)\r\n\r\napp.get(\"/api/users/:id\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userId = ctx.getParam(\"id\")\r\n  await ctx.json(%*{\r\n    \"userId\": userId,\r\n    \"name\": \"User \" \u0026 userId,\r\n    \"email\": \"user\" \u0026 userId \u0026 \"@example.com\"\r\n  })\r\n)\r\n\r\napp.post(\"/api/users\", proc(ctx: Context): Future[void] {.async.} =\r\n  let userData = ctx.jsonBody()\r\n  await ctx.json(%*{\r\n    \"created\": userData,\r\n    \"id\": \"new-user-id\",\r\n    \"timestamp\": $now()\r\n  })\r\n)\r\n\r\n# File operations\r\napp.get(\"/download/:file\", proc(ctx: Context): Future[void] {.async.} =\r\n  let filename = ctx.getParam(\"file\")\r\n  await ctx.sendFile(\"files/\" \u0026 filename)\r\n)\r\n\r\n# Error handling\r\napp.get(\"/api/error\", proc(ctx: Context): Future[void] {.async.} =\r\n  discard ctx.status(Http400)\r\n  await ctx.json(%*{\r\n    \"error\": \"This is a demo error\",\r\n    \"code\": 400\r\n  })\r\n)\r\n\r\n# Start server\r\nwaitFor app.listen(3000, proc() =\r\n  echo \"🚀 Rakta Framework Server running at http://localhost:3000\"\r\n)\r\n```\r\n\r\n## Contributing\r\n\r\nContributions are welcome! Please feel free to submit a Pull Request.\r\n\r\n## License\r\n```\r\nMIT License\r\n\r\nCopyright (c) 2025 DitzDev\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fditzdev%2Frakta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fditzdev%2Frakta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fditzdev%2Frakta/lists"}