{"id":40968898,"url":"https://github.com/arferreira/rapina","last_synced_at":"2026-02-27T23:46:49.030Z","repository":{"id":333776083,"uuid":"1134697920","full_name":"arferreira/rapina","owner":"arferreira","description":"An opinionated Rust web framework exploring better DX in an AI-assisted world","archived":false,"fork":false,"pushed_at":"2026-01-22T05:08:04.000Z","size":375,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-22T18:55:59.408Z","etag":null,"topics":["api","async","fastapi","http","hyper","rest-api","rust","tokio","web-framework"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/arferreira.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-15T04:26:05.000Z","updated_at":"2026-01-22T15:38:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/arferreira/rapina","commit_stats":null,"previous_names":["arferreira/rapina"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/arferreira/rapina","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arferreira%2Frapina","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arferreira%2Frapina/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arferreira%2Frapina/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arferreira%2Frapina/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arferreira","download_url":"https://codeload.github.com/arferreira/rapina/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arferreira%2Frapina/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28880841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T10:31:27.438Z","status":"ssl_error","status_checked_at":"2026-01-29T10:31:01.017Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["api","async","fastapi","http","hyper","rest-api","rust","tokio","web-framework"],"created_at":"2026-01-22T06:31:14.595Z","updated_at":"2026-02-27T23:46:49.018Z","avatar_url":"https://github.com/arferreira.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/static/images/logo.png\" alt=\"Rapina\" width=\"120\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eRapina\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA Rust web framework for APIs. So simple it feels like cheating.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://crates.io/crates/rapina\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/rapina.svg\" alt=\"Crates.io\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://docs.rs/rapina\"\u003e\u003cimg src=\"https://docs.rs/rapina/badge.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/arferreira/rapina/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/arferreira/rapina/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://discord.gg/Z4ww64YBQj\"\u003e\u003cimg src=\"https://img.shields.io/badge/Discord-Join-5865F2?logo=discord\u0026logoColor=white\" alt=\"Discord\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n```rust\nuse rapina::prelude::*;\n\n#[get(\"/users\")]\nasync fn list_users(db: Db) -\u003e Result\u003cJson\u003cVec\u003cUser\u003e\u003e\u003e {\n    let users = User::find_all(db.conn()).await?;\n    Ok(Json(users))\n}\n\n#[post(\"/users\")]\nasync fn create_user(input: Validated\u003cJson\u003cCreateUser\u003e\u003e, db: Db) -\u003e Result\u003cJson\u003cUser\u003e\u003e {\n    let user = User::create(db.conn(), input.into_inner()).await?;\n    Ok(Json(user))\n}\n\n#[tokio::main]\nasync fn main() -\u003e std::io::Result\u003c()\u003e {\n    Rapina::new()\n        .discover()\n        .listen(\"127.0.0.1:3000\")\n        .await\n}\n```\n\nNo router configuration. No manual wiring. Annotate your handlers, call `.discover()`, ship.\n\n## Get started\n\n```bash\ncargo install rapina-cli\nrapina new my-app\ncd my-app\nrapina dev\n```\n\nYour API is running. That's it.\n\n## What you get\n\n**Auto-discovery** — annotate handlers with `#[get]`, `#[post]`, `#[put]`, `#[delete]`. Rapina finds them at startup. Your `main.rs` stays three lines.\n\n**Database from day one** — define your schema declaratively. `author: User` becomes a foreign key. `posts: Vec\u003cPost\u003e` becomes a relationship. SeaORM entities are auto-generated.\n\n```rust\nschema! {\n    User {\n        name: String,\n        email: String,\n        posts: Vec\u003cPost\u003e\n    }\n\n    Post {\n        title: String,\n        body: String,\n        author: User\n    }\n}\n```\n\n**Auth that works** — JWT authentication, protected by default. Mark public routes with `#[public]`. Access the current user with the `CurrentUser` extractor.\n\n```rust\n#[public]\n#[post(\"/login\")]\nasync fn login(body: Json\u003cLoginRequest\u003e, auth: State\u003cAuthConfig\u003e) -\u003e Result\u003cJson\u003cTokenResponse\u003e\u003e {\n    let token = auth.create_token(\u0026body.username)?;\n    Ok(Json(TokenResponse::new(token, auth.expiration())))\n}\n\n#[get(\"/me\")]\nasync fn me(user: CurrentUser) -\u003e Json\u003cUserResponse\u003e {\n    Json(UserResponse { id: user.id })\n}\n```\n\n**CRUD in one command** — scaffold an entire resource with handlers, DTOs, errors, schema, and migration.\n\n```bash\nrapina add resource Post\n```\n\n**OpenAPI built-in** — spec generation, breaking change detection, and validation from the CLI.\n\n```bash\nrapina openapi export -o openapi.json\nrapina openapi diff --base main\n```\n\n**Production middleware** — rate limiting, compression, CORS, and Prometheus metrics out of the box.\n\n```rust\nRapina::new()\n    .with_rate_limit(RateLimitConfig::per_minute(100))\n    .with_compression(CompressionConfig::default())\n    .with_cors(CorsConfig::permissive())\n    .discover()\n    .listen(\"0.0.0.0:3000\")\n    .await\n```\n\n**CLI for everything** — create, develop, test, inspect, generate.\n\n```bash\nrapina new my-app              # Scaffold a new project\nrapina dev                     # Dev server with hot reload\nrapina test --coverage         # Tests with coverage report\nrapina test --watch            # Watch mode\nrapina routes                  # List all routes\nrapina doctor                  # Health checks and diagnostics\nrapina migrate new             # Create a migration\nrapina add resource Post       # Full CRUD scaffolding\n```\n\n## 10 extractors\n\nEverything you need to pick apart a request, type-safe and compile-time checked.\n\n`Json\u003cT\u003e` · `Form\u003cT\u003e` · `Path\u003cT\u003e` · `Query\u003cT\u003e` · `Headers` · `Cookie\u003cT\u003e` · `State\u003cT\u003e` · `Validated\u003cT\u003e` · `CurrentUser` · `Db`\n\n## Standardized errors\n\nEvery error includes a `trace_id`. No more guessing in production.\n\n```json\n{\n  \"error\": { \"code\": \"NOT_FOUND\", \"message\": \"user not found\" },\n  \"trace_id\": \"550e8400-e29b-41d4-a716-446655440000\"\n}\n```\n\n## Project status\n\nRapina is in active development. We ship fast and we ship often — 9 releases since January 2026. The API is stabilizing but breaking changes may still occur before `1.0.0`.\n\nSee the [roadmap](https://userapina.com/roadmap/) for what's coming next.\n\n## Documentation\n\nFull documentation at [userapina.com](https://userapina.com/)\n\n- [Getting Started](https://userapina.com/guide/getting-started/)\n- [Database](https://userapina.com/guide/database/)\n- [Authentication](https://userapina.com/guide/authentication/)\n- [CLI Reference](https://userapina.com/cli/)\n\n## Contributing\n\nContributions are welcome. Check out the [open issues](https://github.com/arferreira/rapina/issues) or join us on [Discord](https://discord.gg/Z4ww64YBQj).\n\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farferreira%2Frapina","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farferreira%2Frapina","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farferreira%2Frapina/lists"}