{"id":36213157,"url":"https://github.com/k-arindam/shelf_essentials","last_synced_at":"2026-01-13T22:01:04.451Z","repository":{"id":330026113,"uuid":"1120339586","full_name":"k-arindam/shelf_essentials","owner":"k-arindam","description":"Essential utilities and middleware for building web servers with Shelf in Dart and Flutter.","archived":false,"fork":false,"pushed_at":"2025-12-22T21:45:08.000Z","size":217,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-11T10:16:19.037Z","etag":null,"topics":["backend","dart","flutter","shelf","web-server"],"latest_commit_sha":null,"homepage":"https://karindam.in/shelf_essentials/","language":"Dart","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/k-arindam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["k-arindam"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-12-21T01:55:37.000Z","updated_at":"2025-12-22T21:54:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/k-arindam/shelf_essentials","commit_stats":null,"previous_names":["k-arindam/shelf_essentials"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/k-arindam/shelf_essentials","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k-arindam%2Fshelf_essentials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k-arindam%2Fshelf_essentials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k-arindam%2Fshelf_essentials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k-arindam%2Fshelf_essentials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k-arindam","download_url":"https://codeload.github.com/k-arindam/shelf_essentials/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k-arindam%2Fshelf_essentials/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28400397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["backend","dart","flutter","shelf","web-server"],"created_at":"2026-01-11T04:05:43.991Z","updated_at":"2026-01-13T22:01:04.425Z","avatar_url":"https://github.com/k-arindam.png","language":"Dart","funding_links":["https://github.com/sponsors/k-arindam"],"categories":[],"sub_categories":[],"readme":"# shelf_essentials\n\n![license](https://img.shields.io/github/license/k-arindam/shelf_essentials)\n![dart](https://img.shields.io/badge/Dart-3%2B-blue)\n\n**Essential utilities for building HTTP servers with `shelf`.**\n\n`shelf_essentials` provides commonly needed extensions and helpers for:\n- Reading request bodies\n- Parsing JSON requests\n- Handling multipart form data\n- Working with HTTP methods safely\n\nDesigned to be **lightweight**, **idiomatic**, and **shelf-native**.\n\n---\n\n## Features\n\n- 🔌 `Request` extensions for body, JSON, and form data\n- 📦 Multipart form parsing with fields \u0026 files\n- 🧭 Type-safe HTTP method enum\n- 🧱 Zero framework lock-in\n- ⚡ Minimal dependencies\n\n---\n\n## Installation\n\nAdd this to your `pubspec.yaml`:\n\n```yaml\ndependencies:\n  shelf_essentials: ^1.0.0\n```\n\nThen run:\n\n```bash\ndart pub get\n```\n\n---\n\n## Usage\n\n### Import\n\n```dart\nimport 'package:shelf_essentials/shelf_essentials.dart';\n```\n\n---\n\n## Request Extensions\n\n### Read Request Body\n\n```dart\nfinal body = await request.body();\n```\n\n---\n\n### Parse JSON Body\n\n```dart\nfinal data = await request.json();\n\nprint(data['email']);\n```\n\n\u003e The returned value can be a `Map`, `List`, `String`, `num`, or `bool`.\n\n---\n\n### Access HTTP Method Safely\n\n```dart\nswitch (request.httpMethod) {\n  case HttpMethod.get:\n    return Response.ok('GET request');\n  case HttpMethod.post:\n    return Response.ok('POST request');\n  default:\n    return Response.notFound('Unsupported method');\n}\n```\n\n---\n\n## Form Data Handling\n\n### Parse Multipart Form Data\n\n```dart\nfinal form = await request.formData();\n```\n\n---\n\n### Access Fields\n\n```dart\nfinal username = form.fields['username'];\nfinal email = form.fields['email'];\n```\n\n---\n\n### Access Uploaded Files\n\n```dart\nfinal avatar = form.files['avatar'];\n\nif (avatar != null) {\n  final bytes = await avatar.readAsBytes();\n  print('Uploaded file: ${avatar.name}');\n}\n```\n\n---\n\n## CORS Headers\n\n### Enable CORS for All Origins\n\nAdd CORS headers to all responses with default settings:\n\n```dart\nfinal handler = Pipeline()\n  .addMiddleware(corsHeaders())\n  .addHandler((request) =\u003e Response.ok('Hello'));\n```\n\n---\n\n### Restrict CORS to Specific Origins\n\nAllow CORS only from specific origins:\n\n```dart\nfinal handler = Pipeline()\n  .addMiddleware(corsHeaders(\n    originChecker: originOneOf(['https://example.com', 'https://app.example.com']),\n  ))\n  .addHandler((request) =\u003e Response.ok('Hello'));\n```\n\n---\n\n### Add Custom Headers\n\nInclude additional custom headers in CORS responses:\n\n```dart\nfinal handler = Pipeline()\n  .addMiddleware(corsHeaders(\n    addedHeaders: {\n      'X-Custom-Header': 'custom-value',\n      'Access-Control-Allow-Credentials': 'true',\n    },\n    originChecker: originOneOf(['https://example.com']),\n  ))\n  .addHandler((request) =\u003e Response.ok('Hello'));\n```\n\n---\n\n### CORS Defaults\n\nWhen using `corsHeaders` middleware, the following defaults are applied:\n\n- **Allowed Methods**: DELETE, GET, OPTIONS, PATCH, POST, PUT\n- **Allowed Headers**: accept, accept-encoding, authorization, content-type, dnt, origin, user-agent\n- **Credentials**: true\n- **Max-Age**: 86400 seconds (24 hours)\n\n---\n\n## UploadedFile\n\nEach uploaded file provides:\n\n```dart\nfinal name = file.name;\nfinal contentType = file.contentType;\nfinal bytes = await file.readAsBytes();\n```\n\n⚠️ **Note:**  \nFile streams are **single-use**. Call either `readAsBytes()` **or** `openRead()` once.\n\n---\n\n### API Overview\n\n| Feature | Description |\n|---------|------------|\n| **Request Extensions** | Methods to read body, parse JSON, handle forms, access HTTP method |\n| **CORS Middleware** | Add CORS headers with origin validation |\n| **Form Data Parsing** | Support for URL-encoded and multipart form data |\n| **Uploaded Files** | Access file name, content-type, and read contents |\n| **HTTP Methods** | Type-safe enum for common HTTP methods |\n\n---\n\n#### RequestExtension Methods\n\n| Method | Returns | Description |\n|--------|---------|------------|\n| `body()` | `Future\u003cString\u003e` | Reads request body as String |\n| `json()` | `Future\u003cdynamic\u003e` | Parses body as JSON (Map, List, String, num, bool) |\n| `formData()` | `Future\u003cFormData\u003e` | Parses multipart or URL-encoded form data |\n| `httpMethod` | `HttpMethod` | Type-safe HTTP method enum |\n| `connectionInfo` | `HttpConnectionInfo?` | Socket connection information |\n\n---\n\n#### CORS Functions\n\n| Function | Description |\n|----------|------------|\n| `corsHeaders()` | Middleware to add CORS headers to responses |\n| `originAllowAll()` | Origin checker that allows all origins |\n| `originOneOf()` | Origin checker that allows specific origins |\n\n---\n\n## Example Shelf Server\n\n```dart\nimport 'package:shelf/shelf.dart';\nimport 'package:shelf/shelf_io.dart';\nimport 'package:shelf_essentials/shelf_essentials.dart';\n\nvoid main() async {\n  final handler = (Request request) async {\n    if (request.httpMethod == HttpMethod.post) {\n      final data = await request.json();\n      return Response.ok('Hello ${data['name']}');\n    }\n    return Response.ok('Send a POST request');\n  };\n\n  await serve(handler, 'localhost', 8080);\n  print('Server running on http://localhost:8080');\n}\n```\n\n---\n\n## Design Goals\n\n- ✅ Minimal surface area\n- ✅ Idiomatic Dart\n- ✅ Shelf-first\n- ✅ No hidden magic\n- ✅ Easy to extend\n\n---\n\n## Roadmap\n\n- Content-Type validation helpers\n- Typed JSON parsing utilities\n- Streaming file size helpers\n- Improved error handling\n- Middleware utilities\n\n---\n\n## Contributing\n\nContributions are welcome!\n\n- Open an issue for bugs or feature requests\n- Submit a PR with clear description and tests\n- Keep APIs simple and shelf-compatible\n\n---\n\n## License\n\nMIT License © 2025  \nUse it freely in open-source and commercial projects.\n\n---\n\n## Acknowledgements\n\n- Inspired by the simplicity of the [`shelf`](https://pub.dev/packages/shelf) package\n- Special thanks to [`dart-frog`](https://dart-frog.dev)\n- Special thanks to [`shelf-cors-headers`](https://github.com/lenniezelk/shelf-cors-headers)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk-arindam%2Fshelf_essentials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk-arindam%2Fshelf_essentials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk-arindam%2Fshelf_essentials/lists"}